bend_puzzle/index.html
2026-07-31 12:54:46 +09:00

169 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<title>&#x66F2;&#x7DDA;&#x30D5;&#x30A3;&#x30FC;&#x30EB;&#x30C9;</title>
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="alternate icon" href="favicon.ico">
<link rel="stylesheet" href="style.css">
</head>
<body class="loading" data-ready="false" data-loading-text="&#x8AAD;&#x307F;&#x8FBC;&#x307F;&#x4E2D;">
<div id="app">
<div id="topbar">
<div class="brand">&#x66F2;&#x7DDA;&#x30D5;&#x30A3;&#x30FC;&#x30EB;&#x30C9; <small></small></div>
<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>
<div class="stat fps-stat" aria-label="描画フレームレート"><b id="fpsCounter" data-fps="idle">FPS 待機</b></div>
<div class="stat compact-selected"><b id="selectedInfo" aria-live="polite">&#x30EC;&#x30D9;&#x30EB;1</b></div>
<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>
<button class="pill cloud-status" id="cloudBtn" type="button" title="&#x540C;&#x671F;">&#x7AEF;&#x672B;&#x306E;&#x307F;</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>
<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;">
<div id="clearFeed" class="clear-feed" aria-live="polite" aria-label="共有クリア速報"></div>
<div class="minimap-head"><b>&#x30DE;&#x30C3;&#x30D7;</b></div>
<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>
<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>
</aside>
<div id="reactionRadial" role="menu" aria-label="リアクションを選択" hidden></div>
<div id="toast" role="status" aria-live="polite"></div>
<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="exportBtn" type="button">&#x66F8;&#x304D;&#x51FA;&#x3057;</button>
<button class="pill" id="importBtn" type="button">&#x8AAD;&#x307F;&#x8FBC;&#x307F;</button>
<input id="importFile" type="file" accept="application/x-bend-field-save,.bfsave,application/json,.json" hidden>
<button class="pill danger" id="freshBtn" type="button">&#x6700;&#x521D;&#x304B;&#x3089;</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">
<h2 id="helpTitle">&#x66F2;&#x7DDA;&#x30D5;&#x30A3;&#x30FC;&#x30EB;&#x30C9;</h2>
<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>
<label class="debug-items-toggle"><input id="debugAllItemsToggle" type="checkbox"><span><b>DEBUG</b><small id="debugAllItemsState">OFF · 通常所持数を使用</small></span></label>
<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">
<div class="settings-heading"><div><small>SETTINGS</small><h2 id="settingsTitle">設定</h2></div></div>
<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>
<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>
</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">
<div class="time-attack-heading"><div><small>TIME ATTACK</small><h2 id="timeAttackTitle">タイムアタック</h2></div><strong id="timeAttackHeadingScore">タイム加算</strong></div>
<section id="timeAttackSetup">
<p class="time-attack-intro">制限時間内に盤面を解き、獲得ジェムを伸ばします。集めた量に応じて報酬倍率が上がります。</p>
<p class="time-attack-kicker">コースを選択</p>
<div class="time-attack-durations">
<button type="button" data-time-minutes="3"><span class="duration-value"><b>3</b><small></small></span><strong>QUICK</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>STANDARD</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>LONG</strong><em class="duration-status">じっくり挑戦</em></button>
</div>
<div class="time-attack-rules">
<div><b>獲得ジェムで倍率UP</b><span>時間内の合計獲得量に応じて、自動的に最も高い倍率が適用されます。</span></div>
<div class="time-attack-ladder" aria-label="報酬倍率">
<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>
</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>
<p class="time-attack-kicker">RESULT</p>
<div class="time-attack-result-grid"><span>制限時間 <b id="timeAttackResultLimit">3分</b></span><span>クリア数 <b id="timeAttackResultSolves">0</b></span><span>獲得ジェム <b id="timeAttackResultCollected">0</b></span><span>実効倍率 <b id="timeAttackResultMultiplier">×1.25</b></span><span>タイム加算 <b id="timeAttackResultBonus">+0</b></span><span>合計 <b id="timeAttackResultTotal">0</b></span></div>
<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>
<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>
<script src="app.js"></script>
</body>
</html>