diff --git a/README.md b/README.md new file mode 100644 index 0000000..08b101d --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# tarinai v39.15.39 + +## 変更点 + +- PC表示を再度ロールバックし、PC側の変更はクイックスクロールの「本体」「道具」ボタン非表示に限定。道具UI本体は維持。 +- PC上部ボタンを右詰め・やや大きめに調整し、ゲームタイトルがボタンに押されて省略されないように修正。 +- スマホ用のスクロールスナップ系指定を無効化し、通常スクロールを妨げないように修正。 +- スマホで「家系図」へ移動したとき、更新OFFでも手動ジャンプ扱いで現在の家系図を描画してからスクロールするように修正。 +- スマホの自動スクロールボタンは、初期折り畳み部分を開いてから目的地へ移動。ユーザーが手動で閉じた部分は開かない挙動を維持。 +- たりない/道具系ツールチップの最大幅・折り返し・画面端補正を維持。 +- 「333の部屋に移動」のリンク先は `https://2012r2.nishi.boats/~333/`。 +- 「観察」は「たりないデータ」の表記を維持。 + +## 確認 + +- `node --check js/*.js` passed +- `python3 scripts/regression_check.py` passed +- version synchronized: `39.15.39` diff --git a/SENSOR_IDEAS.md b/SENSOR_IDEAS.md new file mode 100644 index 0000000..59d2b36 --- /dev/null +++ b/SENSOR_IDEAS.md @@ -0,0 +1,43 @@ +# センサー系アイデア + +実験観察ゲームとして、直接介入ではなく「測る」ための道具案。 + +## 低コストで入れやすいもの + +| センサー | 役割 | 記録する値 | 観察上の使い道 | +|---|---|---|---| +| ストレスセンサー | 範囲内の緊張度を測る | 平均ストレス / 最大ストレス / 急上昇回数 | 地形・混雑・病気・王者個体の影響を見る | +| 通過カウンター | 置いた地点を通った回数を数える | 通過数 / 個体別通過数 | 道・縄張り・回避行動の発見 | +| 滞在センサー | 範囲内にいた時間を測る | 滞在秒数 / 個体ID / 世代 | 好まれる場所・避けられる場所の比較 | +| けんかセンサー | 範囲内の争いを記録 | 勝者 / 敗者 / 勝率変化 | 王者候補・危険地帯の検出 | +| 汚染センサー | ずんち・病気・汚れを見る | 汚染量 / 増加量 / 感染者数 | スプリンクラーや隔離の効果検証 | +| 出生センサー | 近くで生まれた個体を記録 | 親 / 子 / 遺伝値 | 繁殖条件・血統観察 | + +## 中コストのセンサー + +| センサー | 仕様 | +|---|---| +| 個体追跡ビーコン | 特定個体に付ける。移動経路、接触相手、食事、喧嘩、睡眠を時系列で記録する。 | +| 関係センサー | 範囲内で友好・敵対が増減した時だけログを残す。群れの分裂や王者の圧力を見やすくする。 | +| 遺伝スキャナー | 選択個体の寿命・サイズ・攻撃・速度の遺伝倍率を読み取る。家系図の補助UIにも使える。 | +| 行動理由センサー | 近くの個体が「なぜその行動を選んだか」を短く記録する。空腹、恐怖、王者回避、繁殖欲求など。 | +| 死因センサー | 範囲内の死亡時に、直前の状態・接触相手・地面・病気・道具をまとめる。事故検証用。 | + +## 高コストだが強いもの + +| センサー | 仕様 | +|---|---| +| ヒートマップ装置 | ストレス、滞在、喧嘩、死亡、汚染、出生を色で重ねて表示する。 | +| A/B実験レコーダー | 2つの区画に別条件を設定し、生存数・出生数・平均寿命・王者発生率を比較する。 | +| 血統観察端末 | 家系ごとの平均寿命、平均サイズ、勝率、移動速度、病気耐性をランキング表示する。 | +| 社会構造センサー | 群れの中心個体、孤立個体、王者、敵対ネットワークをグラフ化する。 | + +## 特に相性が良い実装順 + +1. 通過カウンター +2. ストレスセンサー +3. けんかセンサー +4. 遺伝スキャナー +5. ヒートマップ装置 + +最初は「画面内に結果を出す道具」ではなく、ログとグラフに測定値を流すだけでも十分に実験感が出る。 diff --git a/app_manifest.json b/app_manifest.json index d6bf065..06bddab 100644 --- a/app_manifest.json +++ b/app_manifest.json @@ -1,5 +1,5 @@ { - "version": "39.15.27", + "version": "39.15.39", "css": [ "css/base.css", "css/layout.css", diff --git a/assets/sounds/major_damage_01.wav b/assets/sounds/major_damage_01.wav new file mode 100644 index 0000000..8892aab Binary files /dev/null and b/assets/sounds/major_damage_01.wav differ diff --git a/assets/sounds/major_damage_02.wav b/assets/sounds/major_damage_02.wav new file mode 100644 index 0000000..fb88720 Binary files /dev/null and b/assets/sounds/major_damage_02.wav differ diff --git a/assets/sounds/major_damage_03.wav b/assets/sounds/major_damage_03.wav new file mode 100644 index 0000000..8c40633 Binary files /dev/null and b/assets/sounds/major_damage_03.wav differ diff --git a/assets/sounds/major_damage_04.wav b/assets/sounds/major_damage_04.wav new file mode 100644 index 0000000..aa0fb39 Binary files /dev/null and b/assets/sounds/major_damage_04.wav differ diff --git a/css/base.css b/css/base.css index 66a0007..ea7c7e6 100644 --- a/css/base.css +++ b/css/base.css @@ -557,7 +557,7 @@ h1 { top: 0; z-index: 12; display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 6px; padding: 8px 4px 9px; margin: -2px 0 2px; diff --git a/css/components.css b/css/components.css index 554b5c2..6eed2b6 100644 --- a/css/components.css +++ b/css/components.css @@ -278,14 +278,14 @@ position: relative; } .panel-card-state::before { - content: "▾"; + content: "\25be "; position: absolute; left: 0; top: 50%; transform: translateY(-52%); color: rgba(98, 82, 64, 0.72); } -.collapsible-card.collapsed .panel-card-state::before { content: "▸"; } +.collapsible-card.collapsed .panel-card-state::before { content: "\25b8 "; } .collapsible-card.collapsed .panel-card-body { display: none; } .panel-card-body { padding-top: 12px; } @@ -756,7 +756,7 @@ background: rgba(238, 247, 255, 0.98); } .tool-category[data-tool-category="operate"] .tool-category-body { - grid-template-columns: repeat(5, minmax(0, 1fr)); + grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 5px; } .tool-category[data-tool-category="operate"] .tool { @@ -785,3 +785,19 @@ @media (max-width: 980px) { .tool-category[data-tool-category="operate"]:not(.collapsed) { top: 58px; } } + +/* v39.15.38: prevent long tooltips from spilling outside the viewport. */ +.tool-tip-popover { + width: max-content; + min-width: 160px; + max-width: min(320px, calc(100vw - 18px)); + box-sizing: border-box; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; +} +@media (max-width: 980px) { + body.touch-mobile-ui .tool-tip-popover { + max-width: min(280px, calc(100vw - 24px)); + } +} diff --git a/css/layout.css b/css/layout.css index d69ca60..7c24ae7 100644 --- a/css/layout.css +++ b/css/layout.css @@ -11,13 +11,13 @@ .tool[data-tool="poke"] { --tool-emoji: "\1F448"; } .tool[data-tool="pinch"] { --tool-emoji: "\1F90F"; } .tool[data-tool="water_hose"] { --tool-emoji: "\1F6BF"; } -.tool[data-tool="copy"] { --tool-emoji: "⧉"; } -.tool[data-tool="area_delete"] { --tool-emoji: "×"; } -.tool[data-tool="rope"] { --tool-emoji: "╰"; } -.tool[data-tool="rod"] { --tool-emoji: "━"; } -.tool[data-tool="reciprocator"] { --tool-emoji: "⇄"; } -.tool[data-tool="undo"] { --tool-emoji: "↶"; } -.tool[data-tool="redo"] { --tool-emoji: "↷"; } +.tool[data-tool="copy"] { --tool-emoji: "\29c9 "; } +.tool[data-tool="area_delete"] { --tool-emoji: "\d7 "; } +.tool[data-tool="rope"] { --tool-emoji: "\2570 "; } +.tool[data-tool="rod"] { --tool-emoji: "\2501 "; } +.tool[data-tool="reciprocator"] { --tool-emoji: "\21c4 "; } +.tool[data-tool="undo"] { --tool-emoji: "\21b6 "; } +.tool[data-tool="redo"] { --tool-emoji: "\21b7 "; } .tool.tool-emoji-icon { --tool-icon: none; } .tool.tool-emoji-icon::before { content: var(--tool-emoji); @@ -50,7 +50,8 @@ transform: translateY(-54%) scale(var(--tool-icon-zoom, 1)); } .tool-category[data-tool-category="operate"] .tool[data-tool="area_delete"].tool-emoji-icon::before { - transform: translate(-50%, -54%) scale(var(--tool-icon-zoom, 1)); + top: 42% !important; + transform: translate(-50%, -50%) scale(var(--tool-icon-zoom, 1)) !important; } .tool[data-tool="ball"] { --tool-icon-zoom: 1.36; } diff --git a/css/mobile.css b/css/mobile.css index eacaddb..a3c1f51 100644 --- a/css/mobile.css +++ b/css/mobile.css @@ -166,7 +166,6 @@ body.touch-mobile-ui .mobile-mode-controls:not([hidden]) { display: flex; } body:not(.touch-mobile-ui) .mobile-mode-controls { display: none !important; } body.touch-mobile-ui.mobile-mode-camera #gameCanvas { cursor: grab; } body.touch-mobile-ui.mobile-mode-tool #gameCanvas { cursor: crosshair; } -body.touch-mobile-ui.mobile-mode-family .lineage-main-card { z-index: 9; } /* Keep panel themes on narrow layouts. */ @@ -174,3 +173,256 @@ body.touch-mobile-ui.mobile-mode-family .lineage-main-card { z-index: 9; } .card.selected-card { --ui-theme-rgb: 204, 121, 167; background: linear-gradient(180deg, rgba(253, 245, 250, 0.94), rgba(249, 235, 244, 0.91)); border-color: rgba(204, 121, 167, 0.24); } .card.colony-card { --ui-theme-rgb: 0, 158, 115; background: linear-gradient(180deg, rgba(240, 250, 247, 0.94), rgba(229, 245, 239, 0.91)); border-color: rgba(0, 158, 115, 0.24); } .card.log-card { --ui-theme-rgb: 230, 159, 0; background: linear-gradient(180deg, rgba(255, 249, 236, 0.94), rgba(253, 242, 215, 0.91)); border-color: rgba(230, 159, 0, 0.24); } + + +/* v39.15.35: mobile controls and scroll affordances */ +@media (max-width: 980px) { + body.touch-mobile-ui .mobile-mode-controls:not([hidden]) { + display: flex !important; + } + .panel-quick-tabs { + grid-template-columns: repeat(5, minmax(0, 1fr)); + position: sticky; + top: 0; + } + .panel-quick-tabs button { + padding-left: 3px; + padding-right: 3px; + font-size: 10.5px; + } +} +body.touch-mobile-ui .tool-tip-popover { + max-width: min(240px, calc(100vw - 24px)); +} + +/* v39.15.36: mobile navigation redesign without family input mode */ +@media (max-width: 980px) { + body.touch-mobile-ui .mobile-mode-controls:not([hidden]) { + position: fixed; + left: 50%; + right: auto; + bottom: calc(env(safe-area-inset-bottom, 0px) + 10px); + transform: translateX(-50%); + z-index: 12001; + max-width: calc(100vw - 22px); + } + .panel-quick-tabs { + grid-template-columns: repeat(6, minmax(0, 1fr)); + } + .lineage-main-card { + margin: 10px 0 0; + contain: content; + } + .lineage-main-card .lineage-head { + gap: 8px; + } + .lineage-main-card .lineage-actions { + flex-wrap: wrap; + } + body.touch-mobile-ui .tool-category:not([data-tool-category="operate"]).collapsed .tool-category-body { + display: none; + } + body.touch-mobile-ui .log { + max-height: 240px; + } +} +.back-to-game-btn { + position: fixed; + right: calc(env(safe-area-inset-right, 0px) + 12px); + bottom: calc(env(safe-area-inset-bottom, 0px) + 68px); + z-index: 12000; + border: 1px solid rgba(103,178,44,.38); + border-radius: 999px; + padding: 9px 12px; + background: rgba(246, 255, 236, 0.94); + color: #3f5f2b; + font-weight: 900; + font-size: 12px; + box-shadow: 0 10px 25px rgba(54, 76, 40, .20); + backdrop-filter: blur(8px); +} +.back-to-game-btn[hidden] { display: none !important; } +@media (min-width: 981px) { + .back-to-game-btn { display: none !important; } +} + +/* v39.15.38: keep desktop layout close to v39.15.36; only hide the PC quick-scroll buttons that duplicate the canvas/tool card. */ +@media (min-width: 981px) { + .panel-quick-tabs { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + .panel-quick-tabs [data-panel-tab="game"], + .panel-quick-tabs [data-panel-tab="tools"] { + display: none !important; + } +} + +/* v39.15.38: mobile navigation/footer room and family-graph reachability. */ +@media (max-width: 980px) { + html, + body { + max-width: 100%; + overflow-x: hidden; + } + #app { + width: 100%; + max-width: 100%; + box-sizing: border-box; + padding-left: max(10px, env(safe-area-inset-left, 0px)); + padding-right: max(10px, env(safe-area-inset-right, 0px)); + padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 92px); + overflow-x: clip; + } + .topbar, + .top-left, + .brand, + .layout, + .stage-wrap, + .panel, + .card, + .lineage-main-card { + min-width: 0; + max-width: 100%; + box-sizing: border-box; + } + .top-actions { + width: 100%; + max-width: 100%; + display: flex; + flex-wrap: nowrap; + justify-content: flex-start; + gap: 5px; + overflow-x: auto; + overflow-y: hidden; + padding: 1px 0 5px; + -webkit-overflow-scrolling: touch; + scrollbar-width: thin; + } + .top-actions > .btn, + .top-actions > .sound-menu, + .top-actions .sound-menu-btn { + flex: 0 0 auto; + white-space: nowrap; + } + .top-actions .btn { + padding: 7px 9px; + font-size: 11px; + } + .room-link { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + } + body.touch-mobile-ui .mobile-mode-controls:not([hidden]) { + position: absolute; + left: 50%; + right: auto; + bottom: 10px; + transform: translateX(-50%); + z-index: 24; + max-width: calc(100% - 18px); + } + body.touch-mobile-ui .panel-quick-tabs { + position: fixed; + left: max(8px, env(safe-area-inset-left, 0px)); + right: max(8px, env(safe-area-inset-right, 0px)); + bottom: calc(env(safe-area-inset-bottom, 0px) + 8px); + top: auto; + z-index: 12002; + width: auto; + max-width: none; + grid-template-columns: repeat(6, minmax(0, 1fr)); + gap: 4px; + margin: 0; + padding: 6px; + border: 1px solid rgba(102, 169, 215, 0.34); + border-radius: 16px; + background: rgba(244, 250, 247, 0.95); + box-shadow: 0 12px 28px rgba(42, 54, 64, 0.18); + } + body.touch-mobile-ui .panel-quick-tabs button { + min-height: 34px; + padding: 5px 2px; + font-size: 10px; + } + body.touch-mobile-ui .selected-card, + body.touch-mobile-ui .tool-card, + body.touch-mobile-ui .colony-card, + body.touch-mobile-ui .log-card, + body.touch-mobile-ui .lineage-main-card { + scroll-margin-top: 10px; + scroll-margin-bottom: calc(env(safe-area-inset-bottom, 0px) + 88px); + } + body.touch-mobile-ui .lineage-main-card { + margin-bottom: calc(env(safe-area-inset-bottom, 0px) + 78px); + } + .back-to-game-btn { + bottom: calc(env(safe-area-inset-bottom, 0px) + 62px); + right: max(10px, env(safe-area-inset-right, 0px)); + } +} + + +/* v39.15.39: desktop rollback guard. Keep the normal PC layout; only remove duplicated quick-scroll buttons. */ +@media (min-width: 981px) { + .topbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 14px 18px; + } + .top-left { + flex: 1 0 auto; + min-width: max-content; + max-width: 100%; + } + .brand, + .brand h1, + h1 { + flex: 0 0 auto; + min-width: max-content; + max-width: none !important; + overflow: visible !important; + text-overflow: clip !important; + } + .top-actions { + flex: 1 1 560px; + margin-left: auto; + justify-content: flex-end; + align-items: center; + gap: 10px; + } + .top-actions .btn, + .top-actions .sound-menu-btn, + .room-link { + min-height: 42px; + padding: 10px 16px; + font-size: 13px; + line-height: 1.15; + } + .panel-quick-tabs { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + .panel-quick-tabs [data-panel-tab="game"], + .panel-quick-tabs [data-panel-tab="tools"] { + display: none !important; + } +} + +/* v39.15.39: mobile scroll must remain manual; disable any CSS scroll snapping. */ +@media (max-width: 980px) { + html, body, #app, .layout, .stage-wrap, .panel, .card, .lineage-main-card { + scroll-snap-type: none !important; + scroll-snap-align: none !important; + scroll-snap-stop: normal !important; + } + .lineage-main-card { + display: block !important; + visibility: visible !important; + margin-bottom: calc(env(safe-area-inset-bottom, 0px) + 132px); + } + .lineage-main-content { + min-height: 360px; + } +} diff --git a/css/panel.css b/css/panel.css index 98037d2..81b8109 100644 --- a/css/panel.css +++ b/css/panel.css @@ -119,6 +119,36 @@ body::before { z-index: 0; pointer-events: none; } + +.family-genetic-stats { + display: block; + margin-top: 2px; + font-size: 9px; + line-height: 1.16; + color: rgba(88, 70, 48, 0.86); + letter-spacing: -0.02em; + white-space: normal; + max-width: 104px; +} +.family-genetic-stats b { + font-weight: 800; + color: rgba(120, 86, 30, 0.92); +} +.lineage-family-tree .tree-node.champion { + border-color: rgba(202, 146, 33, 0.58); + box-shadow: inset 0 0 0 1px rgba(247, 200, 64, 0.30), 0 3px 8px rgba(120, 78, 12, 0.09); +} +.lineage-family-tree .tree-node.champion::before { + content: "♛"; + position: absolute; + right: 6px; + top: 4px; + z-index: 2; + font-size: 14px; + color: rgba(158, 102, 20, 0.95); + text-shadow: 0 1px 0 rgba(255,255,255,0.70); +} + .family-node.alive .family-portrait { opacity: 0.80; } .family-node.dead .family-portrait { opacity: 0.20; } .family-portrait img { @@ -355,9 +385,9 @@ body::before { } .lineage-family-tree .tree-node { position: absolute; - width: 132px; - height: 84px; - min-height: 84px; + width: 150px; + height: 104px; + min-height: 104px; box-sizing: border-box; align-items: flex-start; background: linear-gradient(180deg, #fffdf8, #f8f1e5); diff --git a/index.html b/index.html index 9685d88..6ef0b14 100644 --- a/index.html +++ b/index.html @@ -3,20 +3,20 @@
-