bend_puzzle/index.html

165 lines
14 KiB
HTML
Raw Normal View History

2026-07-30 15:13:53 +09:00
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
2026-08-01 16:06:14 +09:00
<title>LinkFieldリンクフィールド</title>
2026-07-30 15:13:53 +09:00
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="alternate icon" href="favicon.ico">
2026-07-31 12:54:46 +09:00
<link rel="stylesheet" href="style.css">
2026-07-30 15:13:53 +09:00
</head>
<body class="loading" data-ready="false" data-loading-text="&#x8AAD;&#x307F;&#x8FBC;&#x307F;&#x4E2D;">
<div id="app">
<div id="topbar">
2026-08-01 16:06:14 +09:00
<a class="room-back-link" href="https://host.nishi.boats/~333/">333の部屋に戻る</a>
<div class="brand">LinkFieldリンクフィールド <small></small></div>
2026-07-30 15:13:53 +09:00
<div class="stat sr-data">&#x30AF;&#x30EA;&#x30A2; <b id="solvedCount">0</b></div>
<div class="stat score" aria-label="&#x6240;&#x6301;&#x6570;"><span aria-hidden="true">&#x25C6;</span> <b id="scoreCount">0</b></div>
<div class="stat sr-data">&#x76E4;&#x9762; <b id="worldCount">1</b></div>
2026-08-01 16:06:14 +09:00
<div class="stat fps-stat" aria-label="FPS"><b id="fpsCounter" data-fps="idle">FPS 待機</b></div>
2026-07-30 15:13:53 +09:00
<div class="spacer"></div>
<div class="toolbar" aria-label="&#x30B2;&#x30FC;&#x30E0;&#x64CD;&#x4F5C;">
<button class="pill inventory-button" id="inventoryBtn" aria-label="&#x30A2;&#x30A4;&#x30C6;&#x30E0;&#x3092;&#x958B;&#x304F;" aria-haspopup="dialog" aria-expanded="false"><span aria-hidden="true">&#x25A3;</span><span>&#x30A2;&#x30A4;&#x30C6;&#x30E0; <b id="inventoryCount">0</b></span></button>
<button class="pill time-attack" id="timeAttackBtn" aria-label="&#x30BF;&#x30A4;&#x30E0;&#x30A2;&#x30BF;&#x30C3;&#x30AF;&#x3092;&#x958B;&#x304F;" aria-haspopup="dialog" aria-expanded="false"><span aria-hidden="true">&#x25F7;</span><span id="timeAttackButtonLabel">&#x30BF;&#x30A4;&#x30E0;&#x30A2;&#x30BF;&#x30C3;&#x30AF;</span></button>
<button class="pill settings" id="settingsBtn" type="button" aria-label="設定を開く" aria-haspopup="dialog" aria-expanded="false"></button>
<button class="pill help" id="helpBtn" aria-label="&#x904A;&#x3073;&#x65B9;&#x3092;&#x958B;&#x304F;" aria-haspopup="dialog" aria-expanded="false">?</button>
<button class="pill player-name" id="playerNameBtn" type="button" title="プレイヤー名を変更">旅人</button>
</div>
<button id="saveStatus" type="button" aria-live="polite" aria-label="&#x4FDD;&#x5B58;&#x72B6;&#x614B;" title="&#x4FDD;&#x5B58;&#x72B6;&#x614B;&#x3092;&#x78BA;&#x8A8D;">&#x4FDD;&#x5B58;&#x6E08;&#x307F;</button>
</div>
2026-08-01 16:06:14 +09:00
<div class="shared-indicator" id="cloudBtn" data-state="connecting" role="status" aria-live="off" aria-label="共有接続状態" title="共有サーバーへ接続中"><i aria-hidden="true"></i><span>共有</span></div>
2026-07-31 12:54:46 +09:00
<div id="viewport" tabindex="-1" aria-label="&#x66F2;&#x7DDA;&#x30D5;&#x30A3;&#x30FC;&#x30EB;&#x30C9;"><canvas id="noiseCanvas" width="80" height="64" aria-hidden="true"></canvas><canvas id="reactionCanvas" aria-hidden="true"></canvas><canvas id="overviewCanvas" aria-hidden="true" hidden></canvas><div id="world"></div><canvas id="presenceCanvas" aria-hidden="true"></canvas><div id="boardHudLayer" aria-live="polite"></div></div>
<aside id="minimap" aria-label="&#x30DE;&#x30C3;&#x30D7;">
2026-07-30 15:13:53 +09:00
<div id="clearFeed" class="clear-feed" aria-live="polite" aria-label="共有クリア速報"></div>
2026-07-31 12:54:46 +09:00
<div class="minimap-head"><b>&#x30DE;&#x30C3;&#x30D7;</b></div>
2026-07-30 15:13:53 +09:00
<div class="minimap-controls" aria-label="&#x8996;&#x70B9;&#x79FB;&#x52D5;">
<button id="minimapOriginBtn" type="button">&#x539F;&#x70B9;</button>
<button id="minimapRandomBtn" type="button">&#x30E9;&#x30F3;&#x30C0;&#x30E0;</button>
</div>
2026-07-31 12:54:46 +09:00
<canvas id="minimapCanvas" width="210" height="132" role="application" tabindex="0" aria-label="&#x30DE;&#x30C3;&#x30D7;&#x3002;&#x30AF;&#x30EA;&#x30C3;&#x30AF;&#x307E;&#x305F;&#x306F;&#x30C9;&#x30E9;&#x30C3;&#x30B0;&#x3067;&#x8996;&#x70B9;&#x3092;&#x79FB;&#x52D5;&#x3002;&#x5E97;&#x8217;&#x30DE;&#x30FC;&#x30AB;&#x30FC;&#x3092;&#x30AF;&#x30EA;&#x30C3;&#x30AF;&#x3059;&#x308B;&#x3068;&#x30B7;&#x30E7;&#x30C3;&#x30D7;&#x3092;&#x958B;&#x304D;&#x307E;&#x3059;&#x3002;"></canvas>
<div class="minimap-legend" aria-hidden="true"><span class="solved">&#x30AF;&#x30EA;&#x30A2;</span><span class="unsolved">&#x672A;&#x30AF;&#x30EA;&#x30A2;</span><span class="long-line">&#x9577;&#x8DDD;&#x96E2;&#x7DDA;</span><span class="shop">&#x30B7;&#x30E7;&#x30C3;&#x30D7;</span></div>
2026-07-30 15:13:53 +09:00
</aside>
<div id="reactionRadial" role="menu" aria-label="リアクションを選択" hidden></div>
<div id="toast" role="status" aria-live="polite"></div>
2026-08-01 16:06:14 +09:00
<div id="timeAttackCountdownOverlay" aria-live="assertive" aria-atomic="true" hidden><span></span></div>
2026-07-30 15:13:53 +09:00
<div id="specialTooltip" role="tooltip" hidden></div>
<section id="statusPanel" hidden aria-live="assertive">
<p id="statusMessage"></p>
<div class="status-actions">
<button class="pill" id="retryBtn" type="button">&#x518D;&#x8A66;&#x884C;</button>
<button class="pill" id="dismissStatusBtn" type="button">&#x9589;&#x3058;&#x308B;</button>
</div>
</section>
<div id="modal" aria-hidden="true" inert>
<div class="panel" role="dialog" aria-modal="true" aria-labelledby="helpTitle" aria-describedby="helpDescription" tabindex="-1">
2026-08-01 16:06:14 +09:00
<h2 id="helpTitle">LinkFieldリンクフィールド</h2>
2026-07-30 15:13:53 +09:00
<div id="helpDescription">
<div class="tutorial-grid">
<article class="tutorial-card">
<div class="tutorial-demo" data-tutorial="draw" aria-hidden="true"></div>
<h3>&#x30B2;&#x30FC;&#x30C8;&#x3092;&#x3064;&#x306A;&#x3050;</h3><p>&#x540C;&#x3058;&#x8272;&#x306E;&#x30B2;&#x30FC;&#x30C8;&#x3092;&#x7DDA;&#x3067;&#x3064;&#x306A;&#x3050;&#x3002;<strong>長くつながって太くなった線ほど高得点です。</strong></p>
</article>
<article class="tutorial-card">
<div class="tutorial-demo" data-tutorial="bend" aria-hidden="true"></div>
<h3>&#x6570;&#x5B57;&#x306B;&#x5408;&#x308F;&#x305B;&#x308B;</h3><p>&#x6570;&#x5B57;&#x306E;&#x30DE;&#x30B9;&#x3067;&#x3001;&#x6570;&#x5B57;&#x3068;&#x540C;&#x3058;&#x56DE;&#x6570;&#x3060;&#x3051;&#x7DDA;&#x3092;&#x66F2;&#x3052;&#x308B;&#x3002;</p>
</article>
<article class="tutorial-card">
<div class="tutorial-demo" data-tutorial="fill" aria-hidden="true"></div>
<h3>&#x76E4;&#x9762;&#x3092;&#x57CB;&#x3081;&#x308B;</h3><p>&#x7DDA;&#x3092;&#x91CD;&#x306D;&#x305A;&#x3001;&#x3059;&#x3079;&#x3066;&#x306E;&#x30DE;&#x30B9;&#x3092;&#x57CB;&#x3081;&#x308B;&#x3002;</p>
</article>
<article class="tutorial-card">
<div class="tutorial-demo" data-tutorial="shop" aria-hidden="true"></div>
<h3>&#x30A2;&#x30A4;&#x30C6;&#x30E0;&#x3092;&#x4F7F;&#x3046;</h3><p>&#x8CFC;&#x5165;&#x3057;&#x305F;&#x30AB;&#x30FC;&#x30BD;&#x30EB;&#x3084;&#x6A5F;&#x80FD;&#x3092;&#x5207;&#x308A;&#x66FF;&#x3048;&#x308B;&#x3002;</p>
</article>
</div>
<div class="control-chips"><span>&#x5DE6;&#x30C9;&#x30E9;&#x30C3;&#x30B0;&#xFF1A;&#x7DDA;&#x3092;&#x5F15;&#x304F;</span><span>&#x53F3;&#x30C9;&#x30E9;&#x30C3;&#x30B0;&#xFF1A;&#x753B;&#x9762;&#x79FB;&#x52D5;</span><span>&#x30DB;&#x30A4;&#x30FC;&#x30EB;&#xFF1A;&#x62E1;&#x5927;&#x30FB;&#x7E2E;&#x5C0F;</span></div>
</div>
<div class="modal-actions entry-mode-actions" aria-label="&#x30E2;&#x30FC;&#x30C9;&#x3092;&#x9078;&#x629E;">
<button class="pill primary-mode" id="normalPlayBtn" type="button"><b>&#x901A;&#x5E38;&#x30D7;&#x30EC;&#x30A4;</b></button>
<button class="pill time-mode" id="helpTimeAttackBtn" type="button"><b>&#x30BF;&#x30A4;&#x30E0;&#x30A2;&#x30BF;&#x30C3;&#x30AF;</b></button>
</div>
</div>
</div>
<aside id="timeAttackSuggestion" role="status" aria-live="polite" hidden>
<div><b>10枚クリア</b><span>タイムアタックにも挑戦できます。</span></div>
<button class="pill time-mode" id="acceptTimeAttackSuggestion" type="button">開く</button>
<button class="pill quiet" id="dismissTimeAttackSuggestion" type="button" aria-label="提案を閉じる">×</button>
</aside>
<div id="storeModal" aria-hidden="true" inert>
<div class="panel store-panel" role="dialog" aria-modal="true" aria-labelledby="storeTitle" tabindex="-1">
<div class="store-heading"><div><small>&#x30B7;&#x30E7;&#x30C3;&#x30D7;</small><h2 id="storeTitle">&#x30A2;&#x30A4;&#x30C6;&#x30E0;&#x30B7;&#x30E7;&#x30C3;&#x30D7;</h2></div><div class="store-wallet" aria-label="&#x6240;&#x6301;&#x6570;"><span aria-hidden="true">&#x25C6;</span><b id="storeWallet">0</b></div></div>
<p id="storeMeta"></p>
<div id="storeInventory" class="store-inventory"></div>
<div class="modal-actions"><button class="pill close" id="closeStore">&#x9589;&#x3058;&#x308B;</button></div>
</div>
</div>
<div id="inventoryModal" aria-hidden="true" inert>
<div class="panel inventory-panel" role="dialog" aria-modal="true" aria-labelledby="inventoryTitle" tabindex="-1">
<div class="inventory-heading"><div><small>&#x30A2;&#x30A4;&#x30C6;&#x30E0;</small><h2 id="inventoryTitle">&#x6240;&#x6301;&#x30A2;&#x30A4;&#x30C6;&#x30E0;</h2></div><strong id="inventoryTotal">0</strong></div>
<p id="inventoryTarget">&#x30AB;&#x30FC;&#x30BD;&#x30EB;&#x306F;&#x30C7;&#x30B6;&#x30A4;&#x30F3;&#x3092;&#x30AF;&#x30EA;&#x30C3;&#x30AF;&#x3057;&#x3066;&#x5207;&#x308A;&#x66FF;&#x3048;&#x307E;&#x3059;&#x3002;</p>
<div id="inventoryList" class="inventory-list"></div>
<div class="modal-actions"><button class="pill close" id="closeInventory" type="button">&#x9589;&#x3058;&#x308B;</button></div>
</div>
</div>
<div id="settingsModal" aria-hidden="true" inert>
<div class="panel settings-panel" role="dialog" aria-modal="true" aria-labelledby="settingsTitle" tabindex="-1">
2026-08-01 16:06:14 +09:00
<div class="settings-heading"><div><small>設定</small><h2 id="settingsTitle">設定</h2></div></div>
2026-07-30 15:13:53 +09:00
<label class="settings-field"><span>プレイヤー名</span><input id="settingsPlayerName" type="text" maxlength="24" autocomplete="nickname" spellcheck="false"></label>
<label class="settings-toggle"><input id="lightweightRenderingToggle" type="checkbox"><span><b>軽量描画</b><small>背景ノイズ、光、粒子など一部の視覚効果を抑えます。</small></span></label>
<label class="settings-toggle"><input id="soundEnabledToggle" type="checkbox"><span><b>効果音</b><small>操作音とクリア音を再生します。</small></span></label>
2026-07-31 12:54:46 +09:00
<div class="modal-actions settings-actions"><button class="pill quiet" id="resetSettings" type="button">初期化</button><button class="pill close" id="closeSettings" type="button">閉じる</button></div>
2026-07-30 15:13:53 +09:00
</div>
</div>
<div id="timeAttackModal" aria-hidden="true" inert>
<div class="panel time-attack-panel" role="dialog" aria-modal="true" aria-labelledby="timeAttackTitle" tabindex="-1">
2026-08-01 16:06:14 +09:00
<div class="time-attack-heading"><div><small>タイムアタック</small><h2 id="timeAttackTitle">タイムアタック</h2></div><strong id="timeAttackHeadingScore">挑戦結果</strong></div>
2026-07-30 15:13:53 +09:00
<section id="timeAttackSetup">
2026-08-01 16:06:14 +09:00
<p class="time-attack-intro">制限時間内に盤面を解き、ジェムを伸ばします。獲得ジェムに応じて次の通り倍率が上昇します。</p>
2026-07-30 15:13:53 +09:00
<p class="time-attack-kicker">コースを選択</p>
<div class="time-attack-durations">
2026-08-01 16:06:14 +09:00
<button type="button" data-time-minutes="3"><span class="duration-value"><b>3</b><small></small></span><strong>短時間</strong><em class="duration-status">短時間で集中</em></button>
<button type="button" data-time-minutes="5"><span class="duration-value"><b>5</b><small></small></span><strong>標準</strong><em class="duration-status">標準コース</em></button>
<button type="button" data-time-minutes="10"><span class="duration-value"><b>10</b><small></small></span><strong>長時間</strong><em class="duration-status">じっくり挑戦</em></button>
2026-07-30 15:13:53 +09:00
</div>
<div class="time-attack-rules">
2026-08-01 16:06:14 +09:00
<div><b>獲得ジェムの倍率UP</b><span>獲得ジェムに応じて次の通り倍率が上昇します。</span></div>
2026-07-30 15:13:53 +09:00
<div class="time-attack-ladder" aria-label="報酬倍率">
2026-08-01 16:06:14 +09:00
<span><small>基礎累計</small><b>0+</b><strong>×1.25</strong></span><span><small>基礎累計</small><b>100+</b><strong>×1.50</strong></span><span><small>基礎累計</small><b>250+</b><strong>×2.00</strong></span><span><small>基礎累計</small><b>500+</b><strong>×2.50</strong></span><span><small>基礎累計</small><b>1000+</b><strong>×3.00</strong></span>
2026-07-30 15:13:53 +09:00
</div>
</div>
</section>
<section id="timeAttackLive" hidden>
<p class="time-attack-kicker">挑戦中</p>
<div class="time-attack-clock" id="timeAttackClock">03:00</div>
<div class="time-attack-stats"><span>獲得ジェム <b id="timeAttackCollected">0</b></span><span>現在倍率 <b id="timeAttackMultiplier">×1.25</b></span><span>現在合計 <b id="timeAttackProjected">0</b></span></div>
</section>
<section id="timeAttackResult" hidden>
2026-08-01 16:06:14 +09:00
<p class="time-attack-kicker">結果</p>
<div class="time-attack-result-grid"><span>制限時間 <b id="timeAttackResultLimit">3分</b></span><span>クリア数 <b id="timeAttackResultSolves">0</b></span><span>合計 <b id="timeAttackResultTotal">0</b></span></div>
2026-07-30 15:13:53 +09:00
<pre id="timeAttackShareText" aria-label="タイムアタックの結果"></pre>
</section>
<div class="modal-actions time-attack-actions"><button class="pill" id="copyTimeAttack" type="button" hidden>📋 結果をコピー</button><button class="pill close" id="closeTimeAttack" type="button">&#x9589;&#x3058;&#x308B;</button></div>
</div>
</div>
</div>
<div id="customEmojiCursor" aria-hidden="true"></div>
<div id="pickupHandleOverlay" aria-hidden="true"></div>
2026-07-31 12:54:46 +09:00
<script src="build-meta.js"></script>
<script src="shared-contracts.js"></script>
<script src="runtime-config.js"></script>
<script src="store-catalog.generated.js"></script>
<script src="puzzle-patterns.js"></script>
<script src="puzzle-core.js"></script>
<script src="app-logic.js"></script>
<script src="archive-codec.js"></script>
<script src="client/input/frame-scheduler.js"></script>
<script src="client/input/drag.js"></script>
<script src="client/input/interaction-state.js"></script>
<script src="client/input/gesture-coordinator.js"></script>
<script src="client/ui/cursor.js"></script>
<script src="field-persistence.js"></script>
2026-08-01 22:31:04 +09:00
<script src="app.js?v=48.0.3"></script>
2026-07-30 15:13:53 +09:00
</body>
</html>