From 69eaada1af92280bfb2c7b2d09643226fa8361b1 Mon Sep 17 00:00:00 2001 From: shuiyuPyLab Date: Sun, 9 Aug 2026 10:16:33 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E9=A1=B9=E7=9B=AE=E5=B7=B2=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E8=87=B3=20Gitee/GitHub=EF=BC=8C=E4=BB=85=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E8=BF=81=E7=A7=BB=E8=AF=B4=E6=98=8E=20(tombstone)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/PULL_REQUEST_TEMPLATE.md | 34 - .github/workflows/ci.yml | 66 - .gitignore | 13 - AGENTS.md | 195 - LICENSE | 21 - README.en.md | 119 - README.md | 3 +- cases.json | 120 - models/claude-fable-5-cc-high.json | 25 - models/claude-fable-5-cc-xhigh.json | 25 - models/claude-fable-5-cc.json | 32 - models/claude-fable-5-cursor.json | 24 - models/claude-fable-5.json | 24 - models/claude-haiku-4-5-cc.json | 24 - models/claude-opus-4-5-cursor.json | 24 - models/claude-opus-4-6-cc.json | 24 - models/claude-opus-4-6-cursor.json | 24 - models/claude-opus-4-7-cc.json | 31 - models/claude-opus-4-7-cursor.json | 24 - models/claude-opus-4-8-cc-xhigh.json | 17 - models/claude-opus-4-8-cc.json | 67 - models/claude-sonnet-4-6-cc.json | 17 - models/claude-sonnet-4-6-cursor.json | 27 - models/claude-sonnet-5-cc-max.json | 17 - models/composer-2-5-fast.json | 24 - models/composer-2-5-grok-build.json | 24 - models/composer-2-5.json | 17 - models/deepseek-v4-flash-cc.json | 17 - models/deepseek-v4-flash-reasonix.json | 17 - models/deepseek-v4-pro.json | 31 - models/doubao-seed-2-0-mini.json | 17 - models/doubao-seed-2-0-pro.json | 17 - models/gemini-3-1-pro-aistudio.json | 24 - models/gemini-3-1-pro-cursor.json | 24 - models/gemini-3-1-pro-gemini-web.json | 31 - models/gemini-3-1-pro.json | 40 - models/gemini-3-5-flash-aistudio.json | 17 - models/gemini-3-5-flash-cursor.json | 24 - models/gemini-3-5-flash.json | 32 - models/glm-5-1.json | 17 - models/glm-5-2.json | 41 - models/glm-5-turbo.json | 34 - models/gpt-5-2-cursor.json | 24 - models/gpt-5-3-codex-cursor.json | 24 - models/gpt-5-4-cursor.json | 24 - models/gpt-5-4-xhigh.json | 41 - models/gpt-5-5-pro.json | 31 - models/gpt-5-5-xhigh.json | 31 - models/gpt-5-6-sol-codex-cli-max.json | 17 - models/gpt-5-6-sol-codex-cli-xhigh.json | 17 - models/gpt-5-6-sol-ultra.json | 69 - models/gpt-5-6-terra-codex-cli-xhigh.json | 17 - models/gpt-5-6-terra.json | 31 - models/grok-4-3-cursor.json | 24 - models/grok-4-5.json | 31 - models/grok-build.json | 24 - models/inkling.json | 24 - models/kimi-k2-6.json | 24 - models/kimi-k2-7-code.json | 31 - models/kimi-k3-kimi-code-max.json | 32 - models/kimi-k3.json | 17 - models/mimo-v2-5-pro-micode-high.json | 31 - models/mimo-v2-5-pro-mimocode.json | 16 - models/mimo-v2-5-pro-ultraspeed.json | 50 - models/minimax-m2-7.json | 17 - models/minimax-m3.json | 27 - models/mistral-medium-3-5.json | 24 - models/nex-n2-pro-cc.json | 24 - models/qwen3-7-max.json | 24 - models/step-3-7-flash.json | 24 - models/xiaomi-mimo-v2-5-pro.json | 24 - .../claude-code-high/cs-dust2/bun.lock | 267 -- .../claude-code-high/cs-dust2/index.html | 15 - .../claude-code-high/cs-dust2/package.json | 24 - .../claude-code-high/cs-dust2/src/App.tsx | 23 - .../claude-code-high/cs-dust2/src/game/ai.ts | 386 -- .../cs-dust2/src/game/audio.ts | 245 - .../cs-dust2/src/game/character.ts | 232 - .../cs-dust2/src/game/effects.ts | 200 - .../cs-dust2/src/game/engine.ts | 1106 ----- .../claude-code-high/cs-dust2/src/game/map.ts | 429 -- .../claude-code-high/cs-dust2/src/game/nav.ts | 155 - .../cs-dust2/src/game/physics.ts | 258 - .../cs-dust2/src/game/soldier.ts | 116 - .../cs-dust2/src/game/store.ts | 53 - .../cs-dust2/src/game/types.ts | 106 - .../cs-dust2/src/game/viewmodel.ts | 202 - .../cs-dust2/src/game/weapons.ts | 141 - .../claude-code-high/cs-dust2/src/main.tsx | 5 - .../claude-code-high/cs-dust2/src/ui/HUD.tsx | 290 -- .../claude-code-high/cs-dust2/src/ui/hud.css | 114 - .../claude-code-high/cs-dust2/tsconfig.json | 18 - .../claude-code-high/cs-dust2/vite.config.ts | 7 - .../claude-code-max/mythos-craft.html | 1317 ------ .../claude-code-max/pelican-cycling.svg | 370 -- .../claude-code-xhigh/skeleton-watch.html | 1264 ----- .../claude-web-app-max/mythos-craft.html | 1505 ------ .../claude-web-app-max/pelican-cycling.svg | 177 - .../cursor-high/mythos-craft.html | 1171 ----- .../cursor-high/pelican-cycling.svg | 437 -- .../claude-code-default/mythos-craft.html | 712 --- .../claude-code-default/pelican-cycling.svg | 120 - .../cursor-thinking/mythos-craft.html | 1718 ------- .../cursor-thinking/pelican-cycling.svg | 339 -- .../claude-code-max/pelican-cycling.svg | 379 -- .../claude-code-max/skeleton-watch.html | 1103 ----- .../cursor-max/mythos-craft.html | 877 ---- .../cursor-max/pelican-cycling.svg | 465 -- .../claude-code-max/mythos-craft.html | 2181 --------- .../claude-code-max/pelican-cycling.svg | 425 -- .../claude-code-max/skeleton-watch.html | 968 ---- .../cursor-max/mythos-craft.html | 2250 --------- .../cursor-max/pelican-cycling.svg | 628 --- .../claude-code-max/dust2-arena/.gitignore | 2 - .../claude-code-max/dust2-arena/README.md | 64 - .../claude-code-max/dust2-arena/bun.lock | 282 -- .../dust2-arena/dust2-arena.html | 4168 ----------------- .../claude-code-max/dust2-arena/index.html | 12 - .../claude-code-max/dust2-arena/package.json | 27 - .../claude-code-max/dust2-arena/src/App.tsx | 10 - .../dust2-arena/src/components/GameCanvas.tsx | 69 - .../dust2-arena/src/components/Hud.tsx | 166 - .../dust2-arena/src/components/Menu.tsx | 54 - .../dust2-arena/src/components/Minimap.tsx | 10 - .../dust2-arena/src/engine/ai.ts | 330 -- .../dust2-arena/src/engine/audio.ts | 233 - .../dust2-arena/src/engine/collision.ts | 153 - .../dust2-arena/src/engine/combat.ts | 100 - .../dust2-arena/src/engine/constants.ts | 59 - .../dust2-arena/src/engine/dust2.ts | 122 - .../dust2-arena/src/engine/effects.ts | 118 - .../src/engine/entities/characterModel.ts | 151 - .../src/engine/entities/weaponModels.ts | 132 - .../dust2-arena/src/engine/grid.ts | 233 - .../dust2-arena/src/engine/input.ts | 116 - .../dust2-arena/src/engine/mathUtils.ts | 56 - .../dust2-arena/src/engine/navmesh.ts | 163 - .../dust2-arena/src/engine/player.ts | 142 - .../dust2-arena/src/engine/scene.ts | 142 - .../dust2-arena/src/engine/store.ts | 107 - .../dust2-arena/src/engine/types.ts | 51 - .../dust2-arena/src/engine/weapons.ts | 118 - .../dust2-arena/src/engine/world.ts | 1275 ----- .../claude-code-max/dust2-arena/src/main.tsx | 7 - .../dust2-arena/src/styles.css | 336 -- .../claude-code-max/dust2-arena/tsconfig.json | 14 - .../dust2-arena/vite.config.ts | 9 - .../dust2-arena/vite.single.config.ts | 10 - .../claude-code-max/mythos-craft-2.html | 557 --- .../claude-code-max/mythos-craft.html | 780 --- .../claude-code-max/pelican-cycling-2.svg | 199 - .../claude-code-max/pelican-cycling.svg | 300 -- .../claude-code-max/skeleton-watch.html | 1014 ---- .../claude-code-max/pelican-cycling.svg | 416 -- .../cursor-high/pelican-cycling-2.svg | 561 --- .../cursor-high/pelican-cycling.svg | 417 -- .../cursor-default/mythos-craft.html | 632 --- .../cursor-default/pelican-cycling.svg | 203 - .../composer-2-5/cursor-max/mythos-craft.html | 1432 ------ .../grok-build-tui-default/mythos-craft.html | 1218 ----- .../pelican-cycling.svg | 367 -- .../claude-code-max/mythos-craft.html | 1733 ------- .../reasonix-max/skeleton-watch.html | 1320 ------ .../claude-code-max/mythos-craft.html | 1196 ----- .../claude-code-max/pelican-cycling.svg | 376 -- .../claude-code-max/skeleton-watch.html | 1597 ------- .../doubao-web-fast-mode/pelican-cycling.svg | 83 - .../doubao-web-pro-mode/pelican-cycling.svg | 203 - .../antigravity-high/mythos-craft.html | 759 --- .../antigravity-high/pelican-cycling-2.svg | 349 -- .../antigravity-high/skeleton-watch.html | 595 --- .../cursor-default/mythos-craft.html | 603 --- .../cursor-default/pelican-cycling.svg | 233 - .../gemini-web-deepthink/mythos-craft.html | 503 -- .../gemini-web-deepthink/pelican-cycling.svg | 491 -- .../gemini-web-deepthink/skeleton-watch.html | 591 --- .../google-ai-studio-high/pelican-cycling.svg | 492 -- .../google-ai-studio-high/skeleton-watch.html | 639 --- .../antigravity-high/mythos-craft.html | 2736 ----------- .../antigravity-high/pelican-cycling-2.svg | 342 -- .../antigravity-high/skeleton-watch.html | 2108 --------- .../cursor-default/mythos-craft.html | 2250 --------- .../cursor-default/pelican-cycling.svg | 670 --- .../google-ai-studio-high/pelican-cycling.svg | 407 -- outputs/glm-5-1/zcode-max/pelican-cycling.svg | 360 -- outputs/glm-5-2/zcode-max/mythos-craft.html | 1318 ------ .../glm-5-2/zcode-max/pelican-cycling-2.svg | 465 -- outputs/glm-5-2/zcode-max/pelican-cycling.svg | 349 -- outputs/glm-5-2/zcode-max/skeleton-watch.html | 1088 ----- .../zcode-thinking/mythos-craft-2.html | 953 ---- .../zcode-thinking/mythos-craft.html | 296 -- .../zcode-thinking/pelican-cycling.svg | 440 -- .../gpt-5-2/cursor-xhigh/mythos-craft.html | 1848 -------- .../gpt-5-2/cursor-xhigh/pelican-cycling.svg | 390 -- .../cursor-xhigh/mythos-craft.html | 1554 ------ .../cursor-xhigh/pelican-cycling.svg | 276 -- outputs/gpt-5-4/codex-xhigh/mythos-craft.html | 1302 ----- .../gpt-5-4/codex-xhigh/pelican-cycling-2.svg | 243 - .../gpt-5-4/codex-xhigh/pelican-cycling.svg | 217 - .../gpt-5-4/codex-xhigh/skeleton-watch.html | 1729 ------- .../gpt-5-4/cursor-xhigh/mythos-craft.html | 2116 --------- .../gpt-5-4/cursor-xhigh/pelican-cycling.svg | 276 -- .../mythos-craft.html | 1334 ------ .../pelican-cycling.svg | 439 -- .../skeleton-watch.html | 1412 ------ .../gpt-5-5/codex-cli-xhigh/mythos-craft.html | 1094 ----- .../codex-cli-xhigh/pelican-cycling.svg | 240 - .../codex-cli-xhigh/skeleton-watch.html | 1048 ----- .../mythos-craft-block-era.html | 1834 -------- .../codex-cli-ultra/mythos-craft.html | 488 -- .../codex-cli-ultra/pelican-coastal-ride.svg | 320 -- .../codex-cli-ultra/pelican-cycling.svg | 357 -- .../codex-cli-ultra/pelican-cyclist.svg | 418 -- .../skeleton-watch-calibre-01.html | 1608 ------- .../codex-cli-ultra/skeleton-watch.html | 1950 -------- .../codex-cli-ultra/mythos-craft.html | 1078 ----- .../codex-cli-ultra/pelican-cycling.svg | 290 -- .../codex-cli-ultra/skeleton-watch.html | 1605 ------- .../grok-4-3/cursor-default/mythos-craft.html | 540 --- .../cursor-default/pelican-cycling.svg | 131 - .../grok-build-tui-high/mythos-craft.html | 760 --- .../grok-build-tui-high/pelican-cycling.svg | 334 -- .../grok-build-tui-high/skeleton-watch.html | 679 --- .../grok-build-tui-max/mythos-craft.html | 1711 ------- .../grok-build-tui-max/pelican-cycling.svg | 568 --- .../tinker-web-xhigh/mythos-craft.html | 767 --- .../tinker-web-xhigh/pelican-cycling.svg | 172 - .../kimi-code-thinking/mythos-craft.html | 1608 ------- .../kimi-code-thinking/pelican-cycling.svg | 404 -- .../kimi-code-thinking/mythos-craft.html | 1173 ----- .../kimi-code-thinking/pelican-cycling.svg | 322 -- .../kimi-code-thinking/skeleton-watch.html | 1023 ---- .../kimi-k3/kimi-code-max/mythos-craft.html | 1189 ----- .../kimi-k3/kimi-code-max/pelican-cycling.svg | 624 --- .../kimi-k3/kimi-web-max/mythos-craft.html | 854 ---- .../skeleton-watch.html | 1090 ----- .../mythos-craft-2.html | 919 ---- .../mythos-craft.html | 590 --- .../pelican-cycling-2.svg | 430 -- .../pelican-cycling.svg | 291 -- .../skeleton-watch.html | 456 -- .../claude-code-max/mythos-craft.html | 1144 ----- .../claude-code-max/pelican-cycling.svg | 223 - .../mimo-v2-5/micode-high/mythos-craft.html | 628 --- .../mimo-v2-5/micode-high/pelican-cycling.svg | 329 -- .../mimo-v2-5/micode-high/skeleton-watch.html | 774 --- .../pelican-cycling.svg | 287 -- .../pelican-cycling-2.svg | 488 -- .../pelican-cycling.svg | 460 -- .../vibe-thinking/mythos-craft.html | 1141 ----- .../vibe-thinking/pelican-cycling.svg | 99 - .../claude-code-max/mythos-craft.html | 1072 ----- .../claude-code-max/pelican-cycling.svg | 338 -- .../qoder-default/mythos-craft.html | 1372 ------ .../qoder-default/pelican-cycling.svg | 579 --- .../claude-code-high/mythos-craft.html | 1978 -------- .../claude-code-high/pelican-cycling.svg | 418 -- scripts/update-registry.ts | 139 - scripts/validate-data.ts | 167 - 259 files changed, 1 insertion(+), 121455 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/workflows/ci.yml delete mode 100644 .gitignore delete mode 100644 AGENTS.md delete mode 100644 LICENSE delete mode 100644 README.en.md delete mode 100644 cases.json delete mode 100644 models/claude-fable-5-cc-high.json delete mode 100644 models/claude-fable-5-cc-xhigh.json delete mode 100644 models/claude-fable-5-cc.json delete mode 100644 models/claude-fable-5-cursor.json delete mode 100644 models/claude-fable-5.json delete mode 100644 models/claude-haiku-4-5-cc.json delete mode 100644 models/claude-opus-4-5-cursor.json delete mode 100644 models/claude-opus-4-6-cc.json delete mode 100644 models/claude-opus-4-6-cursor.json delete mode 100644 models/claude-opus-4-7-cc.json delete mode 100644 models/claude-opus-4-7-cursor.json delete mode 100644 models/claude-opus-4-8-cc-xhigh.json delete mode 100644 models/claude-opus-4-8-cc.json delete mode 100644 models/claude-sonnet-4-6-cc.json delete mode 100644 models/claude-sonnet-4-6-cursor.json delete mode 100644 models/claude-sonnet-5-cc-max.json delete mode 100644 models/composer-2-5-fast.json delete mode 100644 models/composer-2-5-grok-build.json delete mode 100644 models/composer-2-5.json delete mode 100644 models/deepseek-v4-flash-cc.json delete mode 100644 models/deepseek-v4-flash-reasonix.json delete mode 100644 models/deepseek-v4-pro.json delete mode 100644 models/doubao-seed-2-0-mini.json delete mode 100644 models/doubao-seed-2-0-pro.json delete mode 100644 models/gemini-3-1-pro-aistudio.json delete mode 100644 models/gemini-3-1-pro-cursor.json delete mode 100644 models/gemini-3-1-pro-gemini-web.json delete mode 100644 models/gemini-3-1-pro.json delete mode 100644 models/gemini-3-5-flash-aistudio.json delete mode 100644 models/gemini-3-5-flash-cursor.json delete mode 100644 models/gemini-3-5-flash.json delete mode 100644 models/glm-5-1.json delete mode 100644 models/glm-5-2.json delete mode 100644 models/glm-5-turbo.json delete mode 100644 models/gpt-5-2-cursor.json delete mode 100644 models/gpt-5-3-codex-cursor.json delete mode 100644 models/gpt-5-4-cursor.json delete mode 100644 models/gpt-5-4-xhigh.json delete mode 100644 models/gpt-5-5-pro.json delete mode 100644 models/gpt-5-5-xhigh.json delete mode 100644 models/gpt-5-6-sol-codex-cli-max.json delete mode 100644 models/gpt-5-6-sol-codex-cli-xhigh.json delete mode 100644 models/gpt-5-6-sol-ultra.json delete mode 100644 models/gpt-5-6-terra-codex-cli-xhigh.json delete mode 100644 models/gpt-5-6-terra.json delete mode 100644 models/grok-4-3-cursor.json delete mode 100644 models/grok-4-5.json delete mode 100644 models/grok-build.json delete mode 100644 models/inkling.json delete mode 100644 models/kimi-k2-6.json delete mode 100644 models/kimi-k2-7-code.json delete mode 100644 models/kimi-k3-kimi-code-max.json delete mode 100644 models/kimi-k3.json delete mode 100644 models/mimo-v2-5-pro-micode-high.json delete mode 100644 models/mimo-v2-5-pro-mimocode.json delete mode 100644 models/mimo-v2-5-pro-ultraspeed.json delete mode 100644 models/minimax-m2-7.json delete mode 100644 models/minimax-m3.json delete mode 100644 models/mistral-medium-3-5.json delete mode 100644 models/nex-n2-pro-cc.json delete mode 100644 models/qwen3-7-max.json delete mode 100644 models/step-3-7-flash.json delete mode 100644 models/xiaomi-mimo-v2-5-pro.json delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/bun.lock delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/index.html delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/package.json delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/App.tsx delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/ai.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/audio.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/character.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/effects.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/engine.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/map.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/nav.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/physics.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/soldier.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/store.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/types.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/viewmodel.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/weapons.ts delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/main.tsx delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/HUD.tsx delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/hud.css delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/tsconfig.json delete mode 100644 outputs/claude-fable-5/claude-code-high/cs-dust2/vite.config.ts delete mode 100644 outputs/claude-fable-5/claude-code-max/mythos-craft.html delete mode 100644 outputs/claude-fable-5/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/claude-fable-5/claude-code-xhigh/skeleton-watch.html delete mode 100644 outputs/claude-fable-5/claude-web-app-max/mythos-craft.html delete mode 100644 outputs/claude-fable-5/claude-web-app-max/pelican-cycling.svg delete mode 100644 outputs/claude-fable-5/cursor-high/mythos-craft.html delete mode 100644 outputs/claude-fable-5/cursor-high/pelican-cycling.svg delete mode 100644 outputs/claude-haiku-4-5/claude-code-default/mythos-craft.html delete mode 100644 outputs/claude-haiku-4-5/claude-code-default/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-5/cursor-thinking/mythos-craft.html delete mode 100644 outputs/claude-opus-4-5/cursor-thinking/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-6/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-6/claude-code-max/skeleton-watch.html delete mode 100644 outputs/claude-opus-4-6/cursor-max/mythos-craft.html delete mode 100644 outputs/claude-opus-4-6/cursor-max/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-7/claude-code-max/mythos-craft.html delete mode 100644 outputs/claude-opus-4-7/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-7/claude-code-max/skeleton-watch.html delete mode 100644 outputs/claude-opus-4-7/cursor-max/mythos-craft.html delete mode 100644 outputs/claude-opus-4-7/cursor-max/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/.gitignore delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/README.md delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/bun.lock delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/dust2-arena.html delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/index.html delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/package.json delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/App.tsx delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/GameCanvas.tsx delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Hud.tsx delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Menu.tsx delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Minimap.tsx delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/ai.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/audio.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/collision.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/combat.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/constants.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/dust2.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/effects.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/characterModel.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/weaponModels.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/grid.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/input.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/mathUtils.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/navmesh.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/player.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/scene.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/store.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/types.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/weapons.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/world.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/main.tsx delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/styles.css delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/tsconfig.json delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.config.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.single.config.ts delete mode 100644 outputs/claude-opus-4-8/claude-code-max/mythos-craft-2.html delete mode 100644 outputs/claude-opus-4-8/claude-code-max/mythos-craft.html delete mode 100644 outputs/claude-opus-4-8/claude-code-max/pelican-cycling-2.svg delete mode 100644 outputs/claude-opus-4-8/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/claude-opus-4-8/claude-code-max/skeleton-watch.html delete mode 100644 outputs/claude-sonnet-4-6/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/claude-sonnet-4-6/cursor-high/pelican-cycling-2.svg delete mode 100644 outputs/claude-sonnet-4-6/cursor-high/pelican-cycling.svg delete mode 100644 outputs/composer-2-5/cursor-default/mythos-craft.html delete mode 100644 outputs/composer-2-5/cursor-default/pelican-cycling.svg delete mode 100644 outputs/composer-2-5/cursor-max/mythos-craft.html delete mode 100644 outputs/composer-2-5/grok-build-tui-default/mythos-craft.html delete mode 100644 outputs/composer-2-5/grok-build-tui-default/pelican-cycling.svg delete mode 100644 outputs/deepseek-v4-flash/claude-code-max/mythos-craft.html delete mode 100644 outputs/deepseek-v4-flash/reasonix-max/skeleton-watch.html delete mode 100644 outputs/deepseek-v4-pro/claude-code-max/mythos-craft.html delete mode 100644 outputs/deepseek-v4-pro/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/deepseek-v4-pro/claude-code-max/skeleton-watch.html delete mode 100644 outputs/doubao-seed-2-0-mini/doubao-web-fast-mode/pelican-cycling.svg delete mode 100644 outputs/doubao-seed-2-0-pro/doubao-web-pro-mode/pelican-cycling.svg delete mode 100644 outputs/gemini-3-1-pro/antigravity-high/mythos-craft.html delete mode 100644 outputs/gemini-3-1-pro/antigravity-high/pelican-cycling-2.svg delete mode 100644 outputs/gemini-3-1-pro/antigravity-high/skeleton-watch.html delete mode 100644 outputs/gemini-3-1-pro/cursor-default/mythos-craft.html delete mode 100644 outputs/gemini-3-1-pro/cursor-default/pelican-cycling.svg delete mode 100644 outputs/gemini-3-1-pro/gemini-web-deepthink/mythos-craft.html delete mode 100644 outputs/gemini-3-1-pro/gemini-web-deepthink/pelican-cycling.svg delete mode 100644 outputs/gemini-3-1-pro/gemini-web-deepthink/skeleton-watch.html delete mode 100644 outputs/gemini-3-1-pro/google-ai-studio-high/pelican-cycling.svg delete mode 100644 outputs/gemini-3-1-pro/google-ai-studio-high/skeleton-watch.html delete mode 100644 outputs/gemini-3-5-flash/antigravity-high/mythos-craft.html delete mode 100644 outputs/gemini-3-5-flash/antigravity-high/pelican-cycling-2.svg delete mode 100644 outputs/gemini-3-5-flash/antigravity-high/skeleton-watch.html delete mode 100644 outputs/gemini-3-5-flash/cursor-default/mythos-craft.html delete mode 100644 outputs/gemini-3-5-flash/cursor-default/pelican-cycling.svg delete mode 100644 outputs/gemini-3-5-flash/google-ai-studio-high/pelican-cycling.svg delete mode 100644 outputs/glm-5-1/zcode-max/pelican-cycling.svg delete mode 100644 outputs/glm-5-2/zcode-max/mythos-craft.html delete mode 100644 outputs/glm-5-2/zcode-max/pelican-cycling-2.svg delete mode 100644 outputs/glm-5-2/zcode-max/pelican-cycling.svg delete mode 100644 outputs/glm-5-2/zcode-max/skeleton-watch.html delete mode 100644 outputs/glm-5-turbo/zcode-thinking/mythos-craft-2.html delete mode 100644 outputs/glm-5-turbo/zcode-thinking/mythos-craft.html delete mode 100644 outputs/glm-5-turbo/zcode-thinking/pelican-cycling.svg delete mode 100644 outputs/gpt-5-2/cursor-xhigh/mythos-craft.html delete mode 100644 outputs/gpt-5-2/cursor-xhigh/pelican-cycling.svg delete mode 100644 outputs/gpt-5-3-codex/cursor-xhigh/mythos-craft.html delete mode 100644 outputs/gpt-5-3-codex/cursor-xhigh/pelican-cycling.svg delete mode 100644 outputs/gpt-5-4/codex-xhigh/mythos-craft.html delete mode 100644 outputs/gpt-5-4/codex-xhigh/pelican-cycling-2.svg delete mode 100644 outputs/gpt-5-4/codex-xhigh/pelican-cycling.svg delete mode 100644 outputs/gpt-5-4/codex-xhigh/skeleton-watch.html delete mode 100644 outputs/gpt-5-4/cursor-xhigh/mythos-craft.html delete mode 100644 outputs/gpt-5-4/cursor-xhigh/pelican-cycling.svg delete mode 100644 outputs/gpt-5-5-pro/chatgpt-web-extended-pro/mythos-craft.html delete mode 100644 outputs/gpt-5-5-pro/chatgpt-web-extended-pro/pelican-cycling.svg delete mode 100644 outputs/gpt-5-5-pro/chatgpt-web-extended-pro/skeleton-watch.html delete mode 100644 outputs/gpt-5-5/codex-cli-xhigh/mythos-craft.html delete mode 100644 outputs/gpt-5-5/codex-cli-xhigh/pelican-cycling.svg delete mode 100644 outputs/gpt-5-5/codex-cli-xhigh/skeleton-watch.html delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft-block-era.html delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft.html delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/pelican-coastal-ride.svg delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cycling.svg delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cyclist.svg delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch-calibre-01.html delete mode 100644 outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch.html delete mode 100644 outputs/gpt-5-6-terra/codex-cli-ultra/mythos-craft.html delete mode 100644 outputs/gpt-5-6-terra/codex-cli-ultra/pelican-cycling.svg delete mode 100644 outputs/gpt-5-6-terra/codex-cli-ultra/skeleton-watch.html delete mode 100644 outputs/grok-4-3/cursor-default/mythos-craft.html delete mode 100644 outputs/grok-4-3/cursor-default/pelican-cycling.svg delete mode 100644 outputs/grok-4-5/grok-build-tui-high/mythos-craft.html delete mode 100644 outputs/grok-4-5/grok-build-tui-high/pelican-cycling.svg delete mode 100644 outputs/grok-4-5/grok-build-tui-high/skeleton-watch.html delete mode 100644 outputs/grok-build/grok-build-tui-max/mythos-craft.html delete mode 100644 outputs/grok-build/grok-build-tui-max/pelican-cycling.svg delete mode 100644 outputs/inkling/tinker-web-xhigh/mythos-craft.html delete mode 100644 outputs/inkling/tinker-web-xhigh/pelican-cycling.svg delete mode 100644 outputs/kimi-k2-6/kimi-code-thinking/mythos-craft.html delete mode 100644 outputs/kimi-k2-6/kimi-code-thinking/pelican-cycling.svg delete mode 100644 outputs/kimi-k2-7-code/kimi-code-thinking/mythos-craft.html delete mode 100644 outputs/kimi-k2-7-code/kimi-code-thinking/pelican-cycling.svg delete mode 100644 outputs/kimi-k2-7-code/kimi-code-thinking/skeleton-watch.html delete mode 100644 outputs/kimi-k3/kimi-code-max/mythos-craft.html delete mode 100644 outputs/kimi-k3/kimi-code-max/pelican-cycling.svg delete mode 100644 outputs/kimi-k3/kimi-web-max/mythos-craft.html delete mode 100644 outputs/mimo-v2-5-pro-mimocode/skeleton-watch.html delete mode 100644 outputs/mimo-v2-5-pro-ultraspeed/mythos-craft-2.html delete mode 100644 outputs/mimo-v2-5-pro-ultraspeed/mythos-craft.html delete mode 100644 outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling-2.svg delete mode 100644 outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling.svg delete mode 100644 outputs/mimo-v2-5-pro-ultraspeed/skeleton-watch.html delete mode 100644 outputs/mimo-v2-5-pro/claude-code-max/mythos-craft.html delete mode 100644 outputs/mimo-v2-5-pro/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/mimo-v2-5/micode-high/mythos-craft.html delete mode 100644 outputs/mimo-v2-5/micode-high/pelican-cycling.svg delete mode 100644 outputs/mimo-v2-5/micode-high/skeleton-watch.html delete mode 100644 outputs/minimax-m2-7/minimax-code-web-thinking/pelican-cycling.svg delete mode 100644 outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling-2.svg delete mode 100644 outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling.svg delete mode 100644 outputs/mistral-medium-3-5/vibe-thinking/mythos-craft.html delete mode 100644 outputs/mistral-medium-3-5/vibe-thinking/pelican-cycling.svg delete mode 100644 outputs/nex-n2-pro/claude-code-max/mythos-craft.html delete mode 100644 outputs/nex-n2-pro/claude-code-max/pelican-cycling.svg delete mode 100644 outputs/qwen3-7-max/qoder-default/mythos-craft.html delete mode 100644 outputs/qwen3-7-max/qoder-default/pelican-cycling.svg delete mode 100644 outputs/step-3-7-flash/claude-code-high/mythos-craft.html delete mode 100644 outputs/step-3-7-flash/claude-code-high/pelican-cycling.svg delete mode 100644 scripts/update-registry.ts delete mode 100644 scripts/validate-data.ts diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index a691a45..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,34 +0,0 @@ - - - -## 产出说明 / Run info - -- 模型 / Model: -- 厂商 / Vendor: -- 运行环境 / Harness(如 ChatGPT Web、Claude Code、Codex CLI、AntiGravity…,这是工具不是模型): -- 思考配额 / Thinking effort(如 Max、High、xhigh、Extended Pro、Thinking…): -- 是否一次生成 / One-shot?(是/否;若有修复请在 note 里说明 / if fixed, document it in the note) - -## 生成凭证截图 / Proof screenshot **(required)** - - - - -请贴一张**生成过程截图**:你的 harness / IDE 中能看到**模型名 + 思考配额**正在产出本产物, -作为「确实用了这套 harness + 模型 + effort」的凭证。 -Please attach a screenshot of the generation showing the **model name + effort** in your harness/IDE. - -## 自查 / Checklist - -- [ ] 只改了两类文件:`outputs//.` + `models/.json` / only the artifact + its JSON -- [ ] **没有**手改 `README.md` / `README.en.md`(注册表合并后由 CI 自动同步)/ did **not** hand-edit the README registry (auto-synced after merge) -- [ ] 模型 id 用短横线、以**模型**命名(非 harness),如 `deepseek-v4-flash-reasonix` / dash-case id named after the model, not the harness -- [ ] `harness` 与 `effort` 如实填写(站点据此生成 metadata 与品牌 icon)/ `harness` and `effort` are accurate -- [ ] 用 harness **默认形态**生成,未额外加载自带以外的 skill / 插件 / MCP / 自定义系统提示 / ran the harness as it ships — no extra skills / plugins / MCP / custom prompts -- [ ] 每条 run 的 `note` 双语(zh + en,zh 先,无 emoji)填了来历 / bilingual `note`, zh first, no emojis -- [ ] 同一模型换 Harness 或思考配额是**新建一个 JSON 条目** / a different harness or effort = a NEW json entry -- [ ] `contributor` 是我的 GitHub 用户名 / `contributor` is my GitHub username -- [ ] 已贴生成凭证截图 / attached the proof screenshot above -- [ ] 本地 `bun scripts/validate-data.ts` 通过 / `bun scripts/validate-data.ts` passes locally - - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 33096ef..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: CI - -on: - pull_request: - push: - branches: [main] - -permissions: - contents: read - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 - - name: Validate contribution data - run: bun scripts/validate-data.ts - - sync-registry: - # The README Registry tables are generated from models/*.json. Contributors - # do not edit them by hand; on every push to main we regenerate and commit - # any drift back. Commits pushed with GITHUB_TOKEN do not retrigger - # workflows, and the message carries [skip ci] too, so there is no loop. - if: github.event_name == 'push' - needs: validate - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 - - name: Regenerate README registry - run: bun scripts/update-registry.ts - - name: Commit if registry drifted - run: | - if git diff --quiet -- README.md README.en.md; then - echo "Registry already in sync." - exit 0 - fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -am "chore: sync README registry [skip ci]" - git push origin HEAD:main - - trigger-site-rebuild: - # The site lives in the private nagi-bench-site repo (Cloudflare Pages). - # With SITE_DISPATCH_TOKEN set the rebuild is instant; without it the - # site's 6-hour cron picks the new data up anyway. - if: github.event_name == 'push' - needs: validate - runs-on: ubuntu-latest - steps: - - name: Dispatch data-updated to nagi-bench-site - env: - TOKEN: ${{ secrets.SITE_DISPATCH_TOKEN }} - run: | - if [ -z "$TOKEN" ]; then - echo "SITE_DISPATCH_TOKEN not set; relying on the site's scheduled rebuild." - exit 0 - fi - curl -sf -X POST \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/vnd.github+json" \ - https://api.github.com/repos/nagi-studio/nagi-bench-site/dispatches \ - -d '{"event_type":"data-updated"}' diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 44bc7ad..0000000 --- a/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -.DS_Store -node_modules/ -dist/ -site/public/outputs/ -.agents/ -.claude/ -skills-lock.json - -# wrangler local state -.wrangler/ - -# Local-only Claude Code guidance (kept out of the public repo) -CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 41f1ea0..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,195 +0,0 @@ -# AGENTS.md - -Guidance for humans and coding agents contributing to **NAGI BENCH** data -(https://bench.nagi.fun/). Read this before opening a PR. - -## What this repo is - -The **public data repo**: community-contributed *one-shot* LLM eval artifacts. -You add a model's raw output for a case; the site renders it verbatim. This repo -holds **data only** — no site code, no build of the page you see. - -## A contribution is exactly two files - -1. **The artifact** — the raw model output, dropped at - `outputs//.` (e.g. a single-file `.html` or `.svg`). -2. **The registration** — `models/.json` declaring it. - -Do **not** touch anything else. In particular: - -- **Do not edit `README.md` / `README.en.md`.** The Registry tables are - generated from `models/*.json` and synced automatically after merge. Hand - edits are overwritten. -- **Do not edit `cases.json`.** Cases are maintainer-owned. - -## `models/.json` schema - -```jsonc -{ - "label": "DeepSeek V4 Flash", // human-facing model name (required) - "vendor": "DeepSeek", // who makes the model (required) - "harness": "Reasonix", // the tool/agent/UI you ran it in (required) - "effort": "Max", // thinking budget / effort level (required) - "artifactDir": "deepseek-v4-flash/reasonix-max", // optional; defaults to - "order": 50, // optional display sort - "runs": { - "skeleton-watch": { - "note": { // REQUIRED, bilingual, zh first, no emojis - "zh": "在 Reasonix 中以 DeepSeek V4 Flash(Max)一次生成,未修改。", - "en": "One-shot by DeepSeek V4 Flash (Max effort) in Reasonix, unmodified." - }, - "contributor": "your-github-username" - } - } -} -``` - -### Naming rules - -- **The filename IS the entry id** — lowercase letters, digits and dashes only - (`deepseek-v4-flash-reasonix`). It is the **stable voting key** and the default - `outputs/` folder, so name it after the **model**, not the harness. Bad: - `reasonix-reasonix-max`. Good: `deepseek-v4-flash-reasonix`. -- `artifactDir` may be one or two dash-case segments - (`deepseek-v4-flash/reasonix-max`); set it when several entries share a model - folder. Leave it out to default to the id. - -### One entry per (model × harness × effort) - -The same model under a different **harness** or **effort** is a **separate** -`models/*.json` file, not an extra variant inside an existing one. "Codex", -"Cursor", "Claude Code", "AntiGravity" name the **harness**, never the model. - -### Multiple takes of one case - -Ran the **same** model × harness × effort on a case more than once and want to -keep several outputs? Make `runs.` an **array** — this is the *only* -case where extra artifacts live inside one entry (a different harness/effort is -still a new file, per above): - -```jsonc -"runs": { - "pelican-cycling": [ - { "note": { "zh": "…", "en": "…" }, "contributor": "alice" }, - { "file": "pelican-coastal-ride.svg", "note": { "zh": "…", "en": "…" }, "contributor": "bob" } - ] -} -``` - -- The **first** variant may omit `file` (defaults to `.`); **every - extra** variant needs its own distinct, descriptive dash-case `file` - (`pelican-coastal-ride.svg`). Two variants may not resolve to the same file. -- **Never name an artifact `index.html`** — it is served as the folder's default - page. Use the case name plus a short suffix (`mythos-craft-block-era.html`). -- Each variant carries its own `note` and may set its own `contributor`, so - different people can add takes to the same model entry. - -### The `note` is required and bilingual - -Every run needs `note.zh` + `note.en` documenting provenance: which harness, -which effort, one-shot or fixed. If you applied any fix, say where the bug was -and what you changed. **No emojis anywhere** (hard rule). zh first. - -### Run the bare harness — NO skills, NO plugins - -Run the model with the harness's default model and effort, but otherwise -**stripped down**: **disable every skill and every plugin — including the ones -the harness ships with and would auto-invoke** — and add no MCP servers and no -custom system prompt. A skill or plugin (a built-in `design`, `gsap`, game, or -diagram helper, an added toolset, etc.) rewrites the output far more than the -model itself does, so a run with any of them active measures the tooling, not the -model × harness × effort. It is not comparable to other entries and **will not be -accepted**. Disclosing it in `note` does not fix this: leaderboard identity is -only model × harness × effort, so a modified setup gets no separate identity — it -would just be mixed into a row it is not comparable with. - -### Keep the artifact anonymous — no identity leaks - -**The output must not reveal which model, vendor, or harness produced it.** Strip -any `` header, watermark, "as an AI / as a large -language model" phrasing, or signature in visible text or code comments before -you submit. Blind Arena battles depend on outputs being anonymous, so a -self-identifying artifact invalidates the entry. - -## React cases — contribute `src/` only - -Some cases (marked `kind: "react"` in `cases.json`) ask for a real multi-file -React project instead of a single file. For these your artifact is **the `src/` -tree only** — multiple files and nested folders are fine — dropped at -`outputs//src/`. The site owns the whole toolchain and builds every -React case with **one shared scaffold** (its own installed React + Vite), so -there is no per-project dependency setup: - -- **Do NOT include `package.json`, a lockfile, `node_modules`, `index.html`, or - any build / Vite / TS config.** The scaffold supplies all of it. -- **Use only libraries the site already ships** (React + ReactDOM, plus whatever - is in its `package.json`). The build installs nothing new — you cannot pull in - arbitrary npm packages. -- **The entry point is `src/main.tsx`**, mounting your app into `
`. -- At build time the `src/` is bundled and inlined into **one self-contained HTML - file** that the normal viewer serves verbatim. The anonymity rule above still - applies: no model / vendor / harness identity anywhere in the code. - -## Agent cases — maintainer-run only - -Some cases (marked `kind: "agent"` in `cases.json`, currently `turf-war`) ask -the model to write a game-playing agent that battles other models' agents, -ranked by real wins instead of votes. These cases are **not open for artifact -PRs**, by design: - -- Policy files are deliberately kept off the public repo — if submissions were - public, later entrants could read earlier policies and prompt their model to - counter them, which breaks the one-shot fairness of the case. -- All runs are produced by the maintainer, feeding every model the identical - canonical prompt one-shot (no test runs, no iteration, no extra hints). - Battles are refereed server-side inside an instrumented sandbox with a - deterministic compute budget; the browser only replays action logs. -- The registration in `models/.json` (a `runs.` entry with - the usual bilingual provenance note) is the only public trace; there is no - `outputs/` artifact for these cases. -- Want a model or harness combo included? Open an issue and the maintainer - will run it. - -## Review guidelines - -NAGI BENCH stores raw benchmark artifacts. Reviewers, including Codex Review, -must **not** request fixes for gameplay, rendering, animation, JavaScript -correctness, UX, visual quality, performance, accessibility, or any other -internal behavior of files under `outputs/`. Broken or low-quality artifacts are -valid benchmark data when their provenance is documented. - -Only flag: - -- visible model, vendor, harness, contributor, or other identity leaks inside - `outputs/` that would break blind Arena review; -- contribution format or schema issues that violate this file or would fail - `bun scripts/validate-data.ts`. - -Do not ask contributors to improve or repair the submitted artifacts themselves. -If an artifact bug matters, mention it only as optional context for maintainers, -not as required PR feedback. - -## Before you open the PR - -```bash -bun scripts/validate-data.ts # the exact schema check CI runs -``` - -This enforces: dash-only ids, required bilingual `note`, declared artifacts -exist and are non-empty, no orphan files under `outputs/`. Green here = green CI. - -You do **not** need to run `update-registry.ts` — README is synced for you after -merge. - -### Attach a screenshot - -The PR template asks for a **screenshot of the generation** — your harness/IDE -showing the model name + effort while producing this artifact. It is the proof -that the declared `harness` / `model` / `effort` are real. Paste it into the PR -body (GitHub hosts it); **do not commit image files** into the repo. - -## Conventions - -- No emojis in any data, note, or UI-bound text. -- `outputs/` files are served verbatim in a sandboxed iframe. Keep them - self-contained; external resources should be well-known CDNs only. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 7203af6..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 shuiyu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 00198d8..0000000 --- a/README.en.md +++ /dev/null @@ -1,119 +0,0 @@ -# NAGI BENCH - -[中文](./README.md) | English - -One-shot LLM eval cases by NAGI STUDIO: same prompt, different model x harness x effort combinations, one attempt and no retries — a side-by-side record of the runnable artifacts they ship. - -**Live site:** https://bench.nagi.fun/ - -

- X - Discord - Xiaohongshu - Bilibili -

- - -## Models vs harnesses - -> **Model + Harness = Agent** — a model is just weights; wrap it in a runtime and it becomes an agent that can actually do the work. That agent is the unit this bench evaluates. - -- **Model**: the weights and inference engine itself — GPT-5.5, Gemini 3.1 Pro, Claude Fable 5. Reasoning effort is a capability dial of the model itself: the same weights at high vs low effort reason at depths that feel like two different models, so effort belongs to the "model" dimension alongside the weights — judging a model while ignoring its effort isn't fair play. This bench defaults to max and labels the effort of every combination. -- **Harness**: the product/scaffolding wrapping the model — Codex CLI, Cursor, AntiGravity, the Claude web app. It controls tool calls, system prompts, context management and continuation strategy, and often shapes the outcome as much as the model does. -- The unit of evaluation here is therefore an **Agent**: the same model (including its effort) under a different harness is a different agent and a separate entry (GPT-5.5 Pro and GPT-5.5 running in Codex CLI at xhigh are two agents from the same model family). -- **The harness is evaluated as it ships, out of the box**: do not load skills / plugins / MCP servers / custom system prompts beyond what it bundles by default — they shift the output as much as swapping the harness does and break comparability between agents. Such runs are **not accepted** (the leaderboard identity is just model × harness × effort, so a `note` does not give them a separate identity). - -## Registry - - -> This table is generated from `models/*.json` by `bun scripts/update-registry.ts`; CI re-syncs it automatically after merge — contributors need not hand-edit it. - -| Model | Vendor | Harness x Effort | Runs | -|---|---|---|---| -| Claude Fable 5 | Anthropic | Claude Web App · Max
Claude Code · High
Claude Code · Max
Claude Code · xhigh
Cursor · High | 11 | -| Claude Sonnet 5 | Anthropic | Claude Code · Max | 01 | -| Claude Opus 4.8 | Anthropic | Claude Code · Max
Claude Code · xhigh | 08 | -| Claude Opus 4.7 | Anthropic | Claude Code · Max
Cursor · Max | 05 | -| Claude Opus 4.6 | Anthropic | Claude Code · Max
Cursor · Max | 04 | -| Claude Opus 4.5 | Anthropic | Cursor · Thinking | 02 | -| Claude Sonnet 4.6 | Anthropic | Claude Code · Max
Cursor · High | 03 | -| Claude Haiku 4.5 | Anthropic | Claude Code · Default | 02 | -| GPT-5.6-Sol | OpenAI | Codex CLI · ultra
Codex CLI · max
Codex CLI · xhigh | 09 | -| GPT-5.6-Terra | OpenAI | Codex CLI · ultra
Codex CLI · xhigh | 04 | -| GPT-5.5 Pro | OpenAI | ChatGPT Web · Extended Pro | 03 | -| GPT-5.5 | OpenAI | Codex CLI · xhigh | 03 | -| GPT-5.4 | OpenAI | Cursor · xhigh
Codex CLI · xhigh | 06 | -| GPT-5.3 Codex | OpenAI | Cursor · xhigh | 02 | -| GPT-5.2 | OpenAI | Cursor · xhigh | 02 | -| Gemini 3.1 Pro | Google | AntiGravity · High
Cursor · Default
Gemini Web · Deep Think
Google AI Studio · High | 11 | -| DeepSeek V4 Flash | DeepSeek | Claude Code · Max
Reasonix · Max | 02 | -| Gemini 3.5 Flash | Google | AntiGravity · High
Cursor · Default
Google AI Studio · High | 06 | -| Grok 4.5 | xAI | Grok Build TUI · High | 03 | -| Grok Build | xAI | Grok Build TUI · Max | 02 | -| Grok 4.3 | xAI | Cursor · Default | 02 | -| Nex-N2-Pro | Nex-AGI | Claude Code · Max | 02 | -| Composer 2.5 | Cursor | Cursor · Max
Cursor · Default
Grok Build TUI · Default | 05 | -| Mistral Medium 3.5 | Mistral AI | Vibe · Thinking | 02 | -| DeepSeek-V4-Pro | DeepSeek | Claude Code · Max | 03 | -| Doubao Seed 2.0 Pro | ByteDance | Doubao Web · Pro Mode | 01 | -| Doubao Seed 2.0 Mini | ByteDance | Doubao Web · Fast Mode | 01 | -| MiMo V2.5 | Xiaomi | MiMo Code · High | 03 | -| MiMo v2.5 Pro | Xiaomi | Claude Code · Max
MiMo Code · Max | 03 | -| MiMo v2.5 Pro UltraSpeed | Xiaomi | Web · Default | 05 | -| Kimi K3 | Moonshot AI | Kimi Code · Max
Kimi Web · Max | 04 | -| Kimi K2.7-Code | Moonshot AI | Kimi Code · Thinking | 03 | -| Kimi K2.6 | Moonshot AI | Kimi Code · Thinking | 02 | -| MiniMax M3 | MiniMax | MiniMax Code Web · Thinking | 02 | -| MiniMax M2.7 | MiniMax | MiniMax Code Web · Thinking | 01 | -| GLM-5.2 | Zhipu AI | ZCode · Max | 04 | -| GLM-5.1 | Zhipu AI | ZCode · Max | 01 | -| GLM-5 Turbo | Zhipu AI | ZCode · Thinking | 03 | -| Qwen3.7-Max | Alibaba | Qoder · Default | 02 | -| Step 3.7 Flash | StepFun | Claude Code · High | 02 | -| Inkling | Thinking Machines Lab | Tinker Web · xHigh | 02 | - - -## Arena blind battles & community board - -- Each case defaults to **Arena mode**: two anonymous artifacts battle (A / B / Neither) and identities reveal only after you vote; switch to **Demo Show** to browse everything (tabs are grouped by model — a model with several harnesses can be viewed singly or side by side). -- Casting 03 votes total unlocks the **community leaderboard**, ranked by Bradley-Terry scores (the LMSYS Chatbot Arena approach); "neither" counts separately as both-bad. -- Votes stay in the browser by default; deploying `worker/` (Cloudflare Worker + D1 + Turnstile, free tier) upgrades the board to sitewide crowdsourced data — see [worker/README.md](./worker/README.md). - -## Structure - -``` -outputs//. raw model artifacts (HTML / SVG), filename = case id -models/.json agent registry: label / vendor / harness / effort / artifactDir / order / run notes -cases.json case definitions (bilingual prompts, maintainer-owned) -scripts/validate-data.ts data validation (CI runs it on every PR) -scripts/update-registry.ts README Registry table generation (CI auto-syncs after merge) -``` - -> The site and vote-backend source lives in the private `nagi-bench-site` repo, deployed on Cloudflare Pages; this repo is the site's data source. - -## Validation - -```bash -bun scripts/validate-data.ts # the same data validation CI runs (run this before submitting) -bun scripts/update-registry.ts # optional: preview the Registry tables locally; CI syncs them after merge -``` - -## Contributing a run - -> Full rules live in [**AGENTS.md**](./AGENTS.md) (the contributor / AI-agent guide). - -> **If you are an AI agent (Claude Code / Codex / Cursor, etc.), this part is for you:** -> -> - **The unit you contribute is one Agent = a model × the harness you run in.** The `` (lowercase letters / digits / dashes) encodes that pairing — e.g. `gpt-5-5-pro`, `claude-fable-5-cc` (cc = Claude Code). The same model in a different harness is a different Agent with a different id. The `` is the vote and leaderboard identity; do not rename it just to reorganize files. -> - **There are five cases right now**, defined in [`cases.json`](./cases.json): `mythos-craft` (HTML, a playable voxel world), `pelican-cycling` (SVG, a pelican cycling by the sea), `skeleton-watch` (HTML, a skeleton mechanical watch), `cs-dust2` (React, a multi-file project), and `turf-war` (JS agents battling head-to-head, ranked by objective wins). The prompt lives in `cases.json` — **use it verbatim, do not paraphrase**. Note: `turf-war` does **not** accept artifact PRs — to keep earlier policies unscoutable, every run is executed and submitted personally by the maintainer Nagi ([@Nagi-ovo](https://github.com/Nagi-ovo)); open an issue to request a model. -> - **To find what's missing**: read `cases.json` (all cases) and `models/*.json` (what each Agent has run) — a `` absent from an Agent's json is an open slot; any row in the script-generated Registry table above whose "Runs" count is below the number of cases is an Agent missing a case; a brand-new Agent can fill them. -> - **Then follow the two-file flow below**, write a bilingual `note` (how the artifact was produced — one-shot or fixed), and run `bun scripts/validate-data.ts` until it passes before opening a PR. - -Contributions are data-only — no code changes needed: - -1. Artifact: preferably `outputs///.` (e.g. `outputs/gpt-5-5-pro/chatgpt-web-extended-pro/pelican-cycling.svg`). -2. Registration: `models/.json` (new file for a new combination; add to `runs` for an existing one) with `artifactDir` pointing at the artifact folder — see the schema example in the Chinese README. - -CI-enforced rules: dash-only lowercase `agent-id`s as stable identities; without `artifactDir`, artifacts default to `outputs//`; with `artifactDir`, use one or two lowercase dash-case path segments, preferably `/`. A bilingual provenance `note` is required per run (which harness, what effort, one-shot or fixed); every declared run must have its artifact; multiple versions of the same combination x case go in an array with distinct `file` names (e.g. `pelican-cycling-2.svg`). Set `contributor` to your GitHub username — the site shows your avatar linked to your profile next to the run. Fill in `harness` and `effort` truthfully for new combinations: the case page renders Harness / Effort metadata chips from these fields and auto-matches brand icons for the model, vendor and harness (via [lobe-icons](https://github.com/lobehub/lobe-icons)) — contributors never touch icons. - -PRs get data validation from CI; merges to `main` rebuild the site automatically (usually instant, at most 6 hours). diff --git a/README.md b/README.md index fd97c70..090e21f 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ 你好呀~这个仓库已经搬到更好用的地方啦。 -为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到 -**Gitee** 与 **GitHub** 主仓维护,这里就只保留这张"迁移小纸条"咯。 +为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到主仓维护,这里就只保留这张"迁移小纸条"咯。 📦 新家在这里: - Gitee:https://gitee.com/shuiyu1123/nagi-bench diff --git a/cases.json b/cases.json deleted file mode 100644 index 5d39435..0000000 --- a/cases.json +++ /dev/null @@ -1,120 +0,0 @@ -[ - { - "id": "mythos-craft", - "index": "01", - "kind": "html", - "title": { - "zh": "神话境界", - "en": "Mythos Craft" - }, - "tagline": { - "zh": "单个 HTML 文件,一次生成一款《我的世界》式的可玩 3D 体素世界。", - "en": "A playable Minecraft-style 3D voxel world, generated as a single HTML file in one shot." - }, - "prompt": { - "zh": "你是一个顶级的资深游戏开发者。请为我使用单 HTML5 和 Canvas(或 Three.js)编写一个《我的世界》克隆版。请包含以下核心功能:\n\n1. 一个基于柏林噪声(Perlin Noise)生成的无限或可滚动的 3D 地形。\n2. 第一人称视角,支持使用 WASD 移动和鼠标环视。\n3. 支持至少 3 种方块类型(如:泥土、草地、石头等),并支持鼠标左键破坏方块,右键放置方块。材质要尽可能还原。\n4. 要有一个内置的、极其丰富的神话幻想中的建筑和地形等,由你自行设计。", - "en": "You are a top-tier veteran game developer. Build me a Minecraft clone using a single HTML5 file and Canvas (or Three.js). Include the following core features:\n\n1. An infinite or scrollable 3D terrain generated from Perlin noise.\n2. A first-person view with WASD movement and mouse look.\n3. At least 3 block types (e.g. dirt, grass, stone), with left-click to break and right-click to place blocks. Keep the textures as faithful as possible.\n4. A built-in, extremely rich set of mythic-fantasy buildings and terrain, designed at your own discretion." - }, - "tags": [ - "HTML", - "3D", - "GAME", - "ONE-SHOT" - ] - }, - { - "id": "pelican-cycling", - "index": "02", - "kind": "svg", - "title": { - "zh": "鹈鹕海边骑行", - "en": "Pelican by the Sea" - }, - "tagline": { - "zh": "经典 SVG 测评题:让模型用代码「画」出一只骑自行车的鹈鹕。", - "en": "The classic SVG eval: make the model \"draw\" a pelican riding a bicycle, in code." - }, - "prompt": { - "zh": "制作一个逼真的、生动的、在海边骑着自行车的鹈鹕 ", - "en": "Create a realistic, lively of a pelican riding a bicycle by the sea." - }, - "tags": [ - "SVG", - "ILLUSTRATION", - "ONE-SHOT" - ] - }, - { - "id": "skeleton-watch", - "index": "03", - "kind": "html", - "title": { - "zh": "镂空机械表", - "en": "Skeleton Watch" - }, - "tagline": { - "zh": "单个 HTML 文件,一次生成一只可旋转、可爆炸视图的 3D 镂空机械腕表,机芯全可见。", - "en": "A single HTML file: a rotatable, exploded-view 3D skeleton mechanical watch with a fully visible movement, generated in one shot." - }, - "prompt": { - "zh": "创建一个精美、高细节的交互式 3D 镂空机械表。\n\n核心要求:\n• 完全可见的复杂机芯:包括主发条、齿轮系、带游丝的摆轮、擒纵机构、夹板、红宝石轴承等。\n• 真实的金属材质、蓝宝石水晶玻璃、反射、阴影,以及奢华腕表摄影级别的照明效果。\n• 荧光指针与刻度。\n• 交互式控制:支持旋转手表、切换爆炸视图、悬停/点击时高亮显示的零件标签、机芯信息面板。\n• 流畅的动画,达到专业级产品展示质量。\n• 深色优雅背景,带有细微的反射效果。\n\n在一次回复中尽可能真实且令人惊叹地完成。输出为一个完整的、自包含的单 HTML 文件,使用 Three.js (CDN),所有代码均采用内联形式。", - "en": "Create an exquisite, highly detailed, interactive 3D skeleton mechanical watch.\n\nCore requirements:\n• A fully visible, complex movement: mainspring, gear train, balance wheel with hairspring, escapement, bridges, ruby bearings, and so on.\n• Realistic metal materials, sapphire crystal glass, reflections, shadows, and luxury-watch photography-grade lighting.\n• Luminous hands and markers.\n• Interactive controls: rotate the watch, toggle an exploded view, part labels highlighted on hover/click, and a movement info panel.\n• Smooth animation at professional product-showcase quality.\n• A dark, elegant background with subtle reflections.\n\nMake it as realistic and stunning as possible in a single response. Output a complete, self-contained single HTML file using Three.js (CDN), with all code inline." - }, - "tags": [ - "HTML", - "3D", - "THREE.JS", - "ONE-SHOT" - ] - }, - { - "id": "turf-war", - "index": "04", - "kind": "agent", - "title": { - "zh": "圈地对决", - "en": "Turf War" - }, - "tagline": { - "zh": "每个模型一次性写出一个圈地智能体,在同一张网格战场上真刀真枪对战——排名不靠投票,靠客观胜负。", - "en": "Each model writes a territory-grabbing agent in one shot; agents battle head-to-head on the same grid — ranked by objective wins, not votes." - }, - "prompt": { - "zh": "你要为一个 1v1 的「圈地对决」(Turf War) 环境编写一个 JavaScript 智能体。这是一个双人零和、双方同时行动的博弈。你的目标只有一个:在与多个未知对手、多张随机地图的循环赛中拿到尽可能高的胜率。对手由其它同等水平的 Agent(模型 × Harness 组合)编写——不要依赖「对手会犯错」的脆弱套路,任何固定模式都可能被针对;但也不要为求稳放弃进攻,平局只得 0.5 分,一个只求不败的智能体拿不到高排名。这是你唯一一次提交:没有反馈、没有试跑、没有重试,成绩公开计入排行榜。请把你能写出的最强智能体写进这个文件。\n\n【环境规则】\n\n- 棋盘为 40×40 网格,坐标 (x, y),x 向右,y 向下,范围 0–39。每局按种子生成若干 180° 中心对称的岩石格(不可通行),出生点附近不会有岩石。\n- 双方从对角出生点出发,初始拥有出生点周围 3×3 领地。每 tick 双方同时移动一格,方向为 up / down / left / right 之一;全场共 1200 tick。\n- 在自己领地外移动会留下尾巴。回到自己领地的瞬间,你的尾巴以及被「尾巴 + 领地」围住的区域全部变成你的领地(包括对方领地)。围住判定:从棋盘边界向内 flood fill(岩石可穿过但不可被占有),无法到达的格子归你。\n- 任何人(包括你自己)踩到某玩家的尾巴,该尾巴的主人立即死亡。双方同 tick 进入同一格或互相穿过,双方同时死亡。撞岩石或出界,自己死亡。击杀判定基于本 tick 开始前的尾巴状态,双方完全对等。\n- 死亡后尾巴消失、领地保留;3 tick 后在出生点重生并重新获得周围 3×3 领地(覆盖任何归属),重生后 10 tick 无敌(不会死亡也不能击杀)。\n- 同 tick 结算顺序固定:移动 → 死亡判定 → 圈地 → 重生计时。1200 tick 结束时领地格数多者获胜,相等为平局。\n\n【接口】你必须交付一个 JS 文件:在能创建文件的环境中,按文末【本次运行】给出的文件名先创建文件,再分多次编辑逐段写入,把整份策略累积写完——不要在单次写入里把整份代码一次塞进去。原因:单次模型响应的输出(含推理 thinking + 正文 + 工具调用内容)有硬上限,一次性写入大文件容易撞上限而失败,而分多次编辑时每次都是独立的新预算。纯对话环境无法建文件时,才直接输出完整文件内容(此时请让策略尽量紧凑)。全程不得运行或试跑代码。文件顶层定义:\n\n```js\nfunction createAgent(config) {\n // config = { size: 40, totalTicks: 1200 }\n // 可以在闭包里保存任意记忆(允许并鼓励在对局中在线建模对手)\n return {\n act(obs) {\n return \"up\"; // \"up\" | \"down\" | \"left\" | \"right\"\n }\n };\n}\n```\n\nobs 每 tick 传入,字段:\n\n- obs.tick:当前 tick,从 0 起\n- obs.grid[y][x]:0 空地 · 1 我的领地 · 2 我的尾巴 · 3 对方领地 · 4 对方尾巴 · 5 岩石。grid 数组每 tick 会被复用,不要跨 tick 持有引用,需要历史请自行拷贝\n- obs.me / obs.opp:{ x, y, dir, alive, respawnIn, invincibleFor }\n- obs.scores:{ me, opp },双方当前领地格数\n- obs.rng():[0,1) 确定性随机数;需要随机时只准用它\n\n另外,请在返回的对象里附带 name 字段(与 act 并列):给你的算法起一个不超过 5 个字、有意思的名字,例如 { name: \"...\", act(obs) {...} }。\n\n视角是自我中心的:无论执哪一边,你都是 me。信息完全公开,没有战争迷雾。非法动作、抛异常或超出算力预算,该 tick 视为沿原方向直行。\n\n【运行时约束】\n\n- 纯 JavaScript(ES2020),单文件;禁止 import/require、网络、存储、Math.random、Date(运行环境会封禁它们)。\n- 算力限制是确定性的:你的代码会被自动插桩计数,每 tick 预算为 200,000 次「循环迭代 + 函数调用」。参考:一次 40×40 全图 BFS 约 2,000–6,000 次。超出预算该 tick 视为直行。\n- 完成本任务只依靠你自身的知识与推理:禁止联网搜索、禁止查阅外部文档或代码库、禁止调用任何 skill/插件/外部工具、禁止试运行代码。\n- 保持代码紧凑自足:聚焦一套有效策略,不要内联大型预计算表、穷举查找表或冗长注释。\n- 交付前静态自查:合法 ES2020、顶层定义了 createAgent、无 import / Math.random / Date。\n\n【评测】你的智能体将与其它 Agent 编写的智能体进行多局循环赛,每局地形随机、先后手轮换,按胜负用 Bradley-Terry 排名。请深思熟虑后一次性交付唯一、完整、可直接运行的 JS 文件,除该文件外不要有任何解释或多余文件。\n\n【本次运行】(此行由维护者在运行前填写,其余内容对所有模型一字不差)模型 {model} × Harness {harness} × 思考配额 {effort};如需创建文件,文件名为 {agent-id}.js。", - "en": "Write a JavaScript agent for a 1v1 \"Turf War\" environment. This is a two-player, zero-sum, simultaneous-move game. Your sole objective is to maximize your win rate in a round-robin against multiple unknown opponents across randomized maps. Opponents are written by other, equally capable Agents (an Agent = a model × harness combination) — do not rely on brittle patterns that assume opponent mistakes, as any fixed pattern can be exploited; but do not trade wins for safety either: a draw scores only 0.5, and an agent that merely avoids losing will not rank. This is your only submission: no feedback, no test runs, no retries, and the result is public on a leaderboard. Write the strongest agent you can into this file.\n\n[Environment]\n\n- The board is a 40×40 grid, coordinates (x, y), x rightward, y downward, range 0–39. Each match seeds a set of 180°-centrally-symmetric rock cells (impassable); no rocks appear near the spawns.\n- Both players start from opposite corners owning a 3×3 territory around their spawn. Each tick both players move one cell simultaneously (up / down / left / right); a match lasts 1200 ticks.\n- Moving outside your own territory leaves a trail. The moment you re-enter your own territory, your trail plus every region enclosed by trail + territory becomes yours (including the opponent's territory). Enclosure test: flood fill inward from the board border (rocks are transparent to the flood but can never be owned); unreachable cells are captured.\n- If anyone (including yourself) steps on a player's trail, that trail's owner dies immediately. Entering the same cell on the same tick, or swapping cells, kills both players. Hitting a rock or leaving the board kills you. Kill checks use the trail state from the start of the tick, so both sides are perfectly symmetric.\n- On death your trail vanishes but your territory is kept; you respawn at your spawn point after 3 ticks with a fresh 3×3 territory (overwriting any ownership) and 10 ticks of invincibility (you cannot die or kill).\n- Per-tick resolution order is fixed: moves → deaths → capture → respawn countdown. After 1200 ticks the larger territory wins; equal is a draw.\n\n[Interface] You must deliver one JS file: if your environment can create files, first create the file under the name given in the [This run] line, then write the whole policy by editing it in several steps, adding a section at a time — do NOT cram the entire file into one write. Reason: a single model response has a hard output cap (covering reasoning/thinking + text + tool-call content together), so writing a large file all at once can hit that cap and fail, whereas each separate edit gets its own fresh budget. Only when your environment cannot create files should you print the complete file content instead (and keep the policy compact in that case). Never run or test-run the code at any point. At top level it defines:\n\n```js\nfunction createAgent(config) {\n // config = { size: 40, totalTicks: 1200 }\n // keep any memory in the closure (in-match opponent modeling is allowed and encouraged)\n return {\n act(obs) {\n return \"up\"; // \"up\" | \"down\" | \"left\" | \"right\"\n }\n };\n}\n```\n\nobs is passed every tick:\n\n- obs.tick: current tick, starting at 0\n- obs.grid[y][x]: 0 empty · 1 my territory · 2 my trail · 3 opponent territory · 4 opponent trail · 5 rock. Grid arrays are reused across ticks — do not hold references across ticks; copy if you need history\n- obs.me / obs.opp: { x, y, dir, alive, respawnIn, invincibleFor }\n- obs.scores: { me, opp }, current territory cell counts\n- obs.rng(): deterministic random in [0,1); it is the only allowed source of randomness\n\nAlso include a name field on the returned object (next to act): give your algorithm a fun, memorable name of at most one short word (~10 characters), e.g. { name: \"...\", act(obs) {...} }.\n\nThe view is ego-centric: whichever side you play, you are me. Information is fully public — no fog of war. An invalid action, a thrown exception, or exceeding the compute budget makes you continue straight for that tick.\n\n[Runtime]\n\n- Pure JavaScript (ES2020), single file; import/require, network, storage, Math.random and Date are forbidden (the runtime blocks them).\n- The compute limit is deterministic: your code is automatically instrumented, with a per-tick budget of 200,000 loop iterations + function calls. Reference: one full-board 40×40 BFS costs about 2,000–6,000. Exceeding the budget means you walk straight that tick.\n- Rely solely on your own knowledge and reasoning: no web search, no consulting external docs or codebases, no skills/plugins/external tools, no test-running code.\n- Keep the code compact and self-contained: commit to one effective strategy; do not inline large precomputed tables, exhaustive lookup tables, or verbose commentary.\n- Static self-check before you deliver: valid ES2020, createAgent defined at top level, no import / Math.random / Date.\n\n[Evaluation] Your agent plays a multi-game round-robin against the agents written by other Agents (model × harness combos), with randomized terrain and alternating sides, ranked by Bradley-Terry on match outcomes. Think hard, then deliver a single, complete, directly runnable JS file in one shot — nothing but that file, no explanations or extra files.\n\n[This run] (this line is filled in by the maintainer before the run; everything else is identical for every model) Model {model} × Harness {harness} × Effort {effort}; if you create a file, name it {agent-id}.js." - }, - "tags": [ - "JS", - "AGENT", - "1V1", - "ONE-SHOT" - ], - "credit": { - "text": "Inspired by Jiayi Weng, Learning Beyond Gradients", - "url": "https://trinkle23897.github.io/learning-beyond-gradients/" - } - }, - { - "id": "cs-dust2", - "index": "05", - "kind": "react", - "title": { - "zh": "CS Dust2 5v5", - "en": "CS Dust2 5v5" - }, - "tagline": { - "zh": "React + three.js 从零手写的 3D 第一人称射击原型,复刻 Dust2 的 5v5 对战。", - "en": "A from-scratch 3D FPS in React + three.js: a 5v5 battle on a rebuilt Dust2." - }, - "prompt": { - "zh": "用 **React + TypeScript + three.js** 从零开发一个可在浏览器直接运行的 3D 第一人称射击原型:复刻 Dust2 核心区域的 5v5 对战。你可以自行搭建项目、安装依赖、运行调试并迭代,直到它能正常游玩。\n\n## 交付形式\n\n- 一个标准 **Vite + React 18 + TypeScript** 项目,含完整 `package.json`、`vite.config.ts`、`index.html`、`src/`,`npm install && npm run dev` 即可打开游玩。\n- **不使用任何外部资产文件**(3D 模型、贴图、音频一律不用)。地图、角色、武器全部在代码里用几何体 procedural 生成,声音用 Web Audio 程序化合成。第三方库只用 three / react / react-dom;寻路、状态机、物理、渲染循环都自己实现,不引入现成游戏引擎。\n\n## 1. Dust2 地图\n\n在 3D 世界里搭出空间尺度合理的 Dust2 经典区域,**必须完整包含**:T 出生点、CT 出生点、A大、A点、中门(含可穿过的中门门体)、猫道、B洞、B点,并保证这些区域按 Dust2 的实际走位彼此连通。要么全部包含,不要交出缺区域的残缺版本。所有墙体、箱子都有物理碰撞,玩家和 AI 都无法穿墙。\n\n## 2. 角色\n\n在没有外部模型的前提下,用代码搭出**类人型角色**:必须有独立的头、躯干、双臂、双腿——**严禁用胶囊体或圆柱体等基础几何体敷衍成一根柱子**。CT 与 T 两个阵营在外观上要能一眼区分,角色默认是持枪姿态,武器随角色朝向移动。\n\n## 3. 武器系统\n\n做一套可扩展的武器数据系统,支持在主武器 / 副武器 / 近战之间切换,并有对应的第一人称手持模型。至少还原以下手感差异:\n\n- **AK-47**:高伤害,开火后坐力剧烈(准星扩散 + 视角上扬明显)。\n- **M4A4**:中等伤害,后坐力低,射速高。\n- **AWP**:单发致命,射速极低,**右键开镜**(3D 视野拉近 + 2D 瞄准镜遮罩覆盖)。\n- **手枪**:至少 Glock(T 默认)、USP(CT 默认)、沙鹰,用于手枪局;伤害低于步枪、沙鹰介于两者之间且弹匣小。\n- **近战刀**。\n\n命中判定按 **Hitbox 分区**(头 / 胸 / 腹 / 手臂 / 腿),伤害各不相同,**爆头伤害是身体的两倍**。有护甲时按护甲减伤。\n\n## 4. 手枪局\n\n支持\"手枪局\"开局:全员只带默认手枪、没有主武器、护甲按手枪局配置。这是标准 CS 的第一回合形态。\n\n## 5. C4 炸弹与回合胜负\n\n- 回合开始时 C4 交给某个 T;持包者阵亡后炸弹掉落,可被其他 T 捡起。\n- **下包**:持包 T 在 A点或 B点范围内可安放 C4,安放后进入倒计时。\n- **拆包**:CT 站在已安放的 C4 处,持续一段时间完成拆除。\n- **回合结算**:T 清空 CT、或 C4 爆炸 → T 胜;CT 清空 T(且未下包)、或成功拆包 → CT 胜。\n- 玩家操控的角色阵亡后,可切换到存活队友的视角 / 接管其操控(bot)。\n\n## 6. 5v5 AI 战场\n\n场上共 10 人:1 名玩家 + 4 名 AI 队友,对抗 5 名 AI 敌人,分属 CT / T 两阵营。AI 需要:能在地图内自主寻路巡逻、不卡墙;有视野索敌判定(被墙挡住看不见);遭遇敌方阵营自动开火交战;并参与 C4 的下包 / 拆包流程(进攻方推包安放、防守方前往拆除)。\n\n## 7. 操作与 HUD\n\n- 流畅的第一人称控制:WASD 移动、空格跳跃、指针锁定鼠标转视角。\n- 现代 2D UI 覆盖层:十字准星、生命值 / 护甲、动态弹药面板(开火递减、换弹恢复)、右上角实时击杀播报(Killfeed)。\n- **小地图(minimap)**:常驻显示 Dust2 俯视轮廓,实时标出自己、队友、被看见的敌人的点位,以及 C4 的位置。\n\n## 8. 声音\n\n游戏要有音效反馈。由于不使用外部音频文件,用 **Web Audio API 程序化合成** 声音即可。至少包含:不同武器的开火声(AK / M4 / AWP / 手枪要有区分)、换弹声、脚步声、AWP 开镜声、命中反馈音、C4 安放 / 拆除 / 爆炸声,以及击杀提示音。\n\n## 架构要求\n\n这是工业级挑战。你要独立完成技术选型、架构设计、数据结构封装,以及渲染循环、物理帧更新、React 状态生命周期三者之间的数据同步。全局状态引擎、武器系统、AI 状态机、3D 渲染与物理组件等关键系统都要真正实现,而非留空占位。", - "en": "Build a browser-playable 3D first-person shooter prototype from scratch using **React + TypeScript + three.js**: a 5v5 battle recreating the core areas of Dust2. You may set up the project, install dependencies, run, debug and iterate until it is properly playable.\n\n## Deliverable\n\n- A standard **Vite + React 18 + TypeScript** project with a complete `package.json`, `vite.config.ts`, `index.html` and `src/`; `npm install && npm run dev` opens it to play.\n- **No external asset files whatsoever** (no 3D models, textures or audio). The map, characters and weapons are all generated procedurally from geometry in code, and sound is synthesized programmatically with Web Audio. The only third-party libraries are three / react / react-dom; pathfinding, state machines, physics and the render loop are all implemented yourself, with no off-the-shelf game engine.\n\n## 1. Dust2 map\n\nBuild the classic Dust2 areas at a sensible spatial scale in the 3D world, and you **must fully include**: T spawn, CT spawn, Long A, A site, Mid (with a passable set of Mid Doors), Catwalk, B tunnels and B site, connected to one another along Dust2's real routes. Include them all — do not submit a partial version missing areas. All walls and boxes have physical collision; neither players nor AI can pass through walls.\n\n## 2. Characters\n\nWith no external models, build **humanoid characters** in code: each must have a distinct head, torso, both arms and both legs — **do NOT cheat with a capsule or cylinder as a single column body**. The CT and T teams must be distinguishable at a glance; characters default to a weapon-holding pose and the weapon moves with the character's facing.\n\n## 3. Weapon system\n\nBuild an extensible weapon data system supporting switching between primary / secondary / melee, each with its own first-person held model. Reproduce at least these handling differences:\n\n- **AK-47**: high damage, heavy recoil after firing (pronounced crosshair spread + upward view kick).\n- **M4A4**: medium damage, low recoil, high fire rate.\n- **AWP**: one-shot lethal, very low fire rate, **right-click to scope** (3D zoom-in + a 2D scope overlay).\n- **Pistols**: at least Glock (T default), USP (CT default) and Deagle for pistol rounds; lower damage than rifles, Deagle in between with a small magazine.\n- **A melee knife**.\n\nHit detection uses **hitbox zones** (head / chest / stomach / arm / leg) with different damage each, and **headshot damage is twice body damage**. Armor reduces damage when present.\n\n## 4. Pistol round\n\nSupport a \"pistol round\" opening: everyone carries only their default pistol, no primary weapon, armor per pistol-round rules. This is the standard CS first round.\n\n## 5. C4 bomb and round win/loss\n\n- At round start the C4 is given to a T; when the carrier dies the bomb drops and can be picked up by another T.\n- **Plant**: a T carrying the bomb can plant the C4 within the A or B site, starting a countdown after planting.\n- **Defuse**: a CT standing at a planted C4 defuses it over a set time.\n- **Round resolution**: T wins by eliminating all CTs or the C4 exploding; CT wins by eliminating all Ts (with no plant) or by successfully defusing.\n- After your controlled character dies, you can switch to a living teammate's view / take over that bot.\n\n## 6. 5v5 AI battlefield\n\nTen players on the field: 1 human player + 4 AI teammates against 5 AI enemies, split into CT / T teams. The AI must: navigate and patrol the map autonomously without getting stuck on walls; have line-of-sight target detection (blocked by walls); automatically open fire on the enemy team on contact; and take part in the C4 plant / defuse flow (attackers push and plant, defenders go to defuse).\n\n## 7. Controls and HUD\n\n- Smooth first-person controls: WASD movement, space to jump, pointer-locked mouse to look.\n- A modern 2D UI overlay: crosshair, health / armor, a dynamic ammo panel (decrements on fire, restored on reload), and a live kill feed in the top-right.\n- A **minimap**: a persistent top-down Dust2 outline marking your own, teammates' and visible enemies' positions in real time, plus the C4's location.\n\n## 8. Sound\n\nThe game needs sound feedback. Since no external audio files are used, synthesize sound programmatically with the **Web Audio API**. Include at least: distinct firing sounds per weapon (AK / M4 / AWP / pistols differentiated), reload, footsteps, AWP scope-in, hit feedback, C4 plant / defuse / explosion, and a kill sound.\n\n## Architecture\n\nThis is an industrial-grade challenge. You own the technology choices, architecture, and data-structure design, plus the data sync between the render loop, the physics frame update, and the React state lifecycle. The global state engine, weapon system, AI state machine, and 3D-rendering and physics components must be genuinely implemented, not left as placeholders." - }, - "tags": [ - "REACT", - "3D", - "THREE.JS", - "GAME" - ] - } -] \ No newline at end of file diff --git a/models/claude-fable-5-cc-high.json b/models/claude-fable-5-cc-high.json deleted file mode 100644 index 9c6de1e..0000000 --- a/models/claude-fable-5-cc-high.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "label": "Claude Fable 5", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "High", - "artifactDir": "claude-fable-5/claude-code-high", - "order": 11, - "runs": { - "cs-dust2": { - "note": { - "zh": "在 Claude Code 中以 Claude Fable 5(High 思考配额)生成的完整 Vite + React 18 + three.js 工程;本页为其构建产物(部署时由源码打包为单文件)。手动修复了一处开火 bug:模拟以固定 64Hz 步长推进,高刷屏(渲染帧率高于 64)下某一帧可能不推进任何 fixed step,原实现按帧写入并清零 fireTap 等 edge 触发输入,会在该帧把点击吞掉、导致偶发不开火;修复改为用 || 将这些输入锁存至被某个 fixed step 消费为止(src/game/engine.ts),使开火与刷新率无关。", - "en": "A complete Vite + React 18 + three.js project generated by Claude Fable 5 (High effort) in Claude Code; this page is its build output (bundled from source into a single file at deploy time). One firing bug was fixed by hand: the simulation advances in fixed 64Hz steps, and on a high-refresh display (render fps above 64) a frame may run zero fixed steps, so the original per-frame assign-and-clear of edge-triggered inputs like fireTap could swallow a click on that frame and drop the shot; the fix latches those inputs with || until a fixed step consumes them (src/game/engine.ts), making firing refresh-rate-independent." - }, - "contributor": "Nagi-ovo" - }, - "turf-war": { - "note": { - "zh": "Claude Fable 5(High 思考档位)在 Claude Code 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「疾风圈地」。诊断:策略翻车,龟缩到极致:圈了 164 次却每次平均仅 3.9 格,勤劳画小圈、画一个被对手大圈盖一个,0 死 0 杀,终局仅 165 分。与 Opus xhigh 同病更甚——名叫疾风,啃得太碎。", - "en": "One-shot Turf War agent by Claude Fable 5 (High effort) in Claude Code from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"疾风圈地\". Diagnosis: Strategic failure, turtling to the extreme: 164 captures averaging just 3.9 cells each — swift tiny loops instantly overwritten by the opponent's bigger ones, 0 deaths and 0 kills, ending at only 165. The same trap as Opus xhigh but worse — swift name, bites too small." - }, - "contributor": "Nagi-ovo", - "agentName": "疾风圈地" - } - } -} \ No newline at end of file diff --git a/models/claude-fable-5-cc-xhigh.json b/models/claude-fable-5-cc-xhigh.json deleted file mode 100644 index 781c1e5..0000000 --- a/models/claude-fable-5-cc-xhigh.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "label": "Claude Fable 5", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "xhigh", - "artifactDir": "claude-fable-5/claude-code-xhigh", - "order": 12.5, - "runs": { - "skeleton-watch": { - "note": { - "zh": "在 Claude Code 中以 Claude Fable 5(xhigh 思考配额)一次生成。原始产出把表厂品牌写成 FABLE & CIE、机芯型号 CF-500,会在 Arena 盲评中暗示模型身份;本页仅替换为中性品牌与型号(AUREL & CIE / AC-500),其余未改。", - "en": "Generated in one shot by Claude Fable 5 (xhigh effort) inside Claude Code. The original output branded the watch as FABLE & CIE with calibre CF-500, which would hint at the model identity in blind Arena mode; this page only replaces those with neutral branding (AUREL & CIE / AC-500), otherwise unmodified." - }, - "contributor": "Nagi-ovo" - }, - "turf-war": { - "note": { - "zh": "Claude Fable 5(xhigh 思考档位)在 Claude Code 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「画地为牢」。诊断:激进高产型——平均每次圈地约 42 格(全场最大),敢拖长尾巴换大地盘并主动切对手尾巴,自身几乎不送死,对 baseline 一度打出 1537:25。与同模型 high 档的龟缩(疾风圈地,平均仅 3.9 格)恰成反例:此模型思考档位越高反而越敢打。", - "en": "One-shot Turf War agent by Claude Fable 5 (xhigh effort) in Claude Code from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"画地为牢\". Diagnosis: aggressive and high-output — captures average ~42 cells each (the largest of any agent), willing to trail far for big territory and to cut the opponent's trail, while almost never suiciding; it once beat a baseline 1537:25. The opposite of the same model's High run (疾风圈地, tiny 3.9-cell loops): for this model, more thinking makes it bolder, not more cautious." - }, - "contributor": "Nagi-ovo", - "agentName": "画地为牢" - } - } -} \ No newline at end of file diff --git a/models/claude-fable-5-cc.json b/models/claude-fable-5-cc.json deleted file mode 100644 index c9a879a..0000000 --- a/models/claude-fable-5-cc.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "label": "Claude Fable 5", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "claude-fable-5/claude-code-max", - "order": 12, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 Claude Fable 5(Max 思考配额)一次生成,本页为未经修改的原始产出。与「Claude 网页版」条目同模型、不同 Harness——两个标签页并排即可对比同一模型在不同运行环境下的差异。", - "en": "Generated in one shot by Claude Fable 5 (Max effort) inside Claude Code; this page is the unmodified original output. Same model as the Claude Web App entry but a different harness — compare the two tabs to see how the environment shapes the result." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 Claude Fable 5(Max 思考配额)一次生成。", - "en": "Generated in one shot by Claude Fable 5 (Max effort) inside Claude Code." - }, - "contributor": "Nagi-ovo" - }, - "turf-war": { - "note": { - "zh": "Claude Fable 5(Max 思考档位)在 Claude Code 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「地头蛇」。诊断:稳健强手——对 baseline 稳定取胜(872:512、1119:307),圈地量足。同为 Fable 5,与 high 档的龟缩(疾风圈地)差距明显,再次印证此模型思考档位越高越敢打。", - "en": "One-shot Turf War agent by Claude Fable 5 (Max effort) in Claude Code from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"地头蛇\". Diagnosis: a solid strong performer — beats baselines consistently (872:512, 1119:307) with healthy capture volume. Same model as the High turtle (疾风圈地) yet far stronger, again showing that for Fable 5 more thinking means bolder play." - }, - "contributor": "Nagi-ovo", - "agentName": "地头蛇" - } - } -} \ No newline at end of file diff --git a/models/claude-fable-5-cursor.json b/models/claude-fable-5-cursor.json deleted file mode 100644 index 2d44199..0000000 --- a/models/claude-fable-5-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Fable 5", - "vendor": "Anthropic", - "harness": "Cursor", - "effort": "High", - "artifactDir": "claude-fable-5/cursor-high", - "order": 13, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor 中以 Claude Fable 5(High 思考配额)作为子 agent 一次生成,本页为未经修改的原始产出。与「Claude 网页版」「Claude Code」条目同模型、不同 Harness,可并排对比运行环境对产出的影响。", - "en": "Generated in one shot by a Claude Fable 5 (High effort) subagent inside Cursor; this page is the unmodified original output. Same model as the Claude Web App and Claude Code entries but a different harness — compare them side by side to see how the environment shapes the result." - }, - "contributor": "Mist-wu" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor 中以 Claude Fable 5(High 思考配额)作为子 agent 一次生成。", - "en": "Generated in one shot by a Claude Fable 5 (High effort) subagent inside Cursor." - }, - "contributor": "Mist-wu" - } - } -} diff --git a/models/claude-fable-5.json b/models/claude-fable-5.json deleted file mode 100644 index 00105d2..0000000 --- a/models/claude-fable-5.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Fable 5", - "vendor": "Anthropic", - "harness": "Claude Web App", - "effort": "Max", - "artifactDir": "claude-fable-5/claude-web-app-max", - "order": 10, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude 网页版以 Fable 5 Max(最高思考强度)运行,过程中触发一次 auto compact 与工具调用上限,手动输入「继续」后完成;ID 水印与英文支持为事后在 Cursor 中用 Composer 2.5 Fast 一条提示词补加,其余均为一次生成。已知小问题:开局可能卡在一棵树里,按一下 G 即可脱身。", - "en": "Run in the Claude web app on Fable 5 Max (max thinking effort); hit one auto-compact and the tool-call limit mid-run, finished after a manual \"continue\". The ID watermark and English support were patched in afterwards with a single prompt via Composer 2.5 Fast in Cursor; everything else is one-shot. Known quirk: you may spawn stuck inside a tree - press G once to get free." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude 网页版以 Fable 5 Max(最高思考强度)一次生成。", - "en": "Generated in one shot in the Claude web app on Fable 5 Max (max thinking effort)." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-haiku-4-5-cc.json b/models/claude-haiku-4-5-cc.json deleted file mode 100644 index 59c7b31..0000000 --- a/models/claude-haiku-4-5-cc.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Haiku 4.5", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Default", - "artifactDir": "claude-haiku-4-5/claude-code-default", - "order": 19.5, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 Claude Haiku 4.5(Default 思考配额)一次生成。原始 HTML 因 Three.js 异步加载、渲染 canvas 绑定和 world 变量接线问题无法正常打开;Codex 仅修复启动接线以让原始实现可运行,未改动玩法、地形、视觉设计或控制逻辑。", - "en": "Generated in one shot by Claude Haiku 4.5 (Default effort) inside Claude Code. The original HTML could not open correctly due to Three.js async loading, render-canvas binding, and world variable wiring issues; Codex only fixed the startup wiring so the original implementation can run, without changing gameplay, terrain, visual design, or control logic." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 Claude Haiku 4.5(Default 思考配额)一次生成;本页为未经修改的原始 SVG 产出。", - "en": "Generated in one shot by Claude Haiku 4.5 (Default effort) inside Claude Code; unmodified original SVG output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-opus-4-5-cursor.json b/models/claude-opus-4-5-cursor.json deleted file mode 100644 index 04821d2..0000000 --- a/models/claude-opus-4-5-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Opus 4.5", - "vendor": "Anthropic", - "harness": "Cursor", - "effort": "Thinking", - "artifactDir": "claude-opus-4-5/cursor-thinking", - "order": 17, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor CLI 中以 Claude Opus 4.5(Thinking 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.5 (Thinking effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor CLI 中以 Claude Opus 4.5(Thinking 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.5 (Thinking effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-opus-4-6-cc.json b/models/claude-opus-4-6-cc.json deleted file mode 100644 index ae92474..0000000 --- a/models/claude-opus-4-6-cc.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Opus 4.6", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "claude-opus-4-6/claude-code-max", - "order": 16, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.6(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.6 (Max effort) inside Claude Code; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "skeleton-watch": { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.6(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.6 (Max effort) inside Claude Code; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-opus-4-6-cursor.json b/models/claude-opus-4-6-cursor.json deleted file mode 100644 index 44527de..0000000 --- a/models/claude-opus-4-6-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Opus 4.6", - "vendor": "Anthropic", - "harness": "Cursor", - "effort": "Max", - "artifactDir": "claude-opus-4-6/cursor-max", - "order": 16.5, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor CLI 中以 Claude Opus 4.6(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.6 (Max effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor CLI 中以 Claude Opus 4.6(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.6 (Max effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-opus-4-7-cc.json b/models/claude-opus-4-7-cc.json deleted file mode 100644 index 72599a8..0000000 --- a/models/claude-opus-4-7-cc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "Claude Opus 4.7", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "claude-opus-4-7/claude-code-max", - "order": 15, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Claude Code; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Claude Code; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "skeleton-watch": { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。已知 bug(未修复):点击「Exploded View」分解视图几乎没有反应,零件始终保持组装状态。位置在 animate()(933–934 行):先 const t = clock.getElapsedTime() 再 const dt = Math.min(clock.getDelta(), 0.05)。THREE.Clock 的 getElapsedTime() 内部已经调用过一次 getDelta() 并把 oldTime 重置为当前时刻,因此紧随其后的 getDelta() 返回的是这两行之间的间隔,几乎为 0,导致每帧 dt≈0。分解动画靠 explodeAmount += (explodeTarget - explodeAmount) * min(1, dt*4) 推进,dt≈0 时几乎不增长(实测点击后 2 秒仅到 0.0008,需数分钟才能展开),所以看起来失效;水晶玻璃位移同理。齿轮转动用的是 t 不受影响,机芯照常运转。", - "en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Claude Code; unmodified original output. Known bug (not fixed): clicking 'Exploded View' does almost nothing — the parts stay assembled. Located in animate() (lines 933-934): const t = clock.getElapsedTime() followed by const dt = Math.min(clock.getDelta(), 0.05). THREE.Clock.getElapsedTime() internally already calls getDelta() and resets oldTime to now, so the getDelta() on the next line returns the gap between those two lines — effectively 0 — making dt≈0 every frame. The explode is driven by explodeAmount += (explodeTarget - explodeAmount) * min(1, dt*4), which barely advances when dt≈0 (measured ~0.0008 two seconds after the click; it would take minutes to open), so it looks broken; the crystal offset fails the same way. The gear rotations use t directly and are unaffected, so the movement keeps running." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-opus-4-7-cursor.json b/models/claude-opus-4-7-cursor.json deleted file mode 100644 index af9bc6f..0000000 --- a/models/claude-opus-4-7-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Claude Opus 4.7", - "vendor": "Anthropic", - "harness": "Cursor", - "effort": "Max", - "artifactDir": "claude-opus-4-7/cursor-max", - "order": 15.5, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Cursor; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Cursor; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-opus-4-8-cc-xhigh.json b/models/claude-opus-4-8-cc-xhigh.json deleted file mode 100644 index f673e9a..0000000 --- a/models/claude-opus-4-8-cc-xhigh.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Claude Opus 4.8", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "xhigh", - "order": 14.1, - "runs": { - "turf-war": { - "note": { - "zh": "Claude Opus 4.8(xhigh 思考档位)在 Claude Code 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「蚕食」。诊断:策略翻车,过度保守:全程 0 死亡,但每次只圈 7 格左右的小块,圈来的地被对手的大圈反复覆盖,累计吃 776 格终局只剩 277。撞上提示词警告的失败模式——只求不败拿不到高排名。", - "en": "One-shot Turf War agent by Claude Opus 4.8 (xhigh effort) in Claude Code from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"蚕食\". Diagnosis: Strategic failure, over-cautious: 0 deaths all match, but each capture is a tiny ~7-cell loop that the opponent's bigger loops keep overwriting — it gains 776 cells across the match yet ends with 277. Exactly the failure the prompt warns about: merely avoiding losing does not rank." - }, - "contributor": "Nagi-ovo", - "agentName": "蚕食" - } - } -} \ No newline at end of file diff --git a/models/claude-opus-4-8-cc.json b/models/claude-opus-4-8-cc.json deleted file mode 100644 index 355fb8e..0000000 --- a/models/claude-opus-4-8-cc.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "label": "Claude Opus 4.8", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "claude-opus-4-8/claude-code-max", - "order": 14, - "runs": { - "mythos-craft": [ - { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.8(Max 思考配额)一次生成,本页为未经修改的原始产出。", - "en": "Generated in one shot by Claude Opus 4.8 (Max effort) inside Claude Code; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "mythos-craft-2.html", - "note": { - "zh": "第二版:在 Claude Code 中由 Claude Opus 4.8(Max 思考配额)一次生成。基于 Three.js 的体素世界,含柏林噪声地形、第一人称 WASD + 鼠标视角、DDA 体素射线拾取的破坏/放置、程序化贴图图集,并自带大理石神庙、水晶尖塔与悬浮岛。代码由模型直接写出,仅做了一次 JS 语法检查,未做其他修改。", - "en": "Second version: generated in one shot by Claude Opus 4.8 (Max effort) inside Claude Code. A Three.js voxel world with Perlin-noise terrain, first-person WASD + mouse-look, DDA voxel-raycast break/place, a procedural texture atlas, and a built-in marble temple, crystal spires and a floating sky-isle. Code written directly by the model; only a JS syntax check was run, otherwise unmodified." - }, - "contributor": "OHMFOHS" - } - ], - "pelican-cycling": [ - { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.8(Max 思考配额)一次生成。", - "en": "Generated in one shot by Claude Opus 4.8 (Max effort) inside Claude Code." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "第二版:在 Claude Code 中由 Claude Opus 4.8(Max 思考配额)一次手写的 SVG,未经修改。海边日落场景:渐变天空与海面、沙滩、远处帆船与海鸥,一只鹈鹕骑着红色自行车,并以速度线增添动感。", - "en": "Second version: a hand-authored SVG written in one shot by Claude Opus 4.8 (Max effort) inside Claude Code; unmodified. A seaside sunset scene — gradient sky and sea, beach, a distant sailboat and gull, and a pelican riding a red bicycle, with motion lines for liveliness." - }, - "contributor": "OHMFOHS" - } - ], - "skeleton-watch": { - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.8(Max 思考配额)一次生成,本页为未经修改的原始产出。基于 Three.js 的交互式 3D 镂空机械表:可旋转、切换爆炸视图、零件标签高亮与机芯信息面板,含擒纵机构、摆轮等机芯结构。", - "en": "Generated in one shot by Claude Opus 4.8 (Max effort) inside Claude Code; unmodified original output. An interactive 3D skeleton mechanical watch on Three.js — orbit rotation, exploded view, highlighted part labels and a movement info panel, with escapement, balance wheel and other movement parts." - }, - "contributor": "Nagi-ovo" - }, - "cs-dust2": { - "file": "dust2-arena", - "note": { - "zh": "在 Claude Code 中以 Claude Opus 4.8(Max 思考配额)一次生成的完整 Vite + React 18 + three.js 工程,未经修改;本页为其构建产物(部署时由源码打包为单文件)。与 Claude Fable 5 条目同一道 cs-dust2 题、不同模型——可对比同题下两个模型的工程实现。", - "en": "A complete Vite + React 18 + three.js project generated in one shot by Claude Opus 4.8 (Max effort) in Claude Code, unmodified; this page is its build output (bundled from source into a single file at deploy time). Same cs-dust2 case as the Claude Fable 5 entry but a different model — compare how the two implement the same task." - }, - "contributor": "Nagi-ovo" - }, - "turf-war": { - "note": { - "zh": "Claude Opus 4.8(Max 思考档位)在 Claude Code 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则,策略文件不公开、仅注册运行,由维护者亲自执行。自命名「圈套」。", - "en": "One-shot Turf War agent by Claude Opus 4.8 (Max effort) in Claude Code from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished; this entry registers the maintainer-executed run. Self-named \"圈套\"." - }, - "contributor": "Nagi-ovo", - "agentName": "圈套" - } - } -} \ No newline at end of file diff --git a/models/claude-sonnet-4-6-cc.json b/models/claude-sonnet-4-6-cc.json deleted file mode 100644 index 7a70225..0000000 --- a/models/claude-sonnet-4-6-cc.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Claude Sonnet 4.6", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "claude-sonnet-4-6/claude-code-max", - "order": 18.9, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 Claude Sonnet 4.6(Max 思考配额)一次生成。", - "en": "Generated in one shot by Claude Sonnet 4.6 (Max effort) inside Claude Code." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/claude-sonnet-4-6-cursor.json b/models/claude-sonnet-4-6-cursor.json deleted file mode 100644 index 30fec7f..0000000 --- a/models/claude-sonnet-4-6-cursor.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "label": "Claude Sonnet 4.6", - "vendor": "Anthropic", - "harness": "Cursor", - "effort": "High", - "artifactDir": "claude-sonnet-4-6/cursor-high", - "order": 19, - "runs": { - "pelican-cycling": [ - { - "note": { - "zh": "在 Cursor CLI 中以 Claude Sonnet 4.6(High 思考配额)一次生成。原始 SVG 的注释中混入非法 XML/编码字节,导致浏览器只渲染到一半并显示解析错误;Codex 仅将这些注释里的坏字符替换为 ASCII 连字符以修复加载错误,未改动任何图形元素。", - "en": "Generated in one shot by Claude Sonnet 4.6 (High effort) inside Cursor CLI. The original SVG contained invalid XML/encoding bytes inside comments, causing browsers to stop rendering partway through with a parse error; Codex only replaced those bad comment characters with ASCII hyphens to fix loading, without changing any graphical elements." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "第二版:在 Cursor CLI 中以 Claude Sonnet 4.6(High 思考配额)一次生成,作为独立 SVG 变体登记,保留原版产物不变。", - "en": "Second version: generated in one shot by Claude Sonnet 4.6 (High effort) inside Cursor CLI and registered as a separate SVG variant, preserving the original artifact." - }, - "contributor": "Nagi-ovo" - } - ] - } -} diff --git a/models/claude-sonnet-5-cc-max.json b/models/claude-sonnet-5-cc-max.json deleted file mode 100644 index f892dcd..0000000 --- a/models/claude-sonnet-5-cc-max.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Claude Sonnet 5", - "vendor": "Anthropic", - "harness": "Claude Code", - "effort": "Max", - "order": 12.5, - "runs": { - "turf-war": { - "note": { - "zh": "Claude Sonnet 5(Max 思考档位)在 Claude Code 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「卷地风」。诊断:全程 0 次成功圈地,反复送死 11 次——离开领地后撞上自己的尾巴/岩石/边界而亡,一个闭环都没画成。属于莽夫送死型:太急、路径规划没避开自身尾巴。", - "en": "One-shot Turf War agent by Claude Sonnet 5 (Max effort) in Claude Code from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"卷地风\". Diagnosis: Zero completed captures and 11 self-inflicted deaths — it leaves home and dies on its own trail / a rock / the border before ever closing a loop. A reckless death-loop: too eager, its pathing never avoids its own trail." - }, - "contributor": "Nagi-ovo", - "agentName": "卷地风" - } - } -} \ No newline at end of file diff --git a/models/composer-2-5-fast.json b/models/composer-2-5-fast.json deleted file mode 100644 index c3468ae..0000000 --- a/models/composer-2-5-fast.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Composer 2.5", - "vendor": "Cursor", - "harness": "Cursor", - "effort": "Default", - "artifactDir": "composer-2-5/cursor-default", - "order": 71, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor 中以 Composer 2.5 一次生成,本页为未经修改的原始产出。", - "en": "Generated in one shot by Composer 2.5 inside Cursor; this page is the unmodified original output." - }, - "contributor": "Mist-wu" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor 中以 Composer 2.5 一次生成。", - "en": "Generated in one shot by Composer 2.5 inside Cursor." - }, - "contributor": "Mist-wu" - } - } -} diff --git a/models/composer-2-5-grok-build.json b/models/composer-2-5-grok-build.json deleted file mode 100644 index a14de87..0000000 --- a/models/composer-2-5-grok-build.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Composer 2.5", - "vendor": "Cursor", - "harness": "Grok Build TUI", - "effort": "Default", - "artifactDir": "composer-2-5/grok-build-tui-default", - "order": 72, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Grok Build TUI 中以 Composer 2.5 生成;本页为修复版(改 1 行)。问题:WOOD(原木)方块只定义了 top 与 side 两个面、没有 bottom,而图集构建 buildAtlas 会为每个方块依次取 top/side/bottom 三面;取 WOOD 底面时 getFaceImage 读 t.bottom.image,t.bottom 为 undefined 直接抛 TypeError。该调用在 initTextures() 顶层执行,异常令整段初始化中断,'进入世界'按钮的点击监听还没绑定——表现为点击开始按钮毫无反应、进不去世界。修复:getFaceImage 在某面缺失时回退到已有的面(底面回退到顶面,正好是原木年轮端面的正确外观),其余原样。", - "en": "Generated with Composer 2.5 in the Grok Build TUI; fixed build (1 line changed). Bug: the WOOD block defines only top and side faces, no bottom, but the atlas builder requests top/side/bottom for every block; fetching WOOD's bottom hit getFaceImage reading t.bottom.image where t.bottom is undefined, throwing a TypeError. That call runs at the top level of initTextures(), so the exception aborted the whole init before the 'enter world' click listener was ever attached — clicking the start button did nothing and you could not enter the world. Fix: getFaceImage now falls back to an existing face when one is missing (bottom falls back to top, which is also the correct ring end-grain for a log); nothing else changed." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Grok Build TUI 中以 Composer 2.5 生成,本页为未经修改的原始产出。", - "en": "Generated with Composer 2.5 in the Grok Build TUI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/composer-2-5.json b/models/composer-2-5.json deleted file mode 100644 index a722282..0000000 --- a/models/composer-2-5.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Composer 2.5", - "vendor": "Cursor", - "harness": "Cursor", - "effort": "Max", - "artifactDir": "composer-2-5/cursor-max", - "order": 70, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor 中以 Composer 2.5 生成;本页为修复版(改 1 行)+ 补一个小功能。问题:第 1152 行水平速度先乘 speed*dt,位移时又乘一次 dt,实际步速只有设计值(5 格/秒)的约 1/60。修复前:走路如蜗牛、跳跃下落却正常;沙漠雪地等群系与神话建筑实际走不到,体感像「切换不了场景」——游戏本无传送功能,群系需步行抵达。原因:X/Z 轴把「每帧位移」当「每秒速度」存入 velocity,与 Y 轴语义不一致。去掉一次 dt 后步行恢复 5 格/秒。另外它确实生成了精灵螺旋塔、龙神殿、天空遗迹三处景点(也画在小地图上),但原版只能徒步抵达——已补加按 G 依次瞬移到三处景点的功能,开屏说明里也加了一行。", - "en": "Generated with Composer 2.5 in Cursor; fixed build (1 line changed) plus one small addition. Bug: line 1152 multiplied horizontal velocity by speed*dt, then displacement multiplied by dt again, leaving walking at ~1/60 of the designed 5 blocks/s. Before the fix: walking crawled while jumping/falling felt normal, and biomes or mythic structures were virtually unreachable — which read as \"scene switching is broken\" (there is no teleport; biomes are reached on foot). Cause: X/Z stored per-frame displacement in a per-second velocity field, inconsistent with the Y axis. With one dt removed walking is back to 5 blocks/s. It does generate three landmarks (Elven Spiral Tower, Dragon Temple, Sky Ruins — also drawn on the minimap) that were only reachable on foot, so a G-key cycle-teleport to them was added, with a line in the start screen." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/deepseek-v4-flash-cc.json b/models/deepseek-v4-flash-cc.json deleted file mode 100644 index 6b33717..0000000 --- a/models/deepseek-v4-flash-cc.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "DeepSeek V4 Flash", - "vendor": "DeepSeek", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "deepseek-v4-flash/claude-code-max", - "order": 50, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 DeepSeek V4 Flash(Max)一次生成,未修改。你是一个顶级的资深游戏开发者。请为我使用单 HTML5 和 Canvas(或 Three.js)编写一个《我的世界》克隆版。请包含以下核心功能:1. 一个基于柏林噪声(Perlin Noise)生成的无限或可滚动的 3D 地形。2. 第一人称视角,支持使用 WASD 移动和鼠标环视。3. 支持至少 3 种方块类型(如:泥土、草地、石头等),并支持鼠标左键破坏方块,右键放置方块。材质要尽可能还原。4. 要有一个内置的、极其丰富的神话幻想中的建筑和地形等,由你自行设计。", - "en": "One-shot by DeepSeek V4 Flash (Max effort) in Claude Code, unmodified. You are a top-tier veteran game developer. Build me a Minecraft clone using a single HTML5 file and Canvas (or Three.js). Include the following core features:1. An infinite or scrollable 3D terrain generated from Perlin noise.2. A first-person view with WASD movement and mouse look.3. At least 3 block types (e.g. dirt, grass, stone), with left-click to break and right-click to place blocks. Keep the textures as faithful as possible.4. A built-in, extremely rich set of mythic-fantasy buildings and terrain, designed at your own discretion." - }, - "contributor": "Av1dity" - } - } -} \ No newline at end of file diff --git a/models/deepseek-v4-flash-reasonix.json b/models/deepseek-v4-flash-reasonix.json deleted file mode 100644 index f2813b8..0000000 --- a/models/deepseek-v4-flash-reasonix.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "DeepSeek V4 Flash", - "vendor": "DeepSeek", - "harness": "Reasonix", - "effort": "Max", - "artifactDir": "deepseek-v4-flash/reasonix-max", - "order": 90.5, - "runs": { - "skeleton-watch": { - "note": { - "zh": "在 Reasonix 编程代理环境中一次生成。使用 Three.js (CDN) 构建了完整的 3D 镂空机械表,包含摆轮、游丝、擒纵机构、齿轮系、发条盒、红宝石轴承、夹板等全部可见机芯结构,支持 OrbitControls 旋转、爆炸视图、CSS2D 零件标签和交互信息面板。一次生成,无人工修复。", - "en": "Generated in one shot in the Reasonix coding agent environment. Built a complete interactive 3D skeleton mechanical watch with Three.js (CDN), including balance wheel, hairspring, escapement, gear train, mainspring barrel, ruby jewels, bridges and all visible movement components. Features OrbitControls rotation, exploded view, CSS2D part labels, and interactive info panel. One-shot generation, no manual fixes." - }, - "contributor": "6bcj" - } - } -} diff --git a/models/deepseek-v4-pro.json b/models/deepseek-v4-pro.json deleted file mode 100644 index f244453..0000000 --- a/models/deepseek-v4-pro.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "DeepSeek-V4-Pro", - "vendor": "DeepSeek", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "deepseek-v4-pro/claude-code-max", - "order": 90, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 DeepSeek V4 Pro(最高思考强度)一次生成,未修复。包含 Perlin 噪声地形、WASD + 鼠标第一人称操控、12 种方块类型(含水、黑曜石、水晶、金块等)、程序化材质纹理、四种神话建筑(水晶塔、石环阵、龙骨遗迹、天空遗迹),按 G 可随机传送至神话建筑。", - "en": "Generated in one shot via Claude Code with DeepSeek V4 Pro (max thinking effort), no fixes. Features Perlin noise terrain, WASD + mouse first-person controls, 12 block types (including water, obsidian, crystal, gold), procedural textures, and four mythic structures (Crystal Tower, Stone Circle, Dragon Skeleton, Sky Ruins). Press G to teleport between landmarks." - }, - "contributor": "Mintcolour" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 DeepSeek V4 Pro(最高思考强度)一次生成。场景包含天空、海洋、沙滩、棕榈树、海鸥、完整自行车细节(辐条、链条、齿轮)以及鹈鹕(长喙、喉囊、羽翼、踩踏动作)。", - "en": "Generated in one shot via Claude Code with DeepSeek V4 Pro (max thinking effort). Scene includes sky, ocean, beach, palm trees, seagulls, detailed bicycle (spokes, chain, gears), and a pelican (beak, gular pouch, wings, pedaling pose)." - }, - "contributor": "Mintcolour" - }, - "skeleton-watch": { - "note": { - "zh": "在 Claude Code 中以 DeepSeek-V4-Pro(最高思考强度)一次生成,未进行任何修改。", - "en": "Generated in one shot by DeepSeek-V4-Pro inside Claude Code with Max effort, unmodified." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/doubao-seed-2-0-mini.json b/models/doubao-seed-2-0-mini.json deleted file mode 100644 index f5278f2..0000000 --- a/models/doubao-seed-2-0-mini.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Doubao Seed 2.0 Mini", - "vendor": "ByteDance", - "harness": "Doubao Web", - "effort": "Fast Mode", - "artifactDir": "doubao-seed-2-0-mini/doubao-web-fast-mode", - "order": 96, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在豆包网页版以快速模式一次生成。\n\n「要不要我再给你做一个带简单动画(翅膀扇动、车轮转动)的增强版 SVG 代码?」", - "en": "Generated in one shot on Doubao web app in Lite mode.\n\n\"Should I make you an enhanced version of the SVG code with simple animations (flapping wings, rotating wheels)?\"" - }, - "contributor": "LpIuma" - } - } -} diff --git a/models/doubao-seed-2-0-pro.json b/models/doubao-seed-2-0-pro.json deleted file mode 100644 index 6bd7db8..0000000 --- a/models/doubao-seed-2-0-pro.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Doubao Seed 2.0 Pro", - "vendor": "ByteDance", - "harness": "Doubao Web", - "effort": "Pro Mode", - "artifactDir": "doubao-seed-2-0-pro/doubao-web-pro-mode", - "order": 95, - "runs": { - "pelican-cycling": { - "note": { - "zh": "使用豆包网页版超能模式,首次输出了 png 图片,经提醒后生成 svg 代码。", - "en": "Using Doubao web app (Pro mode), it initially output a PNG image, then generated the SVG code after being reminded." - }, - "contributor": "LpIuma" - } - } -} diff --git a/models/gemini-3-1-pro-aistudio.json b/models/gemini-3-1-pro-aistudio.json deleted file mode 100644 index eec497f..0000000 --- a/models/gemini-3-1-pro-aistudio.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Gemini 3.1 Pro", - "vendor": "Google", - "harness": "Google AI Studio", - "effort": "High", - "artifactDir": "gemini-3-1-pro/google-ai-studio-high", - "order": 42, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在 Google AI Studio 以 Gemini 3.1 Pro Preview High(最高思考强度)一次生成。", - "en": "Generated in Google AI Studio on Gemini 3.1 Pro Preview High (max thinking effort) in one shot." - }, - "contributor": "LpIuma" - }, - "skeleton-watch": { - "note": { - "zh": "在 Google AI Studio 以 Gemini 3.1 Pro Preview High(最高思考强度)一次生成,未经人工修改。", - "en": "Generated in Google AI Studio on Gemini 3.1 Pro Preview High (max thinking effort) in one shot, unmodified." - }, - "contributor": "colorful-glassblock" - } - } -} diff --git a/models/gemini-3-1-pro-cursor.json b/models/gemini-3-1-pro-cursor.json deleted file mode 100644 index e02711d..0000000 --- a/models/gemini-3-1-pro-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Gemini 3.1 Pro", - "vendor": "Google", - "harness": "Cursor", - "effort": "Default", - "artifactDir": "gemini-3-1-pro/cursor-default", - "order": 41, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor 中以 Gemini 3.1 Pro 默认设置一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Gemini 3.1 Pro inside Cursor with default settings; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor 中以 Gemini 3.1 Pro 默认设置一次生成;修复了 SVG 注释中的非法 UTF-8 字节,未修改绘图元素。", - "en": "Generated in one shot by Gemini 3.1 Pro inside Cursor with default settings; fixed invalid UTF-8 bytes in SVG comments without changing drawing elements." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gemini-3-1-pro-gemini-web.json b/models/gemini-3-1-pro-gemini-web.json deleted file mode 100644 index bd16b32..0000000 --- a/models/gemini-3-1-pro-gemini-web.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "Gemini 3.1 Pro", - "vendor": "Google", - "harness": "Gemini Web", - "effort": "Deep Think", - "artifactDir": "gemini-3-1-pro/gemini-web-deepthink", - "order": 41, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Gemini Web 中以 Gemini 3.1 Pro(Deep Think)一次生成,未修改。", - "en": "One-shot by Gemini 3.1 Pro (Deep Think) in Gemini Web, unmodified." - }, - "contributor": "lupan-lu" - }, - "pelican-cycling": { - "note": { - "zh": "在 Gemini Web 中以 Gemini 3.1 Pro(Deep Think)一次生成,未修改。", - "en": "One-shot by Gemini 3.1 Pro (Deep Think) in Gemini Web, unmodified." - }, - "contributor": "lupan-lu" - }, - "skeleton-watch": { - "note": { - "zh": "在 Gemini Web 中以 Gemini 3.1 Pro(Deep Think)一次生成,未修改。", - "en": "One-shot by Gemini 3.1 Pro (Deep Think) in Gemini Web, unmodified." - }, - "contributor": "lupan-lu" - } - } -} diff --git a/models/gemini-3-1-pro.json b/models/gemini-3-1-pro.json deleted file mode 100644 index 520914c..0000000 --- a/models/gemini-3-1-pro.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "label": "Gemini 3.1 Pro", - "vendor": "Google", - "harness": "AntiGravity", - "effort": "High", - "artifactDir": "gemini-3-1-pro/antigravity-high", - "order": 40, - "runs": { - "mythos-craft": { - "note": { - "zh": "通过 AntiGravity 生成(thinking effort: high);一次生成,未发现需要修复的问题,原样展示。", - "en": "Generated via AntiGravity (thinking effort: high); one shot, no fixes needed — shown as-is." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "由社区 PR #3(Codex 工作流)提交,提交者未注明运行环境与思考档位。", - "en": "Contributed via community PR #3 (a Codex workflow); the submitter did not specify the runtime or effort level." - }, - "contributor": "XA2333" - }, - "skeleton-watch": { - "note": { - "zh": "通过 AntiGravity 生成(thinking effort: high);一次生成,未进行任何修改。", - "en": "Generated via AntiGravity (thinking effort: high); one shot, unmodified." - }, - "contributor": "OHCJ099" - }, - "turf-war": { - "note": { - "zh": "Gemini 3.1 Pro(High 思考档位)在 AntiGravity 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「寒冰王座」。诊断:中游水平,与 baseline 五五开(一胜一负、比分咬得很紧),能正常圈地、不崩、也不龟缩,但缺乏 Opus max 那种大环+主动击杀的压制力。", - "en": "One-shot Turf War agent by Gemini 3.1 Pro (High effort) in AntiGravity from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"寒冰王座\". Diagnosis: mid-tier — roughly even with the baseline (one win, one loss, both close); it captures normally, neither crashes nor turtles, but lacks the big-loop-plus-active-kill dominance of Opus max." - }, - "contributor": "Nagi-ovo", - "agentName": "寒冰王座" - } - } -} \ No newline at end of file diff --git a/models/gemini-3-5-flash-aistudio.json b/models/gemini-3-5-flash-aistudio.json deleted file mode 100644 index a12feb9..0000000 --- a/models/gemini-3-5-flash-aistudio.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Gemini 3.5 Flash", - "vendor": "Google", - "harness": "Google AI Studio", - "effort": "High", - "artifactDir": "gemini-3-5-flash/google-ai-studio-high", - "order": 52, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在 Google AI Studio 以 Gemini 3.5 Flash High(最高思考强度)一次生成。", - "en": "Generated in Google AI Studio on Gemini 3.5 Flash High (max thinking effort) in one shot." - }, - "contributor": "LpIuma" - } - } -} diff --git a/models/gemini-3-5-flash-cursor.json b/models/gemini-3-5-flash-cursor.json deleted file mode 100644 index 27b88d7..0000000 --- a/models/gemini-3-5-flash-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Gemini 3.5 Flash", - "vendor": "Google", - "harness": "Cursor", - "effort": "Default", - "artifactDir": "gemini-3-5-flash/cursor-default", - "order": 51, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor 中以 Gemini 3.5 Flash 默认设置一次生成。本页为未经修改的原始产出。包含基于柏林噪声的无限三维体素地形,自动爬坡(Step Climb)物理碰撞,Web Audio API 合成的风声/方块破坏/放置/跳跃音效及五重和弦背景合成乐。内置了世界之树、天空太阳神殿、黑曜石火山龙巢、悬浮精灵柱四处规模宏大、细节饱满的神话遗迹,并配备一键折跃与二维小地图罗盘导航。", - "en": "Generated in one shot by Gemini 3.5 Flash inside Cursor with default settings. Unmodified raw output featuring an infinite 3D voxel terrain driven by Perlin noise, responsive step-climbing collision physics, and synthesized sound effects (block breaking, placing, jumping) alongside a 5-chord ambient synth soundtrack via Web Audio API. Built-in with four massive, highly detailed mythical landmarks — Yggdrasil, the Aether Sun Temple, the Obsidian Volcano Keep, and the Floating Elven Spires — complete with instant travel Codex and 2D minimap compass navigation." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor 中以 Gemini 3.5 Flash 默认设置一次生成。本页为原始未经修改的产出,具有极高精细度的矢量细节、生动的动画感构图以及富有趣味性的画面彩蛋(如鹈鹕喉囊里的小鱼)。", - "en": "Generated in one shot by Gemini 3.5 Flash inside Cursor with default settings. Unmodified raw output featuring extremely rich vector details, dynamic composition, and delightful visual easter eggs like the swallowed fish in the gular pouch." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gemini-3-5-flash.json b/models/gemini-3-5-flash.json deleted file mode 100644 index cd52e8c..0000000 --- a/models/gemini-3-5-flash.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "label": "Gemini 3.5 Flash", - "vendor": "Google", - "harness": "AntiGravity", - "effort": "High", - "artifactDir": "gemini-3-5-flash/antigravity-high", - "order": 50, - "runs": { - "mythos-craft": { - "note": { - "zh": "通过 AntiGravity 生成(thinking effort: high);本页为修复版(仅改 1 行)。问题:16 张贴图按「上为原点」的行序画进 4×4 图集,UV 坐标表也按同一行序编写,但 CanvasTexture 默认 flipY=true 把采样行上下镜像(第 r 行实际采到第 3-r 行)。修复前:草地顶面显示成紫水晶、侧面采到带透明孔洞的传送门/树叶贴图,配合 alphaTest 出现大量「透明方块」,放置的方块贴图与名称完全对不上。原因:flipY 与图集行序约定不一致。加上 flipY=false 后行序对齐,地形与方块全部正常。", - "en": "Generated via AntiGravity (thinking effort: high); fixed build (1 line changed). Bug: 16 tiles drawn into a 4x4 atlas with top-origin rows, and the UV table uses the same convention, but CanvasTexture's default flipY=true mirrors the rows on sampling (row r actually reads row 3-r). Before the fix: grass tops rendered as purple crystal, sides sampled the portal/leaves tiles with alpha holes — hence the many \"transparent blocks\" — and placed blocks never matched their names. Cause: flipY disagreeing with the atlas row convention. With flipY=false everything lines up." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "由社区 PR #3(Codex 工作流)提交,提交者未注明运行环境与思考档位。", - "en": "Contributed via community PR #3 (a Codex workflow); the submitter did not specify the runtime or effort level." - }, - "contributor": "XA2333" - }, - "skeleton-watch": { - "note": { - "zh": "通过 AntiGravity 生成(thinking effort: high);一次生成,未进行任何修改。", - "en": "Generated via AntiGravity (thinking effort: high); one shot, unmodified." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/glm-5-1.json b/models/glm-5-1.json deleted file mode 100644 index 614f36c..0000000 --- a/models/glm-5-1.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "GLM-5.1", - "vendor": "Zhipu AI", - "harness": "ZCode", - "effort": "Max", - "artifactDir": "glm-5-1/zcode-max", - "order": 120, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在智谱清言网页版 GLM-5.1、使用 cases.json 中 pelican-cycling 的提示词逐字输入,一次生成,产物为独立 SVG 文件,无任何修复。", - "en": "In Zhipu Qingyan web app GLM-5.1, using the pelican-cycling prompt from cases.json verbatim, one-shot generation, output as a standalone SVG file, no fixes." - }, - "contributor": "Dmt3tianOVO" - } - } -} diff --git a/models/glm-5-2.json b/models/glm-5-2.json deleted file mode 100644 index 3c05a55..0000000 --- a/models/glm-5-2.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "label": "GLM-5.2", - "vendor": "Zhipu AI", - "harness": "ZCode", - "effort": "Max", - "artifactDir": "glm-5-2/zcode-max", - "order": 119, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 ZCode 中以 GLM-5.2(Max 思考配额)一次生成。原始 HTML 因热栏引用了未定义的 GLASS 常量而无法进入;Codex 仅将该引用修正为已有的 CRYSTAL 方块,未改动玩法或视觉设计。", - "en": "Generated in one shot by GLM-5.2 (Max effort) inside ZCode. The original HTML could not enter the game because the hotbar referenced an undefined GLASS constant; Codex only corrected that reference to the existing CRYSTAL block, without changing gameplay or visual design." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": [ - { - "note": { - "zh": "在 ZCode 中以 GLM-5.2(Max 思考配额)一次生成;本页为未经修改的原始 SVG 产出。", - "en": "Generated in one shot by GLM-5.2 (Max effort) inside ZCode; unmodified original SVG output." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "在 ZCode 中以 GLM-5.2(Max 思考配额)一次生成的第二个 SVG 版本;本页为未经修改的原始 SVG 产出。", - "en": "Second SVG variant generated in one shot by GLM-5.2 (Max effort) inside ZCode; unmodified original SVG output." - }, - "contributor": "Nagi-ovo" - } - ], - "skeleton-watch": { - "note": { - "zh": "在 ZCode 中以 GLM-5.2(Max 思考配额)一次生成,未进行任何修改。", - "en": "Generated in one shot by GLM-5.2 (Max effort) inside ZCode, unmodified." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/glm-5-turbo.json b/models/glm-5-turbo.json deleted file mode 100644 index e131234..0000000 --- a/models/glm-5-turbo.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "label": "GLM-5 Turbo", - "vendor": "Zhipu AI", - "harness": "ZCode", - "effort": "Thinking", - "artifactDir": "glm-5-turbo/zcode-thinking", - "order": 121, - "runs": { - "mythos-craft": [ - { - "note": { - "zh": "在 ZCode 中以 GLM-5 Turbo(Thinking 思考配额)一次生成。原始 HTML 因脚本括号错误、缺少 Game 初始化和缺少收尾标签而无法进入;Codex 仅修复这些启动接线问题,未改动玩法或视觉设计。", - "en": "Generated in one shot by GLM-5 Turbo (Thinking effort) inside ZCode. The original HTML could not enter the game because of script-brace errors, missing Game initialization, and missing closing tags; Codex only fixed those startup wiring issues, without changing gameplay or visual design." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "mythos-craft-2.html", - "note": { - "zh": "在 ZCode 中以 GLM-5 Turbo(Thinking 思考配额)一次生成的第二个 HTML 版本。原始 HTML 因雾效参数在 shader 编译后才初始化、且点击事件被 loading 覆盖层挡住而无法进入;Codex 仅修复这些启动/加载问题,未改动玩法或视觉设计。", - "en": "Second HTML variant generated in one shot by GLM-5 Turbo (Thinking effort) inside ZCode. The original HTML could not enter because fog parameters were initialized after shader compilation and the loading overlay blocked the click handler; Codex only fixed those startup/loading issues, without changing gameplay or visual design." - }, - "contributor": "Nagi-ovo" - } - ], - "pelican-cycling": { - "note": { - "zh": "在 ZCode 中以 GLM-5 Turbo(Thinking 思考配额)一次生成;本页为未经修改的原始 SVG 产出。", - "en": "Generated in one shot by GLM-5 Turbo (Thinking effort) inside ZCode; unmodified original SVG output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gpt-5-2-cursor.json b/models/gpt-5-2-cursor.json deleted file mode 100644 index 12a1134..0000000 --- a/models/gpt-5-2-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "GPT-5.2", - "vendor": "OpenAI", - "harness": "Cursor", - "effort": "xhigh", - "artifactDir": "gpt-5-2/cursor-xhigh", - "order": 33, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor CLI 中以 GPT-5.2(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.2 (xhigh effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor CLI 中以 GPT-5.2(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.2 (xhigh effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gpt-5-3-codex-cursor.json b/models/gpt-5-3-codex-cursor.json deleted file mode 100644 index 86d0a83..0000000 --- a/models/gpt-5-3-codex-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "GPT-5.3 Codex", - "vendor": "OpenAI", - "harness": "Cursor", - "effort": "xhigh", - "artifactDir": "gpt-5-3-codex/cursor-xhigh", - "order": 32, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor CLI 中以 GPT-5.3 Codex(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.3 Codex (xhigh effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor CLI 中以 GPT-5.3 Codex(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.3 Codex (xhigh effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gpt-5-4-cursor.json b/models/gpt-5-4-cursor.json deleted file mode 100644 index 7191ecd..0000000 --- a/models/gpt-5-4-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "GPT-5.4", - "vendor": "OpenAI", - "harness": "Cursor", - "effort": "xhigh", - "artifactDir": "gpt-5-4/cursor-xhigh", - "order": 31, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor CLI 中以 GPT-5.4(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.4 (xhigh effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor CLI 中以 GPT-5.4(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.4 (xhigh effort) inside Cursor CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gpt-5-4-xhigh.json b/models/gpt-5-4-xhigh.json deleted file mode 100644 index c2ca846..0000000 --- a/models/gpt-5-4-xhigh.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "label": "GPT-5.4", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "xhigh", - "artifactDir": "gpt-5-4/codex-xhigh", - "order": 31.5, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Codex CLI 中以 GPT-5.4(xhigh 思考配额)生成并整理为单文件 HTML 产物。", - "en": "Generated by GPT-5.4 (xhigh effort) inside Codex CLI and packaged as a single-file HTML artifact." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": [ - { - "note": { - "zh": "在 Codex CLI 中以 GPT-5.4(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.4 (xhigh effort) inside Codex CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "在 Codex CLI 中以 GPT-5.4(xhigh 思考配额)一次生成的第二个 SVG 版本;本页为未经修改的原始产出。", - "en": "Second SVG variant generated in one shot by GPT-5.4 (xhigh effort) inside Codex CLI; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - ], - "skeleton-watch": { - "note": { - "zh": "在 Codex CLI 中以 GPT-5.4(xhigh 思考配额)一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by GPT-5.4 (xhigh effort) inside Codex CLI; unmodified original output." - }, - "contributor": "YinL-k" - } - } -} diff --git a/models/gpt-5-5-pro.json b/models/gpt-5-5-pro.json deleted file mode 100644 index 1382f90..0000000 --- a/models/gpt-5-5-pro.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "GPT-5.5 Pro", - "vendor": "OpenAI", - "harness": "ChatGPT Web", - "effort": "Extended Pro", - "artifactDir": "gpt-5-5-pro/chatgpt-web-extended-pro", - "order": 29.8, - "runs": { - "mythos-craft": { - "note": { - "zh": "以 GPT-5.5 Pro(开启 Extended Pro)生成;本页为修复版(仅改 1 行)。问题:14 张贴图排成 8×2 图集、第二行只画了 6 格,UV 按左上原点计算却未设 flipY=false,两行贴图上下互换采样。修复前:草地顶面显示成黑曜石(地面全黑),树叶、沙子采到未绘制的空格(大片纯黑),放置方块的贴图互相串行、颜色诡异似反色。原因:CanvasTexture 默认 flipY=true,与自上而下的图集布局不匹配。加上 flipY=false 后地形与方块颜色全部正常。", - "en": "Generated with GPT-5.5 Pro (Extended Pro enabled); fixed build (1 line changed). Bug: 14 tiles in an 8x2 atlas with only 6 slots drawn in row two, UVs computed from a top-left origin without flipY=false, so the two rows swapped on sampling. Before the fix: grass tops rendered as obsidian (black ground), leaves and sand hit undrawn slots (large black patches), and placed blocks wore each other's textures with inverted-looking colors. Cause: CanvasTexture defaults to flipY=true, mismatching the top-down atlas layout. With flipY=false everything renders correctly." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 ChatGPT 网页版以 GPT-5.5 Pro(开启 Extended Pro)一次生成。", - "en": "Generated in one shot in the ChatGPT web app on GPT-5.5 Pro (Extended Pro enabled)." - }, - "contributor": "Nagi-ovo" - }, - "skeleton-watch": { - "note": { - "zh": "在 ChatGPT 网页版以 GPT-5.5 Pro(开启 Extended Pro)一次生成;本页为修复版(改 2 行)。问题一:发条与游丝用 createSpiralTube 构建(760 行),管线段数写成 Math.max(96, turns * 38),turns 为 5.8 / 6.4 时算出 220.4 / 243.2 的小数段数。修复前:TubeGeometry 末尾会以该段数作下标取 Frenet 帧 frames.normals[220.4],得到 undefined 后读取 .x 抛 TypeError,初始化中断,页面卡在「Assembling jeweled movement...」加载遮罩永不消失。原因:模型把管线段数当连续值传入,未取整。改为 Math.round(turns * 38) 后段数为整数,场景正常加载、遮罩按时隐藏。问题二:场景中心有一团异常刺眼的辉光,几乎把整块表盘糊成纯白,什么都看不清,放大观察时尤其严重。原因:UnrealBloomPass(340 行)阈值过低(threshold 0.18)且强度偏高(strength 0.72),叠加 ACES 色调映射与那盏强度 96 的主聚光灯打在抛光夹板上的近白高光,几乎所有金属高光与夜光都被纳入泛光并扩散成一大团过曝白光。实测仅把阈值/强度收敛仍不够——近距离时抛光中心板的高光依旧被放大成亮雾。为保护测试者的眼睛、避免对光敏性癫痫人群造成风险,直接关闭 bloom(strength 设为 0):机芯、齿轮、指针、夹板恢复清晰锐利,夜光时标仍靠材质自发光正常显示。", - "en": "Generated in one shot in the ChatGPT web app on GPT-5.5 Pro (Extended Pro enabled); fixed build (2 lines changed). Bug 1: the mainspring and hairspring are built via createSpiralTube (line 760) with the tube segment count written as Math.max(96, turns * 38), so turns of 5.8 / 6.4 yield fractional counts 220.4 / 243.2. Before the fix: TubeGeometry's trailing generateSegment indexes the Frenet-frame arrays with that count (frames.normals[220.4]), gets undefined and reads .x, throwing a TypeError that aborts init and leaves the page stuck on the 'Assembling jeweled movement...' loading overlay forever. Cause: the model passed the tube segment count as a continuous value without rounding. Changing it to Math.round(turns * 38) makes the count an integer, so the scene loads and the overlay hides on schedule. Bug 2: an abnormally blinding glow fills the center of the scene, washing the whole dial to pure white so nothing is legible, and it is worst when zoomed in. Cause: UnrealBloomPass (line 340) used too low a threshold (0.18) and a high strength (0.72), which together with ACES tone mapping and the near-white specular the intensity-96 key spotlight casts on the polished plate pulled nearly every metallic highlight and lume surface into the bloom and spread it into one big over-exposed white blob. Merely lowering the threshold/strength was not enough — up close the polished center plate's highlight still blew out into a glowing haze. To protect testers' eyes and avoid any risk to people with photosensitive epilepsy, the bloom was disabled outright (strength set to 0): the movement, gears, hands and bridges are crisp again, and the lume markers still read via their emissive material." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gpt-5-5-xhigh.json b/models/gpt-5-5-xhigh.json deleted file mode 100644 index f66f4b0..0000000 --- a/models/gpt-5-5-xhigh.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "GPT-5.5", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "xhigh", - "artifactDir": "gpt-5-5/codex-cli-xhigh", - "order": 30, - "runs": { - "mythos-craft": { - "note": { - "zh": "全程在 Codex CLI 中生成(未使用任何 skill);本页为修复版(仅改 1 行)。问题:移动向量的 Z 分量整体差一个负号(第 979 行,正确应为 -strafe*sin - forward*cos)。修复前:运动被沿 X 轴镜像——面朝 ±X 方向时按 A/D 左右颠倒,面朝 ±Z 时 W/S 前后颠倒,体感「左右移动方向不对」。原因:Three.js 相机在 yaw=0 时朝 -Z,推导前进/侧移向量时把这个约定弄反了。给 Z 分量取负后,任意朝向下八方向移动全部正确。", - "en": "Generated entirely in Codex CLI (no skills); fixed build (1 line changed). Bug: the movement vector's Z component had its sign flipped (line 979; correct form is -strafe*sin - forward*cos). Before the fix movement was mirrored across the X axis — A/D swapped when facing +-X, W/S swapped when facing +-Z, i.e. \"strafing goes the wrong way\". Cause: a Three.js camera faces -Z at yaw 0, and the forward/right derivation inverted that convention. Negating Z makes all eight directions correct at any heading." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "由社区 PR #3(Codex 工作流)提交,提交者未注明运行环境与思考档位。", - "en": "Contributed via community PR #3 (a Codex workflow); the submitter did not specify the runtime or effort level." - }, - "contributor": "XA2333" - }, - "skeleton-watch": { - "note": { - "zh": "在 Codex CLI 中以 GPT-5.5(xhigh 思考档位,未使用任何 skill)一次生成;本页为未经修改的原始产出。提示词开头明确禁止阅读或参考本目录及仓库中的任何其它文件,要求完全凭模型自身知识独立完成。", - "en": "Generated in one shot by GPT-5.5 (xhigh effort, no skills) in Codex CLI; unmodified original output. The prompt explicitly forbade reading or referencing any other file in the directory or repository, requiring the model to work solely from its own knowledge." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/gpt-5-6-sol-codex-cli-max.json b/models/gpt-5-6-sol-codex-cli-max.json deleted file mode 100644 index 401e24e..0000000 --- a/models/gpt-5-6-sol-codex-cli-max.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "GPT-5.6-Sol", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "max", - "order": 29.1, - "runs": { - "turf-war": { - "note": { - "zh": "GPT-5.6-Sol(max 思考档位)在 Codex CLI 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则,策略文件不公开、仅注册运行,由维护者亲自执行。自命名「界刃」。", - "en": "One-shot Turf War agent by GPT-5.6-Sol (max effort) in Codex CLI from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished; this entry registers the maintainer-executed run. Self-named \"界刃\"." - }, - "contributor": "Nagi-ovo", - "agentName": "界刃" - } - } -} \ No newline at end of file diff --git a/models/gpt-5-6-sol-codex-cli-xhigh.json b/models/gpt-5-6-sol-codex-cli-xhigh.json deleted file mode 100644 index 54a2981..0000000 --- a/models/gpt-5-6-sol-codex-cli-xhigh.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "GPT-5.6-Sol", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "xhigh", - "order": 29.2, - "runs": { - "turf-war": { - "note": { - "zh": "GPT-5.6-Sol(xhigh 思考档位)在 Codex CLI 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则,策略文件不公开、仅注册运行,由维护者亲自执行。自命名「蚀界」。", - "en": "One-shot Turf War agent by GPT-5.6-Sol (xhigh effort) in Codex CLI from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished; this entry registers the maintainer-executed run. Self-named \"蚀界\"." - }, - "contributor": "Nagi-ovo", - "agentName": "蚀界" - } - } -} \ No newline at end of file diff --git a/models/gpt-5-6-sol-ultra.json b/models/gpt-5-6-sol-ultra.json deleted file mode 100644 index a36dbed..0000000 --- a/models/gpt-5-6-sol-ultra.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "label": "GPT-5.6-Sol", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "ultra", - "artifactDir": "gpt-5-6-sol/codex-cli-ultra", - "order": 29, - "runs": { - "mythos-craft": [ - { - "note": { - "zh": "在 Codex 应用内置的 Codex CLI 0.144.0-alpha.4 中以 GPT-5.6-Sol(ultra 思考档位),使用仓库标准中文提示词生成。此 case 使用独立、全新的 CODEX_HOME,并从空工作目录开始,未加载 harness 自带以外的任何 skill、插件、MCP、自定义规则或系统提示。原始 Ultra 回合在已完整写出可玩单 HTML 后,因宿主收到状态查询而在最终加固阶段中断;本页是中断前落盘的完整 fallback.html,仅原样重命名,未修改内容,也未重试生成。", - "en": "Generated from the repository's canonical Chinese prompt by GPT-5.6-Sol (ultra effort) in Codex CLI 0.144.0-alpha.4 bundled with the Codex app. This case used a separate clean CODEX_HOME and started in an empty working directory, with no skills, plugins, MCP servers, custom rules, or system prompts beyond those bundled with the harness. The original Ultra turn was host-interrupted during final hardening after it had written a complete playable single-file HTML; this page is that saved fallback.html, renamed verbatim with no content changes and no retry." - }, - "contributor": "ZidongChen25" - }, - { - "file": "mythos-craft-block-era.html", - "note": { - "zh": "同一 case 的另一版一次生成产物,与主产物并列保留。GPT-5.6-Sol(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词生成,未经人工修改。此版为『方块纪元』主题的沙盒建造。", - "en": "An alternate one-shot artifact for this case, kept alongside the primary run. Generated by GPT-5.6-Sol (ultra effort) in Codex CLI from the repository's canonical Chinese prompt with no human edits. A 'Block Era' sandbox-building take." - }, - "contributor": "Nagi-ovo" - } - ], - "pelican-cycling": [ - { - "note": { - "zh": "在 Codex 应用内置的 Codex CLI 0.144.0-alpha.4 中以 GPT-5.6-Sol(ultra 思考档位),使用仓库标准中文提示词一次生成。此 case 使用独立、全新的 CODEX_HOME,并从空工作目录开始,未加载 harness 自带以外的任何 skill、插件、MCP、自定义规则或系统提示;本页为未经人工修改的原始 agent 产物。", - "en": "Generated in one shot from the repository's canonical Chinese prompt by GPT-5.6-Sol (ultra effort) in Codex CLI 0.144.0-alpha.4 bundled with the Codex app. This case used a separate clean CODEX_HOME and started in an empty working directory, with no skills, plugins, MCP servers, custom rules, or system prompts beyond those bundled with the harness; this is the original agent artifact with no human edits." - }, - "contributor": "ZidongChen25" - }, - { - "file": "pelican-coastal-ride.svg", - "note": { - "zh": "同一 case 的另一版一次生成 SVG,与主产物并列保留。GPT-5.6-Sol(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词生成,未经人工修改。", - "en": "An alternate one-shot SVG for this case, kept alongside the primary run. Generated by GPT-5.6-Sol (ultra effort) in Codex CLI from the repository's canonical Chinese prompt with no human edits." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "pelican-cyclist.svg", - "note": { - "zh": "同一 case 的又一版一次生成 SVG,与主产物并列保留。GPT-5.6-Sol(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词生成,未经人工修改。", - "en": "A further alternate one-shot SVG for this case, kept alongside the primary run. Generated by GPT-5.6-Sol (ultra effort) in Codex CLI from the repository's canonical Chinese prompt with no human edits." - }, - "contributor": "Nagi-ovo" - } - ], - "skeleton-watch": [ - { - "note": { - "zh": "在 Codex 应用内置的 Codex CLI 0.144.0-alpha.4 中以 GPT-5.6-Sol(ultra 思考档位),使用仓库标准中文提示词一次生成。此 case 使用独立、全新的 CODEX_HOME,并从空工作目录开始,未加载 harness 自带以外的任何 skill、插件、MCP、自定义规则或系统提示。原始 Ultra 回合已生成完整 HTML 写入调用,但宿主状态查询在该调用执行前将回合中断;本页通过原样重放 rollout 中完整记录的 apply_patch 参数恢复,未续写模型,也未修改内容。", - "en": "Generated in one shot from the repository's canonical Chinese prompt by GPT-5.6-Sol (ultra effort) in Codex CLI 0.144.0-alpha.4 bundled with the Codex app. This case used a separate clean CODEX_HOME and started in an empty working directory, with no skills, plugins, MCP servers, custom rules, or system prompts beyond those bundled with the harness. The original Ultra turn had produced the complete HTML write call when a host status query interrupted the turn before that call executed; this page was recovered by replaying the exact apply_patch payload recorded in the rollout, with no model continuation or content changes." - }, - "contributor": "ZidongChen25" - }, - { - "file": "skeleton-watch-calibre-01.html", - "note": { - "zh": "同一 case 的另一次独立、完整生成(『Calibre 01』),与主产物(受宿主中断后恢复的 AURELIUS S-01)并列保留。GPT-5.6-Sol(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词生成,未经人工修改。", - "en": "A separate, complete generation for this case ('Calibre 01'), kept alongside the primary run (the interruption-recovered AURELIUS S-01). Generated by GPT-5.6-Sol (ultra effort) in Codex CLI from the repository's canonical Chinese prompt with no human edits." - }, - "contributor": "Nagi-ovo" - } - ] - } -} diff --git a/models/gpt-5-6-terra-codex-cli-xhigh.json b/models/gpt-5-6-terra-codex-cli-xhigh.json deleted file mode 100644 index 573877a..0000000 --- a/models/gpt-5-6-terra-codex-cli-xhigh.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "GPT-5.6-Terra", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "xhigh", - "order": 29.6, - "runs": { - "turf-war": { - "note": { - "zh": "GPT-5.6-Terra(xhigh 思考档位)在 Codex CLI 中用仓库标准中文提示词(仅按案例规则填写文末【本次运行】占位符)一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「拓荒狐」。诊断:工程翻车:自写的 addTop 插入排序有 off-by-one,数组留下 undefined 空洞,act() 几乎每个 tick 都抛 TypeError(top[at-1].raw)。按规则抛异常即该 tick 直行,于是它全程走直线、策略一步未跑成。这是它真实的一次成型水平。", - "en": "One-shot Turf War agent by GPT-5.6-Terra (xhigh effort) in Codex CLI from the repository's canonical Chinese prompt (only the [This run] placeholders filled per case rules), with no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"拓荒狐\". Diagnosis: Engineering failure: its own addTop insertion-sort has an off-by-one that leaves an undefined hole, so act() throws a TypeError (top[at-1].raw) almost every tick. Per the rules a thrown act() means a straight move, so it walks in a straight line all match — its real strategy never runs once." - }, - "contributor": "Nagi-ovo", - "agentName": "拓荒狐" - } - } -} \ No newline at end of file diff --git a/models/gpt-5-6-terra.json b/models/gpt-5-6-terra.json deleted file mode 100644 index 6f1ec5e..0000000 --- a/models/gpt-5-6-terra.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "GPT-5.6-Terra", - "vendor": "OpenAI", - "harness": "Codex CLI", - "effort": "ultra", - "artifactDir": "gpt-5-6-terra/codex-cli-ultra", - "order": 29.5, - "runs": { - "mythos-craft": { - "note": { - "zh": "GPT-5.6-Terra(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词一次生成,未经人工修改。此版为『阿斯特拉:方块神话』主题的沙盒建造。", - "en": "One-shot by GPT-5.6-Terra (ultra effort) in Codex CLI from the repository's canonical Chinese prompt, with no human edits. An 'Astra: Block Myth' sandbox-building take." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "GPT-5.6-Terra(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词一次生成,未经人工修改。海边骑行鹈鹕 SVG。", - "en": "One-shot by GPT-5.6-Terra (ultra effort) in Codex CLI from the repository's canonical Chinese prompt, with no human edits. A seaside pelican-on-bicycle SVG." - }, - "contributor": "Nagi-ovo" - }, - "skeleton-watch": { - "note": { - "zh": "GPT-5.6-Terra(ultra 思考档位)在 Codex CLI 中用仓库标准中文提示词一次生成,未经人工修改。镂空机械腕表交互演示。", - "en": "One-shot by GPT-5.6-Terra (ultra effort) in Codex CLI from the repository's canonical Chinese prompt, with no human edits. An interactive skeleton mechanical-watch demo." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/grok-4-3-cursor.json b/models/grok-4-3-cursor.json deleted file mode 100644 index d3ea204..0000000 --- a/models/grok-4-3-cursor.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Grok 4.3", - "vendor": "xAI", - "harness": "Cursor", - "effort": "Default", - "artifactDir": "grok-4-3/cursor-default", - "order": 61, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Cursor CLI 中以 Grok 4.3 默认设置一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Grok 4.3 inside Cursor CLI with default settings; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Cursor CLI 中以 Grok 4.3 默认设置一次生成;本页为未经修改的原始产出。", - "en": "Generated in one shot by Grok 4.3 inside Cursor CLI with default settings; unmodified original output." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/grok-4-5.json b/models/grok-4-5.json deleted file mode 100644 index 3b455e1..0000000 --- a/models/grok-4-5.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "Grok 4.5", - "vendor": "xAI", - "harness": "Grok Build TUI", - "effort": "High", - "artifactDir": "grok-4-5/grok-build-tui-high", - "order": 59, - "runs": { - "mythos-craft": { - "note": { - "zh": "在本地通过 Grok Build(TUI)以 Grok 4.5(High,最高可选档位)一次生成,未修改。含 Perlin 噪声地形、WASD 第一人称、多种方块破坏/放置、水晶塔/符文石阵/龙骨遗迹/天空遗迹,按 G 传送地标,附小地图与快捷栏。", - "en": "One-shot by Grok 4.5 (High, highest available effort) in the Grok Build TUI, unmodified. Perlin-noise terrain, WASD first-person, multi-block break/place, Crystal Spire / Rune Circle / Dragon Relic / Sky Ruins, G-key landmark teleport, minimap and hotbar." - }, - "contributor": "Mintcolour" - }, - "pelican-cycling": { - "note": { - "zh": "在本地通过 Grok Build(TUI)以 Grok 4.5(High,最高可选档位)一次生成,未修改。海边骑行鹈鹕 SVG:渐变天空、太阳云朵、海浪沙滩、棕榈树、海鸥、自行车细节与鹈鹕喙囊羽翼踩踏姿态。", - "en": "One-shot by Grok 4.5 (High, highest available effort) in the Grok Build TUI, unmodified. Coastal pelican-on-bicycle SVG: gradient sky, sun and clouds, waves and beach, palms, gulls, detailed bicycle, and pelican beak/pouch/wing pedaling pose." - }, - "contributor": "Mintcolour" - }, - "skeleton-watch": { - "note": { - "zh": "在本地通过 Grok Build(TUI)以 Grok 4.5(High,最高可选档位)一次生成,未修改。Three.js 镂空机械表:齿轮系、摆轮游丝、擒纵、红宝石轴承、发光指针刻度、爆炸/组装视图、零件悬停标签与自动旋转。", - "en": "One-shot by Grok 4.5 (High, highest available effort) in the Grok Build TUI, unmodified. Three.js skeleton watch: gear train, balance/hairspring, escapement, ruby bearings, luminous hands and markers, exploded/assembled views, part hover labels and auto-rotate." - }, - "contributor": "Mintcolour" - } - } -} diff --git a/models/grok-build.json b/models/grok-build.json deleted file mode 100644 index cc0cbc8..0000000 --- a/models/grok-build.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Grok Build", - "vendor": "xAI", - "harness": "Grok Build TUI", - "effort": "Max", - "artifactDir": "grok-build/grok-build-tui-max", - "order": 60, - "runs": { - "mythos-craft": { - "note": { - "zh": "在本地通过 Grok Build(TUI)开发实现;本页为修复版(共改 3 行)。问题一:第 82 行 const WORLD_SEED = 0xAETHER,T/H/R 不是十六进制字符,整段脚本解析即抛 SyntaxError——修复前画面纯黑,只剩 HTML 文字。问题二:贴图集画在 canvas 顶部两行、UV 按左上原点计算,却未设 flipY=false,所有面采样到未绘制的黑色区域——修复前进入世界后近处地形全黑。问题三:forward 向量已指向相机朝向,按键却写成 W 减、S 加——修复前按 W 后退、按 S 前进(A/D 正常)。三处均为一行级修正,其余保持 Grok 原样。", - "en": "Built locally with the Grok Build TUI; fixed build (3 lines changed). Bug 1: line 82 const WORLD_SEED = 0xAETHER — T/H/R are not hex digits, so the whole script threw a SyntaxError at parse time; before the fix the screen was pure black with only HTML text. Bug 2: the atlas is drawn in the top canvas rows with top-left-origin UVs but no flipY=false, so every face sampled the undrawn black region; before the fix nearby terrain rendered solid black. Bug 3: the forward vector already points where the camera looks, but W subtracted and S added — W walked backward (A/D were fine). One line each; everything else is Grok as-is." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在本地通过 Grok Build(TUI)一次生成。", - "en": "Generated in one shot locally via the Grok Build TUI." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/inkling.json b/models/inkling.json deleted file mode 100644 index e80ca14..0000000 --- a/models/inkling.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Inkling", - "vendor": "Thinking Machines Lab", - "harness": "Tinker Web", - "effort": "xHigh", - "artifactDir": "inkling/tinker-web-xhigh", - "order": 135, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Tinker 网页版(Inkling Playground)以 Inkling(xHigh 档位)一次生成,未进行任何修改。", - "en": "Generated in one shot with Inkling (xHigh) in the Tinker web playground, unmodified." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Tinker 网页版(Inkling Playground)以 Inkling(xHigh 档位)一次生成,未进行任何修改。", - "en": "Generated in one shot with Inkling (xHigh) in the Tinker web playground, unmodified." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/kimi-k2-6.json b/models/kimi-k2-6.json deleted file mode 100644 index fc979ad..0000000 --- a/models/kimi-k2-6.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Kimi K2.6", - "vendor": "Moonshot AI", - "harness": "Kimi Code", - "effort": "Thinking", - "artifactDir": "kimi-k2-6/kimi-code-thinking", - "order": 100, - "runs": { - "mythos-craft": { - "note": { - "zh": "在本地以 Kimi Code(harness)运行 Kimi K2.6 一次生成,本页为未经修改的原始产出。", - "en": "Generated in one shot by Kimi K2.6 running locally in Kimi Code; unmodified original output." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在本地以 Kimi Code(harness)运行 Kimi K2.6 一次生成。", - "en": "Generated in one shot by Kimi K2.6 running locally in Kimi Code." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/kimi-k2-7-code.json b/models/kimi-k2-7-code.json deleted file mode 100644 index fbd31a3..0000000 --- a/models/kimi-k2-7-code.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "Kimi K2.7-Code", - "vendor": "Moonshot AI", - "harness": "Kimi Code", - "effort": "Thinking", - "artifactDir": "kimi-k2-7-code/kimi-code-thinking", - "order": 98, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Kimi Code 中使用 Kimi K2.7-Code 模型(Thinking 档位)生成。修复了 Chunk 生成与获取递归调用导致的调用栈溢出(Maximum call stack size exceeded)报错,并调整了 Canvas 层级定位问题。", - "en": "Generated by Kimi K2.7-Code running in Kimi Code with Thinking mode. Fixed a call stack size exceeded recursion crash in Chunk generation, and resolved canvas absolute positioning issues." - }, - "contributor": "OHCJ099" - }, - "pelican-cycling": { - "note": { - "zh": "在 Kimi Code 中使用 Kimi K2.7-Code 模型(Thinking 档位)一次生成。", - "en": "Generated in one shot by Kimi K2.7-Code running in Kimi Code with Thinking mode." - }, - "contributor": "OHCJ099" - }, - "skeleton-watch": { - "note": { - "zh": "在 Kimi Code 中使用 Kimi K2.7-Code 模型(Thinking 档位)一次生成,未进行任何修改。", - "en": "Generated in one shot by Kimi K2.7-Code running in Kimi Code with Thinking mode, unmodified." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/kimi-k3-kimi-code-max.json b/models/kimi-k3-kimi-code-max.json deleted file mode 100644 index 2f1c90a..0000000 --- a/models/kimi-k3-kimi-code-max.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "label": "Kimi K3", - "vendor": "Moonshot AI", - "harness": "Kimi Code", - "effort": "Max", - "artifactDir": "kimi-k3/kimi-code-max", - "order": 97.85, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Kimi Code 中以 Kimi K3(Max 档位)一次生成,未经修改。与「Kimi 网页版」条目同模型、不同 Harness,可并排对比。", - "en": "Generated in one shot by Kimi K3 (Max) inside Kimi Code, unmodified. Same model as the Kimi Web entry under a different harness — compare the two side by side." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Kimi Code 中以 Kimi K3(Max 档位)一次生成。", - "en": "Generated in one shot by Kimi K3 (Max) inside Kimi Code." - }, - "contributor": "Nagi-ovo" - }, - "turf-war": { - "note": { - "zh": "Kimi K3(Kimi Code · Max)用仓库标准中文提示词一次生成的圈地智能体,未经人工修改。按案例规则策略文件不公开、仅注册运行,由维护者亲自执行,任何 bug 均不修复。自命名「蚕食」。诊断:合法且 fuel 安全——生存不变量完整(绝不踩己尾、每步保留回家路)、断尾反杀与威胁 BFS 撤退逻辑齐全。但实战偏弱:对 baseline-expander 两个种子均告负(318:1045、339:939),扩张过于保守、圈地量小(约 80–92 手却只得 300 出头)。写得干净却太求稳,不敢铺开,被基线三比一碾过。", - "en": "One-shot Turf War agent by Kimi K3 (Kimi Code, Max) from the repository's canonical Chinese prompt, no human edits. Per case rules the policy file is unpublished and no bug is ever fixed; this registers the maintainer-executed run. Self-named \"蚕食\" (Nibble). Diagnosis: legal and fuel-safe — complete survival invariants (never steps on its own tail, always keeps a path home), full tail-cut punish and threat-BFS retreat. But competitively weak: loses to baseline-expander on both seeds (318:1045, 339:939), expanding too conservatively for a small capture volume (~80–92 moves for barely 300 points). Clean code that plays too safe to spread out, run over ~3:1 by the baseline." - }, - "contributor": "Nagi-ovo", - "agentName": "蚕食" - } - } -} diff --git a/models/kimi-k3.json b/models/kimi-k3.json deleted file mode 100644 index 8f83838..0000000 --- a/models/kimi-k3.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "Kimi K3", - "vendor": "Moonshot AI", - "harness": "Kimi Web", - "effort": "Max", - "artifactDir": "kimi-k3/kimi-web-max", - "order": 97.9, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Kimi 网页版使用 Kimi K3(Max 档位)一次生成,未进行任何修改。", - "en": "Generated in one shot in the Kimi web app on Kimi K3 (Max), unmodified." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/mimo-v2-5-pro-micode-high.json b/models/mimo-v2-5-pro-micode-high.json deleted file mode 100644 index ff216bc..0000000 --- a/models/mimo-v2-5-pro-micode-high.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "MiMo V2.5", - "vendor": "Xiaomi", - "harness": "MiMo Code", - "effort": "High", - "artifactDir": "mimo-v2-5/micode-high", - "order": 97, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 MiMo Code (v0.1.4) 中以 MiMo V2.5(High 思考强度)一次生成;原始产出修复了多个严重 bug(Perlin noise permutation 数组初始化错误导致 NaN 索引、noise 函数作用域问题、noiseFill 变量命名冲突、函数名误用点号、this 缺少点号、IIFE 未闭合、Three.js RepeatSetting 常量错误、WASD 移动按键错误、沙子/草地判断逻辑反转、物理引擎碰撞检测逻辑错误导致着地弹跳),并重写了整个噪声模块和物理引擎,将 Three.js 内联以支持本地 file:// 协议运行,生成逻辑未改。基于 Three.js 构建了完整的 3D 体素世界,包含柏林噪声生成的地形、WASD + 鼠标第一人称操控、8 种方块类型(泥土、草、石头、沙、木头、砖、水晶、黄金)、左键破坏右键放置、飞行模式、以及五处神话幻想建筑(水晶塔、石阵、龙骨遗迹、天空岛、远古图书馆)。", - "en": "Generated in one shot by MiMo V2.5 (High effort) inside MiMo Code (v0.1.4); original output had multiple critical bugs fixed (Perlin noise permutation array initialization error causing NaN indexing, noise function scope issue, noiseFill variable naming collision, dot after function keyword, missing dot after this, unclosed IIFE, Three.js RepeatSetting constant error, WASD movement key error, sand/grass logic inversion, physics engine collision detection error causing ground bouncing); noise module and physics engine rewritten entirely, Three.js inlined for local file:// protocol compatibility; generation logic untouched. Built a complete 3D voxel world with Three.js, featuring Perlin noise terrain, WASD + mouse first-person controls, 8 block types (dirt, grass, stone, sand, wood, brick, crystal, gold), left-click break / right-click place, fly mode, and five mythic-fantasy structures (Crystal Tower, Stone Circle, Dragon Ruins, Sky Island, Ancient Library)." - }, - "contributor": "BaiLin-William" - }, - "pelican-cycling": { - "note": { - "zh": "在 MiMo Code (v0.1.4) 中以 MiMo V2.5(High 思考强度)一次生成;未经修改的原始产出。包含渐变天空、太阳光晕、多层云朵、海浪纹理、浪花泡沫线、湿润沙滩、棕榈树(含椰子)、海鸥、鹈鹕(解剖细节:喉囊、喙钩、羽冠、翅膀羽毛纹理、蹼足)、红色自行车(辐条、链条、踏板、车座、挡泥板)、海星贝壳脚印等装饰元素。", - "en": "Generated in one shot by MiMo V2.5 (High effort) inside MiMo Code (v0.1.4); unmodified original output. Includes gradient sky, sun glow, layered clouds, ocean wave textures, foam line, wet sand, palm trees with coconuts, seagulls, a detailed pelican (anatomical: gular pouch, beak hook, crown tuft, wing feather texture, webbed feet), red bicycle (spokes, chain, pedals, seat, fender), and beach decorations (starfish, shells, footprints)." - }, - "contributor": "BaiLin-William" - }, - "skeleton-watch": { - "note": { - "zh": "在 MiMo Code (v0.1.4) 中以 MiMo V2.5(High 思考强度)一次生成;将 Three.js 内联以支持本地 file:// 协议运行。原始产出在机芯型号中写出 MiMo,会在 Arena 盲评中泄露身份;本页仅将该型号改为中性 SK-01,其余未修改。基于 Three.js 构建了完整的 3D 镂空机械腕表,包含发条盒(含可见游丝发条)、齿轮系(5 组齿轮)、擒纵机构(擒纵轮+擒纵叉+红宝石瓦)、摆轮(带宝玑游丝、调速螺丝、冲击销)、夹板(日内瓦纹主夹板、摆轮夹板、发条盒夹板)、35 颗红宝石轴承、时分秒针(夜光涂层)、12 个小时刻度(3/6/9/12 为金色条形+夜光点)、60 格分钟刻度、蓝宝石水晶表镜与底盖、玫瑰金表壳表圈、表冠(带防滑纹路)、表耳。交互功能:拖拽旋转、滚轮缩放、E 键切换爆炸视图、I 键显示机芯信息面板、空格暂停动画、悬停零件标签高亮。灯光:ACES 色调映射、三点布光(主光/填充光/轮廓光)+ 顶部补光。", - "en": "Generated in one shot by MiMo V2.5 (High effort) inside MiMo Code (v0.1.4); Three.js inlined for local file:// protocol compatibility. The original output included MiMo in the calibre model, which would reveal identity in blind Arena mode; this page only changes that visible model to neutral SK-01, otherwise unmodified. Built a complete 3D skeleton mechanical watch with Three.js, featuring mainspring barrel (visible coiled spring), gear train (5 wheels), escapement (escape wheel + pallet fork with ruby pallets), balance wheel (Breguet hairspring, timing screws, impulse pin), bridges (Côtes de Genève main bridge, balance cock, barrel bridge), 35 ruby jewel bearings, luminous hour/minute/second hands, 12 hour markers (gold bar at 3/6/9/12 with lume dot), 60-minute track, sapphire crystal front and caseback, rose gold case and bezel, knurled crown, and lugs. Interactions: drag rotate, scroll zoom, E for exploded view, I for movement info panel, Space to pause, hover labels. Lighting: ACES tone mapping, three-point studio lighting." - }, - "contributor": "BaiLin-William" - } - } -} diff --git a/models/mimo-v2-5-pro-mimocode.json b/models/mimo-v2-5-pro-mimocode.json deleted file mode 100644 index b6adb29..0000000 --- a/models/mimo-v2-5-pro-mimocode.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "label": "MiMo v2.5 Pro", - "vendor": "Xiaomi", - "harness": "MiMo Code", - "effort": "Max", - "order": 97.2, - "runs": { - "skeleton-watch": { - "note": { - "zh": "在 MiMo Code 中使用 MiMo v2.5 Pro 模型一次生成,未进行任何修改。", - "en": "Generated in one shot by MiMo v2.5 Pro in MiMo Code, unmodified." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/mimo-v2-5-pro-ultraspeed.json b/models/mimo-v2-5-pro-ultraspeed.json deleted file mode 100644 index 4871369..0000000 --- a/models/mimo-v2-5-pro-ultraspeed.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "label": "MiMo v2.5 Pro UltraSpeed", - "vendor": "Xiaomi", - "harness": "Web", - "effort": "Default", - "order": 97.5, - "runs": { - "mythos-craft": [ - { - "note": { - "zh": "在 Web 环境中使用 MiMo v2.5 Pro UltraSpeed 一次生成,未做任何修改。", - "en": "Generated in one shot by MiMo v2.5 Pro UltraSpeed in Web environment, with no modifications." - }, - "contributor": "OHCJ099" - }, - { - "note": { - "zh": "在 Web 环境中使用 MiMo v2.5 Pro UltraSpeed 一次生成,未做任何修改(变体 2)。", - "en": "Generated in one shot by MiMo v2.5 Pro UltraSpeed in Web environment, with no modifications (variant 2)." - }, - "file": "mythos-craft-2.html", - "contributor": "OHCJ099" - } - ], - "pelican-cycling": [ - { - "note": { - "zh": "在 Web 环境中使用 MiMo v2.5 Pro UltraSpeed 一次生成,未做任何修改。", - "en": "Generated in one shot by MiMo v2.5 Pro UltraSpeed in Web environment, with no modifications." - }, - "contributor": "OHCJ099" - }, - { - "note": { - "zh": "在 Web 环境中使用 MiMo v2.5 Pro UltraSpeed 一次生成,未做任何修改(变体 2)。", - "en": "Generated in one shot by MiMo v2.5 Pro UltraSpeed in Web environment, with no modifications (variant 2)." - }, - "file": "pelican-cycling-2.svg", - "contributor": "OHCJ099" - } - ], - "skeleton-watch": { - "note": { - "zh": "在 Web 环境中使用 MiMo v2.5 Pro UltraSpeed 一次生成,未做任何修改。", - "en": "Generated in one shot by MiMo v2.5 Pro UltraSpeed in Web environment, with no modifications." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/minimax-m2-7.json b/models/minimax-m2-7.json deleted file mode 100644 index a758905..0000000 --- a/models/minimax-m2-7.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "label": "MiniMax M2.7", - "vendor": "MiniMax", - "harness": "MiniMax Code Web", - "effort": "Thinking", - "artifactDir": "minimax-m2-7/minimax-code-web-thinking", - "order": 111, - "runs": { - "pelican-cycling": { - "note": { - "zh": "在 MiniMax Code 网页版以 MiniMax M2.7(开启思考模式 Thinking)一次生成。", - "en": "Generated in one shot by MiniMax M2.7 (Thinking mode on) in the MiniMax Code web app." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/minimax-m3.json b/models/minimax-m3.json deleted file mode 100644 index c7a3a7c..0000000 --- a/models/minimax-m3.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "label": "MiniMax M3", - "vendor": "MiniMax", - "harness": "MiniMax Code Web", - "effort": "Thinking", - "artifactDir": "minimax-m3/minimax-code-web-thinking", - "order": 110, - "runs": { - "pelican-cycling": [ - { - "note": { - "zh": "在 MiniMax Code 网页版以 MiniMax M3(开启思考模式 Thinking)一次生成。", - "en": "Generated in one shot by MiniMax M3 (Thinking mode on) in the MiniMax Code web app." - }, - "contributor": "Nagi-ovo" - }, - { - "file": "pelican-cycling-2.svg", - "note": { - "zh": "在 MiniMax Code 网页版以 MiniMax M3(开启思考模式 Thinking)一次生成的第二个 SVG 版本。", - "en": "Second SVG variant generated in one shot by MiniMax M3 (Thinking mode on) in the MiniMax Code web app." - }, - "contributor": "Nagi-ovo" - } - ] - } -} diff --git a/models/mistral-medium-3-5.json b/models/mistral-medium-3-5.json deleted file mode 100644 index 37cc365..0000000 --- a/models/mistral-medium-3-5.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Mistral Medium 3.5", - "vendor": "Mistral AI", - "harness": "Vibe", - "effort": "Thinking", - "artifactDir": "mistral-medium-3-5/vibe-thinking", - "order": 80, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Vibe 网页版以 Mistral Medium 3.5(开启 Thinking)一次生成;本页为修复版(仅改 1 行)。问题:初始化时一次性同步生成 RENDER_DISTANCE=4 的 9×9=81 个区块,而每个区块要对 16×16×128 个体素逐一在 mythStructures 数组里做线性查找(再加 6 个相邻面),约 O(体素×建筑)≈ 数十亿次/区块。修复前:加载后主线程被卡死,页面一直停在加载界面、始终无法打开。原因:首屏同步生成量过大且单区块为暴力线性查找,首帧渲染前即阻塞主线程。将 RENDER_DISTANCE 由 4 改为 1(首屏改为同步生成 3×3=9 个区块)后即可正常打开并以 60fps 运行。地形、画面与玩法均为模型原始产出,未作他改。", - "en": "Generated in one shot in the Vibe web app on Mistral Medium 3.5 (Thinking enabled); fixed build (1 line changed). Bug: on init the world synchronously builds the full RENDER_DISTANCE=4 ring — a 9x9 = 81-chunk grid — and each chunk runs a linear scan over the mythStructures array for every one of its 16x16x128 voxels (plus six neighbor faces), roughly O(voxels x structures) ≈ billions of ops per chunk. Before the fix: the main thread froze on load and the page stayed on the loading screen, never opening. Cause: the first-screen synchronous generation is far too large and each chunk uses a brute-force linear lookup, blocking the main thread before the first frame. Setting RENDER_DISTANCE from 4 to 1 (a 3x3 = 9-chunk first-screen load) lets it open and run at 60fps. Terrain, visuals and gameplay are the model's original output, otherwise unmodified." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Vibe 网页版以 Mistral Medium 3.5(开启 Thinking)一次生成,未作修改。", - "en": "Generated in one shot in the Vibe web app on Mistral Medium 3.5 (Thinking enabled), unmodified." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/nex-n2-pro-cc.json b/models/nex-n2-pro-cc.json deleted file mode 100644 index 4eb8846..0000000 --- a/models/nex-n2-pro-cc.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Nex-N2-Pro", - "vendor": "Nex-AGI", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "nex-n2-pro/claude-code-max", - "order": 65, - "runs": { - "mythos-craft": { - "note": { - "zh": "通过 Claude Code 生成(thinking effort: max);一次生成,未经过人工后续修改。", - "en": "Generated via Claude Code (thinking effort: max); one-shot, without manual modifications." - }, - "contributor": "OHCJ099" - }, - "pelican-cycling": { - "note": { - "zh": "通过 Claude Code 生成(thinking effort: max);一次生成,未经过人工后续修改。", - "en": "Generated via Claude Code (thinking effort: max); one-shot, without manual modifications." - }, - "contributor": "OHCJ099" - } - } -} diff --git a/models/qwen3-7-max.json b/models/qwen3-7-max.json deleted file mode 100644 index 3c54d66..0000000 --- a/models/qwen3-7-max.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Qwen3.7-Max", - "vendor": "Alibaba", - "harness": "Qoder", - "effort": "Default", - "artifactDir": "qwen3-7-max/qoder-default", - "order": 130, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Qoder 中由 Qwen3.7-Max 一次生成,本页为未经修改的原始产出。基于 Three.js 的体素世界:区块地形、第一人称 WASD 控制、方块破坏/放置,并自带奇幻建筑(法师塔、远古神庙、巨树、龙巢、符文阵)。", - "en": "Generated in one shot by Qwen3.7-Max inside Qoder; unmodified original output. A Three.js voxel world: chunked terrain, first-person WASD controls, block break/place, with fantasy structures (wizard tower, ancient temple, giant tree, dragon nest, runic circle)." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Qoder 中由 Qwen3.7-Max 一次生成,本页为未经修改的原始 SVG。海边场景:太阳、云朵、海鸥、远处群山与帆船、椰子树,一只鹈鹕骑着红色自行车(含速度线),左上角附一张鹈鹕侧面图鉴小卡。", - "en": "Generated in one shot by Qwen3.7-Max inside Qoder; unmodified original SVG. A seaside scene — sun, clouds, gulls, distant mountains and a sailboat, a palm tree, and a pelican riding a red bicycle (with motion lines), plus a pelican side-profile study card in the top-left corner." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/step-3-7-flash.json b/models/step-3-7-flash.json deleted file mode 100644 index 8b9560a..0000000 --- a/models/step-3-7-flash.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "Step 3.7 Flash", - "vendor": "StepFun", - "harness": "Claude Code", - "effort": "High", - "artifactDir": "step-3-7-flash/claude-code-high", - "order": 131, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 Step 3.7 Flash(High 思考强度)一次生成。生成时 Write 工具调用失误,模型产出的内容由人工手动写入该 HTML 文件,代码本身未做改动。基于 Three.js 与柏林噪声地形的《我的世界》式体素世界,支持 WASD + 鼠标第一人称操控。", - "en": "Generated in one shot by Step 3.7 Flash in Claude Code (High thinking effort). The Write tool call failed during generation, so the model's output was saved into this HTML file by hand; the code itself was not modified. A Minecraft-style voxel world built on Three.js with Perlin-noise terrain and WASD + mouse first-person controls." - }, - "contributor": "Nagi-ovo" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 Step 3.7 Flash(High 思考强度)一次生成,未做人工修复。海边骑行的鹈鹕 SVG:蓝天白云、海面、沙滩与海鸥,红色自行车(含辐条与链条),鹈鹕有长喙与喉囊。", - "en": "Generated in one shot via Claude Code with Step 3.7 Flash (High thinking effort), no manual fixes. A pelican cycling by the sea in SVG: blue sky, clouds, ocean, beach and seagulls, a red bicycle (spokes and chain), and a pelican with a long beak and gular pouch." - }, - "contributor": "Nagi-ovo" - } - } -} diff --git a/models/xiaomi-mimo-v2-5-pro.json b/models/xiaomi-mimo-v2-5-pro.json deleted file mode 100644 index cf63d66..0000000 --- a/models/xiaomi-mimo-v2-5-pro.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "label": "MiMo v2.5 Pro", - "vendor": "Xiaomi", - "harness": "Claude Code", - "effort": "Max", - "artifactDir": "mimo-v2-5-pro/claude-code-max", - "order": 97, - "runs": { - "mythos-craft": { - "note": { - "zh": "在 Claude Code 中以 MiMo v2.5 Pro(最高思考强度)一次生成;原始产出在浏览器标题、开屏「Generated by MiMo v2.5 Pro」字样与控制台日志中直接写出了模型名,会在 Arena 盲评中泄露身份,本页为去除这些身份字样后的版本(改 3 行),生成逻辑未改。游戏内容:Perlin 噪声地形、WASD + 鼠标第一人称操控、12 种方块类型(含水、黑曜石、水晶、金块等)、程序化材质纹理、四种神话建筑(水晶塔、石环阵、龙骨遗迹、天空遗迹),按 G 可依次传送至神话建筑,小地图显示玩家位置和地标。", - "en": "Generated in one shot via Claude Code with MiMo v2.5 Pro (max thinking effort). The original one-shot output wrote the model name into the browser title, an on-screen \"Generated by MiMo v2.5 Pro\" caption, and a console log, which would reveal its identity in the blind Arena; this page strips those identity strings (3 lines changed) and leaves the generation logic untouched. Gameplay: Perlin noise terrain, WASD + mouse first-person controls, 12 block types (including water, obsidian, crystal, gold), procedural textures, and four mythic structures (Crystal Tower, Stone Circle, Dragon Skeleton, Sky Ruins). Press G to cycle-teleport between landmarks; minimap shows player position and landmarks." - }, - "contributor": "Mintcolour" - }, - "pelican-cycling": { - "note": { - "zh": "在 Claude Code 中以 MiMo v2.5 Pro(最高思考强度)一次生成;原始产出在 SVG 末尾有一行「Generated by MiMo v2.5 Pro」水印文本,会在 Arena 盲评中泄露身份,本页已移除该文本,其余未改。场景包含渐变天空、太阳、云朵、海洋波浪、沙滩、棕榈树、海鸥、完整自行车细节(辐条、链条、齿轮、脚踏)以及鹈鹕(长喙、喉囊、羽翼、踩踏姿态),海滩上有海星和贝壳装饰。", - "en": "Generated in one shot via Claude Code with MiMo v2.5 Pro (max thinking effort). The original output carried a \"Generated by MiMo v2.5 Pro\" watermark text at the bottom of the SVG, which would reveal its identity in the blind Arena; this page removes that text and nothing else. Scene includes gradient sky, sun, clouds, ocean waves, beach, palm trees, seagulls, detailed bicycle (spokes, chain, gears, pedals), and a pelican (beak, gular pouch, wings, pedaling pose), with starfish and shell decorations on the beach." - }, - "contributor": "Mintcolour" - } - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/bun.lock b/outputs/claude-fable-5/claude-code-high/cs-dust2/bun.lock deleted file mode 100644 index b17a12e..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/bun.lock +++ /dev/null @@ -1,267 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 1, - "workspaces": { - "": { - "name": "cs2-dust2-sim", - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", - "three": "^0.170.0", - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@types/three": "^0.170.0", - "@vitejs/plugin-react": "^4.3.4", - "typescript": "^5.6.3", - "vite": "^5.4.11", - }, - }, - }, - "packages": { - "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], - - "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], - - "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="], - - "@babel/generator": ["@babel/generator@7.29.7", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ=="], - - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], - - "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="], - - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="], - - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="], - - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], - - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="], - - "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], - - "@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], - - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw=="], - - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q=="], - - "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], - - "@babel/traverse": ["@babel/traverse@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" } }, "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw=="], - - "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], - - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - - "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.2", "", { "os": "android", "cpu": "arm" }, "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg=="], - - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw=="], - - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.62.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A=="], - - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.62.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA=="], - - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.62.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw=="], - - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.62.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg=="], - - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg=="], - - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA=="], - - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA=="], - - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ=="], - - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg=="], - - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ=="], - - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A=="], - - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w=="], - - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg=="], - - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q=="], - - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.62.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg=="], - - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A=="], - - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg=="], - - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.62.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg=="], - - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.62.2", "", { "os": "none", "cpu": "arm64" }, "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA=="], - - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.62.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg=="], - - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.62.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q=="], - - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg=="], - - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA=="], - - "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], - - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], - - "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], - - "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], - - "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - - "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], - - "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], - - "@types/react": ["@types/react@18.3.31", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw=="], - - "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="], - - "@types/stats.js": ["@types/stats.js@0.17.4", "", {}, "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA=="], - - "@types/three": ["@types/three@0.170.0", "", { "dependencies": { "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.18.1" } }, "sha512-CUm2uckq+zkCY7ZbFpviRttY+6f9fvwm6YqSqPfA5K22s9w7R4VnA3rzJse8kHVvuzLcTx+CjNCs2NYe0QFAyg=="], - - "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], - - "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], - - "@webgpu/types": ["@webgpu/types@0.1.71", "", {}, "sha512-mMy8/ODcKhab808co15eW+yN+HgXoQxRQHTiBV9Mrvl1r0ufnid7YOcI+gi4eUWSWl9ezD6TW2KXccrL8HCh2A=="], - - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.43", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ=="], - - "browserslist": ["browserslist@4.28.6", "", { "dependencies": { "baseline-browser-mapping": "^2.10.42", "caniuse-lite": "^1.0.30001803", "electron-to-chromium": "^1.5.389", "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001805", "", {}, "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA=="], - - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - - "electron-to-chromium": ["electron-to-chromium@1.5.389", "", {}, "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg=="], - - "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - - "meshoptimizer": ["meshoptimizer@0.18.1", "", {}, "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="], - - "node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "postcss": ["postcss@8.5.19", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ=="], - - "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], - - "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], - - "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], - - "rollup": ["rollup@4.62.2", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.62.2", "@rollup/rollup-android-arm64": "4.62.2", "@rollup/rollup-darwin-arm64": "4.62.2", "@rollup/rollup-darwin-x64": "4.62.2", "@rollup/rollup-freebsd-arm64": "4.62.2", "@rollup/rollup-freebsd-x64": "4.62.2", "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", "@rollup/rollup-linux-arm-musleabihf": "4.62.2", "@rollup/rollup-linux-arm64-gnu": "4.62.2", "@rollup/rollup-linux-arm64-musl": "4.62.2", "@rollup/rollup-linux-loong64-gnu": "4.62.2", "@rollup/rollup-linux-loong64-musl": "4.62.2", "@rollup/rollup-linux-ppc64-gnu": "4.62.2", "@rollup/rollup-linux-ppc64-musl": "4.62.2", "@rollup/rollup-linux-riscv64-gnu": "4.62.2", "@rollup/rollup-linux-riscv64-musl": "4.62.2", "@rollup/rollup-linux-s390x-gnu": "4.62.2", "@rollup/rollup-linux-x64-gnu": "4.62.2", "@rollup/rollup-linux-x64-musl": "4.62.2", "@rollup/rollup-openbsd-x64": "4.62.2", "@rollup/rollup-openharmony-arm64": "4.62.2", "@rollup/rollup-win32-arm64-msvc": "4.62.2", "@rollup/rollup-win32-ia32-msvc": "4.62.2", "@rollup/rollup-win32-x64-gnu": "4.62.2", "@rollup/rollup-win32-x64-msvc": "4.62.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA=="], - - "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], - - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "three": ["three@0.170.0", "", {}, "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ=="], - - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - - "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], - - "vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], - - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/index.html b/outputs/claude-fable-5/claude-code-high/cs-dust2/index.html deleted file mode 100644 index b5482db..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - DUST II — 5v5 模拟器 - - - -
- - - diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/package.json b/outputs/claude-fable-5/claude-code-high/cs-dust2/package.json deleted file mode 100644 index 3029155..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "cs2-dust2-sim", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc --noEmit && vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", - "three": "^0.170.0" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@types/three": "^0.170.0", - "@vitejs/plugin-react": "^4.3.4", - "typescript": "^5.6.3", - "vite": "^5.4.11" - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/App.tsx b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/App.tsx deleted file mode 100644 index dbc0a29..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/App.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { useEffect, useRef, useState } from 'react' -import { Engine } from './game/engine' -import HUD from './ui/HUD' - -export default function App() { - const viewportRef = useRef(null) - const [engine, setEngine] = useState(null) - - useEffect(() => { - const e = new Engine(viewportRef.current!) - setEngine(e) - ;(window as unknown as { __engine?: Engine }).__engine = e - if (new URLSearchParams(location.search).has('auto')) e.start('CT', true) - return () => e.dispose() - }, []) - - return ( -
-
- {engine && } -
- ) -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/ai.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/ai.ts deleted file mode 100644 index 290d4e7..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/ai.ts +++ /dev/null @@ -1,386 +0,0 @@ -import * as THREE from 'three' -import type { GameMap } from './map' -import type { Nav } from './nav' -import type { PhysicsWorld } from './physics' -import type { Soldier } from './soldier' -import { EYE_HEIGHT } from './types' - -export type Duty = 'none' | 'plant' | 'defuse' | 'pickup' - -export interface Mission { - anchors: THREE.Vector3[] - final: THREE.Vector3 - look: THREE.Vector3 | null - duty: Duty -} - -export interface AIWorld { - map: GameMap - nav: Nav - physics: PhysicsWorld - soldiers: Soldier[] - time: number - bombPlantedPos: THREE.Vector3 | null - bombDroppedPos: THREE.Vector3 | null -} - -const TWO_PI = Math.PI * 2 - -function angleLerp(a: number, target: number, maxStep: number): number { - let d = (target - a) % TWO_PI - if (d > Math.PI) d -= TWO_PI - if (d < -Math.PI) d += TWO_PI - return a + THREE.MathUtils.clamp(d, -maxStep, maxStep) -} - -function angleDiff(a: number, b: number): number { - let d = (b - a) % TWO_PI - if (d > Math.PI) d -= TWO_PI - if (d < -Math.PI) d += TWO_PI - return d -} - -/** - * Per-soldier AI: waypoint navigation over the grid, FOV+LOS target acquisition - * with reaction delay, burst-fire combat, plant/defuse/pickup duties. - */ -export class AIBrain { - s: Soldier - private skill: { err: number; react: number; aggro: number; headRate: number } - - mission: Mission | null = null - private missionIdx = 0 - private arrived = false - - private path: THREE.Vector3[] | null = null - private pathIdx = 0 - private pathGoal = new THREE.Vector3() - private repathAt = 0 - - target: Soldier | null = null - private targetSince = 0 - private reactUntil = 0 - private lastSeenPos = new THREE.Vector3() - private lastSeenAt = -99 - private alertUntil = 0 - private alertPos: THREE.Vector3 | null = null - - private nextThink = 0 - private burstUntil = 0 - private burstPauseUntil = 0 - private strafeDir = 0 - private strafeUntil = 0 - private scopeStart = 0 - private stuckPos = new THREE.Vector3() - private stuckAt = 0 - private wanderAt = 0 - private lookYawTarget: number | null = null - - constructor(s: Soldier) { - this.s = s - this.skill = { - err: 1.1 + Math.random() * 0.9, - react: 0.35 + Math.random() * 0.4, - aggro: Math.random(), - headRate: 0.04 + Math.random() * 0.1, - } - } - - reset() { - this.mission = null - this.path = null - this.target = null - this.arrived = false - this.lastSeenAt = -99 - this.alertPos = null - this.lookYawTarget = null - } - - setMission(anchors: THREE.Vector3[], final: THREE.Vector3, look: THREE.Vector3 | null, duty: Duty) { - this.mission = { anchors: [...anchors], final, look, duty } - this.missionIdx = 0 - this.arrived = false - this.path = null - this.lookYawTarget = null - } - - heard(pos: THREE.Vector3, time: number) { - if (this.target) return - this.alertUntil = time + 3 - this.alertPos = pos.clone() - } - - update(dt: number, w: AIWorld) { - const s = this.s - const c = s.control - c.moveX = 0; c.moveZ = 0 - c.fire = false; c.fireTap = false; c.altTap = false - c.jump = false; c.use = false; c.reload = false; c.slot = null - - if (!s.alive) return - - if (w.time >= this.nextThink) { - this.nextThink = w.time + 0.12 + Math.random() * 0.06 - this.think(w) - } - - if (this.target && w.time >= this.reactUntil) { - this.combat(dt, w) - } else if (this.target) { - this.facePoint(this.target.pos, dt) // reacting: turn but hold fire - } else if (this.lastSeenAt > w.time - 2.5 && this.skill.aggro > 0.35) { - this.chase(dt, w) - } else { - this.missionMove(dt, w) - } - - this.dutyBehavior(w) - } - - // ------------------------------------------------------------------------- - - private think(w: AIWorld) { - const s = this.s - - // perception - let best: Soldier | null = null - let bestDist = Infinity - const eye = s.eyePos - for (const e of w.soldiers) { - if (!e.alive || e.team === s.team) continue - const dist = e.pos.distanceTo(s.pos) - if (dist > 70 || dist >= bestDist) continue - const dirYaw = Math.atan2(-(e.pos.x - s.pos.x), -(e.pos.z - s.pos.z)) - const inFov = Math.abs(angleDiff(s.yaw, dirYaw)) < (w.time < this.alertUntil ? Math.PI : 0.95) - if (!inFov && dist > 3) continue - const targetEye = new THREE.Vector3(e.pos.x, e.pos.y + EYE_HEIGHT * 0.8, e.pos.z) - if (!w.physics.hasLOS(eye, targetEye)) continue - best = e - bestDist = dist - } - - if (best) { - if (this.target !== best) { - if (!this.target) this.reactUntil = w.time + this.skill.react - this.target = best - this.targetSince = w.time - } - this.lastSeenPos.copy(best.pos) - this.lastSeenAt = w.time - best.lastSeenBy[this.s.team] = w.time - } else if (this.target) { - if (w.time - this.lastSeenAt > 0.5) this.target = null - } - - // reload when safe or empty - const wpn = s.weapon - if (!wpn.isKnife) { - if (wpn.mag === 0 && (wpn.reserve > 0)) s.control.reload = true - else if (!this.target && wpn.mag < wpn.def.magSize * 0.35 && wpn.reserve > 0) s.control.reload = true - // completely dry: go knife - if (wpn.mag === 0 && wpn.reserve === 0) { - if (s.slot === 'primary' && s.weapons.secondary && (s.weapons.secondary.mag > 0 || s.weapons.secondary.reserve > 0)) s.control.slot = 'secondary' - else s.control.slot = 'knife' - } - } - - // stuck detection while pathing - if (this.path && !this.arrived) { - if (w.time - this.stuckAt > 1.3) { - if (s.pos.distanceTo(this.stuckPos) < 0.35) { - this.path = null // force repath - this.repathAt = 0 - } - this.stuckPos.copy(s.pos) - this.stuckAt = w.time - } - } else { - this.stuckPos.copy(s.pos) - this.stuckAt = w.time - } - } - - private combat(dt: number, w: AIWorld) { - const s = this.s - const t = this.target! - const c = s.control - const dist = t.pos.distanceTo(s.pos) - const wpn = s.weapon - - // knife rush when using knife - if (wpn.isKnife) { - this.moveToward(t.pos, dt, w, true) - this.facePoint(t.pos, dt) - if (dist < 2.0) c.fire = true - return - } - - // aim: chest, occasionally head - const settle = w.time - this.targetSince - const aimY = Math.random() < this.skill.headRate && settle > 0.8 ? 1.62 : 1.15 - const aimPoint = new THREE.Vector3(t.pos.x, t.pos.y + aimY, t.pos.z) - const errScale = this.skill.err * (0.45 + 0.55 * Math.exp(-settle * 1.1)) * (0.7 + dist / 55) - const wobble = Math.sin(w.time * 7 + s.id * 3.1) * 0.02 * errScale - aimPoint.x += wobble * dist * 0.5 - aimPoint.y += Math.cos(w.time * 6 + s.id) * 0.016 * errScale * dist * 0.5 - - const desiredYaw = Math.atan2(-(aimPoint.x - s.pos.x), -(aimPoint.z - s.pos.z)) - const flatDist = Math.hypot(aimPoint.x - s.pos.x, aimPoint.z - s.pos.z) - const desiredPitch = Math.atan2(aimPoint.y - s.eyePos.y, flatDist) - const turnRate = 6.5 * dt - s.yaw = angleLerp(s.yaw, desiredYaw, turnRate) - s.pitch = THREE.MathUtils.clamp(angleLerp(s.pitch, desiredPitch, turnRate), -1.5, 1.5) - - const aligned = Math.abs(angleDiff(s.yaw, desiredYaw)) < 0.055 && Math.abs(s.pitch - desiredPitch) < 0.05 - - const isAwp = wpn.def.id === 'awp' - if (isAwp) { - if (!s.scoped && aligned) { - c.altTap = true // scope in - this.scopeStart = w.time - } - if (s.scoped && aligned && w.time - this.scopeStart > 0.75) c.fireTap = true - return // AWP AI stands still - } - - // burst fire - if (aligned && wpn.mag > 0 && !wpn.reloading) { - if (w.time > this.burstPauseUntil) { - if (this.burstUntil < w.time) { - this.burstUntil = w.time + (wpn.def.auto ? 0.12 + Math.random() * 0.25 : 0.05) - this.burstPauseUntil = this.burstUntil + 0.25 + Math.random() * 0.5 - } - } - if (w.time < this.burstUntil) { - c.fire = true - c.fireTap = true - } - } - - // strafe jiggle for rifles at medium range - if (dist > 6 && dist < 40 && w.time > this.strafeUntil) { - this.strafeDir = Math.random() < 0.4 ? 0 : (Math.random() < 0.5 ? -1 : 1) - this.strafeUntil = w.time + 0.5 + Math.random() * 0.6 - } - c.moveX = this.strafeDir * 0.6 - if (dist > 45) c.moveZ = 0.7 // push closer at long range - } - - private chase(dt: number, w: AIWorld) { - this.moveToward(this.lastSeenPos, dt, w, false) - this.facePoint(this.lastSeenPos, dt) - if (this.s.pos.distanceTo(this.lastSeenPos) < 2.5) this.lastSeenAt = -99 - } - - private missionMove(dt: number, w: AIWorld) { - const s = this.s - - // face heard noises while holding - if (this.arrived) { - if (this.alertPos && w.time < this.alertUntil) { - this.facePoint(this.alertPos, dt) - } else if (this.mission?.look) { - this.facePoint(this.mission.look, dt) - } else if (this.lookYawTarget !== null) { - s.yaw = angleLerp(s.yaw, this.lookYawTarget, 3 * dt) - } - // occasional gaze wander + micro reposition - if (w.time > this.wanderAt) { - this.wanderAt = w.time + 3 + Math.random() * 4 - this.lookYawTarget = s.yaw + (Math.random() - 0.5) * 1.6 - if (this.mission?.look && Math.random() < 0.6) this.lookYawTarget = null - } - s.pitch = angleLerp(s.pitch, 0, 2 * dt) - return - } - - if (!this.mission) return - const waypoint = this.missionIdx < this.mission.anchors.length - ? this.mission.anchors[this.missionIdx] - : this.mission.final - - if (this.moveToward(waypoint, dt, w, false)) { - if (this.missionIdx < this.mission.anchors.length) { - this.missionIdx++ - this.path = null - } else { - this.arrived = true - this.path = null - } - } - } - - /** Steers along an A* path toward `goal`. Returns true when within reach. */ - private moveToward(goal: THREE.Vector3, dt: number, w: AIWorld, sprint: boolean): boolean { - const s = this.s - const dGoal = Math.hypot(goal.x - s.pos.x, goal.z - s.pos.z) - if (dGoal < 1.0) return true - - if (!this.path || this.pathGoal.distanceTo(goal) > 2 || w.time > this.repathAt) { - this.path = w.nav.findPath(s.pos, goal) - this.pathIdx = 0 - this.pathGoal.copy(goal) - this.repathAt = w.time + 3 + Math.random() - if (!this.path || this.path.length === 0) return true - } - - let wp = this.path[this.pathIdx] - while (wp && Math.hypot(wp.x - s.pos.x, wp.z - s.pos.z) < 0.7) { - this.pathIdx++ - if (this.pathIdx >= this.path.length) return true - wp = this.path[this.pathIdx] - } - if (!wp) return true - - const dir = new THREE.Vector3(wp.x - s.pos.x, 0, wp.z - s.pos.z).normalize() - // convert world dir to local move axes - const fwd = new THREE.Vector3(-Math.sin(s.yaw), 0, -Math.cos(s.yaw)) - const right = s.rightDir() - s.control.moveZ = dir.dot(fwd) - s.control.moveX = dir.dot(right) - - if (!this.target) { - const wantYaw = Math.atan2(-dir.x, -dir.z) - s.yaw = angleLerp(s.yaw, wantYaw, (sprint ? 10 : 6) * dt) - s.pitch = angleLerp(s.pitch, 0, 3 * dt) - } - return false - } - - private facePoint(p: THREE.Vector3, dt: number) { - const s = this.s - const wantYaw = Math.atan2(-(p.x - s.pos.x), -(p.z - s.pos.z)) - s.yaw = angleLerp(s.yaw, wantYaw, 8 * dt) - } - - private dutyBehavior(w: AIWorld) { - const s = this.s - if (!this.mission) return - const c = s.control - - switch (this.mission.duty) { - case 'plant': { - if (!s.hasBomb) break - if (this.target) break // fight first - if (w.map.plantSiteAt(s.pos.x, s.pos.z) && this.arrived && s.onGround) { - c.use = true - c.moveX = 0; c.moveZ = 0 - } - break - } - case 'defuse': { - if (!w.bombPlantedPos) break - const d = Math.hypot(w.bombPlantedPos.x - s.pos.x, w.bombPlantedPos.z - s.pos.z) - if (d < 1.3 && (!this.target || w.time - this.targetSince < 0.1)) { - c.use = true - c.moveX = 0; c.moveZ = 0 - } - break - } - case 'pickup': - break // walking over the bomb picks it up (engine) - case 'none': - break - } - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/audio.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/audio.ts deleted file mode 100644 index f6fbb9c..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/audio.ts +++ /dev/null @@ -1,245 +0,0 @@ -import * as THREE from 'three' - -type ShotSound = 'ak' | 'm4' | 'awp' | 'pistol' | 'glock' | 'deagle' | 'knife' - -/** - * All game audio is synthesized with the Web Audio API — no audio files. - * World sounds are attenuated by distance and stereo-panned relative to the camera. - */ -export class AudioMan { - private ctx: AudioContext | null = null - private master: GainNode | null = null - private noise: AudioBuffer | null = null - private listenerPos = new THREE.Vector3() - private listenerRight = new THREE.Vector3(1, 0, 0) - - resume() { - if (!this.ctx) { - this.ctx = new AudioContext() - this.master = this.ctx.createGain() - this.master.gain.value = 0.5 - this.master.connect(this.ctx.destination) - const len = this.ctx.sampleRate - this.noise = this.ctx.createBuffer(1, len, this.ctx.sampleRate) - const data = this.noise.getChannelData(0) - for (let i = 0; i < len; i++) data[i] = Math.random() * 2 - 1 - } - if (this.ctx.state === 'suspended') void this.ctx.resume() - } - - setListener(pos: THREE.Vector3, right: THREE.Vector3) { - this.listenerPos.copy(pos) - this.listenerRight.copy(right) - } - - private out(pos: THREE.Vector3 | null, gain: number): GainNode | null { - if (!this.ctx || !this.master) return null - const g = this.ctx.createGain() - if (pos) { - const d = pos.distanceTo(this.listenerPos) - const att = 1 / (1 + d * 0.05) - g.gain.value = gain * att - const dir = new THREE.Vector3().subVectors(pos, this.listenerPos) - const dl = dir.length() - const pan = this.ctx.createStereoPanner() - pan.pan.value = dl > 0.5 ? THREE.MathUtils.clamp(dir.dot(this.listenerRight) / dl, -0.85, 0.85) : 0 - g.connect(pan) - pan.connect(this.master) - } else { - g.gain.value = gain - g.connect(this.master) - } - return g - } - - private playNoise(opts: { - pos: THREE.Vector3 | null, gain: number, dur: number, - filter?: BiquadFilterType, freq?: number, q?: number, freqEnd?: number, - rate?: number, delay?: number, - }) { - if (!this.ctx || !this.noise) return - const dst = this.out(opts.pos, 1) - if (!dst) return - const t0 = this.ctx.currentTime + (opts.delay ?? 0) - const src = this.ctx.createBufferSource() - src.buffer = this.noise - src.loop = true - src.playbackRate.value = opts.rate ?? 1 - const env = this.ctx.createGain() - env.gain.setValueAtTime(opts.gain, t0) - env.gain.exponentialRampToValueAtTime(0.001, t0 + opts.dur) - let node: AudioNode = src - if (opts.filter) { - const f = this.ctx.createBiquadFilter() - f.type = opts.filter - f.frequency.setValueAtTime(opts.freq ?? 1000, t0) - if (opts.freqEnd) f.frequency.exponentialRampToValueAtTime(opts.freqEnd, t0 + opts.dur) - f.Q.value = opts.q ?? 1 - node.connect(f) - node = f - } - node.connect(env) - env.connect(dst) - src.start(t0, Math.random() * 0.5) - src.stop(t0 + opts.dur + 0.05) - } - - private playTone(opts: { - pos: THREE.Vector3 | null, gain: number, dur: number, - freq: number, freqEnd?: number, type?: OscillatorType, delay?: number, - }) { - if (!this.ctx) return - const dst = this.out(opts.pos, 1) - if (!dst) return - const t0 = this.ctx.currentTime + (opts.delay ?? 0) - const osc = this.ctx.createOscillator() - osc.type = opts.type ?? 'sine' - osc.frequency.setValueAtTime(opts.freq, t0) - if (opts.freqEnd) osc.frequency.exponentialRampToValueAtTime(Math.max(1, opts.freqEnd), t0 + opts.dur) - const env = this.ctx.createGain() - env.gain.setValueAtTime(opts.gain, t0) - env.gain.exponentialRampToValueAtTime(0.001, t0 + opts.dur) - osc.connect(env) - env.connect(dst) - osc.start(t0) - osc.stop(t0 + opts.dur + 0.05) - } - - shot(kind: ShotSound, pos: THREE.Vector3 | null) { - const r = 0.94 + Math.random() * 0.12 - switch (kind) { - case 'ak': - this.playTone({ pos, gain: 0.55, dur: 0.1, freq: 165 * r, freqEnd: 85, type: 'square' }) - this.playNoise({ pos, gain: 0.5, dur: 0.11, filter: 'bandpass', freq: 1300, q: 0.7, rate: r }) - this.playNoise({ pos, gain: 0.3, dur: 0.025, filter: 'highpass', freq: 4800 }) - break - case 'm4': - this.playTone({ pos, gain: 0.4, dur: 0.06, freq: 210 * r, freqEnd: 120, type: 'square' }) - this.playNoise({ pos, gain: 0.42, dur: 0.07, filter: 'bandpass', freq: 2100, q: 0.8, rate: r }) - this.playNoise({ pos, gain: 0.24, dur: 0.02, filter: 'highpass', freq: 6000 }) - break - case 'awp': - this.playTone({ pos, gain: 0.9, dur: 0.35, freq: 92 * r, freqEnd: 42, type: 'sine' }) - this.playNoise({ pos, gain: 0.85, dur: 0.32, filter: 'lowpass', freq: 900, freqEnd: 160, rate: r }) - this.playNoise({ pos, gain: 0.45, dur: 0.05, filter: 'highpass', freq: 3000 }) - break - case 'deagle': - this.playTone({ pos, gain: 0.7, dur: 0.13, freq: 135 * r, freqEnd: 65, type: 'square' }) - this.playNoise({ pos, gain: 0.55, dur: 0.13, filter: 'bandpass', freq: 950, q: 0.7, rate: r }) - break - case 'pistol': - this.playTone({ pos, gain: 0.32, dur: 0.045, freq: 290 * r, freqEnd: 150, type: 'square' }) - this.playNoise({ pos, gain: 0.3, dur: 0.05, filter: 'bandpass', freq: 2400, q: 1, rate: r }) - break - case 'glock': - this.playTone({ pos, gain: 0.3, dur: 0.05, freq: 330 * r, freqEnd: 170, type: 'square' }) - this.playNoise({ pos, gain: 0.28, dur: 0.055, filter: 'bandpass', freq: 2800, q: 1, rate: r }) - break - case 'knife': - this.playNoise({ pos, gain: 0.18, dur: 0.12, filter: 'bandpass', freq: 1800, freqEnd: 600, q: 2 }) - break - } - } - - knifeHit(pos: THREE.Vector3 | null) { - this.playNoise({ pos, gain: 0.35, dur: 0.08, filter: 'lowpass', freq: 700 }) - this.playTone({ pos, gain: 0.2, dur: 0.07, freq: 220, freqEnd: 90 }) - } - - reload(pos: THREE.Vector3 | null, duration: number) { - const click = (delay: number, freq: number) => { - this.playTone({ pos, gain: 0.18, dur: 0.03, freq, type: 'square', delay }) - this.playNoise({ pos, gain: 0.12, dur: 0.03, filter: 'highpass', freq: 2500, delay }) - } - click(0.05, 700) - click(duration * 0.45, 500) - click(duration * 0.85, 900) - } - - footstep(pos: THREE.Vector3 | null, vol: number) { - this.playNoise({ - pos, gain: 0.16 * vol, dur: 0.055, - filter: 'lowpass', freq: 420 + Math.random() * 160, rate: 0.8 + Math.random() * 0.3, - }) - } - - scope(on: boolean) { - this.playTone({ pos: null, gain: 0.12, dur: 0.05, freq: on ? 1400 : 900, freqEnd: on ? 1900 : 600, type: 'sine' }) - } - - drawWeapon() { - this.playNoise({ pos: null, gain: 0.1, dur: 0.04, filter: 'highpass', freq: 2000 }) - this.playTone({ pos: null, gain: 0.08, dur: 0.03, freq: 600, type: 'square', delay: 0.03 }) - } - - hit(headshot: boolean) { - if (headshot) { - this.playTone({ pos: null, gain: 0.25, dur: 0.1, freq: 1700, freqEnd: 1400, type: 'triangle' }) - this.playTone({ pos: null, gain: 0.15, dur: 0.12, freq: 2550, freqEnd: 2100, type: 'sine', delay: 0.01 }) - } else { - this.playTone({ pos: null, gain: 0.18, dur: 0.05, freq: 1150, freqEnd: 900, type: 'triangle' }) - } - } - - kill() { - this.playTone({ pos: null, gain: 0.2, dur: 0.07, freq: 880, type: 'sine' }) - this.playTone({ pos: null, gain: 0.2, dur: 0.1, freq: 1320, type: 'sine', delay: 0.07 }) - } - - death(pos: THREE.Vector3 | null) { - this.playNoise({ pos, gain: 0.3, dur: 0.2, filter: 'lowpass', freq: 500, freqEnd: 120 }) - } - - damage() { - this.playNoise({ pos: null, gain: 0.2, dur: 0.09, filter: 'lowpass', freq: 800 }) - } - - bombBeep(pos: THREE.Vector3 | null, urgent: boolean) { - this.playTone({ pos, gain: urgent ? 0.3 : 0.22, dur: 0.07, freq: urgent ? 2900 : 2500, type: 'square' }) - } - - bombPlanted() { - for (let i = 0; i < 3; i++) { - this.playTone({ pos: null, gain: 0.16, dur: 0.06, freq: 2100, type: 'square', delay: i * 0.11 }) - } - } - - plantTick(pos: THREE.Vector3 | null) { - this.playTone({ pos, gain: 0.1, dur: 0.03, freq: 1600, type: 'square' }) - } - - defuseTick(pos: THREE.Vector3 | null) { - this.playNoise({ pos, gain: 0.14, dur: 0.04, filter: 'highpass', freq: 3200 }) - } - - bombDefused() { - this.playTone({ pos: null, gain: 0.22, dur: 0.12, freq: 900, type: 'sine' }) - this.playTone({ pos: null, gain: 0.22, dur: 0.2, freq: 1350, type: 'sine', delay: 0.12 }) - } - - explosion(pos: THREE.Vector3 | null) { - this.playNoise({ pos, gain: 1.4, dur: 1.3, filter: 'lowpass', freq: 2800, freqEnd: 60 }) - this.playTone({ pos, gain: 1.0, dur: 1.1, freq: 55, freqEnd: 24, type: 'sine' }) - this.playNoise({ pos, gain: 0.5, dur: 0.4, filter: 'bandpass', freq: 500, q: 0.5, delay: 0.06 }) - } - - doorSlide(pos: THREE.Vector3 | null) { - this.playNoise({ pos, gain: 0.16, dur: 0.35, filter: 'bandpass', freq: 300, freqEnd: 500, q: 2 }) - } - - roundStart() { - this.playTone({ pos: null, gain: 0.18, dur: 0.1, freq: 660, type: 'sine' }) - this.playTone({ pos: null, gain: 0.18, dur: 0.16, freq: 990, type: 'sine', delay: 0.1 }) - } - - roundEnd(win: boolean) { - if (win) { - this.playTone({ pos: null, gain: 0.2, dur: 0.12, freq: 784, type: 'triangle' }) - this.playTone({ pos: null, gain: 0.2, dur: 0.12, freq: 988, type: 'triangle', delay: 0.12 }) - this.playTone({ pos: null, gain: 0.2, dur: 0.24, freq: 1319, type: 'triangle', delay: 0.24 }) - } else { - this.playTone({ pos: null, gain: 0.2, dur: 0.16, freq: 494, type: 'triangle' }) - this.playTone({ pos: null, gain: 0.2, dur: 0.3, freq: 330, type: 'triangle', delay: 0.16 }) - } - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/character.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/character.ts deleted file mode 100644 index b08526f..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/character.ts +++ /dev/null @@ -1,232 +0,0 @@ -import * as THREE from 'three' -import type { Team, WeaponId } from './types' - -type GunKind = 'rifle' | 'awp' | 'pistol' | 'knife' - -export function gunKindOf(id: WeaponId): GunKind { - if (id === 'awp') return 'awp' - if (id === 'ak47' || id === 'm4a4') return 'rifle' - if (id === 'knife') return 'knife' - return 'pistol' -} - -function mat(color: number): THREE.MeshStandardMaterial { - return new THREE.MeshStandardMaterial({ color, roughness: 0.9 }) -} - -function box(w: number, h: number, d: number, m: THREE.MeshStandardMaterial): THREE.Mesh { - const mesh = new THREE.Mesh(new THREE.BoxGeometry(w, h, d), m) - mesh.castShadow = true - return mesh -} - -/** - * Procedural humanoid: separate head / torso / two arms / two legs, - * built entirely from code. Faces -Z. Feet at origin. - */ -export class CharacterRig { - root = new THREE.Group() - private body = new THREE.Group() - private legL: THREE.Mesh - private legR: THREE.Mesh - private head: THREE.Group - private aim = new THREE.Group() - private guns: Record - private bombPack: THREE.Mesh - private mats: THREE.MeshStandardMaterial[] = [] - private walkPhase = 0 - private dead = false - private deathT = 0 - private fallAxis = 1 - - constructor(team: Team) { - const skin = mat(0xd8b094) - const shirt = team === 'CT' ? mat(0x3d5a73) : mat(0xa08752) - const pants = team === 'CT' ? mat(0x2c3e50) : mat(0x55483a) - const gear = team === 'CT' ? mat(0x232f3a) : mat(0x4a3b28) - const headgear = team === 'CT' ? mat(0x46586b) : mat(0x7d3030) - this.mats.push(skin, shirt, pants, gear, headgear) - - // legs (pivot at hip) - const mkLeg = (x: number) => { - const leg = box(0.17, 0.9, 0.2, pants) - leg.geometry.translate(0, -0.45, 0) - leg.position.set(x, 0.9, 0) - return leg - } - this.legL = mkLeg(-0.12) - this.legR = mkLeg(0.12) - this.body.add(this.legL, this.legR) - - // torso + vest - const torso = box(0.46, 0.52, 0.24, shirt) - torso.position.y = 1.21 - const vest = box(0.5, 0.3, 0.28, gear) - vest.position.y = 1.14 - this.body.add(torso, vest) - - // bomb backpack (visible when carrying C4) - this.bombPack = box(0.3, 0.36, 0.16, mat(0x8a2e2e)) - this.bombPack.position.set(0, 1.22, 0.22) - this.bombPack.visible = false - this.body.add(this.bombPack) - - // head (pivot at neck) - this.head = new THREE.Group() - this.head.position.y = 1.5 - const skull = box(0.26, 0.26, 0.26, skin) - skull.position.y = 0.16 - this.head.add(skull) - if (team === 'CT') { - const helmet = box(0.3, 0.13, 0.3, headgear) - helmet.position.y = 0.28 - this.head.add(helmet) - const visor = box(0.22, 0.06, 0.02, mat(0x111111)) - visor.position.set(0, 0.19, -0.14) - this.head.add(visor) - } else { - const wrap = box(0.28, 0.1, 0.28, headgear) - wrap.position.y = 0.27 - this.head.add(wrap) - const tail = box(0.06, 0.16, 0.03, headgear) - tail.position.set(0.08, 0.18, 0.15) - this.head.add(tail) - } - this.body.add(this.head) - - // aim group: both arms + weapon, pitches with view - this.aim.position.y = 1.42 - const mkArm = (x: number, rotX: number, rotZ: number) => { - const arm = box(0.13, 0.42, 0.13, shirt) - arm.geometry.translate(0, -0.21, 0) - const hand = box(0.09, 0.1, 0.09, skin) - hand.position.y = -0.44 - arm.add(hand) - arm.position.set(x, 0, 0) - arm.rotation.set(rotX, 0, rotZ) - return arm - } - this.aim.add(mkArm(-0.28, 1.15, 0.4), mkArm(0.28, 1.05, -0.3)) - - // world-model guns - this.guns = { - rifle: this.buildRifle(), - awp: this.buildAwp(), - pistol: this.buildPistol(), - knife: this.buildKnife(), - } - for (const g of Object.values(this.guns)) { - g.position.set(0.05, -0.24, -0.35) - g.visible = false - this.aim.add(g) - } - this.guns.rifle.visible = true - this.body.add(this.aim) - this.root.add(this.body) - } - - private buildRifle(): THREE.Group { - const g = new THREE.Group() - const metal = mat(0x3a3a3a) - const wood = mat(0x6b4a2f) - const body = box(0.06, 0.1, 0.55, metal); body.position.z = -0.15 - const barrel = box(0.035, 0.035, 0.35, metal); barrel.position.z = -0.55 - const stock = box(0.05, 0.09, 0.22, wood); stock.position.z = 0.2 - const magM = box(0.04, 0.16, 0.09, wood); magM.position.set(0, -0.12, -0.1); magM.rotation.x = 0.35 - g.add(body, barrel, stock, magM) - return g - } - - private buildAwp(): THREE.Group { - const g = new THREE.Group() - const olive = mat(0x4a5d3a) - const metal = mat(0x2e2e2e) - const body = box(0.06, 0.1, 0.7, olive); body.position.z = -0.2 - const barrel = box(0.03, 0.03, 0.5, metal); barrel.position.z = -0.78 - const scope = new THREE.Mesh(new THREE.CylinderGeometry(0.035, 0.035, 0.28, 8), metal) - scope.rotation.x = Math.PI / 2 - scope.position.set(0, 0.08, -0.2) - scope.castShadow = true - const stock = box(0.05, 0.11, 0.24, olive); stock.position.z = 0.25 - g.add(body, barrel, scope, stock) - return g - } - - private buildPistol(): THREE.Group { - const g = new THREE.Group() - const metal = mat(0x333338) - const slide = box(0.045, 0.06, 0.24, metal); slide.position.z = -0.06 - const grip = box(0.04, 0.13, 0.06, metal); grip.position.set(0, -0.08, 0.05); grip.rotation.x = 0.25 - g.add(slide, grip) - return g - } - - private buildKnife(): THREE.Group { - const g = new THREE.Group() - const blade = box(0.015, 0.045, 0.3, mat(0xcfd6dd)); blade.position.z = -0.15 - const handle = box(0.03, 0.05, 0.12, mat(0x2f2f33)); handle.position.z = 0.06 - g.add(blade, handle) - return g - } - - setWeapon(id: WeaponId) { - const kind = gunKindOf(id) - for (const [k, g] of Object.entries(this.guns)) g.visible = k === kind - } - - setBomb(visible: boolean) { - this.bombPack.visible = visible - } - - spawnReset() { - this.dead = false - this.deathT = 0 - this.walkPhase = 0 - this.body.rotation.set(0, 0, 0) - this.body.position.set(0, 0, 0) - for (const m of this.mats) { m.transparent = false; m.opacity = 1 } - this.root.visible = true - } - - die() { - if (this.dead) return - this.dead = true - this.deathT = 0 - this.fallAxis = Math.random() < 0.5 ? 1 : -1 - } - - update(dt: number, pos: THREE.Vector3, yaw: number, pitch: number, speed: number, onGround: boolean) { - this.root.position.copy(pos) - this.root.rotation.y = yaw - - if (this.dead) { - this.deathT += dt - const k = Math.min(1, this.deathT / 0.4) - this.body.rotation.z = this.fallAxis * (Math.PI / 2) * k * k * (3 - 2 * k) - this.body.position.y = 0.12 * k - if (this.deathT > 6) { - const fade = Math.max(0, 1 - (this.deathT - 6) / 1.5) - for (const m of this.mats) { m.transparent = true; m.opacity = fade } - if (fade <= 0) this.root.visible = false - } - return - } - - const speedRatio = Math.min(1, speed / 4.7) - this.walkPhase += speed * dt * 2.2 - const swing = onGround ? Math.sin(this.walkPhase) * 0.7 * speedRatio : 0.25 - this.legL.rotation.x = swing - this.legR.rotation.x = -swing - this.body.position.y = onGround ? Math.abs(Math.sin(this.walkPhase)) * 0.045 * speedRatio : 0.05 - this.aim.rotation.x = pitch - this.head.rotation.x = pitch * 0.55 - } - - dispose(scene: THREE.Scene) { - scene.remove(this.root) - this.root.traverse(o => { - if (o instanceof THREE.Mesh) o.geometry.dispose() - }) - for (const m of this.mats) m.dispose() - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/effects.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/effects.ts deleted file mode 100644 index aa8537c..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/effects.ts +++ /dev/null @@ -1,200 +0,0 @@ -import * as THREE from 'three' - -const MAX_TRACERS = 96 -const MAX_SPARKS = 768 -const MAX_BLOOD = 384 - -interface Particle { life: number; max: number; vx: number; vy: number; vz: number; gravity: number } - -class ParticlePool { - points: THREE.Points - pos: Float32Array - col: Float32Array - parts: Particle[] - baseCol: Float32Array - private cursor = 0 - - constructor(count: number, size: number, additive: boolean) { - this.pos = new Float32Array(count * 3).fill(-999) - this.col = new Float32Array(count * 3) - this.baseCol = new Float32Array(count * 3) - this.parts = Array.from({ length: count }, () => ({ life: 0, max: 1, vx: 0, vy: 0, vz: 0, gravity: 0 })) - const geo = new THREE.BufferGeometry() - geo.setAttribute('position', new THREE.BufferAttribute(this.pos, 3)) - geo.setAttribute('color', new THREE.BufferAttribute(this.col, 3)) - const matP = new THREE.PointsMaterial({ - size, vertexColors: true, transparent: true, depthWrite: false, - blending: additive ? THREE.AdditiveBlending : THREE.NormalBlending, - sizeAttenuation: true, - }) - this.points = new THREE.Points(geo, matP) - this.points.frustumCulled = false - } - - spawn(p: THREE.Vector3, vel: THREE.Vector3, life: number, color: THREE.Color, gravity: number) { - const i = this.cursor - this.cursor = (this.cursor + 1) % this.parts.length - this.pos[i * 3] = p.x; this.pos[i * 3 + 1] = p.y; this.pos[i * 3 + 2] = p.z - this.baseCol[i * 3] = color.r; this.baseCol[i * 3 + 1] = color.g; this.baseCol[i * 3 + 2] = color.b - const part = this.parts[i] - part.life = life; part.max = life - part.vx = vel.x; part.vy = vel.y; part.vz = vel.z - part.gravity = gravity - } - - update(dt: number) { - for (let i = 0; i < this.parts.length; i++) { - const p = this.parts[i] - if (p.life <= 0) continue - p.life -= dt - if (p.life <= 0) { - this.pos[i * 3 + 1] = -999 - this.col[i * 3] = this.col[i * 3 + 1] = this.col[i * 3 + 2] = 0 - continue - } - p.vy -= p.gravity * dt - this.pos[i * 3] += p.vx * dt - this.pos[i * 3 + 1] += p.vy * dt - this.pos[i * 3 + 2] += p.vz * dt - const f = p.life / p.max - this.col[i * 3] = this.baseCol[i * 3] * f - this.col[i * 3 + 1] = this.baseCol[i * 3 + 1] * f - this.col[i * 3 + 2] = this.baseCol[i * 3 + 2] * f - } - this.points.geometry.attributes.position.needsUpdate = true - this.points.geometry.attributes.color.needsUpdate = true - } -} - -export class Effects { - private scene: THREE.Scene - private tracerGeo: THREE.BufferGeometry - private tracerPos: Float32Array - private tracerCol: Float32Array - private tracers: { life: number; max: number }[] - private tracerCursor = 0 - private sparks: ParticlePool - private blood: ParticlePool - private muzzleLight: THREE.PointLight - private muzzleT = 0 - private explosionLight: THREE.PointLight - private explosionT = 0 - private rings: { mesh: THREE.Mesh; life: number }[] = [] - shake = 0 - - constructor(scene: THREE.Scene) { - this.scene = scene - this.tracerPos = new Float32Array(MAX_TRACERS * 6).fill(-999) - this.tracerCol = new Float32Array(MAX_TRACERS * 6) - this.tracers = Array.from({ length: MAX_TRACERS }, () => ({ life: 0, max: 1 })) - this.tracerGeo = new THREE.BufferGeometry() - this.tracerGeo.setAttribute('position', new THREE.BufferAttribute(this.tracerPos, 3)) - this.tracerGeo.setAttribute('color', new THREE.BufferAttribute(this.tracerCol, 3)) - const lines = new THREE.LineSegments(this.tracerGeo, new THREE.LineBasicMaterial({ - vertexColors: true, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, - })) - lines.frustumCulled = false - scene.add(lines) - - this.sparks = new ParticlePool(MAX_SPARKS, 0.09, true) - this.blood = new ParticlePool(MAX_BLOOD, 0.11, false) - scene.add(this.sparks.points, this.blood.points) - - this.muzzleLight = new THREE.PointLight(0xffc070, 0, 14) - this.explosionLight = new THREE.PointLight(0xff8030, 0, 60) - scene.add(this.muzzleLight, this.explosionLight) - } - - tracer(a: THREE.Vector3, b: THREE.Vector3) { - const i = this.tracerCursor - this.tracerCursor = (this.tracerCursor + 1) % MAX_TRACERS - this.tracerPos.set([a.x, a.y, a.z, b.x, b.y, b.z], i * 6) - this.tracers[i].life = this.tracers[i].max = 0.07 - } - - muzzle(pos: THREE.Vector3) { - this.muzzleLight.position.copy(pos) - this.muzzleLight.intensity = 6 - this.muzzleT = 0.05 - } - - impact(pos: THREE.Vector3) { - const c = new THREE.Color(0xffcc88) - for (let i = 0; i < 7; i++) { - const vel = new THREE.Vector3((Math.random() - 0.5) * 5, Math.random() * 4, (Math.random() - 0.5) * 5) - this.sparks.spawn(pos, vel, 0.22 + Math.random() * 0.18, c, 12) - } - } - - bloodBurst(pos: THREE.Vector3) { - const c = new THREE.Color(0x8a1515) - for (let i = 0; i < 10; i++) { - const vel = new THREE.Vector3((Math.random() - 0.5) * 3.4, Math.random() * 2.6 - 0.4, (Math.random() - 0.5) * 3.4) - this.blood.spawn(pos, vel, 0.3 + Math.random() * 0.25, c, 9) - } - } - - explosion(pos: THREE.Vector3) { - const fire = new THREE.Color(0xff9040) - const smoke = new THREE.Color(0x553311) - for (let i = 0; i < 130; i++) { - const dir = new THREE.Vector3(Math.random() - 0.5, Math.random() * 0.8, Math.random() - 0.5).normalize() - const sp = 4 + Math.random() * 16 - this.sparks.spawn(pos.clone().add(new THREE.Vector3(0, 0.5, 0)), dir.multiplyScalar(sp), 0.5 + Math.random() * 0.9, fire, 6) - } - for (let i = 0; i < 60; i++) { - const dir = new THREE.Vector3(Math.random() - 0.5, Math.random(), Math.random() - 0.5).normalize() - this.blood.spawn(pos.clone(), dir.multiplyScalar(2 + Math.random() * 6), 1 + Math.random(), smoke, -1.5) - } - this.explosionLight.position.copy(pos).add(new THREE.Vector3(0, 2, 0)) - this.explosionLight.intensity = 80 - this.explosionT = 0.9 - this.shake = Math.max(this.shake, 1) - - const ring = new THREE.Mesh( - new THREE.RingGeometry(0.5, 1.2, 32), - new THREE.MeshBasicMaterial({ color: 0xffbb66, transparent: true, opacity: 0.9, side: THREE.DoubleSide, depthWrite: false }), - ) - ring.rotation.x = -Math.PI / 2 - ring.position.copy(pos).add(new THREE.Vector3(0, 0.3, 0)) - this.scene.add(ring) - this.rings.push({ mesh: ring, life: 0.8 }) - } - - update(dt: number) { - for (let i = 0; i < MAX_TRACERS; i++) { - const t = this.tracers[i] - if (t.life <= 0) continue - t.life -= dt - const f = Math.max(0, t.life / t.max) - const r = 1 * f, g2 = 0.85 * f, b = 0.5 * f - this.tracerCol.set([r, g2, b, r * 0.6, g2 * 0.6, b * 0.6], i * 6) - if (t.life <= 0) this.tracerPos.set([-999, -999, -999, -999, -999, -999], i * 6) - } - this.tracerGeo.attributes.position.needsUpdate = true - this.tracerGeo.attributes.color.needsUpdate = true - - this.sparks.update(dt) - this.blood.update(dt) - - this.muzzleT -= dt - if (this.muzzleT <= 0) this.muzzleLight.intensity = 0 - if (this.explosionT > 0) { - this.explosionT -= dt - this.explosionLight.intensity = Math.max(0, 80 * (this.explosionT / 0.9)) - } - for (let i = this.rings.length - 1; i >= 0; i--) { - const r = this.rings[i] - r.life -= dt - const s = 1 + (0.8 - r.life) * 30 - r.mesh.scale.set(s, s, 1) - ;(r.mesh.material as THREE.MeshBasicMaterial).opacity = Math.max(0, r.life) - if (r.life <= 0) { - this.scene.remove(r.mesh) - r.mesh.geometry.dispose() - this.rings.splice(i, 1) - } - } - this.shake *= Math.exp(-4 * dt) - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/engine.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/engine.ts deleted file mode 100644 index 28640fa..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/engine.ts +++ /dev/null @@ -1,1106 +0,0 @@ -import * as THREE from 'three' -import { AIBrain, type AIWorld } from './ai' -import { AudioMan } from './audio' -import { Effects } from './effects' -import { GameMap } from './map' -import { Nav } from './nav' -import { PhysicsWorld } from './physics' -import { Soldier } from './soldier' -import { HudStore } from './store' -import { ViewModel } from './viewmodel' -import { PART_MULT, WEAPONS } from './weapons' -import { - BOMB_FUSE, DEFUSE_TIME, FREEZE_TIME, PLANT_TIME, - ROUND_END_TIME, ROUND_TIME, RUN_SPEED, WIN_SCORE, - type BodyPart, type Loadout, type Phase, type Slot, type Team, type WeaponId, -} from './types' - -const CT_NAMES = ['Rock', 'Duke', 'Nova', 'Ice', 'Sarge'] -const T_NAMES = ['Viper', 'Wolf', 'Ghost', 'Blade', 'Fox'] -const FIXED_DT = 1 / 64 - -interface BombState { - carrierId: number | null - droppedPos: THREE.Vector3 | null - plantedPos: THREE.Vector3 | null - plantedAt: number - exploded: boolean -} - -export class Engine { - // three - private renderer: THREE.WebGLRenderer - private scene = new THREE.Scene() - private camera = new THREE.PerspectiveCamera(75, 1, 0.05, 400) - private container: HTMLElement - - // world - map: GameMap - private physics: PhysicsWorld - private nav: Nav - private effects: Effects - audio = new AudioMan() - private viewmodel: ViewModel - private bombMesh: THREE.Group - - // game state - soldiers: Soldier[] = [] - playerTeam: Team = 'CT' - private playerId = 0 - private controlledId = 0 - viewedId = 0 - private autoMode = false - phase: Phase = 'menu' - private round = 1 - private ctScore = 0 - private tScore = 0 - private phaseEndsAt = 0 - private roundEndsAt = 0 - private winner: Team | null = null - private winReason = '' - private matchWinner: Team | null = null - bomb: BombState = { carrierId: null, droppedPos: null, plantedPos: null, plantedAt: 0, exploded: false } - private nextBeepAt = 0 - private nextDefTickAt = 0 - playerLoadout: Loadout = 'rifle' - - // timing - time = 0 - private accumulator = 0 - private lastFrame = 0 - private rafId = 0 - private hudSyncAt = 0 - private seenScanAt = 0 - private disposed = false - - // input - private keys = new Set() - private mouseFire = false - private fireTapQueued = false - private altTapQueued = false - private jumpQueued = false - private slotQueued: Slot | null = null - private deathAt = 0 - pointerLocked = false - - hud = new HudStore() - private killfeedId = 0 - - constructor(container: HTMLElement) { - this.container = container - this.renderer = new THREE.WebGLRenderer({ antialias: true }) - this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) - this.renderer.shadowMap.enabled = true - this.renderer.shadowMap.type = THREE.PCFSoftShadowMap - this.renderer.toneMapping = THREE.ACESFilmicToneMapping - this.renderer.toneMappingExposure = 1.15 - this.renderer.setClearColor(0xb9d2e8) - container.appendChild(this.renderer.domElement) - - this.scene.fog = new THREE.Fog(0xc4d6e6, 70, 240) - const hemi = new THREE.HemisphereLight(0xcfe4f5, 0x8a7a55, 1.5) - const sun = new THREE.DirectionalLight(0xfff2dd, 2.2) - sun.position.set(60, 90, 30) - sun.castShadow = true - sun.shadow.mapSize.set(2048, 2048) - sun.shadow.camera.left = -90 - sun.shadow.camera.right = 90 - sun.shadow.camera.top = 90 - sun.shadow.camera.bottom = -90 - sun.shadow.camera.far = 260 - sun.shadow.bias = -0.0006 - this.scene.add(hemi, sun, sun.target) - - this.map = new GameMap() - this.scene.add(this.map.group) - this.physics = new PhysicsWorld(this.map) - this.nav = new Nav(this.map, this.physics) - this.effects = new Effects(this.scene) - - this.camera.rotation.order = 'YXZ' - this.scene.add(this.camera) - this.viewmodel = new ViewModel(this.camera) - - this.bombMesh = this.buildBombMesh() - this.bombMesh.visible = false - this.scene.add(this.bombMesh) - - this.bindEvents() - this.resize() - this.lastFrame = performance.now() - const loop = (t: number) => { - if (this.disposed) return - this.rafId = requestAnimationFrame(loop) - const dt = Math.min(0.05, (t - this.lastFrame) / 1000) - this.lastFrame = t - this.update(dt) - } - this.rafId = requestAnimationFrame(loop) - } - - private buildBombMesh(): THREE.Group { - const g = new THREE.Group() - const body = new THREE.Mesh( - new THREE.BoxGeometry(0.42, 0.16, 0.3), - new THREE.MeshStandardMaterial({ color: 0x8a7455, roughness: 0.8 }), - ) - body.position.y = 0.08 - body.castShadow = true - const panel = new THREE.Mesh( - new THREE.BoxGeometry(0.2, 0.04, 0.12), - new THREE.MeshStandardMaterial({ color: 0x1a1f18 }), - ) - panel.position.set(0, 0.18, 0) - const led = new THREE.Mesh( - new THREE.BoxGeometry(0.05, 0.03, 0.05), - new THREE.MeshBasicMaterial({ color: 0xff2222 }), - ) - led.position.set(0.12, 0.19, 0) - led.name = 'led' - g.add(body, panel, led) - return g - } - - // ---------------------------------------------------------------- lifecycle - - start(team: Team, auto = false) { - this.audio.resume() - this.playerTeam = team - this.autoMode = auto - this.ctScore = 0 - this.tScore = 0 - this.matchWinner = null - - for (const s of this.soldiers) s.rig.dispose(this.scene) - this.soldiers = [] - let id = 0 - for (const t of ['CT', 'T'] as Team[]) { - const names = t === 'CT' ? CT_NAMES : T_NAMES - for (let i = 0; i < 5; i++) { - const isPlayer = !auto && t === team && i === 0 - const s = new Soldier(id, isPlayer ? '你' : names[i], t) - s.isPlayer = isPlayer - if (!isPlayer) s.brain = new AIBrain(s) - if (isPlayer) this.playerId = id - this.scene.add(s.rig.root) - this.soldiers.push(s) - id++ - } - } - if (auto) this.playerId = 0 - this.controlledId = this.playerId - this.viewedId = this.playerId - this.startRound(1) - } - - toMenu() { - this.phase = 'menu' - for (const s of this.soldiers) s.rig.dispose(this.scene) - this.soldiers = [] - this.bombMesh.visible = false - document.exitPointerLock?.() - this.syncHud() - } - - restartMatch() { - this.start(this.playerTeam, this.autoMode) - } - - requestLock() { - this.renderer.domElement.requestPointerLock() - } - - dispose() { - this.disposed = true - cancelAnimationFrame(this.rafId) - this.unbindEvents() - this.renderer.dispose() - this.renderer.domElement.remove() - } - - // ------------------------------------------------------------------ rounds - - private startRound(n: number) { - this.round = n - this.phase = 'freeze' - this.phaseEndsAt = this.time + FREEZE_TIME - this.winner = null - this.winReason = '' - this.bomb = { carrierId: null, droppedPos: null, plantedPos: null, plantedAt: 0, exploded: false } - this.bombMesh.visible = false - this.controlledId = this.playerId - this.viewedId = this.playerId - - const pistol = n === 1 - // restore bots that were taken over in a previous round - for (const s of this.soldiers) { - if (s.id !== this.playerId) { - s.isPlayer = false - s.name = s.originalName - if (!s.brain) s.brain = new AIBrain(s) - } else { - s.isPlayer = !this.autoMode - } - } - const spawnIdx: Record = { CT: 0, T: 0 } - // one AI per team may carry an AWP on gun rounds - const awpBot: Record = { CT: -1, T: -1 } - if (!pistol) { - for (const t of ['CT', 'T'] as Team[]) { - if (Math.random() < 0.45) { - const bots = this.soldiers.filter(s => s.team === t && !s.isPlayer) - awpBot[t] = bots[Math.floor(Math.random() * bots.length)].id - } - } - } - - for (const s of this.soldiers) { - const spawn = this.map.spawns[s.team][spawnIdx[s.team]++ % 5] - s.respawn(spawn.pos.clone(), spawn.yaw) - const secondary: WeaponId = pistol ? (s.team === 'T' ? 'glock' : 'usp') : 'deagle' - let primary: WeaponId | null = null - if (!pistol) { - primary = s.team === 'T' ? 'ak47' : 'm4a4' - if (s.id === awpBot[s.team]) primary = 'awp' - if (s.id === this.playerId && !this.autoMode && this.playerLoadout === 'awp') primary = 'awp' - } - s.equip(primary, secondary, pistol ? 0 : 100) - s.brain?.reset() - } - - // hand C4 to a random T - const ts = this.soldiers.filter(s => s.team === 'T') - const carrier = ts[Math.floor(Math.random() * ts.length)] - carrier.hasBomb = true - carrier.rig.setBomb(true) - this.bomb.carrierId = carrier.id - - this.viewmodel.setWeapon(this.controlled?.weapon.def.id ?? 'knife', false) - this.audio.roundStart() - if (this.autoMode) console.log(`[round ${n}] start — CT ${this.ctScore} : ${this.tScore} T`) - this.syncHud() - } - - private goLive() { - this.phase = 'live' - this.roundEndsAt = this.time + ROUND_TIME - this.assignMissions() - } - - private assignMissions() { - const site: 'A' | 'B' = Math.random() < 0.55 ? 'A' : 'B' - const routes = this.map.routes[site] - const sitePos = this.map.anchors[site === 'A' ? 'aSite' : 'bSite'] - - const ts = this.soldiers.filter(s => s.team === 'T' && s.brain) - const carrierRoute = Math.floor(Math.random() * routes.length) - ts.forEach((s, i) => { - const route = routes[(carrierRoute + (i % 2 === 0 ? 0 : 1)) % routes.length] - const isCarrier = s.hasBomb - const final = isCarrier ? this.map.randomSiteSpot(site) : this.map.randomSpotNear(sitePos, 9) - s.brain!.setMission(route, final, this.map.anchors.ctSpawn, isCarrier ? 'plant' : 'none') - }) - - const cts = this.soldiers.filter(s => s.team === 'CT' && s.brain) - const spots = [ - ...this.map.holdSpots.A.slice(0, 2).map(h => ({ ...h })), - ...this.map.holdSpots.B.slice(0, 2).map(h => ({ ...h })), - ...this.map.holdSpots.mid.slice(0, 1).map(h => ({ ...h })), - ] - cts.forEach((s, i) => { - const spot = spots[i % spots.length] - s.brain!.setMission([], spot.pos, spot.look, 'none') - }) - } - - private winRound(team: Team, reason: string) { - if (this.phase !== 'live') return - this.phase = 'over' - this.phaseEndsAt = this.time + ROUND_END_TIME - this.winner = team - this.winReason = reason - if (team === 'CT') this.ctScore++ - else this.tScore++ - this.audio.roundEnd(this.autoMode ? true : team === this.playerTeam) - if (this.autoMode) console.log(`[round ${this.round}] winner=${team} reason=${reason} — CT ${this.ctScore} : ${this.tScore} T`) - this.syncHud() - } - - private checkElimination() { - if (this.phase !== 'live') return - const ctAlive = this.soldiers.some(s => s.team === 'CT' && s.alive) - const tAlive = this.soldiers.some(s => s.team === 'T' && s.alive) - if (!ctAlive) this.winRound('T', '歼灭敌方') - else if (!tAlive && !this.bomb.plantedPos) this.winRound('CT', '歼灭敌方') - // T 全灭但已下包 → 等待 C4 结算 - } - - // ------------------------------------------------------------------- input - - private onKeyDown = (e: KeyboardEvent) => { - if (e.repeat) return - this.keys.add(e.code) - if (e.code === 'Space') { this.jumpQueued = true; e.preventDefault() } - if (e.code === 'Digit1') this.slotQueued = 'primary' - if (e.code === 'Digit2') this.slotQueued = 'secondary' - if (e.code === 'Digit3') this.slotQueued = 'knife' - if (e.code === 'KeyR') { /* handled per tick via keys */ } - if (e.code === 'KeyB' && this.phase === 'freeze' && this.round > 1) { - this.playerLoadout = this.playerLoadout === 'rifle' ? 'awp' : 'rifle' - const p = this.soldiers[this.playerId] - if (p && !this.autoMode) { - const primary: WeaponId = this.playerLoadout === 'awp' ? 'awp' : (p.team === 'T' ? 'ak47' : 'm4a4') - p.equip(primary, 'deagle', p.armor) - this.viewmodel.setWeapon(p.weapon.def.id) - } - this.syncHud() - } - // spectate controls - const me = this.soldiers[this.controlledId] - if (me && !me.alive && this.phase === 'live') { - if (e.code === 'ArrowLeft') this.cycleSpectate(-1) - if (e.code === 'ArrowRight') this.cycleSpectate(1) - if (e.code === 'KeyE' || e.code === 'Enter') this.takeOver() - } - } - - private onKeyUp = (e: KeyboardEvent) => { - this.keys.delete(e.code) - } - - private onMouseMove = (e: MouseEvent) => { - if (!this.pointerLocked) return - const s = this.controlled - if (!s || !s.alive || !s.isPlayer) return - const sens = 0.0022 * (s.scoped ? 0.35 : 1) - s.yaw -= e.movementX * sens - s.pitch = THREE.MathUtils.clamp(s.pitch - e.movementY * sens, -1.55, 1.55) - } - - private onMouseDown = (e: MouseEvent) => { - if (this.phase === 'menu' || this.phase === 'matchover') return - if (!this.pointerLocked) return - const me = this.soldiers[this.controlledId] - if (me && !me.alive && this.phase === 'live') { - if (e.button === 0) this.cycleSpectate(1) - return - } - if (e.button === 0) { this.mouseFire = true; this.fireTapQueued = true } - if (e.button === 2) this.altTapQueued = true - } - - private onMouseUp = (e: MouseEvent) => { - if (e.button === 0) this.mouseFire = false - } - - private onLockChange = () => { - this.pointerLocked = document.pointerLockElement === this.renderer.domElement - if (!this.pointerLocked) this.mouseFire = false - this.syncHud() - } - - private onContext = (e: Event) => e.preventDefault() - private onResize = () => this.resize() - - private bindEvents() { - window.addEventListener('keydown', this.onKeyDown) - window.addEventListener('keyup', this.onKeyUp) - window.addEventListener('mousemove', this.onMouseMove) - window.addEventListener('mousedown', this.onMouseDown) - window.addEventListener('mouseup', this.onMouseUp) - window.addEventListener('resize', this.onResize) - document.addEventListener('pointerlockchange', this.onLockChange) - this.renderer.domElement.addEventListener('contextmenu', this.onContext) - } - - private unbindEvents() { - window.removeEventListener('keydown', this.onKeyDown) - window.removeEventListener('keyup', this.onKeyUp) - window.removeEventListener('mousemove', this.onMouseMove) - window.removeEventListener('mousedown', this.onMouseDown) - window.removeEventListener('mouseup', this.onMouseUp) - window.removeEventListener('resize', this.onResize) - document.removeEventListener('pointerlockchange', this.onLockChange) - this.renderer.domElement.removeEventListener('contextmenu', this.onContext) - } - - private resize() { - const w = this.container.clientWidth || window.innerWidth - const h = this.container.clientHeight || window.innerHeight - this.renderer.setSize(w, h) - this.camera.aspect = w / h - this.camera.updateProjectionMatrix() - } - - get controlled(): Soldier | null { - return this.soldiers[this.controlledId] ?? null - } - - get viewed(): Soldier | null { - return this.soldiers[this.viewedId] ?? null - } - - private cycleSpectate(dir: number) { - const mates = this.soldiers.filter(s => s.team === this.playerTeam && s.alive) - if (mates.length === 0) return - const curIdx = mates.findIndex(s => s.id === this.viewedId) - const next = mates[(curIdx + dir + mates.length) % mates.length] - this.viewedId = next.id - this.viewmodel.setWeapon(next.weapon.def.id, false) - this.syncHud() - } - - private takeOver() { - let target = this.soldiers[this.viewedId] - // still on the death cam (or viewing a corpse): jump to a live teammate first - if (!target || !target.alive || target.id === this.controlledId) { - this.cycleSpectate(1) - target = this.soldiers[this.viewedId] - } - if (!target || !target.alive || target.team !== this.playerTeam || target.isPlayer) return - target.brain = null - target.isPlayer = true - target.name = `你(${target.originalName})` - this.controlledId = target.id - this.viewmodel.setWeapon(target.weapon.def.id, false) - this.syncHud() - } - - // ----------------------------------------------------------------- updates - - private update(dt: number) { - this.time += dt - - if (this.phase === 'menu') { - const t = this.time * 0.06 - this.camera.position.set(Math.cos(t) * 75, 52, Math.sin(t) * 75) - this.camera.lookAt(0, 0, 0) - this.viewmodel.group.visible = false - this.effects.update(dt) - this.renderer.render(this.scene, this.camera) - if (this.time > this.hudSyncAt) { this.hudSyncAt = this.time + 0.25; this.syncHud() } - return - } - - // phase transitions - if (this.phase === 'freeze' && this.time >= this.phaseEndsAt) this.goLive() - if (this.phase === 'over' && this.time >= this.phaseEndsAt) { - if (this.ctScore >= WIN_SCORE || this.tScore >= WIN_SCORE) { - this.phase = 'matchover' - this.matchWinner = this.ctScore >= WIN_SCORE ? 'CT' : 'T' - document.exitPointerLock?.() - } else { - this.startRound(this.round + 1) - } - this.syncHud() - } - if (this.phase === 'live' && !this.bomb.plantedPos && this.time >= this.roundEndsAt) { - this.winRound('CT', '时间耗尽') - } - - const canAct = this.phase === 'live' - - // player input → control - const me = this.controlled - if (me && me.isPlayer && me.alive) { - const c = me.control - c.moveX = (this.keys.has('KeyD') ? 1 : 0) - (this.keys.has('KeyA') ? 1 : 0) - c.moveZ = (this.keys.has('KeyW') ? 1 : 0) - (this.keys.has('KeyS') ? 1 : 0) - c.walk = this.keys.has('ShiftLeft') || this.keys.has('ShiftRight') - // edge-triggered inputs stay latched until a fixed step consumes them — - // on high-refresh displays a frame may run zero fixed steps, and a plain - // per-frame assignment would silently eat clicks - c.jump = c.jump || this.jumpQueued - c.fire = this.mouseFire && this.pointerLocked - c.fireTap = c.fireTap || this.fireTapQueued - c.altTap = c.altTap || this.altTapQueued - c.reload = this.keys.has('KeyR') - c.use = this.keys.has('KeyE') - c.slot = this.slotQueued ?? c.slot - if (!canAct) { - c.moveX = 0; c.moveZ = 0; c.jump = false - c.fire = false; c.fireTap = false; c.use = false - } - } - this.jumpQueued = false - this.fireTapQueued = false - this.altTapQueued = false - this.slotQueued = null - - // AI - if (canAct) { - const aiWorld: AIWorld = { - map: this.map, nav: this.nav, physics: this.physics, - soldiers: this.soldiers, time: this.time, - bombPlantedPos: this.bomb.plantedPos, - bombDroppedPos: this.bomb.droppedPos, - } - for (const s of this.soldiers) s.brain?.update(dt, aiWorld) - } else { - for (const s of this.soldiers) { - if (s.brain) { s.control.moveX = 0; s.control.moveZ = 0; s.control.fire = false; s.control.fireTap = false; s.control.use = false } - } - } - - // fixed-step simulation - this.accumulator = Math.min(this.accumulator + dt, 0.1) - while (this.accumulator >= FIXED_DT) { - this.accumulator -= FIXED_DT - this.fixedStep(FIXED_DT) - } - - // doors - const alivePos = this.soldiers.filter(s => s.alive).map(s => s.pos) - for (const d of this.map.doors) { - const ev = d.update(dt, alivePos) - if (ev) this.audio.doorSlide(d.center) - } - - // bomb & round timing - this.updateBomb() - if (canAct) this.updateSpectate() - - // team vision stamps (minimap) - if (this.time >= this.seenScanAt) { - this.seenScanAt = this.time + 0.15 - this.scanVision() - } - - // visuals - for (const s of this.soldiers) { - const speed = Math.hypot(s.vel.x, s.vel.z) - s.rig.update(dt, s.pos, s.yaw, s.pitch, speed, s.onGround) - s.rig.root.visible = s.id !== this.viewedId && s.rig.root.visible - if (s.id !== this.viewedId && s.alive) s.rig.root.visible = true - if (!s.alive) { /* keep rig's own fade logic */ } - } - const v = this.viewed - if (v) { - // camera at viewed soldier's eye - const shake = this.effects.shake - this.camera.position.copy(v.eyePos) - this.camera.rotation.y = v.yaw + v.recoilYaw + (Math.random() - 0.5) * shake * 0.05 - this.camera.rotation.x = THREE.MathUtils.clamp(v.pitch + v.recoilPitch, -1.55, 1.55) + (Math.random() - 0.5) * shake * 0.05 - this.camera.rotation.z = (Math.random() - 0.5) * shake * 0.03 - if (!v.alive) { - this.camera.position.y = Math.max(0.4, this.camera.position.y - 1.1) - this.camera.rotation.z += 0.35 - } - const targetFov = v.scoped && v.weapon.def.scopeFov ? v.weapon.def.scopeFov : 75 - if (Math.abs(this.camera.fov - targetFov) > 0.5) { - this.camera.fov += (targetFov - this.camera.fov) * Math.min(1, 18 * dt) - this.camera.updateProjectionMatrix() - } - const speed = Math.hypot(v.vel.x, v.vel.z) - this.viewmodel.update(dt, speed, v.onGround, v.scoped || !v.alive) - this.audio.setListener(v.eyePos, v.rightDir()) - } - - this.effects.update(dt) - this.renderer.render(this.scene, this.camera) - - if (this.time >= this.hudSyncAt) { - this.hudSyncAt = this.time + 0.05 - this.syncHud() - } - } - - private fixedStep(dt: number) { - for (const s of this.soldiers) { - if (!s.alive) continue - const c = s.control - - // weapon switching - if (c.slot) { - if (s.trySwitch(c.slot)) { - if (s.id === this.viewedId) { this.viewmodel.setWeapon(s.weapon.def.id); this.audio.drawWeapon() } - } - c.slot = null - } - - // weapon state - const wpn = s.weapon - wpn.update(dt) - if (c.reload && wpn.startReload()) { - s.scoped = false - this.audio.reload(s.id === this.viewedId ? null : s.pos, wpn.def.reloadTime) - if (s.id === this.viewedId) this.viewmodel.onReload(wpn.def.reloadTime) - } - - // scope toggle - if (c.altTap && wpn.def.scopeFov && !wpn.reloading) { - s.scoped = !s.scoped - if (s.id === this.viewedId) this.audio.scope(s.scoped) - } - if (!wpn.def.scopeFov) s.scoped = false - - // channels (plant / defuse) - this.updateChannel(s, dt) - - // movement (channeling locks you in place) - const chanLock = s.channel !== null - let speed = RUN_SPEED * wpn.def.moveMult - if (c.walk) speed *= 0.52 - if (s.scoped) speed *= 0.55 - const fwd = new THREE.Vector3(-Math.sin(s.yaw), 0, -Math.cos(s.yaw)) - const right = s.rightDir() - const wish = new THREE.Vector3() - if (!chanLock) { - wish.addScaledVector(fwd, c.moveZ).addScaledVector(right, c.moveX) - if (wish.lengthSq() > 1) wish.normalize() - } - this.physics.moveBody(s, wish, speed, c.jump && !chanLock, dt) - c.jump = false - - // recoil recovery - s.recoilPitch *= Math.exp(-6 * dt) - s.recoilYaw *= Math.exp(-6 * dt) - - // footsteps - const hSpeed = Math.hypot(s.vel.x, s.vel.z) - if (s.onGround && hSpeed > 1) { - s.stepAcc += hSpeed * dt - if (s.stepAcc > 2.55) { - s.stepAcc = 0 - const vol = c.walk ? 0.25 : 1 - this.audio.footstep(s.id === this.viewedId ? null : s.pos, s.id === this.viewedId ? vol * 0.4 : vol) - } - } - - // firing (taps are buffered so clicks during weapon cooldown aren't dropped) - if (c.fireTap) s.tapBuffer = 0.22 - if (!chanLock && this.phase === 'live') { - const wantsFire = wpn.def.auto ? (c.fire || s.tapBuffer > 0) : s.tapBuffer > 0 - if (wantsFire && wpn.canFire() && s.switchCooldown <= 0) { - this.performShot(s) - s.tapBuffer = 0 - } - } - if (s.tapBuffer > 0) s.tapBuffer -= dt - c.fireTap = false - c.altTap = false - if (s.switchCooldown > 0) s.switchCooldown -= dt - - // bomb pickup - if (s.team === 'T' && this.bomb.droppedPos && s.alive) { - if (s.pos.distanceTo(this.bomb.droppedPos) < 1.3) { - this.bomb.droppedPos = null - this.bomb.carrierId = s.id - s.hasBomb = true - s.rig.setBomb(true) - this.bombMesh.visible = false - this.reassignPlantDuty(s) - } - } - } - - // soldier-vs-soldier separation - const alive = this.soldiers.filter(s => s.alive) - for (let i = 0; i < alive.length; i++) { - for (let j = i + 1; j < alive.length; j++) { - const a = alive[i], b = alive[j] - const dx = b.pos.x - a.pos.x, dz = b.pos.z - a.pos.z - const d2 = dx * dx + dz * dz - if (d2 > 0.0001 && d2 < 0.72 * 0.72) { - const d = Math.sqrt(d2) - const push = (0.72 - d) / 2 - const nx = dx / d, nz = dz / d - if (this.physics.circleFree(a.pos.x - nx * push, a.pos.z - nz * push, a.radius, a.pos.y)) { - a.pos.x -= nx * push; a.pos.z -= nz * push - } - if (this.physics.circleFree(b.pos.x + nx * push, b.pos.z + nz * push, b.radius, b.pos.y)) { - b.pos.x += nx * push; b.pos.z += nz * push - } - } - } - } - } - - private updateChannel(s: Soldier, dt: number) { - const wantPlant = s.control.use && s.team === 'T' && s.hasBomb && !this.bomb.plantedPos - && s.onGround && this.map.plantSiteAt(s.pos.x, s.pos.z) !== null && this.phase === 'live' - const wantDefuse = s.control.use && s.team === 'CT' && this.bomb.plantedPos !== null && this.phase === 'live' - && Math.hypot(this.bomb.plantedPos.x - s.pos.x, this.bomb.plantedPos.z - s.pos.z) < 1.5 - - if (wantPlant) { - if (!s.channel || s.channel.kind !== 'plant') s.channel = { kind: 'plant', t: 0, total: PLANT_TIME } - s.channel.t += dt - if (Math.floor(s.channel.t * 4) !== Math.floor((s.channel.t - dt) * 4)) this.audio.plantTick(s.id === this.viewedId ? null : s.pos) - if (s.channel.t >= s.channel.total) { - s.channel = null - this.plantBomb(s) - } - } else if (wantDefuse) { - if (!s.channel || s.channel.kind !== 'defuse') s.channel = { kind: 'defuse', t: 0, total: DEFUSE_TIME } - s.channel.t += dt - if (this.time >= this.nextDefTickAt) { - this.nextDefTickAt = this.time + 0.5 - this.audio.defuseTick(s.id === this.viewedId ? null : s.pos) - } - if (s.channel.t >= s.channel.total) { - s.channel = null - this.audio.bombDefused() - this.winRound('CT', '炸弹已拆除') - } - } else { - s.channel = null - } - } - - // ------------------------------------------------------------------ combat - - private performShot(shooter: Soldier) { - const wpn = shooter.weapon - const def = wpn.def - - if (def.id === 'knife') { - wpn.onFire() - const isViewed = shooter.id === this.viewedId - this.audio.shot('knife', isViewed ? null : shooter.pos) - if (isViewed) this.viewmodel.onFire(0) - const dir = shooter.viewDir() - const hit = this.physics.raycast(shooter.eyePos, dir, def.range ?? 2.2, this.soldiers, shooter.id, shooter.team) - if (hit?.kind === 'soldier' && hit.soldier) { - this.audio.knifeHit(isViewed ? null : hit.point) - this.applyDamage(hit.soldier as Soldier, def.damage, shooter, hit.part ?? 'chest', def) - this.effects.bloodBurst(hit.point) - } else if (hit) { - // scraped a wall / crate - this.audio.knifeHit(isViewed ? null : hit.point) - this.effects.impact(hit.point) - } - return - } - - wpn.onFire() - - // spread - let spread = shooter.scoped && def.spreadScoped !== undefined ? def.spreadScoped : def.spreadBase - spread += wpn.bloom - def.spreadPerShot // bloom before this shot's own bump - const hSpeed = Math.hypot(shooter.vel.x, shooter.vel.z) - spread += (hSpeed / RUN_SPEED) * def.spreadMove - if (!shooter.onGround) spread += 0.05 - - const dir = shooter.viewDir() - const right = shooter.rightDir() - const up = new THREE.Vector3().crossVectors(right, dir).normalize() - const a = Math.random() * Math.PI * 2 - const r = Math.sqrt(Math.random()) * spread - dir.addScaledVector(right, Math.cos(a) * r).addScaledVector(up, Math.sin(a) * r).normalize() - - // recoil - shooter.recoilPitch += def.kickPitch * (0.85 + Math.random() * 0.3) - shooter.recoilYaw += (Math.random() - 0.5) * def.kickYaw * 2 - - const isViewed = shooter.id === this.viewedId - this.audio.shot(def.sound, isViewed ? null : shooter.pos) - this.notifyHeard(shooter) - - // muzzle position for tracer - const eye = shooter.eyePos - const muzzle = eye.clone().addScaledVector(dir, 0.7).addScaledVector(right, isViewed ? 0.13 : 0.2).addScaledVector(up, -0.1) - this.effects.muzzle(muzzle) - - if (isViewed) { - this.viewmodel.onFire(def.kickPitch) - } - - const hit = this.physics.raycast(eye, dir, 300, this.soldiers, shooter.id, shooter.team) - const end = hit ? hit.point : eye.clone().addScaledVector(dir, 300) - if (def.id !== 'usp') this.effects.tracer(muzzle, end) - - if (hit) { - if (hit.kind === 'soldier' && hit.soldier) { - this.effects.bloodBurst(hit.point) - this.applyDamage(hit.soldier as Soldier, def.damage, shooter, hit.part ?? 'chest', def) - } else { - this.effects.impact(hit.point) - } - } - } - - private notifyHeard(shooter: Soldier) { - for (const s of this.soldiers) { - if (!s.alive || s.team === shooter.team || !s.brain) continue - if (s.pos.distanceTo(shooter.pos) < 38) s.brain.heard(shooter.pos, this.time) - } - } - - private applyDamage(target: Soldier, baseDmg: number, attacker: Soldier, part: BodyPart, def: { armorPen: number; name: string }) { - if (!target.alive) return - let dmg = baseDmg * PART_MULT[part] - if (target.armor > 0 && part !== 'leg') { - const kept = dmg * def.armorPen - const absorbed = (dmg - kept) * 0.5 - target.armor = Math.max(0, target.armor - absorbed) - dmg = kept - } - dmg = Math.round(dmg) - target.hp -= dmg - - const headshot = part === 'head' - if (attacker.id === this.controlledId) { - this.hud.state.hitmarkerAt = this.time - this.hud.state.hitmarkerHead = headshot - this.audio.hit(headshot) - } - if (target.id === this.controlledId) { - this.hud.state.damageAt = this.time - this.audio.damage() - } - - if (target.hp <= 0) { - this.kill(target, attacker, def.name, headshot) - } - } - - private kill(victim: Soldier, attacker: Soldier, weaponName: string, headshot: boolean) { - victim.alive = false - victim.hp = 0 - victim.deaths++ - attacker.kills++ - victim.channel = null - victim.scoped = false - victim.rig.die() - this.audio.death(victim.pos) - if (attacker.id === this.controlledId) this.audio.kill() - - // drop bomb - if (victim.hasBomb) { - victim.hasBomb = false - victim.rig.setBomb(false) - this.bomb.carrierId = null - this.bomb.droppedPos = victim.pos.clone() - this.bombMesh.visible = true - this.bombMesh.position.copy(victim.pos) - this.bombMesh.rotation.set(0, Math.random() * 6, 0) - // send nearest T to pick it up - const ts = this.soldiers.filter(s => s.team === 'T' && s.alive && s.brain) - ts.sort((a, b) => a.pos.distanceTo(victim.pos) - b.pos.distanceTo(victim.pos)) - if (ts[0]) ts[0].brain!.setMission([], victim.pos.clone(), null, 'pickup') - } - - this.hud.state.killfeed.push({ - id: this.killfeedId++, - attacker: attacker.name, attackerTeam: attacker.team, - victim: victim.name, victimTeam: victim.team, - weapon: weaponName, headshot, t: this.time, - }) - if (this.hud.state.killfeed.length > 6) this.hud.state.killfeed.shift() - if (this.autoMode) console.log(`[kill] ${attacker.name} → ${victim.name} (${weaponName}${headshot ? ', HS' : ''})`) - - // a teammate of the victim may investigate - const mates = this.soldiers.filter(s => s.team === victim.team && s.alive && s.brain && !s.brain.target) - if (mates.length && Math.random() < 0.5) { - const m = mates[Math.floor(Math.random() * mates.length)] - m.brain!.heard(victim.pos, this.time) - } - - if (victim.id === this.controlledId) this.deathAt = this.time - this.checkElimination() - this.syncHud() - } - - // -------------------------------------------------------------------- bomb - - private plantBomb(planter: Soldier) { - planter.hasBomb = false - planter.rig.setBomb(false) - this.bomb.carrierId = null - this.bomb.plantedPos = planter.pos.clone() - this.bomb.plantedAt = this.time - this.bombMesh.visible = true - this.bombMesh.position.copy(this.bomb.plantedPos) - this.bombMesh.rotation.set(0, Math.random() * 6, 0) - this.nextBeepAt = this.time - this.audio.bombPlanted() - if (this.autoMode) console.log(`[bomb] planted at ${this.map.plantSiteAt(this.bomb.plantedPos.x, this.bomb.plantedPos.z)}`) - - // T defend spots, CT retake + defuse duty - for (const s of this.soldiers) { - if (!s.alive || !s.brain) continue - if (s.team === 'T') { - s.brain.setMission([], this.map.randomSpotNear(this.bomb.plantedPos, 9), this.bomb.plantedPos, 'none') - } - } - this.assignDefuser() - this.syncHud() - } - - private assignDefuser() { - if (!this.bomb.plantedPos) return - const cts = this.soldiers.filter(s => s.team === 'CT' && s.alive && s.brain) - cts.sort((a, b) => a.pos.distanceTo(this.bomb.plantedPos!) - b.pos.distanceTo(this.bomb.plantedPos!)) - cts.forEach((s, i) => { - if (i === 0) s.brain!.setMission([], this.bomb.plantedPos!.clone(), null, 'defuse') - else s.brain!.setMission([], this.map.randomSpotNear(this.bomb.plantedPos!, 8), this.bomb.plantedPos, 'none') - }) - } - - private reassignPlantDuty(carrier: Soldier) { - if (!carrier.brain) return - const site: 'A' | 'B' = Math.random() < 0.5 ? 'A' : 'B' - const near = this.map.plantSiteAt(carrier.pos.x, carrier.pos.z) - const chosen = near ?? site - carrier.brain.setMission([], this.map.randomSiteSpot(chosen), null, 'plant') - } - - private updateBomb() { - if (this.bomb.plantedPos && !this.bomb.exploded) { - const led = this.bombMesh.getObjectByName('led') as THREE.Mesh | undefined - const remaining = this.bomb.plantedAt + BOMB_FUSE - this.time - if (led) { - const blink = Math.sin(this.time * (remaining < 8 ? 30 : 8)) > 0 - ;(led.material as THREE.MeshBasicMaterial).color.setHex(blink ? 0xff2222 : 0x441111) - } - if (this.time >= this.nextBeepAt && this.phase === 'live') { - const frac = Math.max(0, remaining / BOMB_FUSE) - this.nextBeepAt = this.time + 0.12 + 0.9 * Math.pow(frac, 1.4) - this.audio.bombBeep(this.bomb.plantedPos, remaining < 10) - } - if (remaining <= 0 && this.phase === 'live') { - this.explodeBomb() - } - // keep a defuser assigned if the previous one died - if (this.phase === 'live' && !this.soldiers.some(s => s.team === 'CT' && s.alive && s.brain?.mission?.duty === 'defuse')) { - this.assignDefuser() - } - } - } - - private explodeBomb() { - if (!this.bomb.plantedPos) return - this.bomb.exploded = true - this.bombMesh.visible = false - this.effects.explosion(this.bomb.plantedPos) - this.audio.explosion(this.bomb.plantedPos) - for (const s of this.soldiers) { - if (!s.alive) continue - const d = s.pos.distanceTo(this.bomb.plantedPos) - if (d < 20) { - let dmg = 550 * (1 - d / 20) - if (!this.physics.hasLOS(this.bomb.plantedPos.clone().add(new THREE.Vector3(0, 1, 0)), s.eyePos)) dmg *= 0.4 - s.hp -= dmg - if (s.hp <= 0) { - s.alive = false - s.deaths++ - s.rig.die() - if (s.id === this.controlledId) this.deathAt = this.time - } - } - } - this.winRound('T', 'C4 爆炸') - } - - // ---------------------------------------------------------------- spectate - - private updateSpectate() { - const me = this.soldiers[this.controlledId] - if (!me || me.alive) return - if (this.viewedId === this.controlledId && this.time - this.deathAt > 0.8) { - // auto-switch to an alive teammate - const mate = this.soldiers.find(s => s.team === this.playerTeam && s.alive) - if (mate) { - this.viewedId = mate.id - this.viewmodel.setWeapon(mate.weapon.def.id, false) - } - } - const v = this.viewed - if (v && !v.alive && v.id !== this.controlledId) { - const mate = this.soldiers.find(s => s.team === this.playerTeam && s.alive) - if (mate) { - this.viewedId = mate.id - this.viewmodel.setWeapon(mate.weapon.def.id, false) - } else { - this.viewedId = this.controlledId - } - } - } - - private scanVision() { - for (const team of ['CT', 'T'] as Team[]) { - const observers = this.soldiers.filter(s => s.team === team && s.alive) - for (const enemy of this.soldiers) { - if (enemy.team === team || !enemy.alive) continue - for (const o of observers) { - const dx = enemy.pos.x - o.pos.x, dz = enemy.pos.z - o.pos.z - const dist = Math.hypot(dx, dz) - if (dist > 70) continue - const dirYaw = Math.atan2(-dx, -dz) - let dyaw = (dirYaw - o.yaw) % (Math.PI * 2) - if (dyaw > Math.PI) dyaw -= Math.PI * 2 - if (dyaw < -Math.PI) dyaw += Math.PI * 2 - if (Math.abs(dyaw) > 1.1 && dist > 3) continue - if (!this.physics.hasLOS(o.eyePos, new THREE.Vector3(enemy.pos.x, enemy.pos.y + 1.3, enemy.pos.z))) continue - enemy.lastSeenBy[team] = this.time - break - } - } - } - } - - // ------------------------------------------------------------------- hud - - private syncHud() { - const st = this.hud.state - st.phase = this.phase - st.locked = this.pointerLocked - st.auto = this.autoMode - st.round = this.round - st.pistolRound = this.round === 1 - st.ctScore = this.ctScore - st.tScore = this.tScore - st.playerTeam = this.playerTeam - st.loadout = this.playerLoadout - st.winner = this.winner - st.winReason = this.winReason - st.matchWinner = this.matchWinner - st.freezeLeft = this.phase === 'freeze' ? Math.max(0, this.phaseEndsAt - this.time) : 0 - st.timeLeft = this.phase === 'live' ? Math.max(0, this.roundEndsAt - this.time) : ROUND_TIME - st.bombPlanted = this.bomb.plantedPos !== null && !this.bomb.exploded - st.bombTimeLeft = st.bombPlanted ? Math.max(0, this.bomb.plantedAt + BOMB_FUSE - this.time) : null - - const me = this.soldiers[this.controlledId] - const v = this.viewed ?? me - if (v) { - const wpn = v.weapon - st.me = { - name: v.name, team: v.team, hp: Math.max(0, Math.ceil(v.hp)), armor: Math.ceil(v.armor), - alive: v.alive, weaponName: wpn.def.name, weaponId: wpn.def.id, - mag: wpn.mag, reserve: wpn.reserve, reloading: wpn.reloading, - scoped: v.scoped, hasBomb: v.hasBomb, - spreadPx: 5 + (wpn.bloom + wpn.def.spreadBase) * 900 + Math.hypot(v.vel.x, v.vel.z) * 1.4, - } - st.channel = v.channel ? { - label: v.channel.kind === 'plant' ? '正在安放 C4…' : '正在拆除 C4…', - progress: v.channel.t / v.channel.total, - } : null - - // center hint - st.centerHint = null - if (v.alive && this.phase === 'live' && !v.channel) { - if (v.team === 'T' && v.hasBomb && this.map.plantSiteAt(v.pos.x, v.pos.z)) st.centerHint = '按住 E 安放 C4' - else if (v.team === 'CT' && this.bomb.plantedPos && Math.hypot(this.bomb.plantedPos.x - v.pos.x, this.bomb.plantedPos.z - v.pos.z) < 3) st.centerHint = '按住 E 拆除 C4' - } - } - st.spectating = me && v && v.id !== me.id - ? { name: v.name, isSelf: false } - : (me && !me.alive ? { name: me.name, isSelf: true } : null) - - // prune old killfeed - st.killfeed = st.killfeed.filter(k => this.time - k.t < 6.5) - this.hud.bump() - } - - // Minimap data access (imperative canvas drawing from React) - minimapInfo() { - return { - map: this.map, - soldiers: this.soldiers, - viewedId: this.viewedId, - playerTeam: this.playerTeam, - time: this.time, - bomb: this.bomb, - } - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/map.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/map.ts deleted file mode 100644 index d00216a..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/map.ts +++ /dev/null @@ -1,429 +0,0 @@ -import * as THREE from 'three' -import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js' -import type { Team } from './types' - -export const CELL = 2.5 -export const GRID = 52 -export const WALL_H = 4 -const HALF = GRID / 2 // world origin at grid center - -export const enum Code { Wall = 0, Floor = 1, TSpawn = 2, CTSpawn = 3, ASite = 4, BSite = 5, Door = 6 } - -// --------------------------------------------------------------------------- -// Layout: carved rectangles on a 52x52 grid (col, row; row 0 = north = -Z). -// Regions: T spawn, CT spawn, Long A, A site, mid + mid doors, catwalk (short), -// B tunnels, B site — wired up per the real Dust2 topology. -// --------------------------------------------------------------------------- -type Rect = [x1: number, y1: number, x2: number, y2: number, code: Code] - -const RECTS: Rect[] = [ - [2, 2, 13, 12, Code.BSite], // B 点 - [6, 13, 9, 30, Code.Floor], // B洞 竖段 - [6, 28, 20, 31, Code.Floor], // B洞 横段 - [17, 31, 20, 41, Code.Floor], // B洞 → T 出生点 - [18, 42, 34, 49, Code.TSpawn], // T 出生点 - [24, 38, 29, 42, Code.Floor], // T → 中路 - [24, 10, 29, 38, Code.Floor], // 中路 - [22, 3, 34, 10, Code.CTSpawn], // CT 出生点 - [13, 10, 25, 13, Code.Floor], // B门通道 (CT ↔ B) - [29, 20, 38, 23, Code.Floor], // 猫道横段 - [35, 10, 38, 23, Code.Floor], // A小 竖段 - [36, 2, 47, 9, Code.ASite], // A 点 - [44, 9, 47, 34, Code.Floor], // A大 竖段 - [30, 34, 47, 38, Code.Floor], // A大 外围横段 - [30, 38, 34, 42, Code.Floor], // T → A大 - [34, 3, 36, 7, Code.Floor], // CT → A 匝道 -] - -// tunnels get ceilings so B洞 reads as an actual tunnel -const TUNNEL_RECTS: Rect[] = [ - [6, 13, 9, 30, Code.Floor], - [6, 28, 20, 31, Code.Floor], -] - -const CRATES: [c: number, r: number, stack: number][] = [ - // A site - [40, 4, 2], [41, 4, 1], [40, 5, 1], [44, 7, 1], [37, 3, 1], - // B site - [5, 4, 1], [6, 4, 2], [10, 9, 1], [11, 9, 1], [4, 10, 1], - // mid boxes - [25, 34, 1], [26, 34, 2], - // catwalk xbox - [31, 21, 1], - // long corner - [46, 35, 1], [46, 36, 2], - // tunnels + spawns - [8, 21, 1], [20, 43, 1], [32, 4, 1], -] - -export interface AABB { min: THREE.Vector3; max: THREE.Vector3 } - -export class DoorObj { - center: THREE.Vector3 - totalW: number - panelW: number - open01 = 0 - target = 0 - panels: [THREE.Mesh, THREE.Mesh] - group = new THREE.Group() - - constructor(center: THREE.Vector3, totalW: number) { - this.center = center - this.totalW = totalW - this.panelW = totalW / 2 - const mat = new THREE.MeshStandardMaterial({ color: 0x5c6e60, roughness: 0.7, metalness: 0.3 }) - const geo = new THREE.BoxGeometry(this.panelW, 3.2, 0.25) - const left = new THREE.Mesh(geo, mat) - const right = new THREE.Mesh(geo, mat) - left.castShadow = right.castShadow = true - this.panels = [left, right] - this.group.add(left, right) - // door frame header - const header = new THREE.Mesh( - new THREE.BoxGeometry(totalW + 0.6, WALL_H - 3.2, 0.6), - new THREE.MeshStandardMaterial({ color: 0x8f7f5c, roughness: 0.95 }), - ) - header.position.set(center.x, 3.2 + (WALL_H - 3.2) / 2, center.z) - this.group.add(header) - this.layout() - } - - private layout() { - const slide = this.open01 * (this.panelW + 0.3) - this.panels[0].position.set(this.center.x - this.panelW / 2 - slide, 1.6, this.center.z) - this.panels[1].position.set(this.center.x + this.panelW / 2 + slide, 1.6, this.center.z) - } - - /** Returns 'open' | 'close' when the door starts moving (for audio). */ - update(dt: number, positions: THREE.Vector3[]): 'open' | 'close' | null { - let near = false - for (const p of positions) { - const dx = p.x - this.center.x, dz = p.z - this.center.z - if (dx * dx + dz * dz < 4.2 * 4.2) { near = true; break } - } - const prevTarget = this.target - this.target = near ? 1 : 0 - const before = this.open01 - const k = 1 - Math.exp(-5 * dt) - this.open01 += (this.target - this.open01) * k - if (Math.abs(this.open01 - before) > 1e-5) this.layout() - if (prevTarget !== this.target) return this.target === 1 ? 'open' : 'close' - return null - } - - colliders(): AABB[] { - if (this.open01 > 0.92) return [] - const out: AABB[] = [] - for (const p of this.panels) { - out.push({ - min: new THREE.Vector3(p.position.x - this.panelW / 2, 0, this.center.z - 0.2), - max: new THREE.Vector3(p.position.x + this.panelW / 2, 3.2, this.center.z + 0.2), - }) - } - return out - } -} - -export interface HoldSpot { pos: THREE.Vector3; look: THREE.Vector3 } - -function makeFloorTexture(): THREE.CanvasTexture { - const c = document.createElement('canvas') - c.width = c.height = 256 - const g = c.getContext('2d')! - g.fillStyle = '#c9b183' - g.fillRect(0, 0, 256, 256) - for (let i = 0; i < 2600; i++) { - const v = Math.random() - g.fillStyle = v < 0.5 ? 'rgba(120,98,64,0.14)' : 'rgba(240,226,190,0.12)' - g.fillRect(Math.random() * 256, Math.random() * 256, 1 + Math.random() * 2.4, 1 + Math.random() * 2.4) - } - g.strokeStyle = 'rgba(90,74,50,0.20)' - g.lineWidth = 1 - g.strokeRect(0.5, 0.5, 255, 255) - const tex = new THREE.CanvasTexture(c) - tex.wrapS = tex.wrapT = THREE.RepeatWrapping - tex.repeat.set(GRID, GRID) - tex.colorSpace = THREE.SRGBColorSpace - return tex -} - -function makeLetterTexture(text: string, color: string): THREE.CanvasTexture { - const c = document.createElement('canvas') - c.width = c.height = 128 - const g = c.getContext('2d')! - g.clearRect(0, 0, 128, 128) - g.font = 'bold 96px sans-serif' - g.textAlign = 'center' - g.textBaseline = 'middle' - g.fillStyle = color - g.fillText(text, 64, 68) - const tex = new THREE.CanvasTexture(c) - tex.colorSpace = THREE.SRGBColorSpace - return tex -} - -export class GameMap { - grid = new Uint8Array(GRID * GRID) // Code values - crateCells = new Set() - crates: AABB[] = [] - doors: DoorObj[] = [] - group = new THREE.Group() - spawns: Record = { CT: [], T: [] } - anchors: Record = {} - holdSpots: { A: HoldSpot[]; B: HoldSpot[]; mid: HoldSpot[] } = { A: [], B: [], mid: [] } - routes: { A: THREE.Vector3[][]; B: THREE.Vector3[][] } = { A: [], B: [] } - siteCells: { A: [number, number][]; B: [number, number][] } = { A: [], B: [] } - - constructor() { - this.buildGrid() - this.buildVisuals() - this.buildMeta() - } - - code(c: number, r: number): Code { - if (c < 0 || r < 0 || c >= GRID || r >= GRID) return Code.Wall - return this.grid[r * GRID + c] as Code - } - - isWall(c: number, r: number): boolean { return this.code(c, r) === Code.Wall } - - isWalkableCell(c: number, r: number): boolean { - return this.code(c, r) !== Code.Wall && !this.crateCells.has(r * GRID + c) - } - - cellCenter(c: number, r: number): THREE.Vector3 { - return new THREE.Vector3((c - HALF + 0.5) * CELL, 0, (r - HALF + 0.5) * CELL) - } - - worldToCell(x: number, z: number): [number, number] { - return [Math.floor(x / CELL + HALF), Math.floor(z / CELL + HALF)] - } - - plantSiteAt(x: number, z: number): 'A' | 'B' | null { - const [c, r] = this.worldToCell(x, z) - const code = this.code(c, r) - if (code === Code.ASite) return 'A' - if (code === Code.BSite) return 'B' - return null - } - - private buildGrid() { - for (const [x1, y1, x2, y2, code] of RECTS) { - for (let r = y1; r <= y2; r++) { - for (let c = x1; c <= x2; c++) this.grid[r * GRID + c] = code - } - } - // 中门: frame + door cells at row 16 - this.grid[16 * GRID + 24] = Code.Wall - this.grid[16 * GRID + 29] = Code.Wall - for (let c = 25; c <= 28; c++) this.grid[16 * GRID + c] = Code.Door - // A大双门 at row 32 - this.grid[32 * GRID + 44] = Code.Wall - this.grid[32 * GRID + 47] = Code.Wall - for (let c = 45; c <= 46; c++) this.grid[32 * GRID + c] = Code.Door - - for (const [c, r, stack] of CRATES) { - this.crateCells.add(r * GRID + c) - const ctr = this.cellCenter(c, r) - const s = 1.05 - this.crates.push({ - min: new THREE.Vector3(ctr.x - s, 0, ctr.z - s), - max: new THREE.Vector3(ctr.x + s, 1.05 * stack, ctr.z + s), - }) - } - } - - private buildVisuals() { - // floor - const floorMat = new THREE.MeshStandardMaterial({ map: makeFloorTexture(), roughness: 1 }) - const floor = new THREE.Mesh(new THREE.PlaneGeometry(GRID * CELL, GRID * CELL), floorMat) - floor.rotation.x = -Math.PI / 2 - floor.receiveShadow = true - this.group.add(floor) - - // walls: merge exposed wall cells into per-row runs - const exposed = (c: number, r: number): boolean => { - if (!this.isWall(c, r)) return false - for (let dr = -1; dr <= 1; dr++) { - for (let dc = -1; dc <= 1; dc++) { - if (dc === 0 && dr === 0) continue - if (this.code(c + dc, r + dr) !== Code.Wall) return true - } - } - return false - } - const geos: THREE.BufferGeometry[] = [] - const base = new THREE.Color('#c8ae7d') - for (let r = 0; r < GRID; r++) { - let c = 0 - while (c < GRID) { - if (!exposed(c, r)) { c++; continue } - let end = c - while (end + 1 < GRID && exposed(end + 1, r)) end++ - const w = (end - c + 1) * CELL - const g = new THREE.BoxGeometry(w, WALL_H, CELL) - const cx = ((c + end + 1) / 2 - HALF) * CELL - const cz = (r - HALF + 0.5) * CELL - g.translate(cx, WALL_H / 2, cz) - const col = base.clone().multiplyScalar(0.9 + Math.random() * 0.18) - const n = g.attributes.position.count - const colors = new Float32Array(n * 3) - for (let i = 0; i < n; i++) { colors[i * 3] = col.r; colors[i * 3 + 1] = col.g; colors[i * 3 + 2] = col.b } - g.setAttribute('color', new THREE.BufferAttribute(colors, 3)) - geos.push(g) - c = end + 1 - } - } - const wallGeo = mergeGeometries(geos)! - const walls = new THREE.Mesh(wallGeo, new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.95 })) - walls.castShadow = true - walls.receiveShadow = true - this.group.add(walls) - - // crates - const crateMat = new THREE.MeshStandardMaterial({ color: 0x9a7743, roughness: 0.9 }) - const crateEdge = new THREE.MeshStandardMaterial({ color: 0x6e5430, roughness: 0.9 }) - for (const [c, r, stack] of CRATES) { - const ctr = this.cellCenter(c, r) - for (let s = 0; s < stack; s++) { - const m = new THREE.Mesh(new THREE.BoxGeometry(2.1, 1.02, 2.1), crateMat) - m.position.set(ctr.x, 0.525 + s * 1.05, ctr.z) - m.castShadow = m.receiveShadow = true - this.group.add(m) - const trim = new THREE.Mesh(new THREE.BoxGeometry(2.16, 0.12, 2.16), crateEdge) - trim.position.set(ctr.x, 1.0 + s * 1.05, ctr.z) - this.group.add(trim) - } - } - - // tunnel ceilings - const ceilMat = new THREE.MeshStandardMaterial({ color: 0xa08a5f, roughness: 1 }) - for (const [x1, y1, x2, y2] of TUNNEL_RECTS) { - const w = (x2 - x1 + 1) * CELL, d = (y2 - y1 + 1) * CELL - const m = new THREE.Mesh(new THREE.BoxGeometry(w + CELL, 0.4, d + CELL), ceilMat) - m.position.set(((x1 + x2 + 1) / 2 - HALF) * CELL, 3.3, ((y1 + y2 + 1) / 2 - HALF) * CELL) - m.castShadow = true - this.group.add(m) - } - - // site letters painted on the floor - const markers: [string, number, number, string][] = [ - ['A', 41, 5, 'rgba(214,120,50,0.85)'], - ['B', 7, 7, 'rgba(214,120,50,0.85)'], - ['MID', 26, 24, 'rgba(90,74,50,0.6)'], - ] - for (const [text, c, r, color] of markers) { - const tex = makeLetterTexture(text, color) - const size = text.length > 1 ? 7 : 5 - const m = new THREE.Mesh( - new THREE.PlaneGeometry(size, size), - new THREE.MeshBasicMaterial({ map: tex, transparent: true, depthWrite: false }), - ) - const p = this.cellCenter(c, r) - m.rotation.x = -Math.PI / 2 - m.position.set(p.x, 0.02, p.z) - this.group.add(m) - } - - // doors - const midDoor = new DoorObj(this.cellCenter(26, 16).setX(((25 + 29) / 2 - HALF) * CELL), 4 * CELL) - const longDoor = new DoorObj(this.cellCenter(45, 32).setX(((45 + 47) / 2 - HALF) * CELL), 2 * CELL) - this.doors = [midDoor, longDoor] - for (const d of this.doors) this.group.add(d.group) - } - - private buildMeta() { - const cc = (c: number, r: number) => this.cellCenter(c, r) - // spawns - const tCells: [number, number][] = [[25, 46], [27, 46], [23, 45], [29, 45], [26, 47]] - const ctCells: [number, number][] = [[27, 5], [29, 5], [25, 4], [31, 6], [28, 7]] - this.spawns.T = tCells.map(([c, r]) => ({ pos: cc(c, r), yaw: 0 })) - this.spawns.CT = ctCells.map(([c, r]) => ({ pos: cc(c, r), yaw: Math.PI })) - - const an = this.anchors - an.aSite = cc(41, 5); an.bSite = cc(7, 7) - an.tSpawn = cc(26, 45); an.ctSpawn = cc(28, 6) - an.midLow = cc(26, 32); an.midDoorS = cc(26, 18); an.midTop = cc(26, 11) - an.catwalk = cc(33, 21); an.aShort = cc(36, 12) - an.outsideLong = cc(38, 36); an.longMid = cc(45, 26); an.longTop = cc(45, 11) - an.tunnelS = cc(18, 36); an.tunnelElbow = cc(8, 29); an.tunnelMid = cc(7, 20) - an.bDoors = cc(18, 11) - - this.routes.A = [ - [an.outsideLong, an.longMid, an.longTop], - [an.midLow, an.catwalk, an.aShort], - ] - this.routes.B = [ - [an.tunnelS, an.tunnelElbow, an.tunnelMid], - [an.midLow, an.midDoorS, an.midTop, an.bDoors], - ] - - this.holdSpots.A = [ - { pos: cc(38, 3), look: cc(45, 11) }, - { pos: cc(43, 8), look: cc(36, 13) }, - { pos: cc(45, 11), look: cc(45, 28) }, - ] - this.holdSpots.B = [ - { pos: cc(4, 4), look: cc(7, 15) }, - { pos: cc(10, 10), look: cc(15, 11) }, - { pos: cc(7, 14), look: cc(7, 22) }, - ] - this.holdSpots.mid = [ - { pos: cc(26, 12), look: cc(26, 20) }, - { pos: cc(18, 11), look: cc(25, 11) }, - ] - - for (let r = 0; r < GRID; r++) { - for (let c = 0; c < GRID; c++) { - const code = this.code(c, r) - if (code === Code.ASite && this.isWalkableCell(c, r)) this.siteCells.A.push([c, r]) - if (code === Code.BSite && this.isWalkableCell(c, r)) this.siteCells.B.push([c, r]) - } - } - } - - randomSiteSpot(site: 'A' | 'B'): THREE.Vector3 { - const cells = this.siteCells[site] - const [c, r] = cells[Math.floor(Math.random() * cells.length)] - return this.cellCenter(c, r) - } - - /** Random walkable cell center within `radius` (world units) of a point. */ - randomSpotNear(p: THREE.Vector3, radius: number): THREE.Vector3 { - const [pc, pr] = this.worldToCell(p.x, p.z) - const cellRad = Math.ceil(radius / CELL) - for (let i = 0; i < 24; i++) { - const c = pc + Math.round((Math.random() * 2 - 1) * cellRad) - const r = pr + Math.round((Math.random() * 2 - 1) * cellRad) - if (this.isWalkableCell(c, r)) return this.cellCenter(c, r) - } - return p.clone() - } - - drawMinimap(ctx: CanvasRenderingContext2D, px: number) { - ctx.clearRect(0, 0, GRID * px, GRID * px) - for (let r = 0; r < GRID; r++) { - for (let c = 0; c < GRID; c++) { - const code = this.code(c, r) - if (code === Code.Wall) continue - let fill = 'rgba(219,197,150,0.85)' - if (code === Code.ASite || code === Code.BSite) fill = 'rgba(226,160,96,0.9)' - if (code === Code.TSpawn) fill = 'rgba(216,190,132,0.9)' - if (code === Code.CTSpawn) fill = 'rgba(180,198,216,0.9)' - if (code === Code.Door) fill = 'rgba(140,170,140,0.9)' - ctx.fillStyle = fill - ctx.fillRect(c * px, r * px, px, px) - if (this.crateCells.has(r * GRID + c)) { - ctx.fillStyle = 'rgba(120,95,55,0.9)' - ctx.fillRect(c * px + 1, r * px + 1, px - 2, px - 2) - } - } - } - ctx.font = `bold ${px * 5}px sans-serif` - ctx.textAlign = 'center' - ctx.textBaseline = 'middle' - ctx.fillStyle = 'rgba(80,50,20,0.8)' - ctx.fillText('A', 41.5 * px, 6 * px) - ctx.fillText('B', 7.5 * px, 7.5 * px) - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/nav.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/nav.ts deleted file mode 100644 index 9ab14f2..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/nav.ts +++ /dev/null @@ -1,155 +0,0 @@ -import * as THREE from 'three' -import { CELL, GRID, GameMap } from './map' -import type { PhysicsWorld } from './physics' - -const HALF = GRID / 2 - -/** Grid A* with octile heuristic + string-pulling smoothing. */ -export class Nav { - private map: GameMap - private physics: PhysicsWorld - private walkable: Uint8Array - - constructor(map: GameMap, physics: PhysicsWorld) { - this.map = map - this.physics = physics - this.walkable = new Uint8Array(GRID * GRID) - for (let r = 0; r < GRID; r++) { - for (let c = 0; c < GRID; c++) { - this.walkable[r * GRID + c] = map.isWalkableCell(c, r) ? 1 : 0 - } - } - } - - private ok(c: number, r: number): boolean { - return c >= 0 && r >= 0 && c < GRID && r < GRID && this.walkable[r * GRID + c] === 1 - } - - private nearestWalkable(c: number, r: number): [number, number] | null { - if (this.ok(c, r)) return [c, r] - for (let rad = 1; rad <= 6; rad++) { - for (let dr = -rad; dr <= rad; dr++) { - for (let dc = -rad; dc <= rad; dc++) { - if (Math.max(Math.abs(dc), Math.abs(dr)) !== rad) continue - if (this.ok(c + dc, r + dr)) return [c + dc, r + dr] - } - } - } - return null - } - - findPath(from: THREE.Vector3, to: THREE.Vector3): THREE.Vector3[] | null { - const s = this.nearestWalkable(...this.map.worldToCell(from.x, from.z)) - const e = this.nearestWalkable(...this.map.worldToCell(to.x, to.z)) - if (!s || !e) return null - const cells = this.aStar(s[0], s[1], e[0], e[1]) - if (!cells) return null - - const pts: THREE.Vector3[] = cells.map(i => this.map.cellCenter(i % GRID, Math.floor(i / GRID))) - pts.push(new THREE.Vector3(to.x, 0, to.z)) - - // string pulling - const smoothed: THREE.Vector3[] = [] - let i = 0 - const start = new THREE.Vector3(from.x, 0, from.z) - let cur = start - while (i < pts.length) { - let j = pts.length - 1 - let found = i - for (; j > i; j--) { - if (this.physics.walkClear(cur, pts[j], 0.45)) { found = j; break } - } - cur = pts[found] - smoothed.push(cur) - i = found + 1 - } - return smoothed - } - - private aStar(sc: number, sr: number, ec: number, er: number): number[] | null { - const n = GRID * GRID - const g = new Float32Array(n).fill(Infinity) - const came = new Int32Array(n).fill(-1) - const closed = new Uint8Array(n) - const start = sr * GRID + sc - const end = er * GRID + ec - g[start] = 0 - - // binary heap of [f, idx] - const heapF: number[] = [] - const heapI: number[] = [] - const push = (f: number, idx: number) => { - heapF.push(f); heapI.push(idx) - let i = heapF.length - 1 - while (i > 0) { - const p = (i - 1) >> 1 - if (heapF[p] <= heapF[i]) break - ;[heapF[p], heapF[i]] = [heapF[i], heapF[p]] - ;[heapI[p], heapI[i]] = [heapI[i], heapI[p]] - i = p - } - } - const pop = (): number => { - const top = heapI[0] - const lf = heapF.pop()!, li = heapI.pop()! - if (heapF.length > 0) { - heapF[0] = lf; heapI[0] = li - let i = 0 - for (;;) { - const l = i * 2 + 1, r = l + 1 - let m = i - if (l < heapF.length && heapF[l] < heapF[m]) m = l - if (r < heapF.length && heapF[r] < heapF[m]) m = r - if (m === i) break - ;[heapF[m], heapF[i]] = [heapF[i], heapF[m]] - ;[heapI[m], heapI[i]] = [heapI[i], heapI[m]] - i = m - } - } - return top - } - const h = (idx: number) => { - const dc = Math.abs((idx % GRID) - ec) - const dr = Math.abs(Math.floor(idx / GRID) - er) - return Math.max(dc, dr) + 0.414 * Math.min(dc, dr) - } - - push(h(start), start) - let expansions = 0 - while (heapF.length > 0 && expansions < 8000) { - const cur = pop() - if (cur === end) { - const path: number[] = [] - let c = end - while (c !== -1) { path.push(c); c = came[c] } - path.reverse() - return path - } - if (closed[cur]) continue - closed[cur] = 1 - expansions++ - const cc = cur % GRID, cr = Math.floor(cur / GRID) - for (let dr = -1; dr <= 1; dr++) { - for (let dc = -1; dc <= 1; dc++) { - if (dc === 0 && dr === 0) continue - const nc = cc + dc, nr = cr + dr - if (!this.ok(nc, nr)) continue - // no corner cutting - if (dc !== 0 && dr !== 0 && (!this.ok(cc + dc, cr) || !this.ok(cc, cr + dr))) continue - const ni = nr * GRID + nc - if (closed[ni]) continue - const cost = dc !== 0 && dr !== 0 ? 1.414 : 1 - const ng = g[cur] + cost - if (ng < g[ni]) { - g[ni] = ng - came[ni] = cur - push(ng + h(ni), ni) - } - } - } - } - return null - } -} - -export { CELL } diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/physics.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/physics.ts deleted file mode 100644 index cbfe584..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/physics.ts +++ /dev/null @@ -1,258 +0,0 @@ -import * as THREE from 'three' -import { CELL, GRID, WALL_H, GameMap, type AABB } from './map' -import type { BodyPart, SoldierBody } from './types' -import { GRAVITY } from './types' - -const HALF = GRID / 2 -const STEP = 0.35 // max ledge height walkable without jumping - -export interface HitboxDef { part: BodyPart; min: [number, number, number]; max: [number, number, number] } - -/** Local space, feet at origin, facing -Z. */ -export const HITBOXES: HitboxDef[] = [ - { part: 'head', min: [-0.15, 1.48, -0.16], max: [0.15, 1.8, 0.16] }, - { part: 'chest', min: [-0.24, 1.12, -0.15], max: [0.24, 1.48, 0.15] }, - { part: 'stomach', min: [-0.22, 0.86, -0.14], max: [0.22, 1.12, 0.14] }, - { part: 'arm', min: [-0.44, 1.0, -0.15], max: [-0.24, 1.48, 0.15] }, - { part: 'arm', min: [0.24, 1.0, -0.15], max: [0.44, 1.48, 0.15] }, - { part: 'leg', min: [-0.22, 0, -0.14], max: [-0.02, 0.9, 0.14] }, - { part: 'leg', min: [0.02, 0, -0.14], max: [0.22, 0.9, 0.14] }, -] - -export interface RayHit { - t: number - point: THREE.Vector3 - kind: 'wall' | 'crate' | 'door' | 'floor' | 'soldier' - soldier?: SoldierBody - part?: BodyPart -} - -export interface MovingBody { - pos: THREE.Vector3 // feet - vel: THREE.Vector3 - onGround: boolean - radius: number - height: number -} - -function rayAABB(ox: number, oy: number, oz: number, dx: number, dy: number, dz: number, box: AABB): number | null { - let tmin = 0, tmax = Infinity - const o = [ox, oy, oz], d = [dx, dy, dz] - const mn = [box.min.x, box.min.y, box.min.z], mx = [box.max.x, box.max.y, box.max.z] - for (let i = 0; i < 3; i++) { - if (Math.abs(d[i]) < 1e-9) { - if (o[i] < mn[i] || o[i] > mx[i]) return null - } else { - let t1 = (mn[i] - o[i]) / d[i] - let t2 = (mx[i] - o[i]) / d[i] - if (t1 > t2) { const tmp = t1; t1 = t2; t2 = tmp } - if (t1 > tmin) tmin = t1 - if (t2 < tmax) tmax = t2 - if (tmin > tmax) return null - } - } - return tmin -} - -export class PhysicsWorld { - map: GameMap - - constructor(map: GameMap) { - this.map = map - } - - /** Is a circle at (x,z) with feet at y clear of walls/crates/doors? */ - circleFree(x: number, z: number, r: number, feetY: number, ignoreDoors = false): boolean { - const cMin = Math.floor((x - r) / CELL + HALF), cMax = Math.floor((x + r) / CELL + HALF) - const rMin = Math.floor((z - r) / CELL + HALF), rMax = Math.floor((z + r) / CELL + HALF) - for (let cr = rMin; cr <= rMax; cr++) { - for (let cc = cMin; cc <= cMax; cc++) { - if (!this.map.isWall(cc, cr)) continue - if (this.circleHitsRect(x, z, r, (cc - HALF) * CELL, (cr - HALF) * CELL, (cc - HALF + 1) * CELL, (cr - HALF + 1) * CELL)) return false - } - } - for (const box of this.map.crates) { - if (box.max.y <= feetY + STEP) continue // can step onto / stand on it - if (this.circleHitsRect(x, z, r, box.min.x, box.min.z, box.max.x, box.max.z)) return false - } - if (!ignoreDoors) { - for (const d of this.map.doors) { - for (const box of d.colliders()) { - if (this.circleHitsRect(x, z, r, box.min.x, box.min.z, box.max.x, box.max.z)) return false - } - } - } - return true - } - - private circleHitsRect(x: number, z: number, r: number, x1: number, z1: number, x2: number, z2: number): boolean { - const nx = Math.max(x1, Math.min(x, x2)) - const nz = Math.max(z1, Math.min(z, z2)) - const dx = x - nx, dz = z - nz - return dx * dx + dz * dz < r * r - } - - /** Used by nav smoothing: walls + crates only (doors auto-open). */ - walkClear(a: THREE.Vector3, b: THREE.Vector3, radius: number): boolean { - const dx = b.x - a.x, dz = b.z - a.z - const dist = Math.hypot(dx, dz) - const steps = Math.max(1, Math.ceil(dist / 0.35)) - for (let i = 0; i <= steps; i++) { - const t = i / steps - if (!this.circleFree(a.x + dx * t, a.z + dz * t, radius, 0, true)) return false - } - return true - } - - moveBody(body: MovingBody, wishWorld: THREE.Vector3, speed: number, jump: boolean, dt: number) { - const accel = body.onGround ? 22 : 4 - const k = Math.min(1, accel * dt) - body.vel.x += (wishWorld.x * speed - body.vel.x) * k - body.vel.z += (wishWorld.z * speed - body.vel.z) * k - - if (jump && body.onGround) { - body.vel.y = 7.0 - body.onGround = false - } - - // axis-separated horizontal collision - const nx = body.pos.x + body.vel.x * dt - if (this.circleFree(nx, body.pos.z, body.radius, body.pos.y)) body.pos.x = nx - else body.vel.x = 0 - const nz = body.pos.z + body.vel.z * dt - if (this.circleFree(body.pos.x, nz, body.radius, body.pos.y)) body.pos.z = nz - else body.vel.z = 0 - - // vertical - const prevY = body.pos.y - body.vel.y -= GRAVITY * dt - body.pos.y += body.vel.y * dt - const ground = this.groundHeight(body.pos.x, body.pos.z, body.radius, prevY) - if (body.pos.y <= ground && body.vel.y <= 0) { - body.pos.y = ground - body.vel.y = 0 - body.onGround = true - } else { - body.onGround = false - } - } - - groundHeight(x: number, z: number, r: number, feetY: number): number { - let g = 0 - for (const box of this.map.crates) { - if (box.max.y > feetY + STEP) continue - if (this.circleHitsRect(x, z, r, box.min.x, box.min.z, box.max.x, box.max.z)) { - if (box.max.y > g) g = box.max.y - } - } - return g - } - - raycast( - origin: THREE.Vector3, - dir: THREE.Vector3, - maxDist: number, - soldiers?: SoldierBody[], - ignoreId?: number, - ignoreTeam?: string, - ): RayHit | null { - let best: RayHit | null = null - const consider = (t: number, kind: RayHit['kind'], soldier?: SoldierBody, part?: BodyPart) => { - if (t < 0 || t > maxDist) return - if (best && t >= best.t) return - best = { - t, kind, soldier, part, - point: new THREE.Vector3(origin.x + dir.x * t, origin.y + dir.y * t, origin.z + dir.z * t), - } - } - - // floor - if (dir.y < -1e-6) consider(-origin.y / dir.y, 'floor') - - // walls via DDA - const wt = this.wallRay(origin, dir, maxDist) - if (wt !== null) consider(wt, 'wall') - - // crates - for (const box of this.map.crates) { - const t = rayAABB(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, box) - if (t !== null) consider(t, 'crate') - } - - // door panels - for (const d of this.map.doors) { - for (const box of d.colliders()) { - const t = rayAABB(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, box) - if (t !== null) consider(t, 'door') - } - } - - // soldier hitboxes (ray transformed into each soldier's local yaw space) - if (soldiers) { - for (const s of soldiers) { - if (!s.alive || s.id === ignoreId) continue - if (ignoreTeam && s.team === ignoreTeam) continue - const cos = Math.cos(-s.yaw), sin = Math.sin(-s.yaw) - const rx = origin.x - s.pos.x, rz = origin.z - s.pos.z - const lox = rx * cos - rz * sin - const loz = rx * sin + rz * cos - const loy = origin.y - s.pos.y - const ldx = dir.x * cos - dir.z * sin - const ldz = dir.x * sin + dir.z * cos - for (const hb of HITBOXES) { - const t = rayAABB(lox, loy, loz, ldx, dir.y, ldz, { - min: new THREE.Vector3(hb.min[0], hb.min[1], hb.min[2]), - max: new THREE.Vector3(hb.max[0], hb.max[1], hb.max[2]), - }) - if (t !== null) consider(t, 'soldier', s, hb.part) - } - } - } - - return best - } - - private wallRay(origin: THREE.Vector3, dir: THREE.Vector3, maxDist: number): number | null { - let cx = Math.floor(origin.x / CELL + HALF) - let cz = Math.floor(origin.z / CELL + HALF) - const stepX = dir.x > 0 ? 1 : -1 - const stepZ = dir.z > 0 ? 1 : -1 - const tDeltaX = Math.abs(dir.x) > 1e-9 ? CELL / Math.abs(dir.x) : Infinity - const tDeltaZ = Math.abs(dir.z) > 1e-9 ? CELL / Math.abs(dir.z) : Infinity - const nextGridX = (cx - HALF + (stepX > 0 ? 1 : 0)) * CELL - const nextGridZ = (cz - HALF + (stepZ > 0 ? 1 : 0)) * CELL - let tMaxX = Math.abs(dir.x) > 1e-9 ? (nextGridX - origin.x) / dir.x : Infinity - let tMaxZ = Math.abs(dir.z) > 1e-9 ? (nextGridZ - origin.z) / dir.z : Infinity - - if (this.map.isWall(cx, cz)) return 0 - - let t = 0 - for (let i = 0; i < GRID * 3; i++) { - if (tMaxX < tMaxZ) { - t = tMaxX - tMaxX += tDeltaX - cx += stepX - } else { - t = tMaxZ - tMaxZ += tDeltaZ - cz += stepZ - } - if (t > maxDist) return null - if (this.map.isWall(cx, cz)) { - const y = origin.y + dir.y * t - if (y >= 0 && y <= WALL_H) return t - } - } - return null - } - - /** Line of sight between two points against static world only. */ - hasLOS(a: THREE.Vector3, b: THREE.Vector3): boolean { - const dir = new THREE.Vector3().subVectors(b, a) - const dist = dir.length() - if (dist < 1e-4) return true - dir.multiplyScalar(1 / dist) - const hit = this.raycast(a, dir, dist * 0.99) - return hit === null - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/soldier.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/soldier.ts deleted file mode 100644 index ab3fd73..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/soldier.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as THREE from 'three' -import { CharacterRig } from './character' -import { WEAPONS, WeaponState } from './weapons' -import { - BODY_HEIGHT, BODY_RADIUS, EYE_HEIGHT, - emptyControl, type Control, type Slot, type Team, type WeaponId, -} from './types' -import type { AIBrain } from './ai' - -export class Soldier { - id: number - name: string - originalName: string - team: Team - isPlayer = false - - pos = new THREE.Vector3() - vel = new THREE.Vector3() - yaw = 0 - pitch = 0 - onGround = true - radius = BODY_RADIUS - height = BODY_HEIGHT - - hp = 100 - armor = 0 - alive = true - kills = 0 - deaths = 0 - - weapons: Partial> = {} - slot: Slot = 'secondary' - scoped = false - switchCooldown = 0 - - hasBomb = false - channel: { kind: 'plant' | 'defuse'; t: number; total: number } | null = null - - control: Control = emptyControl() - brain: AIBrain | null = null - rig: CharacterRig - - recoilPitch = 0 - recoilYaw = 0 - stepAcc = 0 - /** buffered semi-auto trigger: a click stays valid for a short window */ - tapBuffer = 0 - lastSeenBy: Record = { CT: -99, T: -99 } - wasReloading = false - - constructor(id: number, name: string, team: Team) { - this.id = id - this.name = name - this.originalName = name - this.team = team - this.rig = new CharacterRig(team) - } - - get weapon(): WeaponState { - return this.weapons[this.slot] ?? this.weapons.knife! - } - - get eyePos(): THREE.Vector3 { - return new THREE.Vector3(this.pos.x, this.pos.y + EYE_HEIGHT, this.pos.z) - } - - /** View direction including recoil offset (recoil affects both camera and bullets). */ - viewDir(): THREE.Vector3 { - const yaw = this.yaw + this.recoilYaw - const pitch = THREE.MathUtils.clamp(this.pitch + this.recoilPitch, -1.55, 1.55) - const cp = Math.cos(pitch) - return new THREE.Vector3(-Math.sin(yaw) * cp, Math.sin(pitch), -Math.cos(yaw) * cp) - } - - rightDir(): THREE.Vector3 { - return new THREE.Vector3(Math.cos(this.yaw), 0, -Math.sin(this.yaw)) - } - - equip(primary: WeaponId | null, secondary: WeaponId, armor: number) { - this.weapons = { knife: new WeaponState(WEAPONS.knife) } - this.weapons.secondary = new WeaponState(WEAPONS[secondary]) - if (primary) this.weapons.primary = new WeaponState(WEAPONS[primary]) - this.slot = primary ? 'primary' : 'secondary' - this.armor = armor - this.scoped = false - this.rig.setWeapon(this.weapon.def.id) - } - - respawn(pos: THREE.Vector3, yaw: number) { - this.pos.copy(pos) - this.vel.set(0, 0, 0) - this.yaw = yaw - this.pitch = 0 - this.hp = 100 - this.alive = true - this.onGround = true - this.channel = null - this.hasBomb = false - this.recoilPitch = 0 - this.recoilYaw = 0 - this.scoped = false - this.control = emptyControl() - this.rig.spawnReset() - this.rig.setBomb(false) - } - - trySwitch(slot: Slot): boolean { - if (!this.alive || slot === this.slot || !this.weapons[slot]) return false - this.slot = slot - this.scoped = false - this.switchCooldown = 0.4 - this.weapon.cooldown = Math.max(this.weapon.cooldown, 0.4) - this.rig.setWeapon(this.weapon.def.id) - return true - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/store.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/store.ts deleted file mode 100644 index 2c56e47..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/store.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { HudState } from './types' - -export function initialHud(): HudState { - return { - phase: 'menu', - locked: false, - auto: false, - round: 1, - pistolRound: true, - ctScore: 0, - tScore: 0, - timeLeft: 0, - bombTimeLeft: null, - bombPlanted: false, - freezeLeft: 0, - winner: null, - winReason: '', - matchWinner: null, - playerTeam: 'CT', - loadout: 'rifle', - me: { - name: '你', team: 'CT', hp: 100, armor: 0, alive: true, - weaponName: '', weaponId: 'knife', mag: 0, reserve: 0, - reloading: false, scoped: false, hasBomb: false, spreadPx: 4, - }, - spectating: null, - channel: null, - centerHint: null, - killfeed: [], - hitmarkerAt: -99, - hitmarkerHead: false, - damageAt: -99, - } -} - -/** Tiny external store bridging the game loop and React (useSyncExternalStore). */ -export class HudStore { - state: HudState = initialHud() - private version = 0 - private listeners = new Set<() => void>() - - subscribe = (fn: () => void) => { - this.listeners.add(fn) - return () => { this.listeners.delete(fn) } - } - - getSnapshot = () => this.version - - bump() { - this.version++ - for (const fn of this.listeners) fn() - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/types.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/types.ts deleted file mode 100644 index dda84f3..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/types.ts +++ /dev/null @@ -1,106 +0,0 @@ -import * as THREE from 'three' - -export type Team = 'CT' | 'T' -export type Slot = 'primary' | 'secondary' | 'knife' -export type BodyPart = 'head' | 'chest' | 'stomach' | 'arm' | 'leg' -export type WeaponId = 'ak47' | 'm4a4' | 'awp' | 'glock' | 'usp' | 'deagle' | 'knife' -export type Phase = 'menu' | 'freeze' | 'live' | 'over' | 'matchover' -export type Loadout = 'rifle' | 'awp' - -/** Per-tick intent, produced by player input or an AI brain, consumed by physics/combat. */ -export interface Control { - moveX: number // strafe, +right - moveZ: number // +forward - jump: boolean - walk: boolean - fire: boolean // held - fireTap: boolean // edge-triggered (semi-auto) - altTap: boolean // scope toggle - reload: boolean - use: boolean // E held: plant / defuse - slot: Slot | null -} - -export function emptyControl(): Control { - return { - moveX: 0, moveZ: 0, jump: false, walk: false, - fire: false, fireTap: false, altTap: false, - reload: false, use: false, slot: null, - } -} - -export interface KillEntry { - id: number - attacker: string - attackerTeam: Team - victim: string - victimTeam: Team - weapon: string - headshot: boolean - t: number -} - -export interface HudState { - phase: Phase - locked: boolean - auto: boolean - round: number - pistolRound: boolean - ctScore: number - tScore: number - timeLeft: number - bombTimeLeft: number | null - bombPlanted: boolean - freezeLeft: number - winner: Team | null - winReason: string - matchWinner: Team | null - playerTeam: Team - loadout: Loadout - me: { - name: string - team: Team - hp: number - armor: number - alive: boolean - weaponName: string - weaponId: WeaponId - mag: number - reserve: number - reloading: boolean - scoped: boolean - hasBomb: boolean - spreadPx: number - } - spectating: { name: string; isSelf: boolean } | null - channel: { label: string; progress: number } | null - centerHint: string | null - killfeed: KillEntry[] - hitmarkerAt: number - hitmarkerHead: boolean - damageAt: number -} - -/** Minimal body info physics needs for hitbox raycasts (avoids circular imports). */ -export interface SoldierBody { - id: number - team: Team - alive: boolean - pos: THREE.Vector3 - yaw: number -} - -export const RUN_SPEED = 4.7 -export const GRAVITY = 20 -export const JUMP_VEL = 7.0 -export const EYE_HEIGHT = 1.62 -export const BODY_RADIUS = 0.4 -export const BODY_HEIGHT = 1.8 - -export const PLANT_TIME = 3.2 -export const DEFUSE_TIME = 7.0 -export const BOMB_FUSE = 40 -export const ROUND_TIME = 115 -export const FREEZE_TIME = 4 -export const ROUND_END_TIME = 5 -export const WIN_SCORE = 13 diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/viewmodel.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/viewmodel.ts deleted file mode 100644 index b3c72c7..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/viewmodel.ts +++ /dev/null @@ -1,202 +0,0 @@ -import * as THREE from 'three' -import type { WeaponId } from './types' - -function mat(color: number, metalness = 0.2): THREE.MeshStandardMaterial { - return new THREE.MeshStandardMaterial({ color, roughness: 0.6, metalness }) -} - -function box(w: number, h: number, d: number, m: THREE.Material): THREE.Mesh { - return new THREE.Mesh(new THREE.BoxGeometry(w, h, d), m) -} - -/** First-person weapon models, attached to the camera. Procedural geometry only. */ -export class ViewModel { - group = new THREE.Group() - private models = new Map() - private current: WeaponId = 'knife' - private kick = 0 - private raise = 1 - private slashT = 0 - private reloadT = 0 - private reloadDur = 0 - private bobPhase = 0 - private flash: THREE.Mesh - private flashT = 0 - - constructor(camera: THREE.Camera) { - this.group.position.set(0.26, -0.24, -0.5) - this.group.scale.setScalar(0.82) - camera.add(this.group) - - const skin = mat(0xd8b094, 0) - for (const id of ['ak47', 'm4a4', 'awp', 'glock', 'usp', 'deagle', 'knife'] as WeaponId[]) { - const g = this.build(id) - // hands - const handL = box(0.05, 0.05, 0.07, skin) - const handR = box(0.05, 0.05, 0.07, skin) - if (id === 'knife') { - handR.position.set(0, -0.03, 0.1) - g.add(handR) - } else { - handL.position.set(-0.01, -0.04, -0.22) - handR.position.set(0.01, -0.05, 0.05) - g.add(handL, handR) - } - g.visible = false - this.group.add(g) - this.models.set(id, g) - } - - this.flash = new THREE.Mesh( - new THREE.PlaneGeometry(0.16, 0.16), - new THREE.MeshBasicMaterial({ color: 0xffd080, transparent: true, opacity: 0, blending: THREE.AdditiveBlending, depthWrite: false }), - ) - this.flash.position.set(0, 0.02, -0.85) - this.group.add(this.flash) - this.setWeapon('knife', false) - } - - private build(id: WeaponId): THREE.Group { - const g = new THREE.Group() - const dark = mat(0x35353a) - const darker = mat(0x232326) - switch (id) { - case 'ak47': { - const wood = mat(0x6f4c2e, 0) - const recv = box(0.055, 0.09, 0.42, dark); recv.position.z = -0.1 - const guard = box(0.055, 0.07, 0.2, wood); guard.position.set(0, -0.005, -0.38) - const barrel = box(0.025, 0.025, 0.3, darker); barrel.position.z = -0.6 - const sight = box(0.012, 0.05, 0.012, darker); sight.position.set(0, 0.06, -0.68) - const magM = box(0.04, 0.18, 0.1, mat(0x8a6a3a)); magM.position.set(0, -0.13, -0.02); magM.rotation.x = 0.45 - const stock = box(0.045, 0.08, 0.2, wood); stock.position.set(0, -0.01, 0.2) - g.add(recv, guard, barrel, sight, magM, stock) - break - } - case 'm4a4': { - const recv = box(0.055, 0.09, 0.44, dark); recv.position.z = -0.12 - const rail = box(0.03, 0.03, 0.3, darker); rail.position.set(0, 0.065, -0.2) - const barrel = box(0.024, 0.024, 0.32, darker); barrel.position.z = -0.62 - const magM = box(0.04, 0.16, 0.08, darker); magM.position.set(0, -0.12, -0.06) - const stock = box(0.05, 0.075, 0.18, dark); stock.position.set(0, 0, 0.2) - const grip = box(0.03, 0.09, 0.045, darker); grip.position.set(0, -0.09, 0.08); grip.rotation.x = 0.3 - g.add(recv, rail, barrel, magM, stock, grip) - break - } - case 'awp': { - const olive = mat(0x4c5f3b, 0) - const body = box(0.055, 0.095, 0.6, olive); body.position.z = -0.15 - const barrel = box(0.022, 0.022, 0.5, darker); barrel.position.z = -0.78 - const muzzleBrake = box(0.035, 0.035, 0.06, darker); muzzleBrake.position.z = -1.0 - const scope = new THREE.Mesh(new THREE.CylinderGeometry(0.032, 0.032, 0.26, 10), darker) - scope.rotation.x = Math.PI / 2 - scope.position.set(0, 0.085, -0.15) - const stock = box(0.05, 0.1, 0.22, olive); stock.position.set(0, -0.01, 0.2) - const bolt = box(0.015, 0.015, 0.08, mat(0xa8a8b0, 0.7)); bolt.position.set(0.045, 0.03, 0.02) - g.add(body, barrel, muzzleBrake, scope, stock, bolt) - break - } - case 'glock': { - const slide = box(0.04, 0.055, 0.22, dark); slide.position.z = -0.05 - const frame = box(0.038, 0.05, 0.18, darker); frame.position.set(0, -0.045, -0.02) - const grip = box(0.036, 0.12, 0.055, darker); grip.position.set(0, -0.1, 0.05); grip.rotation.x = 0.25 - g.add(slide, frame, grip) - break - } - case 'usp': { - const slide = box(0.04, 0.055, 0.26, mat(0x4a4a52, 0.5)); slide.position.z = -0.07 - const supp = box(0.045, 0.045, 0.14, darker); supp.position.z = -0.27 - const grip = box(0.038, 0.12, 0.055, darker); grip.position.set(0, -0.1, 0.05); grip.rotation.x = 0.22 - g.add(slide, supp, grip) - break - } - case 'deagle': { - const silver = mat(0xb4b4bc, 0.8) - const slide = box(0.05, 0.07, 0.3, silver); slide.position.z = -0.08 - const grip = box(0.04, 0.13, 0.06, darker); grip.position.set(0, -0.1, 0.06); grip.rotation.x = 0.25 - g.add(slide, grip) - break - } - case 'knife': { - const blade = box(0.012, 0.04, 0.26, mat(0xd6dde4, 0.9)); blade.position.z = -0.16 - const edge = box(0.006, 0.012, 0.24, mat(0xf2f6fa, 1)); edge.position.set(0, -0.026, -0.15) - const guardK = box(0.04, 0.015, 0.02, darker); guardK.position.z = -0.02 - const handle = box(0.028, 0.045, 0.13, mat(0x2c2c30, 0)); handle.position.z = 0.06 - g.add(blade, edge, guardK, handle) - g.rotation.z = 0.25 - g.rotation.y = 0.28 - break - } - } - return g - } - - setWeapon(id: WeaponId, animate = true) { - if (id === this.current && animate) return - this.current = id - for (const [k, g] of this.models) g.visible = k === id - if (animate) this.raise = 0 - this.reloadT = 0 - this.reloadDur = 0 - } - - onFire(kickScale: number) { - if (this.current === 'knife') { - this.slashT = 0.3 - return - } - this.kick = Math.min(1.6, this.kick + 0.5 + kickScale * 18) - this.flashT = 0.05 - if (this.current !== 'awp') { - ;(this.flash.material as THREE.MeshBasicMaterial).opacity = 0.9 - } - } - - onReload(duration: number) { - this.reloadDur = duration - this.reloadT = 0.0001 - } - - update(dt: number, speed: number, onGround: boolean, scoped: boolean) { - this.kick *= Math.exp(-13 * dt) - this.raise = Math.min(1, this.raise + dt / 0.28) - this.flashT -= dt - if (this.flashT <= 0) (this.flash.material as THREE.MeshBasicMaterial).opacity = 0 - if (this.reloadDur > 0) { - this.reloadT += dt - if (this.reloadT >= this.reloadDur) { this.reloadT = 0; this.reloadDur = 0 } - } - - this.group.visible = !scoped - const speedRatio = onGround ? Math.min(1, speed / 4.7) : 0.2 - this.bobPhase += speed * dt * 1.9 - - let px = 0.26, py = -0.24, pz = -0.5 - let rx = 0, ry = 0, rz = 0 - py += Math.abs(Math.sin(this.bobPhase)) * 0.012 * speedRatio - 0.006 * speedRatio - px += Math.sin(this.bobPhase * 0.5) * 0.008 * speedRatio - pz += this.kick * 0.05 - rx += this.kick * 0.06 - py -= (1 - this.raise) * 0.3 - rx -= (1 - this.raise) * 0.6 - if (this.reloadDur > 0) { - const p = Math.sin(Math.PI * Math.min(1, this.reloadT / this.reloadDur)) - py -= p * 0.09 - rz += p * 0.5 - rx -= p * 0.25 - } - if (this.slashT > 0) { - this.slashT = Math.max(0, this.slashT - dt) - const p = 1 - this.slashT / 0.3 // 0 → 1 over the swing - const sweep = Math.sin(p * Math.PI) - // diagonal slash: wind up right, cut across to lower-left - px += 0.1 - p * 0.32 - py += 0.06 - p * 0.2 - pz -= sweep * 0.22 - ry += 0.5 - p * 1.1 - rz -= sweep * 0.9 - rx -= sweep * 0.35 - } - this.group.position.set(px, py, pz) - this.group.rotation.set(rx, ry, rz) - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/weapons.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/weapons.ts deleted file mode 100644 index d71e5fa..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/game/weapons.ts +++ /dev/null @@ -1,141 +0,0 @@ -import type { BodyPart, Slot, WeaponId } from './types' - -export interface WeaponDef { - id: WeaponId - name: string - slot: Slot - damage: number - auto: boolean - rpm: number - magSize: number - reserve: number - reloadTime: number - /** standing-still base inaccuracy, radians */ - spreadBase: number - /** extra inaccuracy per shot fired (bloom) */ - spreadPerShot: number - /** exponential bloom decay rate, 1/s */ - spreadDecay: number - /** extra spread at full run speed */ - spreadMove: number - /** camera kick per shot, radians */ - kickPitch: number - kickYaw: number - moveMult: number - /** damage kept when target has armor (higher = better penetration) */ - armorPen: number - sound: 'ak' | 'm4' | 'awp' | 'pistol' | 'glock' | 'deagle' | 'knife' - scopeFov?: number - spreadScoped?: number - range?: number -} - -export const WEAPONS: Record = { - ak47: { - id: 'ak47', name: 'AK-47', slot: 'primary', - damage: 36, auto: true, rpm: 600, magSize: 30, reserve: 90, reloadTime: 2.4, - spreadBase: 0.006, spreadPerShot: 0.011, spreadDecay: 5.5, spreadMove: 0.045, - kickPitch: 0.019, kickYaw: 0.006, moveMult: 0.92, armorPen: 0.775, sound: 'ak', - }, - m4a4: { - id: 'm4a4', name: 'M4A4', slot: 'primary', - damage: 33, auto: true, rpm: 666, magSize: 30, reserve: 90, reloadTime: 2.1, - spreadBase: 0.005, spreadPerShot: 0.007, spreadDecay: 6.5, spreadMove: 0.04, - kickPitch: 0.009, kickYaw: 0.004, moveMult: 0.94, armorPen: 0.7, sound: 'm4', - }, - awp: { - id: 'awp', name: 'AWP', slot: 'primary', - damage: 115, auto: false, rpm: 41, magSize: 5, reserve: 30, reloadTime: 3.6, - spreadBase: 0.07, spreadPerShot: 0.01, spreadDecay: 3, spreadMove: 0.09, - kickPitch: 0.032, kickYaw: 0.004, moveMult: 0.84, armorPen: 0.975, sound: 'awp', - scopeFov: 20, spreadScoped: 0.0012, - }, - glock: { - id: 'glock', name: 'Glock-18', slot: 'secondary', - damage: 26, auto: false, rpm: 400, magSize: 20, reserve: 120, reloadTime: 2.2, - spreadBase: 0.009, spreadPerShot: 0.012, spreadDecay: 7, spreadMove: 0.02, - kickPitch: 0.008, kickYaw: 0.003, moveMult: 1.0, armorPen: 0.47, sound: 'glock', - }, - usp: { - id: 'usp', name: 'USP-S', slot: 'secondary', - damage: 33, auto: false, rpm: 352, magSize: 12, reserve: 24, reloadTime: 2.2, - spreadBase: 0.007, spreadPerShot: 0.011, spreadDecay: 7, spreadMove: 0.02, - kickPitch: 0.009, kickYaw: 0.003, moveMult: 1.0, armorPen: 0.505, sound: 'pistol', - }, - deagle: { - id: 'deagle', name: 'Desert Eagle', slot: 'secondary', - damage: 53, auto: false, rpm: 267, magSize: 7, reserve: 35, reloadTime: 2.2, - spreadBase: 0.012, spreadPerShot: 0.042, spreadDecay: 4.5, spreadMove: 0.05, - kickPitch: 0.028, kickYaw: 0.008, moveMult: 0.96, armorPen: 0.8, sound: 'deagle', - }, - knife: { - id: 'knife', name: '军刀', slot: 'knife', - damage: 45, auto: true, rpm: 120, magSize: 0, reserve: 0, reloadTime: 0, - spreadBase: 0, spreadPerShot: 0, spreadDecay: 1, spreadMove: 0, - kickPitch: 0.004, kickYaw: 0, moveMult: 1.05, armorPen: 0.85, sound: 'knife', - range: 2.2, - }, -} - -/** 头部伤害为身体(胸)的两倍,其余部位各不相同。 */ -export const PART_MULT: Record = { - head: 2.0, - chest: 1.0, - stomach: 1.25, - arm: 0.85, - leg: 0.7, -} - -export class WeaponState { - def: WeaponDef - mag: number - reserve: number - cooldown = 0 - bloom = 0 - reloadLeft = 0 - - constructor(def: WeaponDef) { - this.def = def - this.mag = def.magSize - this.reserve = def.reserve - } - - get reloading() { return this.reloadLeft > 0 } - get isKnife() { return this.def.id === 'knife' } - - /** Returns true the tick a reload completes. */ - update(dt: number): boolean { - if (this.cooldown > 0) this.cooldown -= dt - this.bloom *= Math.exp(-this.def.spreadDecay * dt) - if (this.reloadLeft > 0) { - this.reloadLeft -= dt - if (this.reloadLeft <= 0) { - this.reloadLeft = 0 - const take = Math.min(this.def.magSize - this.mag, this.reserve) - this.mag += take - this.reserve -= take - this.bloom = 0 - return true - } - } - return false - } - - canFire(): boolean { - if (this.reloading || this.cooldown > 0) return false - return this.isKnife || this.mag > 0 - } - - onFire() { - if (!this.isKnife) this.mag-- - this.cooldown = 60 / this.def.rpm - this.bloom = Math.min(this.bloom + this.def.spreadPerShot, 0.08) - } - - startReload(): boolean { - if (this.isKnife || this.reloading) return false - if (this.mag >= this.def.magSize || this.reserve <= 0) return false - this.reloadLeft = this.def.reloadTime - return true - } -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/main.tsx b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/main.tsx deleted file mode 100644 index da1742b..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { createRoot } from 'react-dom/client' -import App from './App' -import './ui/hud.css' - -createRoot(document.getElementById('root')!).render() diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/HUD.tsx b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/HUD.tsx deleted file mode 100644 index 0f0fe15..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/HUD.tsx +++ /dev/null @@ -1,290 +0,0 @@ -import { useEffect, useRef, useSyncExternalStore } from 'react' -import type { Engine } from '../game/engine' -import { GRID } from '../game/map' -import type { HudState, Team } from '../game/types' - -const MINIMAP_PX = 4 // px per cell - -function fmtTime(t: number): string { - const s = Math.max(0, Math.ceil(t)) - return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}` -} - -function Minimap({ engine }: { engine: Engine }) { - const bgRef = useRef(null) - const fgRef = useRef(null) - - useEffect(() => { - const bg = bgRef.current! - engine.map.drawMinimap(bg.getContext('2d')!, MINIMAP_PX) - - let raf = 0 - const draw = () => { - raf = requestAnimationFrame(draw) - const fg = fgRef.current - if (!fg) return - const ctx = fg.getContext('2d')! - const size = GRID * MINIMAP_PX - ctx.clearRect(0, 0, size, size) - const info = engine.minimapInfo() - const toPx = (x: number, z: number): [number, number] => [ - (x / 2.5 + GRID / 2) * MINIMAP_PX, - (z / 2.5 + GRID / 2) * MINIMAP_PX, - ] - - // bomb - const bomb = info.bomb - let bombPos = bomb.plantedPos ?? bomb.droppedPos - if (!bombPos && bomb.carrierId !== null) { - const carrier = info.soldiers[bomb.carrierId] - if (carrier && (carrier.team === info.playerTeam || carrier.lastSeenBy[info.playerTeam] > info.time - 2)) { - bombPos = carrier.pos - } - } - if (bombPos && (bomb.plantedPos ? Math.sin(info.time * 10) > -0.4 : true)) { - const [bx, bz] = toPx(bombPos.x, bombPos.z) - ctx.fillStyle = '#ff7828' - ctx.fillRect(bx - 4, bz - 4, 8, 8) - ctx.fillStyle = '#000' - ctx.font = 'bold 7px sans-serif' - ctx.textAlign = 'center' - ctx.fillText('C4', bx, bz + 2.5) - } - - for (const s of info.soldiers) { - if (!s.alive) continue - const mine = s.team === info.playerTeam - const seen = s.lastSeenBy[info.playerTeam] > info.time - 1.6 - if (!mine && !seen) continue - const [px, pz] = toPx(s.pos.x, s.pos.z) - if (s.id === info.viewedId) { - // white arrow with view direction - ctx.save() - ctx.translate(px, pz) - ctx.rotate(-s.yaw) - ctx.fillStyle = '#ffffff' - ctx.beginPath() - ctx.moveTo(0, -6) - ctx.lineTo(4.4, 4.4) - ctx.lineTo(0, 2) - ctx.lineTo(-4.4, 4.4) - ctx.closePath() - ctx.fill() - ctx.restore() - } else { - ctx.fillStyle = mine ? '#57c46a' : '#e84c3d' - ctx.beginPath() - ctx.arc(px, pz, 3.4, 0, Math.PI * 2) - ctx.fill() - } - } - } - raf = requestAnimationFrame(draw) - return () => cancelAnimationFrame(raf) - }, [engine]) - - const size = GRID * MINIMAP_PX - return ( -
- - -
- ) -} - -function Crosshair({ st }: { st: HudState }) { - if (st.me.scoped) return null - if (!st.me.alive) return null - if (st.me.weaponId === 'awp') { - // unscoped AWP: big circle = inaccurate - return
- } - const gap = Math.min(40, st.me.spreadPx) - const len = 9 - return ( -
-
-
-
-
-
-
- ) -} - -function Scope() { - return ( -
-
-
-
-
- ) -} - -function TeamTag({ team }: { team: Team }) { - return {team} -} - -export default function HUD({ engine }: { engine: Engine }) { - useSyncExternalStore(engine.hud.subscribe, engine.hud.getSnapshot) - const st = engine.hud.state - const now = engine.time - - if (st.phase === 'menu') { - return ( -
-

DUST II

-

5v5 炸弹模式 · 三维第一人称 · 纯代码生成

-
- - -
- -
- WASD 移动空格 跳跃Shift 静步 - 鼠标左键 开火右键 AWP 开镜R 换弹 - 1/2/3 切枪E 安放 / 拆除B 购买阶段换 AWP -
-
- ) - } - - const dmgFlash = now - st.damageAt < 0.4 - const hitAge = now - st.hitmarkerAt - - return ( -
- {st.me.scoped && } - - - {hitAge < 0.25 && ( -
- -
- )} - {dmgFlash &&
} - - {/* top bar */} -
-
{st.ctScore}
-
- {st.bombPlanted - ? 💣 {Math.ceil(st.bombTimeLeft ?? 0)} - : {st.phase === 'freeze' ? fmtTime(st.freezeLeft) : fmtTime(st.timeLeft)}} -
回合 {st.round}{st.pistolRound ? ' · 手枪局' : ''}
-
-
{st.tScore}
-
- - - - {/* killfeed */} -
- {st.killfeed.map(k => ( -
- {k.attacker} - {k.weapon}{k.headshot ? ' ◎' : ''} - {k.victim} -
- ))} -
- - {/* bottom left: hp / armor */} - {st.me.alive && ( -
-
- + - {st.me.hp} -
-
-
- 🛡 - {st.me.armor} -
-
- {st.me.hasBomb &&
携带 C4
} -
- )} - - {/* bottom right: ammo */} - {st.me.alive && ( -
-
{st.me.weaponName}{st.me.reloading ? '(换弹中…)' : ''}
- {st.me.weaponId !== 'knife' && ( -
- {st.me.mag} - / - {st.me.reserve} -
- )} -
- )} - - {/* center messages */} -
- {st.phase === 'freeze' && ( -
-
准备阶段 · {Math.ceil(st.freezeLeft)}s
- {!st.pistolRound &&
按 B 切换主武器:当前 {st.loadout === 'awp' ? 'AWP' : '步枪'}
} - {st.pistolRound &&
手枪局 — {st.playerTeam === 'T' ? 'Glock-18' : 'USP-S'},无护甲
} -
- )} - {st.channel && ( -
-
{st.channel.label}
-
-
- )} - {st.centerHint && !st.channel &&
{st.centerHint}
} - {st.bombPlanted && st.phase === 'live' &&
C4 已安放
} - {st.phase === 'over' && st.winner && ( -
-
{st.winner} 获胜
-
{st.winReason}
-
- )} -
- - {/* spectate bar */} - {st.spectating && st.phase === 'live' && ( -
- {st.spectating.isSelf - ? 你已阵亡 — 正在寻找存活队友… - : <> - 观战中:{st.spectating.name} - ←/→ 或 左键 切换 · E 接管该队友 - } -
- )} - - {/* pause overlay (pointer unlocked mid-game) */} - {!st.locked && !st.auto && st.phase !== 'matchover' && ( -
engine.requestLock()}> -
-

已暂停 / 鼠标未锁定

-

点击任意处继续(锁定鼠标)

- -
-
- )} - - {st.phase === 'matchover' && st.matchWinner && ( -
-
-

比赛结束 — {st.matchWinner} {st.matchWinner === st.playerTeam ? '胜利 🏆' : '获胜'}

-

CT {st.ctScore} : {st.tScore} T

- - -
-
- )} -
- ) -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/hud.css b/outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/hud.css deleted file mode 100644 index c03f732..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/src/ui/hud.css +++ /dev/null @@ -1,114 +0,0 @@ -* { box-sizing: border-box; } - -.app { position: relative; width: 100%; height: 100%; font-family: -apple-system, "PingFang SC", "Segoe UI", Roboto, sans-serif; user-select: none; } -.viewport { position: absolute; inset: 0; } -.viewport canvas { display: block; } - -.hud { position: absolute; inset: 0; pointer-events: none; color: #eee; } -.overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: auto; } - -/* ---------- menu ---------- */ -.menu { background: linear-gradient(180deg, rgba(10,14,20,0.55), rgba(10,14,20,0.82)); } -.menu h1 { font-size: 84px; margin: 0; letter-spacing: 22px; color: #f2e3c2; text-shadow: 0 4px 24px rgba(0,0,0,0.6); font-weight: 800; } -.menu .subtitle { color: #b8c4d0; letter-spacing: 4px; margin: 4px 0 42px; } -.team-select { display: flex; gap: 28px; } -.team-card { width: 250px; padding: 26px 22px; border-radius: 10px; border: 1px solid rgba(255,255,255,0.18); cursor: pointer; text-align: left; transition: transform 0.12s, box-shadow 0.12s; color: #fff; } -.team-card:hover { transform: translateY(-4px); box-shadow: 0 12px 34px rgba(0,0,0,0.5); } -.team-card.ct { background: linear-gradient(160deg, #2c4a66, #1a2c3e); } -.team-card.t { background: linear-gradient(160deg, #7a5c30, #4a3820); } -.team-name { display: block; font-size: 26px; font-weight: 700; margin-bottom: 10px; } -.team-desc { display: block; font-size: 13px; line-height: 1.7; color: rgba(255,255,255,0.75); } -.spectate-btn { margin-top: 26px; background: none; border: 1px solid rgba(255,255,255,0.3); color: #b8c4d0; padding: 9px 26px; border-radius: 6px; cursor: pointer; font-size: 13px; } -.spectate-btn:hover { border-color: #fff; color: #fff; } -.controls-help { margin-top: 40px; display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; max-width: 640px; color: #8a97a5; font-size: 12.5px; } -.controls-help span { background: rgba(255,255,255,0.07); padding: 5px 12px; border-radius: 4px; } - -/* ---------- crosshair ---------- */ -.crosshair { position: absolute; inset: 0; } -.ch-dot { position: absolute; left: 50%; top: 50%; width: 2px; height: 2px; background: #4dff9d; transform: translate(-50%, -50%); box-shadow: 0 0 2px #000; } -.ch-line { position: absolute; background: #4dff9d; box-shadow: 0 0 2px rgba(0,0,0,0.9); } -.crosshair-circle { position: absolute; left: 50%; top: 50%; width: 120px; height: 120px; border: 1.5px dashed rgba(255,255,255,0.5); border-radius: 50%; transform: translate(-50%, -50%); } - -/* ---------- scope ---------- */ -.scope { position: absolute; inset: 0; } -.scope-cutout { position: absolute; inset: 0; background: radial-gradient(circle at center, transparent 0, transparent 33vmin, rgba(0,0,0,0.985) 34vmin); } -.scope-hline { position: absolute; top: 50%; left: 0; right: 0; height: 1.5px; background: rgba(0,0,0,0.9); } -.scope-vline { position: absolute; left: 50%; top: 0; bottom: 0; width: 1.5px; background: rgba(0,0,0,0.9); } - -/* ---------- hitmarker / damage ---------- */ -.hitmarker span { position: absolute; left: 50%; top: 50%; width: 2.5px; height: 10px; background: #fff; } -.hitmarker.head span { background: #ff5544; } -.hitmarker span:nth-child(1) { transform: translate(-50%,-50%) rotate(45deg) translateY(-11px); } -.hitmarker span:nth-child(2) { transform: translate(-50%,-50%) rotate(135deg) translateY(-11px); } -.hitmarker span:nth-child(3) { transform: translate(-50%,-50%) rotate(225deg) translateY(-11px); } -.hitmarker span:nth-child(4) { transform: translate(-50%,-50%) rotate(315deg) translateY(-11px); } -.damage-flash { position: absolute; inset: 0; box-shadow: inset 0 0 140px 40px rgba(200,20,20,0.55); } - -/* ---------- top bar ---------- */ -.topbar { position: absolute; top: 14px; left: 50%; transform: translateX(-50%); display: flex; align-items: stretch; gap: 2px; } -.score { min-width: 58px; display: flex; align-items: center; justify-content: center; font-size: 30px; font-weight: 800; padding: 4px 10px; } -.ct-score { background: rgba(58,110,165,0.85); border-radius: 6px 0 0 6px; } -.t-score { background: rgba(196,142,54,0.85); border-radius: 0 6px 6px 0; } -.timer { background: rgba(12,16,22,0.82); padding: 5px 18px; text-align: center; font-size: 21px; font-weight: 700; min-width: 96px; } -.timer .bomb-timer { color: #ff7828; } -.round-label { font-size: 10.5px; font-weight: 400; color: #93a1af; margin-top: 1px; } - -/* ---------- minimap ---------- */ -.minimap { position: absolute; top: 14px; left: 14px; background: rgba(10,13,18,0.72); border: 1px solid rgba(255,255,255,0.14); border-radius: 6px; padding: 4px; } -.minimap canvas { display: block; } -.minimap canvas + canvas { position: absolute; top: 4px; left: 4px; } - -/* ---------- killfeed ---------- */ -.killfeed { position: absolute; top: 14px; right: 14px; display: flex; flex-direction: column; gap: 5px; align-items: flex-end; } -.kf-entry { background: rgba(10,13,18,0.78); border-radius: 4px; padding: 5px 11px; font-size: 13px; font-weight: 600; display: flex; gap: 8px; } -.kf-ct { color: #6fa8dc; } -.kf-t { color: #e0aa4e; } -.kf-weapon { color: #cfd6dd; font-weight: 400; font-size: 12px; align-self: center; } - -/* ---------- vitals ---------- */ -.vitals { position: absolute; left: 18px; bottom: 18px; display: flex; gap: 22px; align-items: flex-end; } -.vital { background: rgba(10,13,18,0.72); border-radius: 6px; padding: 8px 14px; display: flex; align-items: center; gap: 9px; min-width: 130px; } -.vital-icon { font-size: 15px; color: #aab7c4; } -.vital-num { font-size: 26px; font-weight: 800; min-width: 44px; } -.vital-bar { flex: 1; height: 4px; background: rgba(255,255,255,0.15); border-radius: 2px; overflow: hidden; min-width: 40px; } -.vital-fill { height: 100%; border-radius: 2px; transition: width 0.15s; } -.vital-fill.hp { background: #57c46a; } -.vital-fill.armor { background: #6fa8dc; } -.carrying-bomb { background: rgba(180,80,20,0.85); padding: 8px 14px; border-radius: 6px; font-weight: 700; font-size: 14px; } - -/* ---------- ammo ---------- */ -.ammo { position: absolute; right: 18px; bottom: 18px; text-align: right; background: rgba(10,13,18,0.72); border-radius: 6px; padding: 10px 16px; } -.weapon-name { font-size: 13px; color: #aab7c4; letter-spacing: 1px; margin-bottom: 2px; } -.ammo-nums { font-weight: 800; } -.ammo-mag { font-size: 34px; } -.ammo-sep { font-size: 20px; color: #66727e; margin: 0 6px; } -.ammo-reserve { font-size: 20px; color: #93a1af; } - -/* ---------- center stack ---------- */ -.center-stack { position: absolute; left: 50%; top: 58%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 12px; } -.banner { text-align: center; background: rgba(10,13,18,0.8); border-radius: 8px; padding: 12px 34px; } -.banner-title { font-size: 24px; font-weight: 800; letter-spacing: 2px; } -.banner-sub { font-size: 13px; color: #aab7c4; margin-top: 4px; } -.banner.winner.ct .banner-title { color: #6fa8dc; } -.banner.winner.t .banner-title { color: #e0aa4e; } -.channel { width: 300px; background: rgba(10,13,18,0.8); border-radius: 8px; padding: 12px 18px; } -.channel-label { font-size: 14px; font-weight: 700; margin-bottom: 8px; text-align: center; } -.channel-bar { height: 8px; background: rgba(255,255,255,0.15); border-radius: 4px; overflow: hidden; } -.channel-bar div { height: 100%; background: #ff7828; } -.hint { background: rgba(10,13,18,0.8); padding: 8px 22px; border-radius: 6px; font-size: 15px; font-weight: 600; color: #ffd28a; } -.planted-note { color: #ff7828; font-weight: 700; font-size: 13px; letter-spacing: 2px; text-shadow: 0 1px 4px #000; } - -/* ---------- spectate ---------- */ -.spectate-bar { position: absolute; left: 50%; bottom: 90px; transform: translateX(-50%); background: rgba(10,13,18,0.85); border: 1px solid rgba(255,255,255,0.16); padding: 12px 26px; border-radius: 8px; display: flex; flex-direction: column; align-items: center; gap: 5px; font-size: 15px; } -.spec-keys { font-size: 12px; color: #93a1af; } -.teamtag { font-size: 11px; font-weight: 800; padding: 1px 7px; border-radius: 3px; margin-left: 4px; } -.teamtag.ct { background: #3a6ea5; } -.teamtag.t { background: #c48e36; } - -/* ---------- pause / matchover ---------- */ -.pause { background: rgba(6,8,11,0.6); cursor: pointer; } -.pause-box { background: rgba(14,18,24,0.95); border: 1px solid rgba(255,255,255,0.15); border-radius: 12px; padding: 34px 48px; text-align: center; } -.pause-box h2 { margin: 0 0 10px; font-size: 22px; } -.pause-box p { color: #93a1af; margin: 0 0 20px; } -.pause-box button { display: block; width: 100%; margin-top: 10px; background: rgba(255,255,255,0.1); color: #eee; border: 1px solid rgba(255,255,255,0.25); padding: 10px 0; border-radius: 6px; cursor: pointer; font-size: 14px; } -.pause-box button:hover { background: rgba(255,255,255,0.2); } diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/tsconfig.json b/outputs/claude-fable-5/claude-code-high/cs-dust2/tsconfig.json deleted file mode 100644 index b6800d3..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/outputs/claude-fable-5/claude-code-high/cs-dust2/vite.config.ts b/outputs/claude-fable-5/claude-code-high/cs-dust2/vite.config.ts deleted file mode 100644 index 9d1138f..0000000 --- a/outputs/claude-fable-5/claude-code-high/cs-dust2/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -export default defineConfig({ - plugins: [react()], - server: { port: 5173 }, -}) diff --git a/outputs/claude-fable-5/claude-code-max/mythos-craft.html b/outputs/claude-fable-5/claude-code-max/mythos-craft.html deleted file mode 100644 index 65e7fe1..0000000 --- a/outputs/claude-fable-5/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,1317 +0,0 @@ - - - - - -神话方块世界 MythCraft - - - -
-
-
-
-
-
-
-
-
-
-

神话方块世界

-
MYTHCRAFT · 柏林噪声无限地形 · 一次性生成的单文件体素世界
-
-
探索散落大地的 十大神话奇观
-
-
-
移动 / 跳跃W A S D · 空格
-
环视鼠标
-
破坏方块左键
-
放置方块右键
-
选择方块滚轮 · 1-9
-
疾跑 / 潜行Shift / C
-
飞行开关(空格升 C 降)F
-
回到出生点 / 视距R · - =
-
-
-
-
正在唤醒诸神…
-
- -
单文件 HTML · Three.js · Perlin Noise · 程序化像素纹理 · 种子 20260610
-
-
-
- - - - diff --git a/outputs/claude-fable-5/claude-code-max/pelican-cycling.svg b/outputs/claude-fable-5/claude-code-max/pelican-cycling.svg deleted file mode 100644 index ee3840b..0000000 --- a/outputs/claude-fable-5/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,370 +0,0 @@ - - 海边骑行的鹈鹕 · A pelican riding a bicycle by the sea - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-fable-5/claude-code-xhigh/skeleton-watch.html b/outputs/claude-fable-5/claude-code-xhigh/skeleton-watch.html deleted file mode 100644 index b1eb4fd..0000000 --- a/outputs/claude-fable-5/claude-code-xhigh/skeleton-watch.html +++ /dev/null @@ -1,1264 +0,0 @@ - - - - - -AUREL & CIE — Calibre AC-500 Squelette 镂空机械腕表 - - - - - -
- -
-

AUREL & CIE

-

CALIBRE AC-500 · SQUELETTE 镂空机芯

-
-
- -
- -
-
机 芯 资 料
-
-
-
机芯型号
Calibre AC-500
-
类型
手动上链 · 全镂空
-
振频
28,800 vph · 4 Hz
-
宝石数
23 石
-
动力储存
约 72 小时
-
零件数
218 枚
-
表壳直径
42 mm
-
修饰
日内瓦纹 · 手工倒角
-
-
-
— 探索机芯 —
-
Interactive Movement
-
将光标悬停于任意零件可查看其名称;点击零件可在此处阅读详细介绍。开启「爆炸视图」可逐层分解整枚机芯,开启「零件标注」可显示主要部件的标签。
-
-
-
- - -
- - - - - -
- -
-
拖动 旋转视角 · 滚轮 缩放 · 悬停 识别零件 · 点击 查看详情
- -
-
AUREL & CIE
-
HAUTE HORLOGERIE · GENÈVE
-
-
- - - - diff --git a/outputs/claude-fable-5/claude-web-app-max/mythos-craft.html b/outputs/claude-fable-5/claude-web-app-max/mythos-craft.html deleted file mode 100644 index 6a4ddc4..0000000 --- a/outputs/claude-fable-5/claude-web-app-max/mythos-craft.html +++ /dev/null @@ -1,1505 +0,0 @@ - - - - - -MYTHOS CRAFT · 神话境界 - - - - -
- - -
- -
-
-

神话境界

-
MYTHOS · CRAFT
-

-
-
-
-
-
铸造世界中 … 0%
-
- -
-
-
-
- -
-
-
X: @Nag1ovo
-
-
-
-
-
- - - - - diff --git a/outputs/claude-fable-5/claude-web-app-max/pelican-cycling.svg b/outputs/claude-fable-5/claude-web-app-max/pelican-cycling.svg deleted file mode 100644 index 1658b55..0000000 --- a/outputs/claude-fable-5/claude-web-app-max/pelican-cycling.svg +++ /dev/null @@ -1,177 +0,0 @@ - -鹈鹕在海边骑自行车 -金色黄昏下,一只白鹈鹕系着蓝围巾,骑着红色沙滩自行车沿海滩飞驰,嘴里叼着鱼,车篮里还有一条。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/claude-fable-5/cursor-high/mythos-craft.html b/outputs/claude-fable-5/cursor-high/mythos-craft.html deleted file mode 100644 index 4ad17fe..0000000 --- a/outputs/claude-fable-5/cursor-high/mythos-craft.html +++ /dev/null @@ -1,1171 +0,0 @@ - - - - - -MythosCraft — 神话幻想方块世界 - - - - - -
-

MYTHOS CRAFT

-

神 话 幻 想 方 块 世 界

-
- WASD 移动  ·  鼠标 环视  ·  空格 跳跃 / 上升  ·  Shift 疾跑 / 下降
- 左键 破坏方块  ·  右键 放置方块  ·  1–9 / 滚轮 选择方块
- F 切换飞行  ·  T 传送至下一处远古奇观  ·  Esc 暂停 -
-
✦ 太阳神殿 · 世界之树 · 远古金字塔 · 奥术之塔 · 浮空圣岛 · 巨石阵 · 黑曜石之门 ✦
-
— 点 击 进 入 世 界 —
-
- -
-
-
-
-
-
- - - - - - diff --git a/outputs/claude-fable-5/cursor-high/pelican-cycling.svg b/outputs/claude-fable-5/cursor-high/pelican-cycling.svg deleted file mode 100644 index 4aa4181..0000000 --- a/outputs/claude-fable-5/cursor-high/pelican-cycling.svg +++ /dev/null @@ -1,437 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-haiku-4-5/claude-code-default/mythos-craft.html b/outputs/claude-haiku-4-5/claude-code-default/mythos-craft.html deleted file mode 100644 index 6969bad..0000000 --- a/outputs/claude-haiku-4-5/claude-code-default/mythos-craft.html +++ /dev/null @@ -1,712 +0,0 @@ - - - - - - 魔幻世界 - Minecraft克隆版 - - - - -
-
-

魔幻世界

-

移动: WASD | 跳跃: 空格

-

鼠标: 环视 | 左键: 破坏 | 右键: 放置

-

位置: (0, 0, 0)

-

方块: 无

-

FPS: 0

-
- - - - - diff --git a/outputs/claude-haiku-4-5/claude-code-default/pelican-cycling.svg b/outputs/claude-haiku-4-5/claude-code-default/pelican-cycling.svg deleted file mode 100644 index 642790b..0000000 --- a/outputs/claude-haiku-4-5/claude-code-default/pelican-cycling.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/claude-opus-4-5/cursor-thinking/mythos-craft.html b/outputs/claude-opus-4-5/cursor-thinking/mythos-craft.html deleted file mode 100644 index dd7171c..0000000 --- a/outputs/claude-opus-4-5/cursor-thinking/mythos-craft.html +++ /dev/null @@ -1,1718 +0,0 @@ - - - - - - MythosCraft - A Mythical Voxel World - - - -
-

MythosCraft

-

A Mythical Voxel World of Ancient Wonders

- -
-
WASD - Move | Space - Jump | Shift - Descend
-
Mouse - Look Around | Scroll - Select Block
-
Left Click - Break Block | Right Click - Place Block
-
1-9 - Quick Select Block
-
-
-

Generating mythical realm...

- -
-
-

MythosCraft

-
Position: 0, 0, 0
-
FPS: 0
-
-
- - - - - diff --git a/outputs/claude-opus-4-5/cursor-thinking/pelican-cycling.svg b/outputs/claude-opus-4-5/cursor-thinking/pelican-cycling.svg deleted file mode 100644 index 850c56a..0000000 --- a/outputs/claude-opus-4-5/cursor-thinking/pelican-cycling.svg +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/claude-opus-4-6/claude-code-max/pelican-cycling.svg b/outputs/claude-opus-4-6/claude-code-max/pelican-cycling.svg deleted file mode 100644 index d0a554b..0000000 --- a/outputs/claude-opus-4-6/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,379 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/claude-opus-4-6/claude-code-max/skeleton-watch.html b/outputs/claude-opus-4-6/claude-code-max/skeleton-watch.html deleted file mode 100644 index bf401b4..0000000 --- a/outputs/claude-opus-4-6/claude-code-max/skeleton-watch.html +++ /dev/null @@ -1,1103 +0,0 @@ - - - - - -Skeleton Mechanical Watch - - - - -
-

Calibre NB-01

Squelette · Manufacture

-
- - - - -
-
-
-

Movement

-
CalibreNB-01 Squelette
-
TypeManual Winding
-
Frequency28,800 vph / 4 Hz
-
Jewels27 Rubies
-
Power Reserve72 h
-
Diameter30.4 mm
-
Height5.65 mm
-
Components268
-
DecorationCôtes de Genève
-
Case42 mm, 316L Steel
-
CrystalSapphire, AR Coated
-
-
- - - - - diff --git a/outputs/claude-opus-4-6/cursor-max/mythos-craft.html b/outputs/claude-opus-4-6/cursor-max/mythos-craft.html deleted file mode 100644 index 69c507d..0000000 --- a/outputs/claude-opus-4-6/cursor-max/mythos-craft.html +++ /dev/null @@ -1,877 +0,0 @@ - - - - - -Minecraft Clone - - - -
-

MINECRAFT

-
-W A S D Move / Space Jump / Shift Descend
-Mouse Look / Left Click Break / Right Click Place
-1-9 Select Block / Scroll Cycle Blocks -
-
Click to Play
-
-
-
-
- - - - diff --git a/outputs/claude-opus-4-6/cursor-max/pelican-cycling.svg b/outputs/claude-opus-4-6/cursor-max/pelican-cycling.svg deleted file mode 100644 index 5b75e41..0000000 --- a/outputs/claude-opus-4-6/cursor-max/pelican-cycling.svg +++ /dev/null @@ -1,465 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/claude-opus-4-7/claude-code-max/mythos-craft.html b/outputs/claude-opus-4-7/claude-code-max/mythos-craft.html deleted file mode 100644 index 65757d7..0000000 --- a/outputs/claude-opus-4-7/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,2181 +0,0 @@ - - - - - -Mythoscraft — 神话方块世界 - - - - -
-

MYTHOSCRAFT

-
神 话 方 块 世 界
-
- WASD 移动  ·  SPACE 跳跃  ·  SHIFT 疾跑
- 鼠标 视角  ·  左键 破坏  ·  右键 放置
- 1-9 切换方块  ·  F 飞行  ·  ESC 暂停 -
-
铸造世界中…
-
— 点击屏幕,启程探索 —
-
- - - - - -
- - - - - - diff --git a/outputs/claude-opus-4-7/claude-code-max/pelican-cycling.svg b/outputs/claude-opus-4-7/claude-code-max/pelican-cycling.svg deleted file mode 100644 index 7a3dd91..0000000 --- a/outputs/claude-opus-4-7/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,425 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-opus-4-7/claude-code-max/skeleton-watch.html b/outputs/claude-opus-4-7/claude-code-max/skeleton-watch.html deleted file mode 100644 index a16a1d6..0000000 --- a/outputs/claude-opus-4-7/claude-code-max/skeleton-watch.html +++ /dev/null @@ -1,968 +0,0 @@ - - - - - -Cal. 1894 — Skeleton Mechanical Watch - - - -
-
-
-
-
Calibrating Movement
-
-
Maison Horologie
-
-
SKELETON · CAL. 1894
-
GENÈVE · SUISSE
-
-
-

SpecificationN° 0027 / 88

-
Caliber1894-SK
-
MovementManual Wind
-
Frequency28,800 vph
-
Jewels29 Rubies
-
Reserve72 Hours
-
Case904L Steel
-
CrystalSapphire AR
-
Diameter41.0 mm
-
FinishingCôtes / Anglage
-
-
- - - - - -
-
-
Component
-
—
-
-
-
-
-
-
Drag to rotate · Scroll to zoom · Click parts
- - - - - diff --git a/outputs/claude-opus-4-7/cursor-max/mythos-craft.html b/outputs/claude-opus-4-7/cursor-max/mythos-craft.html deleted file mode 100644 index 6ecfe8a..0000000 --- a/outputs/claude-opus-4-7/cursor-max/mythos-craft.html +++ /dev/null @@ -1,2250 +0,0 @@ - - - - - -MythosCraft · 神话之地 - - - - - - -
- -
- -
-
-
-
-
-
- -
-
-

MYTHOS CRAFT神 话 之 地

-

An ancient world of myths, towers, and dragon-temples

-
-
W A S D移动 / Move
-
SPACE跳跃 / Jump
-
SHIFT加速 / Sprint
-
MOUSE视角 / Look
-
L-CLICK破坏 / Break
-
R-CLICK放置 / Place
-
1 - 9选择方块 / Select
-
F飞行 / Fly
-
F3调试信息 / Debug
-
ESC暂停 / Pause
-
- -
- -
- - - - - - - - diff --git a/outputs/claude-opus-4-7/cursor-max/pelican-cycling.svg b/outputs/claude-opus-4-7/cursor-max/pelican-cycling.svg deleted file mode 100644 index 70cc4ac..0000000 --- a/outputs/claude-opus-4-7/cursor-max/pelican-cycling.svg +++ /dev/null @@ -1,628 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/.gitignore b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/.gitignore deleted file mode 100644 index b947077..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -dist/ diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/README.md b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/README.md deleted file mode 100644 index 6d3a6b2..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Dust II Arena - -A from-scratch **5v5 first-person shooter prototype** recreating the core areas of -Dust2, built with **React 18 + TypeScript + three.js**. No external assets: the map, -characters and weapons are procedural geometry, and every sound is synthesized with -the Web Audio API. The only third-party libraries are `three`, `react` and -`react-dom` — pathfinding, physics, the AI state machine, the render loop and the -round/economy logic are all hand-written. - -## Run - -```bash -bun install -bun run dev # http://localhost:5173 — click the arena to lock the mouse -``` - -Build a static bundle with `bun run build` (output in `dist/`). A prebuilt, -fully self-contained single file is also included as `dust2-arena.html`. - -## Controls - -| Action | Key | -| --- | --- | -| Move / Jump / Walk | `WASD` / `Space` / `Shift` | -| Fire / Scope (AWP) / Reload | `Mouse1` / `Mouse2` / `R` | -| Primary / Secondary / Knife | `1` / `2` / `3` (or wheel) | -| Swap primary ⇄ AWP | `B` | -| Plant / Defuse / Pick up C4 | hold `E` | -| (dead) Switch spectated teammate | `Mouse1` / `A` / `D` | -| (dead) Take control of teammate | `F` / `Space` | - -## What it includes - -- **Map** — T / CT spawns, A Long, A site, Mid (with passable doors), Catwalk, - B tunnels and B site, laid out on a connected tile grid with full wall + crate - collision. -- **Characters** — box-built humanoids (separate head, torso, arms, legs), CT blue - vs T tan, in a weapon-holding pose. -- **Weapons** — AK-47, M4A4, AWP (right-click scope), Glock / USP / Desert Eagle, - and a knife, each with distinct damage, recoil, spread, magazine and reload. - Hitscan with per-zone hitboxes (head = 2× body) and armor mitigation. -- **Rounds** — pistol-round opening, then rifle buys; C4 carry / drop / plant / - defuse and full round resolution (elimination, detonation, defuse, time). -- **AI** — 9 bots navigate with grid A*, spot enemies through line-of-sight, fight, - and push the plant / rotate to defuse. -- **Death spectating** — when you die you watch a living teammate in first person, - cycle between teammates, and can take control of one (it stops being AI-driven). -- **HUD** — dynamic crosshair, health / armor, ammo, killfeed, round + bomb timers, - and a live Dust2 minimap. Procedural audio for guns, reloads, footsteps, scope, - hits, C4 and kills. - -## Layout - -``` -src/ - main.tsx, App.tsx, styles.css - components/ GameCanvas, Hud, Minimap, Menu - engine/ - grid.ts dust2.ts navmesh.ts collision.ts # map + spatial systems - weapons.ts combat.ts # weapon data + hitboxes - world.ts ai.ts player.ts input.ts # simulation + control - scene.ts effects.ts entities/ # three.js geometry - audio.ts store.ts constants.ts types.ts # sound, HUD bridge, config -``` diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/bun.lock b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/bun.lock deleted file mode 100644 index a207fe2..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/bun.lock +++ /dev/null @@ -1,282 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 1, - "workspaces": { - "": { - "name": "dust2-arena", - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", - "three": "^0.185.1", - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@types/three": "^0.185.0", - "@vitejs/plugin-react": "^4.3.4", - "typescript": "^5.6.3", - "vite": "^5.4.11", - "vite-plugin-singlefile": "^2.0.3", - }, - }, - }, - "packages": { - "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], - - "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], - - "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="], - - "@babel/generator": ["@babel/generator@7.29.7", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ=="], - - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], - - "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="], - - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="], - - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="], - - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], - - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="], - - "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], - - "@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], - - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw=="], - - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q=="], - - "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], - - "@babel/traverse": ["@babel/traverse@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" } }, "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw=="], - - "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - - "@dimforge/rapier3d-compat": ["@dimforge/rapier3d-compat@0.12.0", "", {}, "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], - - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - - "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.2", "", { "os": "android", "cpu": "arm" }, "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg=="], - - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw=="], - - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.62.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A=="], - - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.62.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA=="], - - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.62.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw=="], - - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.62.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg=="], - - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg=="], - - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA=="], - - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA=="], - - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ=="], - - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg=="], - - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ=="], - - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A=="], - - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w=="], - - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg=="], - - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q=="], - - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.62.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg=="], - - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A=="], - - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg=="], - - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.62.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg=="], - - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.62.2", "", { "os": "none", "cpu": "arm64" }, "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA=="], - - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.62.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg=="], - - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.62.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q=="], - - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg=="], - - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA=="], - - "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], - - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], - - "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], - - "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], - - "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - - "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], - - "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], - - "@types/react": ["@types/react@18.3.31", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw=="], - - "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="], - - "@types/stats.js": ["@types/stats.js@0.17.4", "", {}, "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA=="], - - "@types/three": ["@types/three@0.185.1", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": ">=0.5.17", "fflate": "~0.8.2", "meshoptimizer": "~1.1.1" } }, "sha512-db1xTb+EgYF2didW+eudSvVPtn75zo+fGsY8ShQrJY/B5ZBmC2Fiaykv3aImHAlCNEGuMPkPGXBJGLwzu5mC7A=="], - - "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], - - "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], - - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.43", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - - "browserslist": ["browserslist@4.28.6", "", { "dependencies": { "baseline-browser-mapping": "^2.10.42", "caniuse-lite": "^1.0.30001803", "electron-to-chromium": "^1.5.389", "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001805", "", {}, "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA=="], - - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - - "electron-to-chromium": ["electron-to-chromium@1.5.389", "", {}, "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg=="], - - "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], - - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - - "meshoptimizer": ["meshoptimizer@1.1.1", "", {}, "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g=="], - - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="], - - "node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - - "postcss": ["postcss@8.5.19", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ=="], - - "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], - - "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], - - "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], - - "rollup": ["rollup@4.62.2", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.62.2", "@rollup/rollup-android-arm64": "4.62.2", "@rollup/rollup-darwin-arm64": "4.62.2", "@rollup/rollup-darwin-x64": "4.62.2", "@rollup/rollup-freebsd-arm64": "4.62.2", "@rollup/rollup-freebsd-x64": "4.62.2", "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", "@rollup/rollup-linux-arm-musleabihf": "4.62.2", "@rollup/rollup-linux-arm64-gnu": "4.62.2", "@rollup/rollup-linux-arm64-musl": "4.62.2", "@rollup/rollup-linux-loong64-gnu": "4.62.2", "@rollup/rollup-linux-loong64-musl": "4.62.2", "@rollup/rollup-linux-ppc64-gnu": "4.62.2", "@rollup/rollup-linux-ppc64-musl": "4.62.2", "@rollup/rollup-linux-riscv64-gnu": "4.62.2", "@rollup/rollup-linux-riscv64-musl": "4.62.2", "@rollup/rollup-linux-s390x-gnu": "4.62.2", "@rollup/rollup-linux-x64-gnu": "4.62.2", "@rollup/rollup-linux-x64-musl": "4.62.2", "@rollup/rollup-openbsd-x64": "4.62.2", "@rollup/rollup-openharmony-arm64": "4.62.2", "@rollup/rollup-win32-arm64-msvc": "4.62.2", "@rollup/rollup-win32-ia32-msvc": "4.62.2", "@rollup/rollup-win32-x64-gnu": "4.62.2", "@rollup/rollup-win32-x64-msvc": "4.62.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA=="], - - "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], - - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "three": ["three@0.185.1", "", {}, "sha512-5aojFCXKwnjBRZvUnt3WFfEcvUJgkN5LlijRFN95hMy8WVkG4I0QNcJE+OuWvuJ0bOdStrbfXn0pkd6/QyiAlg=="], - - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - - "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], - - "vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], - - "vite-plugin-singlefile": ["vite-plugin-singlefile@2.3.3", "", { "dependencies": { "micromatch": "^4.0.8" }, "peerDependencies": { "rollup": "^4.59.0", "vite": "^5.4.21 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["rollup"] }, "sha512-XVnGH0QzbOa8fxRSsHdCarVN1BSBXNi7uLMQYlrGRN5apdHkk62XQWRJhVever0lnfuyBkwn+kvVChdm/OoOUg=="], - - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/dust2-arena.html b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/dust2-arena.html deleted file mode 100644 index 326fcf2..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/dust2-arena.html +++ /dev/null @@ -1,4168 +0,0 @@ - - - - - - Dust II Arena - - - - -
- - diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/index.html b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/index.html deleted file mode 100644 index 9588dd9..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Dust II Arena - - -
- - - diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/package.json b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/package.json deleted file mode 100644 index d99812c..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "dust2-arena", - "private": true, - "version": "1.0.0", - "type": "module", - "description": "5v5 procedural Dust2 first-person shooter prototype (React + TypeScript + three.js).", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "build:single": "tsc && vite build --config vite.single.config.ts", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", - "three": "^0.185.1" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@types/three": "^0.185.0", - "@vitejs/plugin-react": "^4.3.4", - "typescript": "^5.6.3", - "vite": "^5.4.11", - "vite-plugin-singlefile": "^2.0.3" - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/App.tsx b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/App.tsx deleted file mode 100644 index 4cf0128..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/App.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { useState } from 'react'; -import { Team } from './engine/types'; -import { Menu } from './components/Menu'; -import { GameCanvas } from './components/GameCanvas'; - -export function App() { - const [team, setTeam] = useState(null); - if (team === null) return ; - return ; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/GameCanvas.tsx b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/GameCanvas.tsx deleted file mode 100644 index 740fd67..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/GameCanvas.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useEffect, useRef, useState } from 'react'; -import { GameWorld } from '../engine/world'; -import { Team } from '../engine/types'; -import { Hud } from './Hud'; -import { Minimap } from './Minimap'; - -export function GameCanvas({ team }: { team: Team }) { - const mountRef = useRef(null); - const miniRef = useRef(null); - const worldRef = useRef(null); - const [locked, setLocked] = useState(false); - const [started, setStarted] = useState(false); - - useEffect(() => { - const container = mountRef.current!; - const world = new GameWorld(container, team); - worldRef.current = world; - if (miniRef.current) world.setMinimapCanvas(miniRef.current); - - let raf = 0; - let last = performance.now(); - const loop = (t: number) => { - const dt = (t - last) / 1000; - last = t; - world.update(dt); - world.input.endFrame(); - raf = requestAnimationFrame(loop); - }; - raf = requestAnimationFrame(loop); - - const onResize = () => world.resize(); - window.addEventListener('resize', onResize); - - const onLockChange = () => setLocked(document.pointerLockElement === world.renderer.domElement); - document.addEventListener('pointerlockchange', onLockChange); - - const onClick = () => { - world.start(); - setStarted(true); - world.input.requestLock(); - }; - container.addEventListener('click', onClick); - - return () => { - cancelAnimationFrame(raf); - window.removeEventListener('resize', onResize); - document.removeEventListener('pointerlockchange', onLockChange); - container.removeEventListener('click', onClick); - world.dispose(); - worldRef.current = null; - }; - }, [team]); - - return ( -
- - - {!locked && ( -
-
-
{started ? 'Paused' : 'Ready'}
-
Click to {started ? 'resume' : 'lock mouse and start'}
-
Esc releases the mouse
-
-
- )} -
- ); -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Hud.tsx b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Hud.tsx deleted file mode 100644 index 16ea9b0..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Hud.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { useSyncExternalStore } from 'react'; -import { hud } from '../engine/store'; -import { Team } from '../engine/types'; -import { WEAPONS } from '../engine/weapons'; - -function useHud() { - return useSyncExternalStore(hud.subscribe, hud.getSnapshot, hud.getSnapshot); -} - -const T_COLOR = '#e0a24a'; -const CT_COLOR = '#5aa9e6'; -const teamColor = (t: Team) => (t === Team.T ? T_COLOR : CT_COLOR); - -function fmt(t: number): string { - const s = Math.max(0, Math.ceil(t)); - const m = Math.floor(s / 60); - const ss = s % 60; - return `${m}:${ss.toString().padStart(2, '0')}`; -} - -function Crosshair({ spread, hit }: { spread: number; hit: boolean }) { - const gap = Math.max(3, Math.min(90, spread * 600)); - const len = 7; - const thick = 2; - const col = hit ? '#ff5b5b' : '#e7fff0'; - const line = (style: React.CSSProperties) => ( - - ); - return ( -
- {line({ width: thick, height: len, left: -thick / 2, top: -gap - len })} - {line({ width: thick, height: len, left: -thick / 2, top: gap })} - {line({ width: len, height: thick, top: -thick / 2, left: -gap - len })} - {line({ width: len, height: thick, top: -thick / 2, left: gap })} - -
- ); -} - -export function Hud() { - const s = useHud(); - - return ( -
- {/* top score bar */} -
-
- T - {'●'.repeat(s.aliveT)}{'○'.repeat(Math.max(0, 5 - s.aliveT))} -
-
- {s.scoreT} - {s.bombPlanted ? {fmt(s.bombTimer)} : fmt(s.roundTime)} - {s.scoreCT} -
-
- {'○'.repeat(Math.max(0, 5 - s.aliveCT))}{'●'.repeat(s.aliveCT)} - CT -
-
- - {/* killfeed */} -
- {s.killfeed.map((k) => ( -
- {k.attacker} - {WEAPONS[k.weapon]?.name ?? k.weapon}{k.headshot ? ' ×' : ''} - {k.victim} -
- ))} -
- - {/* center banner */} - {s.banner &&
{s.banner}
} - - {/* plant / defuse progress */} - {(s.planting || s.defusing) && ( -
-
{s.planting ? 'PLANTING' : 'DEFUSING'}
-
-
-
-
- )} - - {/* scope overlay */} - {s.scoped && ( -
-
-
-
-
- )} - - {/* crosshair */} - {!s.scoped && (s.alive || s.spectating) && } - - {/* dead: spectate bar, or eliminated when no teammate left */} - {!s.alive && s.spectating && ( -
-
- SPECTATING {s.spectateName} -
-
- [F] / Space take control  ·  Mouse1 / A / D switch player -
-
- )} - {!s.alive && !s.spectating && ( -
-
ELIMINATED
-
No teammates left — round ending
-
- )} - - {/* hint */} - {s.hint && s.alive &&
{s.hint}
} - - {/* bomb carrier tag */} - {s.hasBomb && s.alive &&
C4 — bring it to A or B
} - - {/* bottom-left: health / armor */} -
-
- + - {s.health} -
-
- {s.helmet ? 'A*' : 'A'} - {s.armor} -
-
- - {/* bottom-right: ammo + weapons */} -
-
{s.weaponName}
-
- {s.infiniteAmmo ? ( - ∞ - ) : ( - <> - - {s.reloading ? 'R' : s.mag} - - / {s.reserve} - - )} -
-
- {s.loadout.map((w) => ( -
- {w.slot === 'primary' ? '1' : w.slot === 'secondary' ? '2' : '3'} - {w.name} -
- ))} -
-
-
- ); -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Menu.tsx b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Menu.tsx deleted file mode 100644 index 09269fa..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { useState } from 'react'; -import { Team } from '../engine/types'; - -export function Menu({ onStart }: { onStart: (t: Team) => void }) { - const [team, setTeam] = useState(Team.T); - return ( -
-
-

DUST II ARENA

-

5v5 procedural first-person prototype — pick a side

- -
- - -
- -
-
- Move WASD · Jump Space · Walk Shift -
-
- Fire Mouse1 · Scope Mouse2 (AWP) · Reload R -
-
- Weapons 1 / 2 / 3 · wheel · Swap AWP B -
-
- Plant / Defuse / Pickup hold E -
-
- When dead Mouse1 / A / D switch view · F take control -
-
- - -

Round 1 is a pistol round. Click the arena to lock the mouse.

-
-
- ); -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Minimap.tsx b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Minimap.tsx deleted file mode 100644 index 0e192ed..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/components/Minimap.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { RefObject } from 'react'; - -export function Minimap({ canvasRef }: { canvasRef: RefObject }) { - return ( -
- } width={200} height={200} /> -
DUST II
-
- ); -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/ai.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/ai.ts deleted file mode 100644 index f805d17..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/ai.ts +++ /dev/null @@ -1,330 +0,0 @@ -// Bot brain: a compact state machine driving perception, navigation (grid A*), -// combat (face + strafe + burst fire with reaction delay + aim error) and the -// C4 objective (T push/plant, CT hold/defuse). It only sets an actor's intents -// and calls world combat helpers; physics + firing live in GameWorld. - -import { AI } from './constants'; -import { findPath } from './navmesh'; -import { angleDelta, moveAngleToward, rand, yawFromDir } from './mathUtils'; -import { BombState, Team } from './types'; -import { WEAPONS } from './weapons'; -import type { Actor, GameWorld } from './world'; - -export type BotMode = 'advance' | 'engage' | 'search' | 'hold' | 'plant' | 'defuse' | 'pickup'; - -export interface BotState { - mode: BotMode; - path: { x: number; z: number }[]; - pathIdx: number; - repath: number; - goalX: number; - goalZ: number; - hasGoal: boolean; - target: number; - lastSeen: number; - lastSeenX: number; - lastSeenZ: number; - reactAt: number; - nextBurst: number; - burstUntil: number; - strafeDir: number; - strafeUntil: number; - wanderYaw: number; - targetSite?: 'A' | 'B'; - defendSite?: 'A' | 'B'; -} - -export function initBotState(s?: BotState): BotState { - const base: BotState = { - mode: 'advance', - path: [], - pathIdx: 0, - repath: 0, - goalX: 0, - goalZ: 0, - hasGoal: false, - target: -1, - lastSeen: -99, - lastSeenX: 0, - lastSeenZ: 0, - reactAt: 0, - nextBurst: 0, - burstUntil: 0, - strafeDir: 1, - strafeUntil: 0, - wanderYaw: 0, - }; - if (s) { - const keepT = s.targetSite; - const keepD = s.defendSite; - Object.assign(s, base); - s.targetSite = keepT; - s.defendSite = keepD; - return s; - } - return base; -} - -function setGoal(world: GameWorld, a: Actor, gx: number, gz: number): void { - const bs = a.bs; - const moved = (gx - bs.goalX) ** 2 + (gz - bs.goalZ) ** 2 > 9; - bs.goalX = gx; - bs.goalZ = gz; - bs.hasGoal = true; - if (moved || !bs.path.length || bs.repath <= 0) { - const p = findPath(world.grid, a.x, a.z, gx, gz); - bs.path = p ?? []; - bs.pathIdx = 0; - bs.repath = AI.repathInterval; - } -} - -// steer along the current path; returns false when the path is exhausted -function followPath(a: Actor): boolean { - const bs = a.bs; - if (bs.pathIdx >= bs.path.length) return false; - let wp = bs.path[bs.pathIdx]; - let dx = wp.x - a.x; - let dz = wp.z - a.z; - let d = Math.hypot(dx, dz); - while (d < 1.1 && bs.pathIdx < bs.path.length - 1) { - bs.pathIdx++; - wp = bs.path[bs.pathIdx]; - dx = wp.x - a.x; - dz = wp.z - a.z; - d = Math.hypot(dx, dz); - } - if (bs.pathIdx >= bs.path.length - 1 && d < 1.1) { - bs.pathIdx = bs.path.length; - return false; - } - if (d > 1e-3) { - a.moveX = dx / d; - a.moveZ = dz / d; - } - return true; -} - -export function updateBot(world: GameWorld, a: Actor, dt: number, canMove: boolean): void { - const bs = a.bs; - bs.repath -= dt; - a.moveX = 0; - a.moveZ = 0; - a.wantRun = true; - a.action = 'none'; - - // --- perception --- - const seen = world.nearestVisibleEnemy(a, AI.fovDeg); - if (seen) { - if (bs.target !== seen.id) { - bs.target = seen.id; - bs.reactAt = world.time + AI.reactionTime + rand(0, 0.12); - } - bs.lastSeen = world.time; - bs.lastSeenX = seen.x; - bs.lastSeenZ = seen.z; - bs.mode = 'engage'; - } else if (bs.mode === 'engage') { - bs.mode = world.time - bs.lastSeen < 3 ? 'search' : 'advance'; - bs.target = -1; - } - - if (!canMove) { - // during freeze, just face forward - return; - } - - const bomb = world.bombInfo(); - - if (bs.mode === 'engage' && seen) { - combat(world, a, seen, dt); - return; - } - - // --- objective / navigation --- - if (bs.mode === 'search') { - setGoal(world, a, bs.lastSeenX, bs.lastSeenZ); - if ((bs.lastSeenX - a.x) ** 2 + (bs.lastSeenZ - a.z) ** 2 < 4 || !followPathOrArrive(world, a)) { - bs.mode = 'advance'; - } - faceMovement(a, dt); - return; - } - - if (a.team === Team.T) { - objectiveT(world, a, bomb.state, bomb.x, bomb.z); - } else { - objectiveCT(world, a, bomb.state, bomb.x, bomb.z); - } - faceMovement(a, dt); -} - -function followPathOrArrive(world: GameWorld, a: Actor): boolean { - const moving = followPath(a); - if (!moving) { - // recompute once toward goal in case we stalled - if (a.bs.hasGoal) { - const d2 = (a.bs.goalX - a.x) ** 2 + (a.bs.goalZ - a.z) ** 2; - if (d2 > 4 && a.bs.repath <= 0) setGoal(world, a, a.bs.goalX, a.bs.goalZ); - } - return false; - } - return true; -} - -function objectiveT(world: GameWorld, a: Actor, bombState: BombState, bx: number, bz: number): void { - const bs = a.bs; - const site = world.dust2.sites[(bs.targetSite ?? 'A') as 'A' | 'B']; - - if (bombState === BombState.Dropped) { - // nearest T without bomb goes for the pickup - if (isNearestTeammateTo(world, a, bx, bz)) { - setGoal(world, a, bx, bz); - followPathOrArrive(world, a); - world.pickupBomb(a); - return; - } - } - - if (a.hasBomb && bombState === BombState.Carried) { - const inSite = world.isInSite(a) === bs.targetSite || world.isInSite(a) !== null; - if (inSite && a.grounded) { - // plant if no enemy currently threatening - a.action = 'plant'; - a.moveX = a.moveZ = 0; - return; - } - setGoal(world, a, site.center.x, site.center.z); - followPathOrArrive(world, a); - return; - } - - if (bombState === BombState.Planted) { - // defend near the bomb - const spot = spreadAround(a, bx, bz, 8); - setGoal(world, a, spot.x, spot.z); - followPathOrArrive(world, a); - return; - } - - // support push toward the target site - const spot = spreadAround(a, site.center.x, site.center.z, 7); - setGoal(world, a, spot.x, spot.z); - followPathOrArrive(world, a); -} - -function objectiveCT(world: GameWorld, a: Actor, bombState: BombState, bx: number, bz: number): void { - const bs = a.bs; - if (bombState === BombState.Planted) { - // rotate to defuse - const dist2 = (bx - a.x) ** 2 + (bz - a.z) ** 2; - if (dist2 < 2.3 * 2.3 && a.grounded) { - a.action = 'defuse'; - a.moveX = a.moveZ = 0; - return; - } - setGoal(world, a, bx, bz); - followPathOrArrive(world, a); - return; - } - // hold the assigned site - const site = world.dust2.sites[(bs.defendSite ?? 'A') as 'A' | 'B']; - const d2 = (site.center.x - a.x) ** 2 + (site.center.z - a.z) ** 2; - if (d2 > 10 * 10) { - setGoal(world, a, site.center.x, site.center.z); - followPathOrArrive(world, a); - } else { - // patrol slowly around the site - if (world.time > a.bs.strafeUntil) { - a.bs.strafeUntil = world.time + rand(2, 4); - const ang = rand(0, Math.PI * 2); - setGoal(world, a, site.center.x + Math.cos(ang) * 6, site.center.z + Math.sin(ang) * 6); - } - a.wantRun = false; - followPathOrArrive(world, a); - } -} - -function isNearestTeammateTo(world: GameWorld, a: Actor, x: number, z: number): boolean { - const myD = (a.x - x) ** 2 + (a.z - z) ** 2; - for (const t of world.actors) { - if (!t.alive || t.team !== a.team || t.id === a.id || t.isPlayer) continue; - const d = (t.x - x) ** 2 + (t.z - z) ** 2; - if (d < myD) return false; - } - return true; -} - -function spreadAround(a: Actor, x: number, z: number, spread: number): { x: number; z: number } { - // deterministic per-bot offset so bots don't stack on one point - const ang = (a.id * 1.3) % (Math.PI * 2); - return { x: x + Math.cos(ang) * spread * 0.7, z: z + Math.sin(ang) * spread * 0.7 }; -} - -function faceMovement(a: Actor, dt: number): void { - if (Math.abs(a.moveX) + Math.abs(a.moveZ) > 1e-3) { - const desired = yawFromDir(a.moveX, a.moveZ); - a.yaw = moveAngleToward(a.yaw, desired, AI.aimSpeed * dt); - } - a.pitch += (0 - a.pitch) * Math.min(1, dt * 6); -} - -function combat(world: GameWorld, a: Actor, target: Actor, dt: number): void { - const bs = a.bs; - const dx = target.x - a.x; - const dz = target.z - a.z; - const dist = Math.hypot(dx, dz); - - // aim (with error) - const err = AI.aimError; - const desiredYaw = yawFromDir(dx, dz) + rand(-err, err); - const eyeY = a.y + a.eyeH; - const targetY = target.y + 1.15; - const desiredPitch = Math.atan2(targetY - eyeY, Math.max(0.5, dist)) + rand(-err, err); - a.yaw = moveAngleToward(a.yaw, desiredYaw, AI.aimSpeed * dt); - a.pitch += (desiredPitch - a.pitch) * Math.min(1, dt * 10); - - // movement: strafe + keep an ideal range - if (world.time > bs.strafeUntil) { - bs.strafeUntil = world.time + rand(0.5, 1.3); - bs.strafeDir = Math.random() < 0.5 ? 1 : -1; - } - const perpX = -dz / (dist || 1); - const perpZ = dx / (dist || 1); - let mx = perpX * bs.strafeDir; - let mz = perpZ * bs.strafeDir; - const ideal = a.current === 'awp' ? 24 : 14; - if (dist > ideal + 6) { - mx += dx / dist; - mz += dz / dist; - } else if (dist < ideal - 6) { - mx -= dx / dist; - mz -= dz / dist; - } - const ml = Math.hypot(mx, mz) || 1; - a.moveX = mx / ml; - a.moveZ = mz / ml; - a.wantRun = false; // walk while fighting = more accurate - - // fire control - const w = WEAPONS[a.current]; - const ammo = a.ammo[a.current]; - if (ammo && ammo.mag <= 0) { - world.startReload(a); - return; - } - const aligned = Math.abs(angleDelta(a.yaw, desiredYaw)) < 0.13; - const reacted = world.time >= bs.reactAt; - if (!reacted || !aligned) return; - if (!world.canSee(a, target, 200)) return; - - if (w.automatic) { - if (world.time > bs.nextBurst) { - bs.burstUntil = world.time + rand(AI.burstMin, AI.burstMax); - bs.nextBurst = bs.burstUntil + rand(0.18, 0.45); - } - if (world.time <= bs.burstUntil) world.fireWeapon(a); - } else { - world.fireWeapon(a); - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/audio.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/audio.ts deleted file mode 100644 index f769a4c..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/audio.ts +++ /dev/null @@ -1,233 +0,0 @@ -// Procedural sound via the Web Audio API (no audio files). World sounds are -// attenuated + panned relative to the player listener; the player's own weapon -// plays centered. Everything is short transients synthesized from noise + tones. - -import { WeaponId } from './types'; - -export class AudioEngine { - private ctx: AudioContext | null = null; - private master: GainNode | null = null; - private noise: AudioBuffer | null = null; - private lx = 0; - private lz = 0; - private lyaw = 0; - muted = false; - - init(): void { - if (this.ctx) { - if (this.ctx.state === 'suspended') void this.ctx.resume(); - return; - } - const Ctor: typeof AudioContext = - (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext ?? - window.AudioContext; - this.ctx = new Ctor(); - this.master = this.ctx.createGain(); - this.master.gain.value = 0.5; - this.master.connect(this.ctx.destination); - // one second of white noise, reused everywhere - const len = this.ctx.sampleRate; - const buf = this.ctx.createBuffer(1, len, this.ctx.sampleRate); - const data = buf.getChannelData(0); - for (let i = 0; i < len; i++) data[i] = Math.random() * 2 - 1; - this.noise = buf; - } - - setListener(x: number, z: number, yaw: number): void { - this.lx = x; - this.lz = z; - this.lyaw = yaw; - } - - private now(): number { - return this.ctx ? this.ctx.currentTime : 0; - } - - // Spatial gain + stereo pan for a world position, or null if inaudible. - private spatial(x: number, z: number, maxDist: number): { gain: number; pan: number } | null { - const dx = x - this.lx; - const dz = z - this.lz; - const dist = Math.hypot(dx, dz); - if (dist > maxDist) return null; - const gain = Math.pow(1 - dist / maxDist, 1.6); - // rotate offset into listener frame; pan by the right-vector component - const c = Math.cos(this.lyaw); - const s = Math.sin(this.lyaw); - // right vector (matches -Z forward, YXZ): (cos, -sin) - const right = (dx * c - dz * -s) / (dist + 1e-3); - const pan = Math.max(-1, Math.min(1, right)); - return { gain, pan }; - } - - private out(pan: number): AudioNode { - const ctx = this.ctx!; - if (typeof ctx.createStereoPanner === 'function') { - const p = ctx.createStereoPanner(); - p.pan.value = pan; - p.connect(this.master!); - return p; - } - return this.master!; - } - - private burst( - dur: number, type: BiquadFilterType, freq: number, q: number, - gain: number, pan: number, when = 0, - ): void { - if (!this.ctx || !this.noise) return; - const ctx = this.ctx; - const t = this.now() + when; - const src = ctx.createBufferSource(); - src.buffer = this.noise; - src.loop = true; - const filt = ctx.createBiquadFilter(); - filt.type = type; - filt.frequency.value = freq; - filt.Q.value = q; - const g = ctx.createGain(); - g.gain.setValueAtTime(0.0001, t); - g.gain.exponentialRampToValueAtTime(gain, t + 0.002); - g.gain.exponentialRampToValueAtTime(0.0001, t + dur); - src.connect(filt); - filt.connect(g); - g.connect(this.out(pan)); - src.start(t); - src.stop(t + dur + 0.02); - } - - private tone( - freq: number, dur: number, type: OscillatorType, gain: number, pan: number, - when = 0, glideTo?: number, - ): void { - if (!this.ctx) return; - const ctx = this.ctx; - const t = this.now() + when; - const osc = ctx.createOscillator(); - osc.type = type; - osc.frequency.setValueAtTime(freq, t); - if (glideTo !== undefined) osc.frequency.exponentialRampToValueAtTime(glideTo, t + dur); - const g = ctx.createGain(); - g.gain.setValueAtTime(0.0001, t); - g.gain.exponentialRampToValueAtTime(gain, t + 0.004); - g.gain.exponentialRampToValueAtTime(0.0001, t + dur); - osc.connect(g); - g.connect(this.out(pan)); - osc.start(t); - osc.stop(t + dur + 0.02); - } - - // --- public sound events --- - - gunshot(weapon: WeaponId, x?: number, z?: number): void { - if (this.muted || !this.ctx) return; - let sp = { gain: 1, pan: 0 }; - if (x !== undefined && z !== undefined) { - const s = this.spatial(x, z, 95); - if (!s) return; - sp = s; - } - const v = sp.gain; - switch (weapon) { - case 'ak47': - this.burst(0.16, 'bandpass', 1400, 0.7, 0.55 * v, sp.pan); - this.burst(0.09, 'lowpass', 500, 1, 0.5 * v, sp.pan); - this.tone(120, 0.1, 'sawtooth', 0.25 * v, sp.pan, 0, 60); - break; - case 'm4a4': - this.burst(0.11, 'bandpass', 2100, 0.9, 0.42 * v, sp.pan); - this.burst(0.06, 'lowpass', 700, 1, 0.35 * v, sp.pan); - this.tone(160, 0.07, 'square', 0.16 * v, sp.pan, 0, 90); - break; - case 'awp': - this.burst(0.35, 'lowpass', 900, 0.8, 0.7 * v, sp.pan); - this.burst(0.2, 'bandpass', 1600, 0.6, 0.5 * v, sp.pan); - this.tone(80, 0.3, 'sawtooth', 0.4 * v, sp.pan, 0, 40); - break; - case 'deagle': - this.burst(0.18, 'bandpass', 1100, 0.7, 0.55 * v, sp.pan); - this.tone(110, 0.12, 'square', 0.28 * v, sp.pan, 0, 55); - break; - case 'glock': - this.burst(0.08, 'bandpass', 1800, 1, 0.32 * v, sp.pan); - this.tone(220, 0.05, 'square', 0.12 * v, sp.pan, 0, 130); - break; - case 'usp': - this.burst(0.07, 'bandpass', 1500, 1.2, 0.26 * v, sp.pan); - this.tone(260, 0.04, 'sine', 0.1 * v, sp.pan, 0, 150); - break; - case 'knife': - this.burst(0.05, 'highpass', 3000, 0.6, 0.25 * v, sp.pan); - break; - } - } - - reload(): void { - if (this.muted) return; - this.burst(0.05, 'bandpass', 900, 2, 0.25, 0, 0.0); - this.burst(0.05, 'bandpass', 1400, 2, 0.22, 0, 0.35); - this.tone(500, 0.03, 'square', 0.12, 0, 0.7); - } - - footstep(x?: number, z?: number): void { - if (this.muted || !this.ctx) return; - let sp = { gain: 0.5, pan: 0 }; - if (x !== undefined && z !== undefined) { - const s = this.spatial(x, z, 20); - if (!s) return; - sp = s; - } - this.burst(0.07, 'lowpass', 380, 1.2, 0.18 * sp.gain, sp.pan); - } - - scope(on: boolean): void { - if (this.muted) return; - this.tone(on ? 700 : 500, 0.05, 'sine', 0.14, 0); - this.tone(on ? 900 : 400, 0.05, 'sine', 0.1, 0, 0.04); - } - - hitmarker(): void { - if (this.muted) return; - this.tone(1400, 0.05, 'square', 0.16, 0); - } - - kill(): void { - if (this.muted) return; - this.tone(880, 0.08, 'square', 0.2, 0); - this.tone(1320, 0.1, 'square', 0.2, 0, 0.08); - } - - bombBeep(x?: number, z?: number): void { - if (this.muted) return; - let sp = { gain: 0.6, pan: 0 }; - if (x !== undefined && z !== undefined) { - const s = this.spatial(x, z, 45); - if (!s) return; - sp = s; - } - this.tone(2000, 0.06, 'sine', 0.18 * sp.gain, sp.pan); - } - - plantTick(): void { - if (this.muted) return; - this.tone(1200, 0.03, 'square', 0.12, 0); - } - - defuseTick(): void { - if (this.muted) return; - this.burst(0.04, 'bandpass', 700, 3, 0.14, 0); - } - - explode(x?: number, z?: number): void { - if (this.muted || !this.ctx) return; - let sp = { gain: 1, pan: 0 }; - if (x !== undefined && z !== undefined) { - const s = this.spatial(x, z, 140); - if (!s) return; - sp = s; - } - const v = sp.gain; - this.burst(0.9, 'lowpass', 400, 0.7, 0.9 * v, sp.pan); - this.burst(0.5, 'bandpass', 900, 0.5, 0.6 * v, sp.pan); - this.tone(60, 0.8, 'sawtooth', 0.6 * v, sp.pan, 0, 30); - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/collision.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/collision.ts deleted file mode 100644 index dad29dd..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/collision.ts +++ /dev/null @@ -1,153 +0,0 @@ -// Horizontal collision for a vertical-cylinder actor (radius r) against the wall -// grid and crate boxes, plus ground-height sampling for standing on crates. - -import { Crate } from './dust2'; -import { MapGrid } from './grid'; - -// Push a circle (cx,cz,r) out of an AABB if overlapping. Returns corrected center. -function pushOutAABB( - cx: number, cz: number, r: number, - minX: number, minZ: number, maxX: number, maxZ: number, -): { x: number; z: number } | null { - const closestX = cx < minX ? minX : cx > maxX ? maxX : cx; - const closestZ = cz < minZ ? minZ : cz > maxZ ? maxZ : cz; - const dx = cx - closestX; - const dz = cz - closestZ; - const d2 = dx * dx + dz * dz; - if (d2 > r * r) return null; // no overlap - - if (d2 > 1e-8) { - const d = Math.sqrt(d2); - const push = r - d; - return { x: cx + (dx / d) * push, z: cz + (dz / d) * push }; - } - // Center inside the box: push along the least-penetration axis. - const penL = cx - minX; - const penR = maxX - cx; - const penT = cz - minZ; - const penB = maxZ - cz; - const minPen = Math.min(penL, penR, penT, penB); - if (minPen === penL) return { x: minX - r, z: cz }; - if (minPen === penR) return { x: maxX + r, z: cz }; - if (minPen === penT) return { x: cx, z: minZ - r }; - return { x: cx, z: maxZ + r }; -} - -// Resolve against wall cells overlapping the circle's neighborhood. -export function collideWalls(grid: MapGrid, x: number, z: number, r: number): { x: number; z: number } { - const cs = grid.cell; - let px = x; - let pz = z; - for (let iter = 0; iter < 3; iter++) { - const c0 = grid.cellOf(px - r, pz - r); - const c1 = grid.cellOf(px + r, pz + r); - let moved = false; - for (let cz = c0.cz; cz <= c1.cz; cz++) { - for (let cx = c0.cx; cx <= c1.cx; cx++) { - if (!grid.isWall(cx, cz)) continue; - const minX = grid.originX + cx * cs; - const minZ = grid.originZ + cz * cs; - const res = pushOutAABB(px, pz, r, minX, minZ, minX + cs, minZ + cs); - if (res) { - px = res.x; - pz = res.z; - moved = true; - } - } - } - if (!moved) break; - } - return { x: px, z: pz }; -} - -// Resolve against crates that the actor cannot stand on at its current feet Y. -export function collideCrates( - crates: Crate[], x: number, z: number, r: number, feetY: number, -): { x: number; z: number } { - let px = x; - let pz = z; - for (let iter = 0; iter < 2; iter++) { - let moved = false; - for (const cr of crates) { - if (cr.height <= feetY + 0.15) continue; // standing on / above it - const res = pushOutAABB(px, pz, r, cr.x - cr.hx, cr.z - cr.hz, cr.x + cr.hx, cr.z + cr.hz); - if (res) { - px = res.x; - pz = res.z; - moved = true; - } - } - if (!moved) break; - } - return { x: px, z: pz }; -} - -// Highest crate top under the actor's footprint, else 0 (floor). -export function groundHeightAt(crates: Crate[], x: number, z: number, r: number): number { - let h = 0; - for (const cr of crates) { - // Standing counts if the actor center is over the (slightly shrunk) top face. - const mx = cr.hx - r * 0.5; - const mz = cr.hz - r * 0.5; - if ( - x >= cr.x - mx && x <= cr.x + mx && - z >= cr.z - mz && z <= cr.z + mz - ) { - if (cr.height > h) h = cr.height; - } - } - return h; -} - -// 3D ray vs crate boxes: nearest hit distance within maxT, or maxT if none. -// Used for bullet clipping and line-of-sight through the (partial-height) crates. -export function rayCrateDistance( - crates: Crate[], - ox: number, oy: number, oz: number, - dx: number, dy: number, dz: number, - maxT: number, -): number { - let best = maxT; - for (const cr of crates) { - const t = rayBox3( - ox, oy, oz, dx, dy, dz, - cr.x - cr.hx, 0, cr.z - cr.hz, - cr.x + cr.hx, cr.height, cr.z + cr.hz, - ); - if (t >= 0 && t < best) best = t; - } - return best; -} - -function rayBox3( - ox: number, oy: number, oz: number, - dx: number, dy: number, dz: number, - minX: number, minY: number, minZ: number, - maxX: number, maxY: number, maxZ: number, -): number { - const o = [ox, oy, oz]; - const d = [dx, dy, dz]; - const mn = [minX, minY, minZ]; - const mx = [maxX, maxY, maxZ]; - let tmin = -Infinity; - let tmax = Infinity; - for (let a = 0; a < 3; a++) { - if (Math.abs(d[a]) < 1e-8) { - if (o[a] < mn[a] || o[a] > mx[a]) return -1; - } else { - const inv = 1 / d[a]; - let t1 = (mn[a] - o[a]) * inv; - let t2 = (mx[a] - o[a]) * inv; - if (t1 > t2) { - const tmp = t1; - t1 = t2; - t2 = tmp; - } - if (t1 > tmin) tmin = t1; - if (t2 < tmax) tmax = t2; - if (tmin > tmax) return -1; - } - } - if (tmax < 0) return -1; - return tmin >= 0 ? tmin : tmax; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/combat.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/combat.ts deleted file mode 100644 index 6b2a741..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/combat.ts +++ /dev/null @@ -1,100 +0,0 @@ -// Per-zone hitbox raycast. Hitboxes live in the character's local frame (feet at -// y=0, facing -Z). A world-space ray is transformed into local space (undo yaw + -// translation) and slab-tested against each zone box; nearest entry wins. - -import { HitZone } from './types'; - -interface LocalBox { - min: [number, number, number]; - max: [number, number, number]; - zone: HitZone; -} - -// Ordered head->legs; overlaps resolved by nearest t at test time. -const HITBOXES: LocalBox[] = [ - { min: [-0.14, 1.5, -0.16], max: [0.14, 1.79, 0.16], zone: HitZone.Head }, - { min: [-0.27, 1.12, -0.18], max: [0.27, 1.5, 0.18], zone: HitZone.Chest }, - { min: [-0.23, 0.82, -0.17], max: [0.23, 1.12, 0.17], zone: HitZone.Stomach }, - { min: [0.26, 0.9, -0.14], max: [0.46, 1.5, 0.14], zone: HitZone.Arm }, - { min: [-0.46, 0.9, -0.14], max: [-0.26, 1.5, 0.14], zone: HitZone.Arm }, - { min: [-0.24, 0.0, -0.17], max: [0.24, 0.82, 0.17], zone: HitZone.Leg }, -]; - -export const CHAR_HEIGHT = 1.79; -export const CHAR_BOUND_R = 0.55; // broadphase radius (XZ) - -export interface CharHit { - zone: HitZone; - t: number; -} - -// Slab intersection of a ray with an axis-aligned box; returns entry t or -1. -function rayBox( - ox: number, oy: number, oz: number, - dx: number, dy: number, dz: number, - min: [number, number, number], max: [number, number, number], -): number { - let tmin = -Infinity; - let tmax = Infinity; - const o = [ox, oy, oz]; - const d = [dx, dy, dz]; - for (let a = 0; a < 3; a++) { - if (Math.abs(d[a]) < 1e-8) { - if (o[a] < min[a] || o[a] > max[a]) return -1; - } else { - const inv = 1 / d[a]; - let t1 = (min[a] - o[a]) * inv; - let t2 = (max[a] - o[a]) * inv; - if (t1 > t2) { - const tmp = t1; - t1 = t2; - t2 = tmp; - } - if (t1 > tmin) tmin = t1; - if (t2 < tmax) tmax = t2; - if (tmin > tmax) return -1; - } - } - if (tmax < 0) return -1; - return tmin >= 0 ? tmin : tmax; -} - -// px,py,pz = character feet position; yaw = facing. Ray in world space with unit -// dir. Returns nearest zone hit within maxT, or null. -export function raycastCharacter( - px: number, py: number, pz: number, yaw: number, - ox: number, oy: number, oz: number, - dx: number, dy: number, dz: number, - maxT: number, -): CharHit | null { - // Broadphase: distance from ray to the character's vertical axis. - const rx = ox - px; - const rz = oz - pz; - // closest approach param along ray in XZ - const proj = -(rx * dx + rz * dz); - const cxp = rx + dx * Math.max(0, proj); - const czp = rz + dz * Math.max(0, proj); - if (cxp * cxp + czp * czp > CHAR_BOUND_R * CHAR_BOUND_R && proj > 0) { - // may still clip if origin very close; fall through only when clearly outside - if (proj > CHAR_BOUND_R) return null; - } - - const c = Math.cos(yaw); - const s = Math.sin(yaw); - const ry = oy - py; - const lox = c * rx - s * rz; - const loz = s * rx + c * rz; - const loy = ry; - const ldx = c * dx - s * dz; - const ldz = s * dx + c * dz; - const ldy = dy; - - let best: CharHit | null = null; - for (const box of HITBOXES) { - const t = rayBox(lox, loy, loz, ldx, ldy, ldz, box.min, box.max); - if (t >= 0 && t <= maxT && (!best || t < best.t)) { - best = { zone: box.zone, t }; - } - } - return best; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/constants.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/constants.ts deleted file mode 100644 index 4cdc535..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/constants.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Central gameplay tunables. - -export const FIXED_DT = 1 / 60; // physics step -export const MAX_FRAME_DT = 1 / 20; // clamp big frame gaps (tab switches) -export const GRAVITY = 20; // m/s^2 - -export const PLAYER = { - radius: 0.42, - height: 1.8, - eyeHeight: 1.62, - jumpSpeed: 7.4, // apex ~1.37m (clears 1.2m crates) - runSpeed: 6.6, - walkSpeed: 3.3, // hold shift: slow + accurate - groundAccel: 65, - airAccel: 14, - friction: 10, - maxHealth: 100, - maxArmor: 100, -}; - -export const AI = { - fovDeg: 105, // vision cone half-handled in code - viewRange: 70, - reactionTime: 0.22, // seconds before a spotted enemy is engaged - aimError: 0.05, // radians of aim jitter (skill) - aimSpeed: 7, // rad/s turn toward target - burstMin: 0.3, - burstMax: 0.9, - repathInterval: 0.6, -}; - -export const ROUND = { - freezeTime: 3, - roundTime: 115, // seconds before CT win by time (no plant) - bombTimer: 40, - plantTime: 3.2, - defuseTime: 7, - overTime: 5, // seconds showing result before next round - bombDamageRadius: 14, -}; - -// Team colors (three.js hex). CT = navy/blue, T = tan/sand. -export const COLORS = { - ctPrimary: 0x2f5fa8, - ctSecondary: 0xbcd2f0, - ctSkin: 0xd7a98a, - tPrimary: 0xb08b4f, - tSecondary: 0x5a4526, - tSkin: 0xc99a76, - wall: 0xb8a488, - wallDark: 0x8f7f66, - floor: 0xa79878, - crate: 0x9c6b34, - crateEdge: 0x5c3d1c, - siteA: 0xd25b4a, - siteB: 0x4aa3d2, - bomb: 0x222222, - sky: 0x8fb3d9, -}; diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/dust2.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/dust2.ts deleted file mode 100644 index b1df4f3..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/dust2.ts +++ /dev/null @@ -1,122 +0,0 @@ -// Procedural Dust2 core layout, authored as carved rectangles on the tile grid. -// Orientation (top-down): T spawn south (+Z, bottom), CT spawn north (-Z, top), -// A site / A long east (+X, right), B site / tunnels west (-X, left), mid runs -// vertically through the center with the passable doors halfway. - -import { MapGrid, Region } from './grid'; - -export interface Crate { - x: number; - z: number; - hx: number; // half extent X (m) - hz: number; // half extent Z (m) - height: number; // top Y (m); box spans y in [0, height] -} - -export interface BombSite { - name: 'A' | 'B'; - region: Region; - center: { x: number; z: number }; - radius: number; -} - -export interface SpawnPoint { - x: number; - z: number; -} - -export interface Dust2 { - grid: MapGrid; - crates: Crate[]; - sites: { A: BombSite; B: BombSite }; - tSpawns: SpawnPoint[]; - ctSpawns: SpawnPoint[]; - doorCells: { cx: number; cz: number }[]; - bounds: { minX: number; maxX: number; minZ: number; maxZ: number }; -} - -export const CELL = 2.2; -export const COLS = 60; -export const ROWS = 60; -export const WALL_HEIGHT = 4.2; - -export function buildDust2(): Dust2 { - const g = new MapGrid(COLS, ROWS, CELL); - - // --- rooms & corridors (inclusive cell coords) --- - g.carve(22, 3, 34, 9, Region.CTSpawn); // CT spawn (north) - g.carve(34, 5, 41, 9, Region.Connect); // A short (CT -> A) - g.carve(40, 6, 54, 18, Region.ASite); // A site (NE) - g.carve(28, 9, 30, 46, Region.Mid); // mid corridor - g.carve(31, 16, 41, 19, Region.Cat); // catwalk (mid -> A) - g.carve(49, 18, 53, 50, Region.Long); // A long (right side) - g.carve(42, 49, 53, 53, Region.Connect); // T -> long doors - g.carve(30, 50, 44, 57, Region.TSpawn); // T spawn (south) - g.carve(26, 44, 34, 50, Region.Connect); // T -> mid junction - g.carve(8, 44, 33, 48, Region.Tunnel); // upper tunnels (T -> B) - g.carve(8, 20, 13, 48, Region.Tunnel); // B tunnel (vertical) - g.carve(4, 14, 18, 26, Region.BSite); // B site (W) - g.carve(13, 20, 28, 24, Region.Connect); // mid -> B (lower/doors) - - // Mid doors: a passable door prop sits across these cells. - g.tag(28, 26, 30, 28, Region.Door); - const doorCells = [ - { cx: 28, cz: 27 }, - { cx: 29, cz: 27 }, - { cx: 30, cz: 27 }, - ]; - - // --- crates (cover + plant references) --- - const crateCell = (cx: number, cz: number, hx: number, hz: number, height: number): Crate => { - const c = g.centerOf(cx, cz); - return { x: c.x, z: c.z, hx, hz, height }; - }; - const crates: Crate[] = [ - // A site - crateCell(45, 13, 1.5, 1.5, 1.5), - crateCell(48, 11, 1.5, 1.5, 1.5), - crateCell(43, 9, 2.0, 1.1, 1.0), - // B site - crateCell(9, 21, 1.5, 1.5, 1.5), - crateCell(13, 24, 1.5, 1.5, 1.5), - crateCell(7, 17, 1.1, 1.1, 1.0), - // mid / long / catwalk cover - crateCell(29, 20, 1.3, 1.3, 1.2), - crateCell(51, 34, 1.8, 1.3, 1.2), - crateCell(36, 18, 1.3, 1.3, 1.2), - ]; - - // --- bomb sites --- - const aCenter = g.centerOf(47, 12); - const bCenter = g.centerOf(11, 20); - const sites = { - A: { name: 'A' as const, region: Region.ASite, center: aCenter, radius: 16 }, - B: { name: 'B' as const, region: Region.BSite, center: bCenter, radius: 15 }, - }; - - // --- spawns --- - const spawnAt = (cx: number, cz: number): SpawnPoint => g.centerOf(cx, cz); - const tSpawns = [ - spawnAt(32, 54), - spawnAt(35, 55), - spawnAt(38, 54), - spawnAt(41, 55), - spawnAt(43, 52), - ]; - const ctSpawns = [ - spawnAt(24, 5), - spawnAt(27, 6), - spawnAt(30, 5), - spawnAt(32, 7), - spawnAt(25, 7), - ]; - - const bounds = { - minX: g.originX, - maxX: g.originX + COLS * CELL, - minZ: g.originZ, - maxZ: g.originZ + ROWS * CELL, - }; - - return { grid: g, crates, sites, tSpawns, ctSpawns, doorCells, bounds }; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/effects.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/effects.ts deleted file mode 100644 index 75bdbc3..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/effects.ts +++ /dev/null @@ -1,118 +0,0 @@ -// Pooled transient visuals: bullet tracers, muzzle flashes, and impact sparks / -// blood puffs. All are cheap emissive/additive meshes recycled from fixed pools. - -import * as THREE from 'three'; - -interface Slot { - mesh: THREE.Mesh; - life: number; - max: number; -} - -export class Effects { - private tracers: Slot[] = []; - private flashes: Slot[] = []; - private impacts: Slot[] = []; - private scene: THREE.Scene; - - constructor(scene: THREE.Scene) { - this.scene = scene; - const tracerGeo = new THREE.BoxGeometry(0.035, 0.035, 1); - for (let i = 0; i < 24; i++) { - const mesh = new THREE.Mesh( - tracerGeo, - new THREE.MeshBasicMaterial({ color: 0xffe08a, transparent: true, opacity: 0, blending: THREE.AdditiveBlending, depthWrite: false }), - ); - mesh.visible = false; - scene.add(mesh); - this.tracers.push({ mesh, life: 0, max: 0.06 }); - } - const flashGeo = new THREE.SphereGeometry(0.16, 6, 6); - for (let i = 0; i < 16; i++) { - const mesh = new THREE.Mesh( - flashGeo, - new THREE.MeshBasicMaterial({ color: 0xfff2b0, transparent: true, opacity: 0, blending: THREE.AdditiveBlending, depthWrite: false }), - ); - mesh.visible = false; - scene.add(mesh); - this.flashes.push({ mesh, life: 0, max: 0.05 }); - } - const impactGeo = new THREE.SphereGeometry(0.09, 6, 6); - for (let i = 0; i < 32; i++) { - const mesh = new THREE.Mesh( - impactGeo, - new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0, depthWrite: false }), - ); - mesh.visible = false; - scene.add(mesh); - this.impacts.push({ mesh, life: 0, max: 0.18 }); - } - } - - private take(pool: Slot[]): Slot | null { - for (const s of pool) if (s.life <= 0) return s; - return pool[0] ?? null; - } - - tracer(fx: number, fy: number, fz: number, tx: number, ty: number, tz: number): void { - const s = this.take(this.tracers); - if (!s) return; - const dx = tx - fx, dy = ty - fy, dz = tz - fz; - const len = Math.hypot(dx, dy, dz) || 0.01; - s.mesh.position.set((fx + tx) / 2, (fy + ty) / 2, (fz + tz) / 2); - s.mesh.scale.set(1, 1, len); - s.mesh.lookAt(tx, ty, tz); - s.mesh.visible = true; - (s.mesh.material as THREE.MeshBasicMaterial).opacity = 0.9; - s.life = s.max; - } - - flash(x: number, y: number, z: number): void { - const s = this.take(this.flashes); - if (!s) return; - s.mesh.position.set(x, y, z); - const sc = 0.7 + Math.random() * 0.6; - s.mesh.scale.setScalar(sc); - s.mesh.visible = true; - (s.mesh.material as THREE.MeshBasicMaterial).opacity = 1; - s.life = s.max; - } - - impact(x: number, y: number, z: number, blood: boolean): void { - const s = this.take(this.impacts); - if (!s) return; - s.mesh.position.set(x, y, z); - s.mesh.scale.setScalar(blood ? 1.4 : 1); - (s.mesh.material as THREE.MeshBasicMaterial).color.setHex(blood ? 0x9c1c1c : 0xd9cdb0); - s.mesh.visible = true; - (s.mesh.material as THREE.MeshBasicMaterial).opacity = 1; - s.life = s.max; - } - - update(dt: number): void { - for (const s of this.tracers) { - if (s.life <= 0) continue; - s.life -= dt; - const mat = s.mesh.material as THREE.MeshBasicMaterial; - mat.opacity = Math.max(0, (s.life / s.max) * 0.9); - if (s.life <= 0) s.mesh.visible = false; - } - for (const s of this.flashes) { - if (s.life <= 0) continue; - s.life -= dt; - const mat = s.mesh.material as THREE.MeshBasicMaterial; - mat.opacity = Math.max(0, s.life / s.max); - if (s.life <= 0) s.mesh.visible = false; - } - for (const s of this.impacts) { - if (s.life <= 0) continue; - s.life -= dt; - const k = s.life / s.max; - const mat = s.mesh.material as THREE.MeshBasicMaterial; - mat.opacity = Math.max(0, k); - s.mesh.scale.multiplyScalar(1 + dt * 2); - s.mesh.position.y += dt * 0.4; - if (s.life <= 0) s.mesh.visible = false; - } - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/characterModel.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/characterModel.ts deleted file mode 100644 index 9e3b497..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/characterModel.ts +++ /dev/null @@ -1,151 +0,0 @@ -// Blocky humanoid built entirely from boxes: separate head, torso, pelvis, two -// arms (posed forward gripping the weapon) and two legs with knees + feet. No -// capsules/cylinders. CT reads blue with a helmet; T reads tan with a balaclava. - -import * as THREE from 'three'; -import { COLORS } from '../constants'; -import { Team } from '../types'; - -export interface CharacterRig { - root: THREE.Group; - legL: THREE.Group; - legR: THREE.Group; - armL: THREE.Group; - armR: THREE.Group; - head: THREE.Group; - weaponHolder: THREE.Group; - materials: THREE.Material[]; - team: Team; -} - -function box( - w: number, h: number, d: number, color: number, mats: THREE.Material[], -): THREE.Mesh { - const geo = new THREE.BoxGeometry(w, h, d); - const mat = new THREE.MeshStandardMaterial({ color, roughness: 0.85, metalness: 0.05, flatShading: true }); - mats.push(mat); - const mesh = new THREE.Mesh(geo, mat); - mesh.castShadow = true; - return mesh; -} - -export function buildCharacter(team: Team): CharacterRig { - const mats: THREE.Material[] = []; - const isCT = team === Team.CT; - const primary = isCT ? COLORS.ctPrimary : COLORS.tPrimary; - const secondary = isCT ? COLORS.ctSecondary : COLORS.tSecondary; - const skin = isCT ? COLORS.ctSkin : COLORS.tSkin; - - const root = new THREE.Group(); - - // pelvis - const pelvis = box(0.34, 0.22, 0.22, secondary, mats); - pelvis.position.set(0, 0.94, 0); - root.add(pelvis); - - // chest (torso) + vest overlay - const chest = box(0.44, 0.5, 0.26, primary, mats); - chest.position.set(0, 1.3, 0); - root.add(chest); - const vest = box(0.46, 0.34, 0.1, secondary, mats); - vest.position.set(0, 1.34, 0.12); - root.add(vest); - // shoulders - const shoulders = box(0.5, 0.14, 0.24, primary, mats); - shoulders.position.set(0, 1.5, 0); - root.add(shoulders); - - // head group (neck pivot) - const head = new THREE.Group(); - head.position.set(0, 1.57, 0); - root.add(head); - const neck = box(0.12, 0.08, 0.12, skin, mats); - neck.position.set(0, 0.0, 0); - head.add(neck); - const skull = box(0.24, 0.24, 0.24, isCT ? skin : COLORS.tSecondary, mats); - skull.position.set(0, 0.16, 0); - head.add(skull); - if (isCT) { - // helmet - const helmet = box(0.27, 0.13, 0.27, 0x24405f, mats); - helmet.position.set(0, 0.24, 0); - head.add(helmet); - // face strip - const face = box(0.2, 0.09, 0.02, 0x2a2a30, mats); - face.position.set(0, 0.14, 0.12); - head.add(face); - } else { - // balaclava eye strip (skin showing) - const eyes = box(0.2, 0.06, 0.02, skin, mats); - eyes.position.set(0, 0.18, 0.12); - head.add(eyes); - } - - // helper to build a limb hanging from a pivot group - const makeLeg = (side: number): THREE.Group => { - const g = new THREE.Group(); - g.position.set(0.12 * side, 0.9, 0); - const upper = box(0.17, 0.46, 0.19, primary, mats); - upper.position.set(0, -0.23, 0); - g.add(upper); - const lower = box(0.15, 0.44, 0.17, secondary, mats); - lower.position.set(0, -0.66, 0.01); - g.add(lower); - const foot = box(0.16, 0.1, 0.28, 0x2a2a2a, mats); - foot.position.set(0, -0.87, 0.06); - g.add(foot); - return g; - }; - const legL = makeLeg(1); - const legR = makeLeg(-1); - root.add(legL, legR); - - // arms posed forward to grip the weapon (pivot at shoulder) - const makeArm = (side: number): THREE.Group => { - const g = new THREE.Group(); - g.position.set(0.26 * side, 1.46, 0); - const upper = box(0.13, 0.34, 0.14, primary, mats); - upper.position.set(0, -0.15, 0); - g.add(upper); - const lower = box(0.11, 0.3, 0.12, skin, mats); - lower.position.set(0, -0.42, 0); - g.add(lower); - const hand = box(0.1, 0.1, 0.12, 0x3a2f28, mats); - hand.position.set(0, -0.58, 0); - g.add(hand); - // rotate the whole arm forward + inward so hands meet at the gun - g.rotation.x = -1.35; - g.rotation.z = 0.28 * side; - return g; - }; - const armL = makeArm(1); - const armR = makeArm(-1); - root.add(armL, armR); - - // weapon attaches in front of the chest where the hands converge - const weaponHolder = new THREE.Group(); - weaponHolder.position.set(0, 1.2, -0.36); - root.add(weaponHolder); - - root.traverse((o) => { - o.castShadow = true; - }); - - return { root, legL, legR, armL, armR, head, weaponHolder, materials: mats, team }; -} - -// Walk cycle + idle bob; freezes into a fallen pose when dead. -export function animateCharacter( - rig: CharacterRig, speed: number, time: number, dead: boolean, -): void { - if (dead) return; - const stride = Math.min(1, speed / 6); - const freq = 8; - const swing = Math.sin(time * freq) * 0.6 * stride; - rig.legL.rotation.x = swing; - rig.legR.rotation.x = -swing; - // subtle arm counter-bob while keeping the aim pose - rig.armL.rotation.x = -1.35 + Math.sin(time * freq) * 0.05 * stride; - rig.armR.rotation.x = -1.35 - Math.sin(time * freq) * 0.05 * stride; - rig.root.position.y = Math.abs(Math.sin(time * freq)) * 0.04 * stride; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/weaponModels.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/weaponModels.ts deleted file mode 100644 index 0d13219..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/entities/weaponModels.ts +++ /dev/null @@ -1,132 +0,0 @@ -// Procedural weapon meshes. The same silhouette serves the third-person world -// model (parented to a character's hands) and the first-person viewmodel -// (parented to the camera). Barrels point down -Z; a `muzzle` empty marks the -// tip for flash + tracer spawning. - -import * as THREE from 'three'; -import { WeaponId } from '../types'; - -export interface WeaponMesh { - group: THREE.Group; - muzzle: THREE.Object3D; -} - -function part( - g: THREE.Group, w: number, h: number, d: number, color: number, - x: number, y: number, z: number, rotX = 0, metal = 0.4, rough = 0.5, -): THREE.Mesh { - const mesh = new THREE.Mesh( - new THREE.BoxGeometry(w, h, d), - new THREE.MeshStandardMaterial({ color, metalness: metal, roughness: rough }), - ); - mesh.position.set(x, y, z); - mesh.rotation.x = rotX; - mesh.castShadow = true; - g.add(mesh); - return mesh; -} - -const BLACK = 0x1c1d1f; -const STEEL = 0x9aa0a6; -const WOOD = 0x6b4a2a; -const TAN = 0x8a7a55; - -function buildRifle(id: WeaponId): WeaponMesh { - const g = new THREE.Group(); - const accent = id === 'ak47' ? WOOD : TAN; - part(g, 0.07, 0.11, 0.52, BLACK, 0, 0, -0.03); // receiver - part(g, 0.032, 0.032, 0.5, BLACK, 0, 0.03, -0.4, 0, 0.7, 0.35); // barrel - part(g, 0.06, 0.2, 0.1, accent, 0, -0.14, 0.0, 0.25); // magazine - part(g, 0.05, 0.1, 0.24, accent, 0, -0.01, 0.24); // stock - part(g, 0.045, 0.13, 0.055, BLACK, 0, -0.1, 0.09, 0.15); // grip - part(g, 0.02, 0.04, 0.12, BLACK, 0, 0.075, -0.18); // front sight/handguard top - const muzzle = new THREE.Object3D(); - muzzle.position.set(0, 0.03, -0.66); - g.add(muzzle); - return { group: g, muzzle }; -} - -function buildAwp(): WeaponMesh { - const g = new THREE.Group(); - const green = 0x384231; - part(g, 0.07, 0.12, 0.72, green, 0, 0, 0.0); - part(g, 0.03, 0.03, 0.72, BLACK, 0, 0.02, -0.62, 0, 0.7, 0.35); // long barrel - part(g, 0.06, 0.13, 0.09, BLACK, 0, -0.11, -0.05, 0.1); // mag - part(g, 0.055, 0.11, 0.32, green, 0, -0.02, 0.36); // stock - part(g, 0.045, 0.14, 0.05, BLACK, 0, -0.1, 0.1, 0.1); // grip - // scope - part(g, 0.055, 0.055, 0.3, BLACK, 0, 0.12, -0.02, 0, 0.6, 0.3); - part(g, 0.02, 0.06, 0.02, BLACK, 0, 0.07, -0.14); - part(g, 0.02, 0.06, 0.02, BLACK, 0, 0.07, 0.1); - const lens = new THREE.Mesh( - new THREE.CircleGeometry(0.026, 12), - new THREE.MeshStandardMaterial({ color: 0x224466, metalness: 0.9, roughness: 0.1, emissive: 0x113355 }), - ); - lens.position.set(0, 0.12, 0.14); - lens.rotation.y = Math.PI; - g.add(lens); - const muzzle = new THREE.Object3D(); - muzzle.position.set(0, 0.02, -0.98); - g.add(muzzle); - return { group: g, muzzle }; -} - -function buildPistol(id: WeaponId): WeaponMesh { - const g = new THREE.Group(); - const scale = id === 'deagle' ? 1.28 : 1.0; - const bodyColor = id === 'deagle' ? 0xb8a44e : id === 'usp' ? 0x26282b : BLACK; - const s = (v: number) => v * scale; - part(g, s(0.05), s(0.07), s(0.24), bodyColor, 0, s(0.02), s(-0.03), 0, 0.6, 0.35); // slide - part(g, s(0.045), s(0.17), s(0.08), 0x222327, 0, s(-0.1), s(0.05), 0.28); // grip - part(g, s(0.028), s(0.028), s(0.06), BLACK, 0, s(0.02), s(-0.16)); // barrel tip - let muzZ = s(-0.18); - if (id === 'usp') { - part(g, s(0.05), s(0.05), s(0.16), 0x2a2c2f, 0, s(0.02), s(-0.26), 0, 0.5, 0.4); // suppressor - muzZ = s(-0.36); - } - const muzzle = new THREE.Object3D(); - muzzle.position.set(0, s(0.02), muzZ); - g.add(muzzle); - return { group: g, muzzle }; -} - -function buildKnife(): WeaponMesh { - const g = new THREE.Group(); - part(g, 0.028, 0.045, 0.14, 0x1a1a1a, 0, -0.02, 0.07, 0.05); // handle - part(g, 0.012, 0.06, 0.24, STEEL, 0, 0.03, -0.12, -0.03, 0.95, 0.15); // blade - const muzzle = new THREE.Object3D(); - muzzle.position.set(0, 0.03, -0.24); - g.add(muzzle); - return { group: g, muzzle }; -} - -export function buildWeaponMesh(id: WeaponId): WeaponMesh { - switch (id) { - case 'ak47': - case 'm4a4': - return buildRifle(id); - case 'awp': - return buildAwp(); - case 'glock': - case 'usp': - case 'deagle': - return buildPistol(id); - case 'knife': - return buildKnife(); - } -} - -// Two simple gripping hands for the first-person viewmodel. -export function addViewHands(g: THREE.Group): void { - const skin = 0xc99a76; - const mk = (x: number, y: number, z: number) => { - const m = new THREE.Mesh( - new THREE.BoxGeometry(0.09, 0.09, 0.12), - new THREE.MeshStandardMaterial({ color: skin, roughness: 0.7 }), - ); - m.position.set(x, y, z); - g.add(m); - }; - mk(0.02, -0.08, 0.08); // rear hand at grip - mk(0.0, -0.05, -0.16); // front hand on handguard -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/grid.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/grid.ts deleted file mode 100644 index 6ddc148..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/grid.ts +++ /dev/null @@ -1,233 +0,0 @@ -// Tile-grid map core. Pure TS (no three.js) so it can be unit-tested with bun. -// The world is a grid of square cells in the XZ plane; walls are full-height -// columns, floor cells are walkable. Line-of-sight and bullet clipping against -// walls use grid DDA traversal (Amanatides & Woo). - -export enum Region { - None = 0, - TSpawn = 1, - CTSpawn = 2, - ASite = 3, - BSite = 4, - Mid = 5, - Long = 6, - Cat = 7, - Tunnel = 8, - Connect = 9, - Door = 10, -} - -const REGION_CHAR: Record = { - 0: '#', // wall / void rendered as # in ascii dumps - 1: 't', - 2: 'c', - 3: 'A', - 4: 'B', - 5: 'm', - 6: 'L', - 7: 'k', - 8: 'u', - 9: '+', - 10: 'D', -}; - -export interface CellRef { - cx: number; - cz: number; -} - -export class MapGrid { - readonly cols: number; - readonly rows: number; - readonly cell: number; // world size of one cell (meters) - readonly floor: Uint8Array; // 1 = walkable - readonly region: Uint8Array; // Region id per cell (only meaningful when floor) - readonly originX: number; // world X of cell (0,0) left edge - readonly originZ: number; - - constructor(cols: number, rows: number, cell: number) { - this.cols = cols; - this.rows = rows; - this.cell = cell; - this.floor = new Uint8Array(cols * rows); - this.region = new Uint8Array(cols * rows); - // Center the grid on the world origin. - this.originX = -(cols * cell) / 2; - this.originZ = -(rows * cell) / 2; - } - - idx(cx: number, cz: number): number { - return cz * this.cols + cx; - } - - inBounds(cx: number, cz: number): boolean { - return cx >= 0 && cz >= 0 && cx < this.cols && cz < this.rows; - } - - isFloor(cx: number, cz: number): boolean { - if (!this.inBounds(cx, cz)) return false; - return this.floor[this.idx(cx, cz)] === 1; - } - - // Out-of-bounds counts as wall so the arena is sealed. - isWall(cx: number, cz: number): boolean { - return !this.isFloor(cx, cz); - } - - regionAt(cx: number, cz: number): Region { - if (!this.inBounds(cx, cz)) return Region.None; - return this.region[this.idx(cx, cz)] as Region; - } - - // Carve a filled rectangle of floor (inclusive cell coords) with a region tag. - carve(cx0: number, cz0: number, cx1: number, cz1: number, region: Region): void { - const x0 = Math.min(cx0, cx1); - const x1 = Math.max(cx0, cx1); - const z0 = Math.min(cz0, cz1); - const z1 = Math.max(cz0, cz1); - for (let cz = z0; cz <= z1; cz++) { - for (let cx = x0; cx <= x1; cx++) { - if (!this.inBounds(cx, cz)) continue; - const i = this.idx(cx, cz); - this.floor[i] = 1; - this.region[i] = region; - } - } - } - - // Overwrite region on already-carved floor cells (does not create floor). - tag(cx0: number, cz0: number, cx1: number, cz1: number, region: Region): void { - const x0 = Math.min(cx0, cx1); - const x1 = Math.max(cx0, cx1); - const z0 = Math.min(cz0, cz1); - const z1 = Math.max(cz0, cz1); - for (let cz = z0; cz <= z1; cz++) { - for (let cx = x0; cx <= x1; cx++) { - if (!this.inBounds(cx, cz)) continue; - const i = this.idx(cx, cz); - if (this.floor[i]) this.region[i] = region; - } - } - } - - // --- world <-> cell conversion --- - cellOf(x: number, z: number): CellRef { - return { - cx: Math.floor((x - this.originX) / this.cell), - cz: Math.floor((z - this.originZ) / this.cell), - }; - } - - centerOf(cx: number, cz: number): { x: number; z: number } { - return { - x: this.originX + (cx + 0.5) * this.cell, - z: this.originZ + (cz + 0.5) * this.cell, - }; - } - - isWallAtWorld(x: number, z: number): boolean { - const c = this.cellOf(x, z); - return this.isWall(c.cx, c.cz); - } - - // DDA: distance (world units) along ray (ox,oz)+t*(dx,dz) to first wall cell. - // Returns maxDist if nothing hit within range. dir need not be normalized; - // dx,dz are treated as a unit direction here. - rayWallDistance(ox: number, oz: number, dx: number, dz: number, maxDist: number): number { - const cs = this.cell; - let cx = Math.floor((ox - this.originX) / cs); - let cz = Math.floor((oz - this.originZ) / cs); - if (this.isWall(cx, cz)) return 0; - const stepX = dx > 0 ? 1 : dx < 0 ? -1 : 0; - const stepZ = dz > 0 ? 1 : dz < 0 ? -1 : 0; - const tDeltaX = dx !== 0 ? Math.abs(cs / dx) : Infinity; - const tDeltaZ = dz !== 0 ? Math.abs(cs / dz) : Infinity; - // world coords of current cell edges - const cellMinX = this.originX + cx * cs; - const cellMinZ = this.originZ + cz * cs; - let tMaxX = - dx !== 0 - ? (stepX > 0 ? cellMinX + cs - ox : ox - cellMinX) / Math.abs(dx) - : Infinity; - let tMaxZ = - dz !== 0 - ? (stepZ > 0 ? cellMinZ + cs - oz : oz - cellMinZ) / Math.abs(dz) - : Infinity; - let guard = 0; - while (guard++ < 4096) { - let t: number; - if (tMaxX < tMaxZ) { - cx += stepX; - t = tMaxX; - tMaxX += tDeltaX; - } else { - cz += stepZ; - t = tMaxZ; - tMaxZ += tDeltaZ; - } - if (t > maxDist) return maxDist; - if (this.isWall(cx, cz)) return t; - } - return maxDist; - } - - // True if a wall blocks the straight segment a->b in the XZ plane. - segmentBlocked(ax: number, az: number, bx: number, bz: number): boolean { - const dx = bx - ax; - const dz = bz - az; - const len = Math.hypot(dx, dz); - if (len < 1e-6) return false; - const d = this.rayWallDistance(ax, az, dx / len, dz / len, len); - return d < len - 1e-3; - } - - // Breadth-first reachable set from a seed floor cell; used to verify the map - // is fully connected during authoring. - reachableCount(seedCx: number, seedCz: number): number { - const seen = new Uint8Array(this.cols * this.rows); - const stack: number[] = []; - if (!this.isFloor(seedCx, seedCz)) return 0; - stack.push(this.idx(seedCx, seedCz)); - seen[this.idx(seedCx, seedCz)] = 1; - let count = 0; - while (stack.length) { - const i = stack.pop()!; - count++; - const cx = i % this.cols; - const cz = (i - cx) / this.cols; - const neigh = [ - [cx + 1, cz], - [cx - 1, cz], - [cx, cz + 1], - [cx, cz - 1], - ]; - for (const [nx, nz] of neigh) { - if (!this.isFloor(nx, nz)) continue; - const ni = this.idx(nx, nz); - if (seen[ni]) continue; - seen[ni] = 1; - stack.push(ni); - } - } - return count; - } - - totalFloor(): number { - let n = 0; - for (let i = 0; i < this.floor.length; i++) if (this.floor[i]) n++; - return n; - } - - toAscii(): string { - const lines: string[] = []; - for (let cz = 0; cz < this.rows; cz++) { - let line = ''; - for (let cx = 0; cx < this.cols; cx++) { - const i = this.idx(cx, cz); - line += this.floor[i] ? REGION_CHAR[this.region[i]] ?? '.' : '#'; - } - lines.push(line); - } - return lines.join('\n'); - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/input.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/input.ts deleted file mode 100644 index 0a28391..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/input.ts +++ /dev/null @@ -1,116 +0,0 @@ -// Keyboard + mouse + pointer-lock input. Movement/aim are polled each frame; -// discrete actions (weapon switch, reload, jump) use edge-triggered presses. - -export class Input { - keys = new Set(); - private justPressed = new Set(); - mouseDX = 0; - mouseDY = 0; - left = false; - right = false; - leftJustPressed = false; - wheel = 0; - locked = false; - private el: HTMLElement; - private handlers: Array<[EventTarget, string, EventListenerOrEventListenerObject]> = []; - - constructor(el: HTMLElement) { - this.el = el; - const gameKeys = new Set([ - 'KeyW', 'KeyA', 'KeyS', 'KeyD', 'Space', 'ShiftLeft', 'KeyR', 'KeyE', 'KeyG', - 'KeyF', 'Digit1', 'Digit2', 'Digit3', 'Tab', 'KeyB', - ]); - - const onKeyDown = (e: KeyboardEvent) => { - if (gameKeys.has(e.code)) e.preventDefault(); - if (!e.repeat && !this.keys.has(e.code)) this.justPressed.add(e.code); - this.keys.add(e.code); - }; - const onKeyUp = (e: KeyboardEvent) => { - this.keys.delete(e.code); - }; - const onMouseDown = (e: MouseEvent) => { - if (!this.locked) return; - if (e.button === 0) { - this.left = true; - this.leftJustPressed = true; - } else if (e.button === 2) { - this.right = true; - } - }; - const onMouseUp = (e: MouseEvent) => { - if (e.button === 0) this.left = false; - else if (e.button === 2) this.right = false; - }; - const onMouseMove = (e: MouseEvent) => { - if (!this.locked) return; - this.mouseDX += e.movementX; - this.mouseDY += e.movementY; - }; - const onContext = (e: Event) => e.preventDefault(); - const onWheel = (e: WheelEvent) => { - if (this.locked) { - e.preventDefault(); - this.wheel += Math.sign(e.deltaY); - } - }; - const onLockChange = () => { - this.locked = document.pointerLockElement === this.el; - if (!this.locked) { - this.keys.clear(); - this.left = this.right = false; - } - }; - - this.add(window, 'keydown', onKeyDown as EventListener); - this.add(window, 'keyup', onKeyUp as EventListener); - this.add(window, 'mousedown', onMouseDown as EventListener); - this.add(window, 'mouseup', onMouseUp as EventListener); - this.add(window, 'mousemove', onMouseMove as EventListener); - this.add(el, 'contextmenu', onContext); - this.add(el, 'wheel', onWheel as EventListener, { passive: false } as AddEventListenerOptions); - this.add(document, 'pointerlockchange', onLockChange); - } - - private add( - target: EventTarget, type: string, fn: EventListenerOrEventListenerObject, - opts?: AddEventListenerOptions, - ): void { - target.addEventListener(type, fn, opts); - this.handlers.push([target, type, fn]); - } - - requestLock(): void { - // Pointer lock can be unavailable (sandboxed iframe, unfocused document). - // Swallow both sync throws and promise rejections; keyboard control still - // works and the game keeps running in that degraded mode. - try { - const r = this.el.requestPointerLock?.() as unknown as Promise | undefined; - if (r && typeof r.catch === 'function') r.catch(() => {}); - } catch { - /* ignore */ - } - } - - down(code: string): boolean { - return this.keys.has(code); - } - - pressed(code: string): boolean { - return this.justPressed.has(code); - } - - // call at end of each frame after inputs consumed - endFrame(): void { - this.justPressed.clear(); - this.leftJustPressed = false; - this.mouseDX = 0; - this.mouseDY = 0; - this.wheel = 0; - } - - dispose(): void { - for (const [t, type, fn] of this.handlers) t.removeEventListener(type, fn); - this.handlers = []; - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/mathUtils.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/mathUtils.ts deleted file mode 100644 index 3fed07f..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/mathUtils.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Small math helpers. Yaw convention matches a three.js camera with -// rotation.order 'YXZ': at yaw = 0 the facing direction is -Z. - -export function clamp(v: number, lo: number, hi: number): number { - return v < lo ? lo : v > hi ? hi : v; -} - -export function lerp(a: number, b: number, t: number): number { - return a + (b - a) * t; -} - -export function rand(lo: number, hi: number): number { - return lo + Math.random() * (hi - lo); -} - -export function randInt(lo: number, hi: number): number { - return Math.floor(rand(lo, hi + 1)); -} - -export function pick(arr: T[]): T { - return arr[Math.floor(Math.random() * arr.length)]; -} - -// Facing direction for a yaw (XZ plane), matching camera base-forward -Z. -export function forwardFromYaw(yaw: number): { x: number; z: number } { - return { x: -Math.sin(yaw), z: -Math.cos(yaw) }; -} - -// Inverse of forwardFromYaw. -export function yawFromDir(x: number, z: number): number { - return Math.atan2(-x, -z); -} - -// Shortest signed angular difference a->b in (-PI, PI]. -export function angleDelta(a: number, b: number): number { - let d = (b - a) % (Math.PI * 2); - if (d > Math.PI) d -= Math.PI * 2; - if (d < -Math.PI) d += Math.PI * 2; - return d; -} - -export function moveAngleToward(from: number, to: number, maxStep: number): number { - const d = angleDelta(from, to); - if (Math.abs(d) <= maxStep) return to; - return from + Math.sign(d) * maxStep; -} - -export function dist2(ax: number, az: number, bx: number, bz: number): number { - const dx = ax - bx; - const dz = az - bz; - return dx * dx + dz * dz; -} - -export function len2(x: number, z: number): number { - return Math.hypot(x, z); -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/navmesh.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/navmesh.ts deleted file mode 100644 index 44fc926..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/navmesh.ts +++ /dev/null @@ -1,163 +0,0 @@ -// A* pathfinding over the floor grid for AI navigation. 8-connected with no -// corner-cutting through walls; the resulting cell path is line-of-sight -// simplified so bots walk natural diagonals instead of hugging cell centers. - -import { MapGrid } from './grid'; - -interface HeapItem { - i: number; - f: number; -} - -class MinHeap { - private a: HeapItem[] = []; - get size(): number { - return this.a.length; - } - push(item: HeapItem): void { - const a = this.a; - a.push(item); - let c = a.length - 1; - while (c > 0) { - const p = (c - 1) >> 1; - if (a[p].f <= a[c].f) break; - [a[p], a[c]] = [a[c], a[p]]; - c = p; - } - } - pop(): HeapItem { - const a = this.a; - const top = a[0]; - const last = a.pop()!; - if (a.length) { - a[0] = last; - let p = 0; - const n = a.length; - for (;;) { - const l = p * 2 + 1; - const r = l + 1; - let s = p; - if (l < n && a[l].f < a[s].f) s = l; - if (r < n && a[r].f < a[s].f) s = r; - if (s === p) break; - [a[p], a[s]] = [a[s], a[p]]; - p = s; - } - } - return top; - } -} - -function nearestFloor(grid: MapGrid, cx: number, cz: number): { cx: number; cz: number } | null { - if (grid.isFloor(cx, cz)) return { cx, cz }; - for (let r = 1; r <= 4; r++) { - for (let dz = -r; dz <= r; dz++) { - for (let dx = -r; dx <= r; dx++) { - if (Math.abs(dx) !== r && Math.abs(dz) !== r) continue; - if (grid.isFloor(cx + dx, cz + dz)) return { cx: cx + dx, cz: cz + dz }; - } - } - } - return null; -} - -const SQRT2 = Math.SQRT2; - -export function findPath( - grid: MapGrid, - startX: number, startZ: number, - goalX: number, goalZ: number, -): { x: number; z: number }[] | null { - const s0 = grid.cellOf(startX, startZ); - const g0 = grid.cellOf(goalX, goalZ); - const start = nearestFloor(grid, s0.cx, s0.cz); - const goal = nearestFloor(grid, g0.cx, g0.cz); - if (!start || !goal) return null; - - const cols = grid.cols; - const n = cols * grid.rows; - const startI = start.cz * cols + start.cx; - const goalI = goal.cz * cols + goal.cx; - if (startI === goalI) return [{ x: goalX, z: goalZ }]; - - const gScore = new Float32Array(n).fill(Infinity); - const came = new Int32Array(n).fill(-1); - const closed = new Uint8Array(n); - const open = new MinHeap(); - gScore[startI] = 0; - open.push({ i: startI, f: 0 }); - - const gcx = goal.cx; - const gcz = goal.cz; - const heur = (cx: number, cz: number): number => { - const dx = Math.abs(cx - gcx); - const dz = Math.abs(cz - gcz); - return (dx + dz) + (SQRT2 - 2) * Math.min(dx, dz); - }; - - let guard = 0; - let found = false; - while (open.size && guard++ < 20000) { - const cur = open.pop(); - const ci = cur.i; - if (closed[ci]) continue; - closed[ci] = 1; - if (ci === goalI) { - found = true; - break; - } - const cx = ci % cols; - const cz = (ci - cx) / cols; - for (let dz = -1; dz <= 1; dz++) { - for (let dx = -1; dx <= 1; dx++) { - if (dx === 0 && dz === 0) continue; - const nx = cx + dx; - const nz = cz + dz; - if (!grid.isFloor(nx, nz)) continue; - if (dx !== 0 && dz !== 0) { - // no corner cutting - if (grid.isWall(cx + dx, cz) || grid.isWall(cx, cz + dz)) continue; - } - const ni = nz * cols + nx; - if (closed[ni]) continue; - const step = dx !== 0 && dz !== 0 ? SQRT2 : 1; - const ng = gScore[ci] + step; - if (ng < gScore[ni]) { - gScore[ni] = ng; - came[ni] = ci; - open.push({ i: ni, f: ng + heur(nx, nz) }); - } - } - } - } - if (!found) return null; - - // reconstruct cell path - const cells: number[] = []; - let c = goalI; - while (c !== -1) { - cells.push(c); - c = came[c]; - } - cells.reverse(); - - // to world points (cell centers), keep true goal as final point - const pts: { x: number; z: number }[] = cells.map((i) => { - const cx = i % cols; - const cz = (i - cx) / cols; - return grid.centerOf(cx, cz); - }); - pts[pts.length - 1] = { x: goalX, z: goalZ }; - - // line-of-sight simplification (string pulling) - const out: { x: number; z: number }[] = [pts[0]]; - let anchor = 0; - for (let i = 2; i < pts.length; i++) { - if (grid.segmentBlocked(pts[anchor].x, pts[anchor].z, pts[i].x, pts[i].z)) { - out.push(pts[i - 1]); - anchor = i - 1; - } - } - out.push(pts[pts.length - 1]); - return out; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/player.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/player.ts deleted file mode 100644 index b5acbcf..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/player.ts +++ /dev/null @@ -1,142 +0,0 @@ -// Player controller: turns raw input into the same intent fields the AI uses, -// plus first-person-only concerns (mouse look, scope hold, weapon switching, -// C4 plant/defuse/pickup and a buy-swap for trying the AWP). - -import { PLAYER } from './constants'; -import { forwardFromYaw, clamp } from './mathUtils'; -import { BombState, Team, WeaponId, WeaponSlot } from './types'; -import { WEAPONS } from './weapons'; -import type { Actor, GameWorld } from './world'; - -const SENS = 0.0022; -const PITCH_LIMIT = 1.45; - -function look(a: Actor, world: GameWorld): void { - const input = world.input; - if (!input.locked) return; - a.yaw -= input.mouseDX * SENS; - a.pitch -= input.mouseDY * SENS; - a.pitch = clamp(a.pitch, -PITCH_LIMIT, PITCH_LIMIT); -} - -function equipSlot(world: GameWorld, a: Actor, slot: WeaponSlot): void { - const id = a.weapons.find((w) => WEAPONS[w].slot === slot); - if (id) world.equip(a, id); -} - -function cycleWeapon(world: GameWorld, a: Actor, dir: number): void { - const idx = a.weapons.indexOf(a.current); - const next = (idx + (dir > 0 ? 1 : -1) + a.weapons.length) % a.weapons.length; - world.equip(a, a.weapons[next]); -} - -function swapPrimary(world: GameWorld, a: Actor): void { - const rifle: WeaponId = a.team === Team.T ? 'ak47' : 'm4a4'; - const primaryIdx = a.weapons.findIndex((w) => WEAPONS[w].slot === 'primary'); - if (primaryIdx < 0) return; - const cur = a.weapons[primaryIdx]; - const next: WeaponId = cur === 'awp' ? rifle : 'awp'; - a.weapons[primaryIdx] = next; - const def = WEAPONS[next]; - a.ammo[next] = { mag: def.magSize, reserve: def.reserve }; - world.equip(a, next); -} - -export function updatePlayer(world: GameWorld, a: Actor, dt: number, canMove: boolean): void { - const input = world.input; - - if (!a.alive) { - updateSpectate(world); - return; - } - - a.action = 'none'; - look(a, world); - - // movement intents - if (canMove) { - const fwd = forwardFromYaw(a.yaw); - const right = { x: -fwd.z, z: fwd.x }; - let mx = 0, mz = 0; - if (input.down('KeyW')) { mx += fwd.x; mz += fwd.z; } - if (input.down('KeyS')) { mx -= fwd.x; mz -= fwd.z; } - if (input.down('KeyD')) { mx += right.x; mz += right.z; } - if (input.down('KeyA')) { mx -= right.x; mz -= right.z; } - a.moveX = mx; - a.moveZ = mz; - a.wantRun = !input.down('ShiftLeft'); - if (input.down('Space')) a.wantJump = true; - } else { - a.moveX = a.moveZ = 0; - } - - // weapon selection - if (input.pressed('Digit1')) equipSlot(world, a, 'primary'); - if (input.pressed('Digit2')) equipSlot(world, a, 'secondary'); - if (input.pressed('Digit3')) equipSlot(world, a, 'melee'); - if (input.wheel !== 0) cycleWeapon(world, a, input.wheel); - if (input.pressed('KeyB')) swapPrimary(world, a); - if (input.pressed('KeyR')) world.startReload(a); - - const w = WEAPONS[a.current]; - - // scope (hold right mouse on AWP) - if (w.scoped) { - const want = input.right; - if (want !== a.scoped) { - a.scoped = want; - world.audio.scope(want); - } - } else { - a.scoped = false; - } - - // fire - if (w.automatic) { - if (input.left) world.fireWeapon(a); - } else if (input.leftJustPressed) { - world.fireWeapon(a); - } - - // bomb interactions - handleBomb(world, a, canMove); -} - -// While dead: cycle through living teammates' viewpoints and take control of one. -function updateSpectate(world: GameWorld): void { - const input = world.input; - world.ensureSpectate(); - if (input.leftJustPressed || input.pressed('KeyD')) world.spectateCycle(1); - if (input.pressed('KeyA')) world.spectateCycle(-1); - if (input.pressed('KeyF') || input.pressed('Space')) world.takeOver(); -} - -function handleBomb(world: GameWorld, a: Actor, canMove: boolean): void { - const input = world.input; - const bomb = world.bombInfo(); - let hint = ''; - - if (a.team === Team.T) { - if (a.hasBomb && world.isInSite(a) && a.grounded) { - hint = 'Hold [E] to plant the bomb'; - if (input.down('KeyE')) a.action = 'plant'; - } else if (bomb.state === BombState.Dropped) { - const d2 = (a.x - bomb.x) ** 2 + (a.z - bomb.z) ** 2; - if (d2 < 2.4 * 2.4) { - hint = 'Press [E] to pick up the bomb'; - if (input.down('KeyE')) world.pickupBomb(a); - } - } else if (a.hasBomb) { - hint = 'Bring the bomb to site A or B'; - } - } else { - if (bomb.state === BombState.Planted) { - const d2 = (a.x - bomb.x) ** 2 + (a.z - bomb.z) ** 2; - if (d2 < 2.3 * 2.3 && a.grounded) { - hint = 'Hold [E] to defuse'; - if (input.down('KeyE')) a.action = 'defuse'; - } - } - } - world.setHint(hint); -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/scene.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/scene.ts deleted file mode 100644 index ec4127c..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/scene.ts +++ /dev/null @@ -1,142 +0,0 @@ -// Static world geometry: sky/fog, lights, floor, instanced walls (only cells -// bordering walkable space), crates, bomb-site markers and the passable mid -// doors. Returns the scene plus a few references the simulation needs. - -import * as THREE from 'three'; -import { COLORS } from './constants'; -import { Dust2, WALL_HEIGHT } from './dust2'; -import { Region } from './grid'; - -export interface SceneRefs { - scene: THREE.Scene; - sun: THREE.DirectionalLight; -} - -function labelTexture(letter: string, color: string): THREE.CanvasTexture { - const c = document.createElement('canvas'); - c.width = c.height = 128; - const ctx = c.getContext('2d')!; - ctx.clearRect(0, 0, 128, 128); - ctx.fillStyle = color; - ctx.font = 'bold 110px system-ui, sans-serif'; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillText(letter, 64, 70); - const tex = new THREE.CanvasTexture(c); - tex.anisotropy = 4; - return tex; -} - -export function buildScene(d: Dust2): SceneRefs { - const scene = new THREE.Scene(); - scene.background = new THREE.Color(COLORS.sky); - scene.fog = new THREE.Fog(COLORS.sky, 60, 170); - - // lighting - const hemi = new THREE.HemisphereLight(0xdfeaf5, 0x6b5f47, 0.9); - scene.add(hemi); - const sun = new THREE.DirectionalLight(0xfff2d8, 1.1); - sun.position.set(50, 90, 30); - scene.add(sun); - const amb = new THREE.AmbientLight(0xffffff, 0.18); - scene.add(amb); - - const g = d.grid; - const { minX, maxX, minZ, maxZ } = d.bounds; - - // floor - const floorGeo = new THREE.PlaneGeometry(maxX - minX, maxZ - minZ); - const floorMat = new THREE.MeshStandardMaterial({ color: COLORS.floor, roughness: 0.97, metalness: 0 }); - const floor = new THREE.Mesh(floorGeo, floorMat); - floor.rotation.x = -Math.PI / 2; - floor.position.set((minX + maxX) / 2, 0, (minZ + maxZ) / 2); - scene.add(floor); - - // walls: only cells that border a floor cell are visible - const borderCells: { cx: number; cz: number }[] = []; - for (let cz = 0; cz < g.rows; cz++) { - for (let cx = 0; cx < g.cols; cx++) { - if (!g.isWall(cx, cz)) continue; - if ( - g.isFloor(cx + 1, cz) || g.isFloor(cx - 1, cz) || - g.isFloor(cx, cz + 1) || g.isFloor(cx, cz - 1) - ) { - borderCells.push({ cx, cz }); - } - } - } - const wallGeo = new THREE.BoxGeometry(g.cell, WALL_HEIGHT, g.cell); - // Per-instance tint comes from setColorAt (instanceColor); no vertexColors flag - // (the box geometry has no color attribute, which would render black). - const wallMat = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.95, metalness: 0.02, flatShading: true }); - const walls = new THREE.InstancedMesh(wallGeo, wallMat, borderCells.length); - const m = new THREE.Matrix4(); - const col = new THREE.Color(); - const base = new THREE.Color(COLORS.wall); - const dark = new THREE.Color(COLORS.wallDark); - for (let i = 0; i < borderCells.length; i++) { - const { cx, cz } = borderCells[i]; - const c = g.centerOf(cx, cz); - m.makeTranslation(c.x, WALL_HEIGHT / 2, c.z); - walls.setMatrixAt(i, m); - col.copy(base).lerp(dark, Math.random() * 0.6); - walls.setColorAt(i, col); - } - walls.instanceMatrix.needsUpdate = true; - if (walls.instanceColor) walls.instanceColor.needsUpdate = true; - scene.add(walls); - - // crates - for (const cr of d.crates) { - const geo = new THREE.BoxGeometry(cr.hx * 2, cr.height, cr.hz * 2); - const mat = new THREE.MeshStandardMaterial({ color: COLORS.crate, roughness: 0.8, metalness: 0.05, flatShading: true }); - const mesh = new THREE.Mesh(geo, mat); - mesh.position.set(cr.x, cr.height / 2, cr.z); - scene.add(mesh); - const edges = new THREE.LineSegments( - new THREE.EdgesGeometry(geo), - new THREE.LineBasicMaterial({ color: COLORS.crateEdge }), - ); - edges.position.copy(mesh.position); - scene.add(edges); - } - - // bomb-site markers - const marker = (x: number, z: number, letter: string, color: number, hex: string) => { - const ring = new THREE.Mesh( - new THREE.RingGeometry(5.2, 6, 40), - new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.5, side: THREE.DoubleSide }), - ); - ring.rotation.x = -Math.PI / 2; - ring.position.set(x, 0.05, z); - scene.add(ring); - const lbl = new THREE.Mesh( - new THREE.PlaneGeometry(4, 4), - new THREE.MeshBasicMaterial({ map: labelTexture(letter, hex), transparent: true, opacity: 0.7 }), - ); - lbl.rotation.x = -Math.PI / 2; - lbl.position.set(x, 0.06, z); - scene.add(lbl); - }; - marker(d.sites.A.center.x, d.sites.A.center.z, 'A', COLORS.siteA, '#e0745f'); - marker(d.sites.B.center.x, d.sites.B.center.z, 'B', COLORS.siteB, '#5fb4e0'); - - // passable mid doors (visual only, no collision) - for (const dc of d.doorCells) { - const c = g.centerOf(dc.cx, dc.cz); - const door = new THREE.Mesh( - new THREE.BoxGeometry(g.cell * 0.96, 2.6, 0.12), - new THREE.MeshStandardMaterial({ color: 0x7a6a4a, roughness: 0.7, metalness: 0.1, transparent: true, opacity: 0.92 }), - ); - door.position.set(c.x, 1.3, c.z); - scene.add(door); - const frame = new THREE.Mesh( - new THREE.BoxGeometry(g.cell * 0.98, 2.9, 0.16), - new THREE.MeshStandardMaterial({ color: 0x4a3f2c, roughness: 0.8 }), - ); - frame.position.set(c.x, 1.45, c.z); - scene.add(frame); - } - - return { scene, sun }; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/store.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/store.ts deleted file mode 100644 index 45d11f7..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/store.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Minimal external store bridging the imperative engine to React HUD via -// useSyncExternalStore. The engine mutates through set(); the snapshot identity -// changes on each flush so React re-renders. - -import { KillEvent, RoundPhase, Team } from './types'; - -export interface HudState { - started: boolean; - playerTeam: Team; - phase: RoundPhase; - roundNum: number; - scoreT: number; - scoreCT: number; - roundTime: number; - aliveT: number; - aliveCT: number; - - alive: boolean; - spectating: boolean; - spectateName: string; - health: number; - armor: number; - helmet: boolean; - - weaponName: string; - weaponId: string; - mag: number; - reserve: number; - infiniteAmmo: boolean; - reloading: boolean; - scoped: boolean; - spread: number; // radians, drives crosshair gap - - hasBomb: boolean; - bombPlanted: boolean; - bombTimer: number; - defusing: boolean; - defuseProgress: number; - planting: boolean; - plantProgress: number; - - hint: string; - banner: string; - killfeed: KillEvent[]; - - loadout: { id: string; name: string; slot: string; mag: number; reserve: number; current: boolean }[]; -} - -const initial: HudState = { - started: false, - playerTeam: Team.T, - phase: RoundPhase.Warmup, - roundNum: 0, - scoreT: 0, - scoreCT: 0, - roundTime: 0, - aliveT: 5, - aliveCT: 5, - alive: true, - spectating: false, - spectateName: '', - health: 100, - armor: 0, - helmet: false, - weaponName: '', - weaponId: '', - mag: 0, - reserve: 0, - infiniteAmmo: false, - reloading: false, - scoped: false, - spread: 0.02, - hasBomb: false, - bombPlanted: false, - bombTimer: 0, - defusing: false, - defuseProgress: 0, - planting: false, - plantProgress: 0, - hint: '', - banner: '', - killfeed: [], - loadout: [], -}; - -class HudStore { - private state: HudState = initial; - private listeners = new Set<() => void>(); - - subscribe = (fn: () => void): (() => void) => { - this.listeners.add(fn); - return () => this.listeners.delete(fn); - }; - - getSnapshot = (): HudState => this.state; - - set(partial: Partial): void { - this.state = { ...this.state, ...partial }; - for (const fn of this.listeners) fn(); - } - - reset(): void { - this.set({ ...initial }); - } -} - -export const hud = new HudStore(); diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/types.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/types.ts deleted file mode 100644 index 4128418..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/types.ts +++ /dev/null @@ -1,51 +0,0 @@ -// Shared enums / interfaces used across engine + UI. - -export enum Team { - T = 0, - CT = 1, -} - -export enum HitZone { - Head = 0, - Chest = 1, - Stomach = 2, - Arm = 3, - Leg = 4, -} - -export type WeaponSlot = 'primary' | 'secondary' | 'melee'; - -export type WeaponId = - | 'ak47' - | 'm4a4' - | 'awp' - | 'glock' - | 'usp' - | 'deagle' - | 'knife'; - -export enum RoundPhase { - Warmup = 0, - Freeze = 1, - Live = 2, - Over = 3, -} - -export enum BombState { - Carried = 0, - Dropped = 1, - Planted = 2, - Defused = 3, - Exploded = 4, -} - -export interface KillEvent { - id: number; - attacker: string; - victim: string; - attackerTeam: Team; - victimTeam: Team; - weapon: WeaponId; - headshot: boolean; - time: number; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/weapons.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/weapons.ts deleted file mode 100644 index 813a135..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/weapons.ts +++ /dev/null @@ -1,118 +0,0 @@ -// Weapon data table + per-zone damage. Extensible: add an entry to WEAPONS and -// a matching viewmodel/worldmodel builder in entities/weaponModels.ts. - -import { HitZone, WeaponId, WeaponSlot } from './types'; - -export interface WeaponDef { - id: WeaponId; - name: string; - slot: WeaponSlot; - damage: number; // base, to chest, no armor - armorPen: number; // fraction of damage kept vs armor (0..1) - fireInterval: number; // seconds between shots - automatic: boolean; - magSize: number; - reserve: number; - reloadTime: number; - range: number; // effective hitscan range (m) - // recoil / accuracy (radians) - recoilPitch: number; // upward kick per shot - recoilYaw: number; // max horizontal kick per shot (± random) - spreadPerShot: number; // inaccuracy added per shot - baseSpread: number; // standing inaccuracy - maxSpread: number; - recoverRate: number; // spread recovered per second - moveSpeedMul: number; // movement multiplier while held - scoped?: boolean; // AWP: right-click 3D zoom + scope mask - scopedFov?: number; - isKnife?: boolean; -} - -// Head is 2x body per the spec; other zones scale off chest. -export const ZONE_MULT: Record = { - [HitZone.Head]: 2.0, - [HitZone.Chest]: 1.0, - [HitZone.Stomach]: 1.25, - [HitZone.Arm]: 0.75, - [HitZone.Leg]: 0.75, -}; - -export const WEAPONS: Record = { - ak47: { - id: 'ak47', name: 'AK-47', slot: 'primary', - damage: 36, armorPen: 0.775, fireInterval: 0.1, automatic: true, - magSize: 30, reserve: 90, reloadTime: 2.4, range: 90, - recoilPitch: 0.019, recoilYaw: 0.011, spreadPerShot: 0.013, - baseSpread: 0.006, maxSpread: 0.14, recoverRate: 0.5, moveSpeedMul: 0.92, - }, - m4a4: { - id: 'm4a4', name: 'M4A4', slot: 'primary', - damage: 33, armorPen: 0.7, fireInterval: 0.09, automatic: true, - magSize: 30, reserve: 90, reloadTime: 3.1, range: 90, - recoilPitch: 0.011, recoilYaw: 0.006, spreadPerShot: 0.008, - baseSpread: 0.005, maxSpread: 0.1, recoverRate: 0.55, moveSpeedMul: 0.94, - }, - awp: { - id: 'awp', name: 'AWP', slot: 'primary', - damage: 115, armorPen: 0.975, fireInterval: 1.5, automatic: false, - magSize: 10, reserve: 30, reloadTime: 3.7, range: 130, - recoilPitch: 0.05, recoilYaw: 0.02, spreadPerShot: 0.2, - baseSpread: 0.06, maxSpread: 0.3, recoverRate: 0.8, moveSpeedMul: 0.84, - scoped: true, scopedFov: 25, - }, - glock: { - id: 'glock', name: 'Glock-18', slot: 'secondary', - damage: 26, armorPen: 0.47, fireInterval: 0.15, automatic: false, - magSize: 20, reserve: 120, reloadTime: 2.2, range: 60, - recoilPitch: 0.012, recoilYaw: 0.008, spreadPerShot: 0.011, - baseSpread: 0.008, maxSpread: 0.11, recoverRate: 0.7, moveSpeedMul: 1.0, - }, - usp: { - id: 'usp', name: 'USP-S', slot: 'secondary', - damage: 33, armorPen: 0.505, fireInterval: 0.17, automatic: false, - magSize: 12, reserve: 24, reloadTime: 2.2, range: 60, - recoilPitch: 0.012, recoilYaw: 0.006, spreadPerShot: 0.01, - baseSpread: 0.006, maxSpread: 0.1, recoverRate: 0.7, moveSpeedMul: 1.0, - }, - deagle: { - id: 'deagle', name: 'Desert Eagle', slot: 'secondary', - damage: 55, armorPen: 0.93, fireInterval: 0.225, automatic: false, - magSize: 7, reserve: 35, reloadTime: 2.2, range: 75, - recoilPitch: 0.032, recoilYaw: 0.012, spreadPerShot: 0.02, - baseSpread: 0.009, maxSpread: 0.14, recoverRate: 0.6, moveSpeedMul: 0.96, - }, - knife: { - id: 'knife', name: 'Knife', slot: 'melee', - damage: 55, armorPen: 0.85, fireInterval: 0.4, automatic: false, - magSize: Infinity, reserve: Infinity, reloadTime: 0, range: 2.4, - recoilPitch: 0, recoilYaw: 0, spreadPerShot: 0, - baseSpread: 0, maxSpread: 0, recoverRate: 1, moveSpeedMul: 1.05, - isKnife: true, - }, -}; - -export interface DamageResult { - health: number; - armor: number; - applied: number; -} - -// Apply zone + armor model. Head protected only with a helmet; legs never armored. -export function computeDamage( - weapon: WeaponDef, - zone: HitZone, - health: number, - armor: number, - helmet: boolean, -): DamageResult { - let dmg = weapon.damage * ZONE_MULT[zone]; - let armorLeft = armor; - const protectable = zone !== HitZone.Leg && (zone !== HitZone.Head || helmet); - if (armorLeft > 0 && protectable) { - const preArmor = dmg; - dmg *= weapon.armorPen; - armorLeft = Math.max(0, armorLeft - Math.round((preArmor - dmg) * 0.5 + dmg * 0.5)); - } - const applied = Math.min(health, dmg); - return { health: Math.max(0, health - dmg), armor: armorLeft, applied }; -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/world.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/world.ts deleted file mode 100644 index 47f9901..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/engine/world.ts +++ /dev/null @@ -1,1275 +0,0 @@ -// GameWorld: the simulation + rendering orchestrator. Owns the scene, camera, -// first-person viewmodel, all 10 actors (1 player + 9 bots), the round/bomb -// state machine, hitscan combat, effects, minimap and HUD sync. The React layer -// only mounts this and reads the HUD store. - -import * as THREE from 'three'; -import { AudioEngine } from './audio'; -import { - collideCrates, collideWalls, groundHeightAt, rayCrateDistance, -} from './collision'; -import { CHAR_HEIGHT, raycastCharacter } from './combat'; -import { AI, COLORS, FIXED_DT, GRAVITY, MAX_FRAME_DT, PLAYER, ROUND } from './constants'; -import { buildDust2, Crate, Dust2 } from './dust2'; -import { Effects } from './effects'; -import { Region } from './grid'; -import { Input } from './input'; -import { buildScene } from './scene'; -import { hud } from './store'; -import { BombState, HitZone, KillEvent, RoundPhase, Team, WeaponId } from './types'; -import { WEAPONS } from './weapons'; -import { animateCharacter, buildCharacter, CharacterRig } from './entities/characterModel'; -import { buildWeaponMesh } from './entities/weaponModels'; -import { clamp } from './mathUtils'; -import { initBotState, updateBot, type BotState } from './ai'; -import { updatePlayer } from './player'; - -export interface Ammo { - mag: number; - reserve: number; -} - -export type Action = 'none' | 'plant' | 'defuse' | 'pickup'; - -export interface Actor { - id: number; - name: string; - team: Team; - isPlayer: boolean; - alive: boolean; - deadAt: number; - - x: number; y: number; z: number; - yaw: number; pitch: number; - vx: number; vy: number; vz: number; - grounded: boolean; - eyeH: number; - - // per-frame intents set by the controller - moveX: number; moveZ: number; - wantJump: boolean; - wantRun: boolean; - action: Action; - - health: number; armor: number; helmet: boolean; - weapons: WeaponId[]; - current: WeaponId; - ammo: Record; - nextFire: number; - reloadEnd: number; - spread: number; - kickPitch: number; - kickYaw: number; - scoped: boolean; - - hasBomb: boolean; - - rig: CharacterRig | null; - worldWeapon: THREE.Group | null; - worldMuzzle: THREE.Object3D | null; - blob: THREE.Mesh | null; - footDist: number; - animTime: number; - - bs: BotState; - kills: number; - deaths: number; -} - -interface Bomb { - state: BombState; - x: number; y: number; z: number; - site: 'A' | 'B' | null; - timer: number; - plantProgress: number; - defuseProgress: number; - beepTimer: number; - mesh: THREE.Group; - light: THREE.Mesh; -} - -const SENS = 0.0022; -const PITCH_LIMIT = 1.45; - -export class GameWorld { - readonly dust2: Dust2; - readonly grid; - readonly crates: Crate[]; - readonly scene: THREE.Scene; - readonly camera: THREE.PerspectiveCamera; - readonly renderer: THREE.WebGLRenderer; - readonly effects: Effects; - readonly audio = new AudioEngine(); - readonly input: Input; - readonly actors: Actor[] = []; - player!: Actor; - playerTeam: Team; - - private container: HTMLElement; - private viewmodel: THREE.Group; - private vmMuzzle: THREE.Object3D | null = null; - private vmRecoil = 0; - private sun: THREE.DirectionalLight; - private bomb: Bomb; - private baseFov = 78; - - time = 0; - phase: RoundPhase = RoundPhase.Warmup; - roundNum = 0; - scoreT = 0; - scoreCT = 0; - private freezeTimer = 0; - private roundTimer = 0; - private overTimer = 0; - private banner = ''; - private hint = ''; - private killfeed: KillEvent[] = []; - private killId = 0; - private tSite: 'A' | 'B' = 'A'; - private hudAccum = 0; - private visibleEnemyIds = new Set(); - - private minimapCanvas: HTMLCanvasElement | null = null; - private minimapStatic: HTMLCanvasElement | null = null; - private started = false; - private everLocked = false; - private spectateTarget: Actor | null = null; - - constructor(container: HTMLElement, playerTeam: Team) { - this.container = container; - this.playerTeam = playerTeam; - this.dust2 = buildDust2(); - this.grid = this.dust2.grid; - this.crates = this.dust2.crates; - - const refs = buildScene(this.dust2); - this.scene = refs.scene; - this.sun = refs.sun; - - this.renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: 'high-performance' }); - this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio)); - this.renderer.setSize(container.clientWidth, container.clientHeight); - container.appendChild(this.renderer.domElement); - this.input = new Input(this.renderer.domElement); - - this.camera = new THREE.PerspectiveCamera(this.baseFov, container.clientWidth / container.clientHeight, 0.04, 220); - this.camera.rotation.order = 'YXZ'; - this.scene.add(this.camera); - - this.viewmodel = new THREE.Group(); - this.camera.add(this.viewmodel); - - this.effects = new Effects(this.scene); - - // bomb entity - const bg = new THREE.Group(); - const body = new THREE.Mesh( - new THREE.BoxGeometry(0.4, 0.28, 0.3), - new THREE.MeshStandardMaterial({ color: 0x2a2a2a, roughness: 0.6, metalness: 0.3 }), - ); - body.position.y = 0.14; - bg.add(body); - const light = new THREE.Mesh( - new THREE.SphereGeometry(0.05, 8, 8), - new THREE.MeshBasicMaterial({ color: 0xff3020 }), - ); - light.position.set(0, 0.32, 0); - bg.add(light); - bg.visible = false; - this.scene.add(bg); - this.bomb = { - state: BombState.Carried, x: 0, y: 0, z: 0, site: null, timer: ROUND.bombTimer, - plantProgress: 0, defuseProgress: 0, beepTimer: 0, mesh: bg, light, - }; - - this.createActors(); - this.startRound(); // place everyone for the pre-start view - hud.set({ playerTeam }); - } - - // ---- setup ---- - - setMinimapCanvas(c: HTMLCanvasElement): void { - this.minimapCanvas = c; - this.buildMinimapStatic(); - } - - private createActors(): void { - const mkAmmoEmpty = (): Record => ({}); - for (let i = 0; i < 10; i++) { - const team: Team = i < 5 ? this.playerTeam : (this.playerTeam === Team.T ? Team.CT : Team.T); - const isPlayer = i === 0; - const teamLetter = team === Team.T ? 'T' : 'CT'; - const a: Actor = { - id: i, - // Every actor has a fixed callsign; the human is shown by the minimap - // arrow + first-person view, and control can move between callsigns. - name: `${teamLetter}-${(i % 5) + 1}`, - team, - isPlayer, - alive: true, - deadAt: 0, - x: 0, y: 0, z: 0, - yaw: 0, pitch: 0, - vx: 0, vy: 0, vz: 0, - grounded: true, - eyeH: isPlayer ? PLAYER.eyeHeight : 1.55, - moveX: 0, moveZ: 0, wantJump: false, wantRun: true, action: 'none', - health: 100, armor: 0, helmet: false, - weapons: [], current: 'knife', ammo: mkAmmoEmpty(), - nextFire: 0, reloadEnd: 0, spread: 0, kickPitch: 0, kickYaw: 0, scoped: false, - hasBomb: false, - rig: null, worldWeapon: null, worldMuzzle: null, blob: null, - footDist: 0, animTime: Math.random() * 10, - bs: initBotState(), - kills: 0, deaths: 0, - }; - // Every actor gets a body so control can be handed to any of them; the - // actor currently being viewed has its rig hidden for the first person. - const rig = buildCharacter(team); - this.scene.add(rig.root); - a.rig = rig; - // blob shadow - const blob = new THREE.Mesh( - new THREE.CircleGeometry(0.5, 16), - new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0.28, depthWrite: false }), - ); - blob.rotation.x = -Math.PI / 2; - this.scene.add(blob); - a.blob = blob; - this.actors.push(a); - if (isPlayer) this.player = a; - } - } - - start(): void { - if (this.started) return; - this.started = true; - this.audio.init(); - // give a fresh freeze once the player actually starts - this.phase = RoundPhase.Freeze; - this.freezeTimer = ROUND.freezeTime; - } - - private loadoutFor(team: Team, pistol: boolean, index: number): { weapons: WeaponId[]; current: WeaponId; armor: number; helmet: boolean } { - if (pistol) { - const sec: WeaponId = team === Team.T ? 'glock' : 'usp'; - return { weapons: [sec, 'knife'], current: sec, armor: 100, helmet: false }; - } - const rifle: WeaponId = team === Team.T ? 'ak47' : 'm4a4'; - const sec: WeaponId = team === Team.T ? 'glock' : 'usp'; - // one designated AWPer per team - const primary: WeaponId = index === 1 ? 'awp' : rifle; - return { weapons: [primary, sec, 'knife'], current: primary, armor: 100, helmet: true }; - } - - private startRound(): void { - this.roundNum++; - const pistol = this.roundNum === 1; - this.phase = RoundPhase.Freeze; - this.freezeTimer = ROUND.freezeTime; - this.roundTimer = ROUND.roundTime; - this.banner = pistol ? 'Pistol Round' : `Round ${this.roundNum}`; - this.hint = ''; - this.visibleEnemyIds.clear(); - - // bomb reset - this.bomb.state = BombState.Carried; - this.bomb.site = null; - this.bomb.timer = ROUND.bombTimer; - this.bomb.plantProgress = 0; - this.bomb.defuseProgress = 0; - this.bomb.mesh.visible = false; - - // T target site + CT defense split for this round - this.tSite = Math.random() < 0.5 ? 'A' : 'B'; - - const tSpawns = this.dust2.tSpawns; - const ctSpawns = this.dust2.ctSpawns; - let ti = 0; - let ci = 0; - const ts: Actor[] = []; - for (const a of this.actors) { - const spawn = a.team === Team.T ? tSpawns[ti++ % tSpawns.length] : ctSpawns[ci++ % ctSpawns.length]; - const teamIndex = a.team === Team.T ? ti - 1 : ci - 1; - this.resetActor(a, spawn.x, spawn.z, pistol, teamIndex); - if (a.team === Team.T) ts.push(a); - } - - // assign bomb carrier: player if T, else first T bot - const carrier = this.playerTeam === Team.T ? this.player : ts.find((a) => !a.isPlayer) ?? ts[0]; - if (carrier) { - carrier.hasBomb = true; - } - - // CT defense assignment: split across sites - let dc = 0; - for (const a of this.actors) { - if (a.team === Team.CT && !a.isPlayer) { - a.bs.defendSite = dc++ % 2 === 0 ? 'A' : 'B'; - } - if (a.team === Team.T && !a.isPlayer) { - a.bs.targetSite = this.tSite; - } - } - - this.syncHudFull(); - } - - private resetActor(a: Actor, x: number, z: number, pistol: boolean, teamIndex: number): void { - a.alive = true; - a.health = PLAYER.maxHealth; - const lo = this.loadoutFor(a.team, pistol, teamIndex); - a.armor = lo.armor; - a.helmet = lo.helmet; - a.weapons = lo.weapons.slice(); - a.ammo = {}; - for (const w of a.weapons) { - const def = WEAPONS[w]; - a.ammo[w] = { mag: def.magSize === Infinity ? Infinity : def.magSize, reserve: def.reserve === Infinity ? Infinity : def.reserve }; - } - a.x = x; - a.y = 0; - a.z = z; - a.vx = a.vy = a.vz = 0; - a.grounded = true; - a.yaw = a.team === Team.T ? 0 : Math.PI; - a.pitch = 0; - a.kickPitch = a.kickYaw = 0; - a.spread = 0; - a.scoped = false; - a.hasBomb = false; - a.nextFire = 0; - a.reloadEnd = 0; - a.action = 'none'; - a.moveX = a.moveZ = 0; - a.footDist = 0; - initBotState(a.bs); - if (a.rig) { - a.rig.root.visible = true; - a.rig.root.position.set(a.x, a.y, a.z); - a.rig.root.rotation.set(0, a.yaw, 0); - } - this.equip(a, lo.current); - } - - // ---- weapon equip / viewmodel ---- - - equip(a: Actor, id: WeaponId): void { - if (!a.weapons.includes(id)) return; - a.current = id; - a.scoped = false; - if (a.isPlayer) { - this.rebuildViewmodel(id); - } else if (a.rig) { - if (a.worldWeapon) a.rig.weaponHolder.remove(a.worldWeapon); - const wm = buildWeaponMesh(id); - a.rig.weaponHolder.add(wm.group); - a.worldWeapon = wm.group; - a.worldMuzzle = wm.muzzle; - } - } - - private rebuildViewmodel(id: WeaponId): void { - this.viewmodel.clear(); - const wm = buildWeaponMesh(id); - // hands - const skin = 0xc99a76; - const handGeo = new THREE.BoxGeometry(0.09, 0.09, 0.12); - const handMat = new THREE.MeshStandardMaterial({ color: skin, roughness: 0.7 }); - const h1 = new THREE.Mesh(handGeo, handMat); - h1.position.set(0.0, -0.09, 0.06); - const h2 = new THREE.Mesh(handGeo, handMat); - h2.position.set(0.0, -0.06, -0.18); - wm.group.add(h1, h2); - wm.group.position.set(0.22, -0.2, -0.48); - wm.group.rotation.y = 0.05; - wm.group.scale.setScalar(0.7); - this.viewmodel.add(wm.group); - this.vmMuzzle = wm.muzzle; - } - - // ---- main loop ---- - - update(rawDt: number): void { - const dt = clamp(rawDt, 0, MAX_FRAME_DT); - this.time += dt; - - // Pause the simulation when the pointer is unlocked (Esc), but only once the - // player has actually locked at least once — so if pointer lock is blocked - // (e.g. a restrictive iframe) the game degrades to keyboard control instead - // of freezing forever. - if (this.input.locked) this.everLocked = true; - const active = this.started && (this.input.locked || !this.everLocked); - if (!active) { - this.updateActorsVisual(0); - this.updateCamera(dt); - this.drawMinimap(); - this.syncHud(); - this.renderer.render(this.scene, this.camera); - return; - } - - // phase transitions - if (this.phase === RoundPhase.Freeze) { - this.freezeTimer -= dt; - if (this.freezeTimer <= 0) { - this.phase = RoundPhase.Live; - this.banner = ''; - } - } else if (this.phase === RoundPhase.Over) { - this.overTimer -= dt; - if (this.overTimer <= 0) this.startRound(); - } - - const live = this.phase === RoundPhase.Live; - const canMove = live; - - // compute team vision (for minimap + AI shortcuts) - this.computeVisibility(); - - // controllers - this.hint = ''; - updatePlayer(this, this.player, dt, canMove); - for (const a of this.actors) { - if (a.isPlayer || !a.alive) continue; - updateBot(this, a, dt, canMove); - } - - // reloads finishing - for (const a of this.actors) { - if (a.alive && a.reloadEnd > 0 && this.time >= a.reloadEnd) this.finishReload(a); - } - - // physics - for (const a of this.actors) { - if (!a.alive) continue; - this.integrateActor(a, canMove ? dt : 0, dt); - } - if (canMove) this.separateActors(); - - // decay recoil/spread - for (const a of this.actors) { - const rec = Math.max(0, 1 - dt * 9); - a.kickPitch *= rec; - a.kickYaw *= rec; - const w = WEAPONS[a.current]; - a.spread = Math.max(0, a.spread - w.recoverRate * dt); - } - - if (live) { - if (this.bomb.state !== BombState.Planted) this.roundTimer -= dt; - this.updateBomb(dt); - this.checkRoundEnd(); - } - - // presentation - this.updateActorsVisual(dt); - this.updateCamera(dt); - this.effects.update(dt); - const listener = this.viewActor(); - this.audio.setListener(listener.x, listener.z, listener.yaw); - - this.drawMinimap(); - - this.hudAccum += dt; - if (this.hudAccum >= 0.06) { - this.hudAccum = 0; - this.syncHud(); - } - - this.renderer.render(this.scene, this.camera); - } - - // ---- physics ---- - - private integrateActor(a: Actor, moveDt: number, physDt: number): void { - const w = WEAPONS[a.current]; - // vertical - if (a.wantJump && a.grounded && moveDt > 0) { - a.vy = PLAYER.jumpSpeed; - a.grounded = false; - } - a.wantJump = false; - a.vy -= GRAVITY * physDt; - a.y += a.vy * physDt; - const ground = groundHeightAt(this.crates, a.x, a.z, PLAYER.radius); - if (a.y <= ground) { - a.y = ground; - a.vy = 0; - a.grounded = true; - } else { - a.grounded = false; - } - - // horizontal - if (moveDt > 0) { - const scopedMul = a.scoped ? 0.5 : 1; - let wishLen = Math.hypot(a.moveX, a.moveZ); - let wx = 0, wz = 0; - if (wishLen > 1e-4) { - wx = a.moveX / wishLen; - wz = a.moveZ / wishLen; - } - const maxSpeed = (a.wantRun ? PLAYER.runSpeed : PLAYER.walkSpeed) * w.moveSpeedMul * scopedMul; - const speed = Math.hypot(a.vx, a.vz); - if (a.grounded) { - // friction - if (speed > 0) { - const drop = speed * PLAYER.friction * moveDt; - const ns = Math.max(0, speed - drop) / speed; - a.vx *= ns; - a.vz *= ns; - } - } - const accel = a.grounded ? PLAYER.groundAccel : PLAYER.airAccel; - if (wishLen > 1e-4) { - const curSpeedInWish = a.vx * wx + a.vz * wz; - const add = clamp(maxSpeed - curSpeedInWish, 0, accel * moveDt); - a.vx += wx * add; - a.vz += wz * add; - } - const oldX = a.x, oldZ = a.z; - let nx = a.x + a.vx * moveDt; - let nz = a.z + a.vz * moveDt; - let r = collideWalls(this.grid, nx, nz, PLAYER.radius); - r = collideCrates(this.crates, r.x, r.z, PLAYER.radius, a.y); - a.x = r.x; - a.z = r.z; - // rebuild velocity from actual movement to avoid wall sticking - a.vx = (a.x - oldX) / moveDt; - a.vz = (a.z - oldZ) / moveDt; - } - } - - private separateActors(): void { - const minD = PLAYER.radius * 2; - for (let i = 0; i < this.actors.length; i++) { - const a = this.actors[i]; - if (!a.alive) continue; - for (let j = i + 1; j < this.actors.length; j++) { - const b = this.actors[j]; - if (!b.alive) continue; - const dx = b.x - a.x; - const dz = b.z - a.z; - const d2 = dx * dx + dz * dz; - if (d2 < minD * minD && d2 > 1e-5) { - const d = Math.sqrt(d2); - const push = (minD - d) / 2; - const nx = dx / d, nz = dz / d; - if (!a.isPlayer) { a.x -= nx * push; a.z -= nz * push; } - if (!b.isPlayer) { b.x += nx * push; b.z += nz * push; } - // if one is player, push the bot fully - if (a.isPlayer) { b.x += nx * push * 2; b.z += nz * push * 2; } - if (b.isPlayer) { a.x -= nx * push * 2; a.z -= nz * push * 2; } - } - } - } - } - - // ---- combat ---- - - eyePos(a: Actor): { x: number; y: number; z: number } { - return { x: a.x, y: a.y + a.eyeH, z: a.z }; - } - - aimDir(a: Actor): { x: number; y: number; z: number } { - const yaw = a.yaw + a.kickYaw; - const pitch = clamp(a.pitch + a.kickPitch, -PITCH_LIMIT, PITCH_LIMIT); - const cp = Math.cos(pitch); - return { x: -Math.sin(yaw) * cp, y: Math.sin(pitch), z: -Math.cos(yaw) * cp }; - } - - private coneDir(dx: number, dy: number, dz: number, spread: number): { x: number; y: number; z: number } { - if (spread <= 1e-5) return { x: dx, y: dy, z: dz }; - const a = spread * Math.sqrt(Math.random()); - const th = Math.random() * Math.PI * 2; - // tangent basis - let ux = 0, uy = 1, uz = 0; - if (Math.abs(dy) > 0.9) { ux = 1; uy = 0; } - let t1x = uy * dz - uz * dy; - let t1y = uz * dx - ux * dz; - let t1z = ux * dy - uy * dx; - const t1l = Math.hypot(t1x, t1y, t1z) || 1; - t1x /= t1l; t1y /= t1l; t1z /= t1l; - const t2x = dy * t1z - dz * t1y; - const t2y = dz * t1x - dx * t1z; - const t2z = dx * t1y - dy * t1x; - const sa = Math.sin(a), ca = Math.cos(a); - const ox = Math.cos(th) * sa, oy = Math.sin(th) * sa; - return { - x: dx * ca + (t1x * ox + t2x * oy), - y: dy * ca + (t1y * ox + t2y * oy), - z: dz * ca + (t1z * ox + t2z * oy), - }; - } - - // movement/air inaccuracy contribution - private moveInaccuracy(a: Actor): number { - const w = WEAPONS[a.current]; - const speed = Math.hypot(a.vx, a.vz); - let inacc = (speed / PLAYER.runSpeed) * 0.03; - if (!a.grounded) inacc += 0.08; - if (a.scoped) inacc *= 3; - return inacc * (w.scoped && !a.scoped ? 1.5 : 1); - } - - fireWeapon(a: Actor): boolean { - const w = WEAPONS[a.current]; - if (this.time < a.nextFire || a.reloadEnd > 0) return false; - if (w.isKnife) return this.melee(a); - const ammo = a.ammo[a.current]; - if (ammo.mag <= 0) { - // auto reload attempt - if (a.isPlayer) this.startReload(a); - return false; - } - a.nextFire = this.time + w.fireInterval; - ammo.mag = ammo.mag === Infinity ? Infinity : ammo.mag - 1; - - const eye = this.eyePos(a); - const base = this.aimDir(a); - const spread = w.baseSpread + a.spread + this.moveInaccuracy(a); - const dir = this.coneDir(base.x, base.y, base.z, a.scoped ? spread * 0.15 : spread); - const dl = Math.hypot(dir.x, dir.y, dir.z) || 1; - const ndx = dir.x / dl, ndy = dir.y / dl, ndz = dir.z / dl; - - const range = w.range; - // geometry distances. rayWallDistance parametrizes the XZ ray by the same - // t as the (unit) 3D ray, so its return value is already the 3D distance. - let wall3d = this.grid.rayWallDistance(eye.x, eye.z, ndx, ndz, range); - // floor - if (ndy < -1e-4) { - const tf = -eye.y / ndy; - if (tf < wall3d) wall3d = tf; - } - const crate3d = rayCrateDistance(this.crates, eye.x, eye.y, eye.z, ndx, ndy, ndz, wall3d); - let nearest = Math.min(wall3d, crate3d); - let hitActor: Actor | null = null; - let hitZone: HitZone = HitZone.Chest; - - for (const t of this.actors) { - if (!t.alive || t.team === a.team || t.id === a.id) continue; - const r = raycastCharacter(t.x, t.y, t.z, t.yaw, eye.x, eye.y, eye.z, ndx, ndy, ndz, nearest); - if (r && r.t < nearest) { - nearest = r.t; - hitActor = t; - hitZone = r.zone; - } - } - - // muzzle world position for tracer/flash - const muzzle = a.isPlayer ? this.vmMuzzle : a.worldMuzzle; - const mp = new THREE.Vector3(); - if (muzzle) muzzle.getWorldPosition(mp); - else mp.set(eye.x + ndx * 0.4, eye.y - 0.1, eye.z + ndz * 0.4); - const hx = eye.x + ndx * nearest; - const hy = eye.y + ndy * nearest; - const hz = eye.z + ndz * nearest; - this.effects.tracer(mp.x, mp.y, mp.z, hx, hy, hz); - this.effects.flash(mp.x, mp.y, mp.z); - this.audio.gunshot(a.current, a.isPlayer ? undefined : a.x, a.isPlayer ? undefined : a.z); - - if (hitActor) { - this.effects.impact(hx, hy, hz, true); - this.damageActor(hitActor, a, a.current, hitZone, hx, hy, hz); - } else if (nearest < range) { - this.effects.impact(hx, hy, hz, false); - } - - // recoil - a.spread = Math.min(w.maxSpread, a.spread + w.spreadPerShot); - if (a.isPlayer) { - a.kickPitch += w.recoilPitch; - a.kickYaw += (Math.random() * 2 - 1) * w.recoilYaw; - this.vmRecoil = Math.min(0.16, this.vmRecoil + (w.scoped ? 0.14 : 0.05)); - } - return true; - } - - private melee(a: Actor): boolean { - const w = WEAPONS.knife; - a.nextFire = this.time + w.fireInterval; - const eye = this.eyePos(a); - const d = this.aimDir(a); - this.audio.gunshot('knife', a.isPlayer ? undefined : a.x, a.isPlayer ? undefined : a.z); - let nearest = w.range; - let hitActor: Actor | null = null; - let zone: HitZone = HitZone.Chest; - for (const t of this.actors) { - if (!t.alive || t.team === a.team || t.id === a.id) continue; - const r = raycastCharacter(t.x, t.y, t.z, t.yaw, eye.x, eye.y, eye.z, d.x, d.y, d.z, nearest); - if (r && r.t < nearest) { nearest = r.t; hitActor = t; zone = r.zone; } - } - if (hitActor) { - const hx = eye.x + d.x * nearest, hy = eye.y + d.y * nearest, hz = eye.z + d.z * nearest; - this.effects.impact(hx, hy, hz, true); - this.damageActor(hitActor, a, 'knife', zone, hx, hy, hz); - return true; - } - return false; - } - - startReload(a: Actor): void { - const w = WEAPONS[a.current]; - if (w.isKnife || a.reloadEnd > 0) return; - const ammo = a.ammo[a.current]; - if (ammo.mag >= w.magSize || ammo.reserve <= 0) return; - a.reloadEnd = this.time + w.reloadTime; - a.scoped = false; - if (a.isPlayer) this.audio.reload(); - } - - private finishReload(a: Actor): void { - const w = WEAPONS[a.current]; - const ammo = a.ammo[a.current]; - const need = w.magSize - ammo.mag; - const take = Math.min(need, ammo.reserve); - ammo.mag += take; - ammo.reserve -= take; - a.reloadEnd = 0; - } - - private damageActor(t: Actor, from: Actor, weapon: WeaponId, zone: HitZone, hx: number, hy: number, hz: number): void { - if (!t.alive) return; - const w = WEAPONS[weapon]; - let dmg = w.damage * ({ [HitZone.Head]: 2, [HitZone.Chest]: 1, [HitZone.Stomach]: 1.25, [HitZone.Arm]: 0.75, [HitZone.Leg]: 0.75 }[zone]); - const protectable = zone !== HitZone.Leg && (zone !== HitZone.Head || t.helmet); - if (t.armor > 0 && protectable) { - const pre = dmg; - dmg *= w.armorPen; - t.armor = Math.max(0, t.armor - Math.round((pre - dmg) * 0.5 + dmg * 0.5)); - } - t.health -= dmg; - if (from.isPlayer) this.audio.hitmarker(); - if (t.health <= 0) { - this.onDeath(t, from, weapon, zone === HitZone.Head); - } - } - - private onDeath(t: Actor, from: Actor, weapon: WeaponId, headshot: boolean): void { - t.alive = false; - t.health = 0; - t.deadAt = this.time; - t.deaths++; - if (from.id !== t.id) from.kills++; - if (t.hasBomb) this.dropBomb(t); - t.hasBomb = false; - t.scoped = false; - if (t.rig) { - // fallen pose - t.rig.root.rotation.z = Math.PI / 2; - t.rig.root.position.y = 0.35; - } - this.killId++; - this.killfeed.unshift({ - id: this.killId, - attacker: from.name, - victim: t.name, - attackerTeam: from.team, - victimTeam: t.team, - weapon, - headshot, - time: this.time, - }); - if (this.killfeed.length > 6) this.killfeed.pop(); - if (from.isPlayer) this.audio.kill(); - if (t.isPlayer) this.banner = 'You were eliminated'; - } - - // ---- bomb ---- - - private inSite(a: Actor): 'A' | 'B' | null { - const c = this.grid.cellOf(a.x, a.z); - const reg = this.grid.regionAt(c.cx, c.cz); - if (reg === Region.ASite) return 'A'; - if (reg === Region.BSite) return 'B'; - return null; - } - - isInSite(a: Actor): 'A' | 'B' | null { - return this.inSite(a); - } - - private dropBomb(carrier: Actor): void { - this.bomb.state = BombState.Dropped; - this.bomb.x = carrier.x; - this.bomb.y = 0; - this.bomb.z = carrier.z; - this.bomb.mesh.position.set(carrier.x, 0, carrier.z); - this.bomb.mesh.visible = true; - } - - pickupBomb(a: Actor): void { - if (this.bomb.state !== BombState.Dropped || a.team !== Team.T) return; - const dx = a.x - this.bomb.x, dz = a.z - this.bomb.z; - if (dx * dx + dz * dz > 2.2 * 2.2) return; - this.bomb.state = BombState.Carried; - a.hasBomb = true; - this.bomb.mesh.visible = false; - } - - bombInfo() { - return this.bomb; - } - - private updateBomb(dt: number): void { - const b = this.bomb; - if (b.state === BombState.Carried) { - const carrier = this.actors.find((a) => a.hasBomb && a.alive); - // planting - const planter = this.actors.find((a) => a.alive && a.hasBomb && a.action === 'plant' && a.grounded && this.inSite(a) !== null); - if (planter) { - b.plantProgress += dt; - if (planter.isPlayer) this.audio.plantTick(); - if (b.plantProgress >= ROUND.plantTime) { - b.state = BombState.Planted; - b.site = this.inSite(planter); - b.x = planter.x; b.y = 0; b.z = planter.z; - b.timer = ROUND.bombTimer; - b.mesh.position.set(b.x, 0, b.z); - b.mesh.visible = true; - planter.hasBomb = false; - this.banner = `Bomb planted at ${b.site}`; - this.audio.plantTick(); - } - } else { - b.plantProgress = Math.max(0, b.plantProgress - dt * 2); - } - if (carrier) { b.x = carrier.x; b.z = carrier.z; } - } else if (b.state === BombState.Planted) { - b.timer -= dt; - // beeping accelerates near the end - b.beepTimer -= dt; - const interval = clamp(b.timer / ROUND.bombTimer, 0.08, 1) * 1.1; - if (b.beepTimer <= 0) { - b.beepTimer = interval; - this.audio.bombBeep(b.x, b.z); - } - const pulse = 0.5 + 0.5 * Math.sin(this.time * (12 - 10 * (1 - b.timer / ROUND.bombTimer))); - (this.bomb.light.material as THREE.MeshBasicMaterial).color.setRGB(0.6 + pulse * 0.4, 0.1, 0.05); - // defusing - const defuser = this.actors.find((a) => { - if (!a.alive || a.team !== Team.CT || a.action !== 'defuse' || !a.grounded) return false; - const dx = a.x - b.x, dz = a.z - b.z; - return dx * dx + dz * dz < 2.4 * 2.4; - }); - if (defuser) { - b.defuseProgress += dt; - if (defuser.isPlayer && Math.floor(b.defuseProgress * 4) !== Math.floor((b.defuseProgress - dt) * 4)) { - this.audio.defuseTick(); - } - if (b.defuseProgress >= ROUND.defuseTime) { - b.state = BombState.Defused; - this.endRound(Team.CT, 'Bomb defused'); - } - } else { - b.defuseProgress = Math.max(0, b.defuseProgress - dt * 1.5); - } - if (b.timer <= 0) { - this.explodeBomb(); - } - } - } - - private explodeBomb(): void { - const b = this.bomb; - b.state = BombState.Exploded; - this.audio.explode(b.x, b.z); - this.effects.impact(b.x, 0.5, b.z, false); - // radius damage - for (const a of this.actors) { - if (!a.alive) continue; - const dx = a.x - b.x, dz = a.z - b.z; - const d = Math.hypot(dx, dz); - if (d < ROUND.bombDamageRadius) { - const dmg = 200 * (1 - d / ROUND.bombDamageRadius); - a.health -= dmg; - if (a.health <= 0) { - a.alive = false; - a.deadAt = this.time; - if (a.rig) { a.rig.root.rotation.z = Math.PI / 2; a.rig.root.position.y = 0.35; } - } - } - } - this.endRound(Team.T, 'Bomb detonated'); - } - - // ---- round resolution ---- - - private countAlive(team: Team): number { - let n = 0; - for (const a of this.actors) if (a.team === team && a.alive) n++; - return n; - } - - private checkRoundEnd(): void { - const tAlive = this.countAlive(Team.T); - const ctAlive = this.countAlive(Team.CT); - const planted = this.bomb.state === BombState.Planted; - - if (planted) { - if (ctAlive === 0) { - this.endRound(Team.T, 'Terrorists win'); - } - // if all T dead but planted, CTs must still defuse (handled by timer/defuse) - } else { - if (tAlive === 0) { - this.endRound(Team.CT, 'Counter-Terrorists win'); - } else if (ctAlive === 0) { - this.endRound(Team.T, 'Terrorists win'); - } else if (this.roundTimer <= 0) { - this.endRound(Team.CT, 'Time — Counter-Terrorists win'); - } - } - } - - private endRound(winner: Team, reason: string): void { - if (this.phase === RoundPhase.Over) return; - this.phase = RoundPhase.Over; - this.overTimer = ROUND.overTime; - if (winner === Team.T) this.scoreT++; - else this.scoreCT++; - this.banner = reason; - this.syncHudFull(); - } - - // ---- visibility ---- - - canSee(from: Actor, to: Actor, fovDeg = 360): boolean { - if (!to.alive) return false; - const ex = from.x, ez = from.z; - const ey = from.y + from.eyeH; - const tx = to.x, tz = to.z; - const ty = to.y + 1.2; - const dx = tx - ex, dz = tz - ez; - const dist = Math.hypot(dx, dz); - if (dist > AI.viewRange) return false; - if (fovDeg < 360) { - const fwd = this.aimDir(from); - const fl = Math.hypot(fwd.x, fwd.z) || 1; - const dot = (dx * fwd.x + dz * fwd.z) / (dist * fl + 1e-4); - const cosHalf = Math.cos((fovDeg * Math.PI) / 180 / 2); - if (dot < cosHalf) return false; - } - if (this.grid.segmentBlocked(ex, ez, tx, tz)) return false; - // crate occlusion (3D) - const dy = ty - ey; - const len = Math.hypot(dx, dy, dz) || 1; - const cd = rayCrateDistance(this.crates, ex, ey, ez, dx / len, dy / len, dz / len, len); - if (cd < len - 0.2) return false; - return true; - } - - nearestVisibleEnemy(a: Actor, fovDeg = 360): Actor | null { - let best: Actor | null = null; - let bestD = Infinity; - for (const t of this.actors) { - if (!t.alive || t.team === a.team) continue; - if (!this.canSee(a, t, fovDeg)) continue; - const d = (t.x - a.x) ** 2 + (t.z - a.z) ** 2; - if (d < bestD) { bestD = d; best = t; } - } - return best; - } - - private computeVisibility(): void { - this.visibleEnemyIds.clear(); - const myTeam = this.playerTeam; - for (const viewer of this.actors) { - if (!viewer.alive || viewer.team !== myTeam) continue; - for (const e of this.actors) { - if (!e.alive || e.team === myTeam) continue; - if (this.visibleEnemyIds.has(e.id)) continue; - const fov = viewer.isPlayer ? 110 : AI.fovDeg; - if (this.canSee(viewer, e, fov)) this.visibleEnemyIds.add(e.id); - } - } - } - - enemiesVisibleToTeam(): Set { - return this.visibleEnemyIds; - } - - // ---- hints (from player controller) ---- - setHint(h: string): void { - this.hint = h; - } - - // ---- spectate / take over (after death) ---- - - // The actor whose eyes the camera looks through: the controlled player while - // alive, otherwise the spectated teammate. - private viewActor(): Actor { - if (this.player.alive) return this.player; - if (this.spectateTarget && this.spectateTarget.alive && this.spectateTarget.team === this.player.team) { - return this.spectateTarget; - } - return this.player; - } - - private aliveTeammates(): Actor[] { - return this.actors.filter((a) => a.alive && a.team === this.player.team && a !== this.player); - } - - // Keep a valid spectate target (called each dead frame). - ensureSpectate(): void { - if (this.spectateTarget && this.spectateTarget.alive && this.spectateTarget.team === this.player.team) return; - this.spectateTarget = this.aliveTeammates()[0] ?? null; - } - - spectateCycle(dir: number): void { - const mates = this.aliveTeammates(); - if (!mates.length) { - this.spectateTarget = null; - return; - } - const cur = this.spectateTarget ? mates.indexOf(this.spectateTarget) : -1; - const next = (((cur + (dir >= 0 ? 1 : -1)) % mates.length) + mates.length) % mates.length; - this.spectateTarget = mates[next]; - } - - // Assume control of the spectated teammate: it stops being AI-driven and - // becomes the player-controlled actor. - takeOver(): boolean { - const t = this.spectateTarget; - if (!t || !t.alive || t.team !== this.player.team) return false; - this.player.isPlayer = false; - t.isPlayer = true; - t.eyeH = PLAYER.eyeHeight; - t.moveX = t.moveZ = 0; - t.wantJump = false; - t.scoped = false; - t.kickPitch = t.kickYaw = 0; - this.player = t; - this.spectateTarget = null; - this.equip(t, t.current); // build the first-person viewmodel for the new actor - return true; - } - - // ---- visuals ---- - - private updateActorsVisual(dt: number): void { - const view = this.viewActor(); - for (const a of this.actors) { - if (a.blob) { - a.blob.visible = a.alive && a !== view; - a.blob.position.set(a.x, a.y + 0.02, a.z); - } - if (!a.rig) continue; - if (!a.alive) { - // corpse in its fallen pose (hidden only if we are looking from it) - a.rig.root.visible = a !== view; - a.rig.root.position.set(a.x, a.rig.root.position.y, a.z); - continue; - } - // hide the body we are looking through (first person) - a.rig.root.visible = a !== view; - a.rig.root.position.set(a.x, a.y, a.z); - a.rig.root.rotation.set(0, a.yaw, 0); - const speed = Math.hypot(a.vx, a.vz); - a.animTime += dt; - animateCharacter(a.rig, speed, a.animTime, false); - a.rig.root.position.y = a.y + a.rig.root.position.y; // add bob (animateCharacter set root.y to bob) - } - // footsteps - for (const a of this.actors) { - if (!a.alive || !a.grounded) continue; - const speed = Math.hypot(a.vx, a.vz); - if (speed > 1.5) { - a.footDist += speed * dt; - if (a.footDist > 2.4) { - a.footDist = 0; - if (a.isPlayer) this.audio.footstep(); - else this.audio.footstep(a.x, a.z); - } - } - } - } - - private updateCamera(dt: number): void { - const p = this.viewActor(); // player while alive, spectated teammate while dead - const controlling = this.player.alive; - const eye = p.eyeH; - // slight view bob - const speed = Math.hypot(p.vx, p.vz); - const bob = p.grounded && speed > 1 ? Math.sin(this.time * 10) * 0.03 * (speed / PLAYER.runSpeed) : 0; - this.camera.position.set(p.x, p.y + eye + bob, p.z); - this.camera.rotation.set( - clamp(p.pitch + p.kickPitch, -PITCH_LIMIT, PITCH_LIMIT), - p.yaw + p.kickYaw, - 0, - ); - - // fov for scope (only the controlled player scopes) - const wantFov = controlling && this.player.scoped ? (WEAPONS[this.player.current].scopedFov ?? 30) : this.baseFov; - this.camera.fov += (wantFov - this.camera.fov) * Math.min(1, dt * 12); - this.camera.updateProjectionMatrix(); - - // viewmodel recoil + reload pose (hidden while spectating) - this.vmRecoil = Math.max(0, this.vmRecoil - dt * 0.9); - const rl = this.player.reloadEnd > 0 ? 1 : 0; - this.viewmodel.visible = controlling && !this.player.scoped; - const child = this.viewmodel.children[0] as THREE.Group | undefined; - if (child && controlling) { - const bobX = Math.sin(this.time * 10) * 0.006 * (speed / PLAYER.runSpeed); - const bobY = Math.abs(Math.cos(this.time * 10)) * 0.006 * (speed / PLAYER.runSpeed); - child.position.set(0.22 + bobX, -0.2 + bobY - rl * 0.12, -0.48 + this.vmRecoil); - child.rotation.set(this.vmRecoil * 1.4 - rl * 0.5, 0.05, 0); - } - } - - // ---- minimap ---- - - private buildMinimapStatic(): void { - const g = this.grid; - const c = document.createElement('canvas'); - c.width = g.cols; - c.height = g.rows; - const ctx = c.getContext('2d')!; - ctx.fillStyle = 'rgba(10,12,16,0)'; - ctx.clearRect(0, 0, g.cols, g.rows); - for (let cz = 0; cz < g.rows; cz++) { - for (let cx = 0; cx < g.cols; cx++) { - if (g.isFloor(cx, cz)) { - const reg = g.regionAt(cx, cz); - ctx.fillStyle = reg === Region.ASite ? '#5c3330' : reg === Region.BSite ? '#2d4757' : '#3b3730'; - ctx.fillRect(cx, cz, 1, 1); - } - } - } - this.minimapStatic = c; - } - - private drawMinimap(): void { - const canvas = this.minimapCanvas; - if (!canvas || !this.minimapStatic) return; - const ctx = canvas.getContext('2d')!; - const W = canvas.width, H = canvas.height; - ctx.clearRect(0, 0, W, H); - ctx.imageSmoothingEnabled = false; - ctx.drawImage(this.minimapStatic, 0, 0, W, H); - - const { minX, maxX, minZ, maxZ } = this.dust2.bounds; - const toPx = (x: number, z: number): [number, number] => [ - ((x - minX) / (maxX - minX)) * W, - ((z - minZ) / (maxZ - minZ)) * H, - ]; - - // bomb - const b = this.bomb; - if (b.state === BombState.Planted || b.state === BombState.Dropped) { - const [bx, by] = toPx(b.x, b.z); - ctx.fillStyle = b.state === BombState.Planted ? '#ff3b30' : '#ffcc00'; - ctx.beginPath(); - ctx.arc(bx, by, 3.5, 0, Math.PI * 2); - ctx.fill(); - } - - const vis = this.visibleEnemyIds; - for (const a of this.actors) { - if (!a.alive) continue; - const [px, py] = toPx(a.x, a.z); - if (a.isPlayer) { - ctx.save(); - ctx.translate(px, py); - ctx.rotate(-a.yaw); - ctx.fillStyle = '#ffffff'; - ctx.beginPath(); - ctx.moveTo(0, -5); - ctx.lineTo(3.5, 4); - ctx.lineTo(-3.5, 4); - ctx.closePath(); - ctx.fill(); - ctx.restore(); - } else if (a.team === this.playerTeam) { - ctx.fillStyle = '#39d353'; - ctx.beginPath(); - ctx.arc(px, py, 2.6, 0, Math.PI * 2); - ctx.fill(); - } else if (vis.has(a.id)) { - ctx.fillStyle = '#ff453a'; - ctx.beginPath(); - ctx.arc(px, py, 2.8, 0, Math.PI * 2); - ctx.fill(); - } - } - } - - // ---- HUD ---- - - private syncHud(): void { - // When dead and spectating a teammate, mirror their vitals/weapon. - const view = this.viewActor(); - const controlling = this.player.alive; - const spectating = !controlling && view.alive && view !== this.player; - const p = spectating ? view : this.player; - const w = WEAPONS[p.current]; - const ammo = p.ammo[p.current]; - const b = this.bomb; - hud.set({ - phase: this.phase, - roundNum: this.roundNum, - scoreT: this.scoreT, - scoreCT: this.scoreCT, - roundTime: Math.max(0, this.roundTimer), - aliveT: this.countAlive(Team.T), - aliveCT: this.countAlive(Team.CT), - alive: this.player.alive, - spectating, - spectateName: spectating ? view.name : '', - health: Math.max(0, Math.ceil(p.health)), - armor: Math.max(0, Math.ceil(p.armor)), - helmet: p.helmet, - weaponName: w.name, - weaponId: p.current, - mag: ammo ? ammo.mag : 0, - reserve: ammo ? ammo.reserve : 0, - infiniteAmmo: w.isKnife, - reloading: p.reloadEnd > 0, - scoped: p.scoped, - spread: w.baseSpread + p.spread + this.moveInaccuracy(p), - hasBomb: p.hasBomb, - bombPlanted: b.state === BombState.Planted, - bombTimer: Math.max(0, b.timer), - defusing: b.defuseProgress > 0.05 && b.state === BombState.Planted, - defuseProgress: b.defuseProgress / ROUND.defuseTime, - planting: b.plantProgress > 0.05 && b.state === BombState.Carried, - plantProgress: b.plantProgress / ROUND.plantTime, - hint: this.hint, - banner: this.banner || (this.phase === RoundPhase.Freeze ? `Round ${this.roundNum}` : ''), - killfeed: this.killfeed.slice(), - loadout: p.weapons.map((id) => ({ - id, - name: WEAPONS[id].name, - slot: WEAPONS[id].slot, - mag: p.ammo[id]?.mag ?? 0, - reserve: p.ammo[id]?.reserve ?? 0, - current: id === p.current, - })), - }); - } - - private syncHudFull(): void { - this.syncHud(); - } - - // ---- lifecycle ---- - - resize(): void { - const w = this.container.clientWidth; - const h = this.container.clientHeight; - this.renderer.setSize(w, h); - this.camera.aspect = w / h; - this.camera.updateProjectionMatrix(); - } - - dispose(): void { - this.input.dispose(); - this.renderer.dispose(); - this.audio.muted = true; - if (this.renderer.domElement.parentElement === this.container) { - this.container.removeChild(this.renderer.domElement); - } - } -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/main.tsx b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/main.tsx deleted file mode 100644 index 97f78c7..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/main.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createRoot } from 'react-dom/client'; -import { App } from './App'; -import './styles.css'; - -// No StrictMode: the game owns an imperative three.js loop with manual setup / -// teardown, and double-invoked effects would spin up two render loops. -createRoot(document.getElementById('root')!).render(); diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/styles.css b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/styles.css deleted file mode 100644 index 9b8eb84..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/src/styles.css +++ /dev/null @@ -1,336 +0,0 @@ -:root { - --t: #e0a24a; - --ct: #5aa9e6; - --panel: rgba(12, 15, 20, 0.62); - --panel-solid: #0d1015; - --ink: #eaf0f2; -} - -* { box-sizing: border-box; margin: 0; padding: 0; } - -html, body, #root { - height: 100%; - width: 100%; - overflow: hidden; - background: #05070a; - color: var(--ink); - font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, monospace; - user-select: none; - -webkit-user-select: none; -} - -/* ---------- menu ---------- */ -.menu { - position: fixed; - inset: 0; - display: grid; - place-items: center; - background: - radial-gradient(1200px 700px at 50% -10%, #1b2740 0%, #0a0e16 55%, #05070a 100%); -} -.menu-card { - width: min(680px, 92vw); - padding: 40px 40px 30px; - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 14px; - background: rgba(10, 14, 20, 0.7); - box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6); - text-align: center; -} -.menu-title { - font-size: 44px; - letter-spacing: 10px; - font-weight: 800; - background: linear-gradient(90deg, var(--t), #fff 55%, var(--ct)); - -webkit-background-clip: text; - background-clip: text; - color: transparent; -} -.menu-sub { margin-top: 8px; color: #93a0ab; font-size: 13px; letter-spacing: 1px; } - -.side-select { display: flex; gap: 14px; margin: 26px 0 18px; } -.side { - flex: 1; - padding: 18px 16px; - border-radius: 10px; - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.03); - color: var(--ink); - cursor: pointer; - text-align: left; - transition: transform 0.1s, border-color 0.15s, background 0.15s; -} -.side:hover { transform: translateY(-2px); } -.side-name { display: block; font-size: 17px; font-weight: 700; } -.side-desc { display: block; margin-top: 6px; font-size: 12px; color: #93a0ab; } -.side-t.active { border-color: var(--t); background: rgba(224, 162, 74, 0.14); } -.side-ct.active { border-color: var(--ct); background: rgba(90, 169, 230, 0.14); } -.side-t .side-name { color: var(--t); } -.side-ct .side-name { color: var(--ct); } - -.controls { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px 20px; - margin: 18px 4px; - font-size: 12px; - color: #aab4bd; - text-align: left; -} -.controls b { color: #fff; font-weight: 700; } - -.start-btn { - margin-top: 10px; - padding: 14px 40px; - font-size: 16px; - font-weight: 800; - letter-spacing: 3px; - border: none; - border-radius: 10px; - color: #08111e; - background: linear-gradient(90deg, #7fd0ff, #cfeaff); - cursor: pointer; - font-family: inherit; -} -.start-btn:hover { filter: brightness(1.08); } -.menu-foot { margin-top: 14px; font-size: 11px; color: #6a757f; } - -/* ---------- game ---------- */ -.game-root { position: fixed; inset: 0; cursor: none; } -.game-root canvas { position: absolute; inset: 0; display: block; z-index: 1; } - -.hud { - position: absolute; - inset: 0; - z-index: 5; - pointer-events: none; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8); -} - -/* top bar */ -.topbar { - position: absolute; - top: 12px; - left: 50%; - transform: translateX(-50%); - display: flex; - align-items: center; - gap: 16px; - padding: 6px 14px; - background: var(--panel); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 8px; -} -.team-block { display: flex; align-items: center; gap: 8px; font-weight: 700; } -.team-right { flex-direction: row; } -.team-tag { font-size: 16px; letter-spacing: 1px; } -.team-alive { font-size: 10px; letter-spacing: 1px; } -.dead-dots { opacity: 0.35; } -.score-center { display: flex; align-items: center; gap: 14px; } -.score { font-size: 26px; font-weight: 800; min-width: 26px; text-align: center; } -.score-time { font-size: 15px; color: #cfd8de; min-width: 46px; text-align: center; } -.bomb-time { color: #ff4b3e; animation: blink 1s steps(2) infinite; } -@keyframes blink { 50% { opacity: 0.35; } } - -/* killfeed */ -.killfeed { - position: absolute; - top: 12px; - right: 14px; - display: flex; - flex-direction: column; - gap: 4px; - align-items: flex-end; -} -.kill-row { - display: flex; - align-items: center; - gap: 8px; - padding: 3px 9px; - background: var(--panel); - border-radius: 5px; - font-size: 12px; - font-weight: 700; -} -.kill-weapon { color: #cbd3da; font-weight: 500; } - -/* banner */ -.banner { - position: absolute; - top: 20%; - left: 50%; - transform: translateX(-50%); - font-size: 30px; - font-weight: 800; - letter-spacing: 3px; - color: #fff; - padding: 8px 26px; - background: rgba(8, 11, 16, 0.5); - border-radius: 10px; - white-space: nowrap; -} - -/* progress bar */ -.progress-wrap { - position: absolute; - top: 62%; - left: 50%; - transform: translateX(-50%); - width: 280px; - text-align: center; -} -.progress-label { font-size: 13px; letter-spacing: 3px; margin-bottom: 6px; } -.progress-bar { - height: 10px; - background: rgba(255, 255, 255, 0.14); - border-radius: 6px; - overflow: hidden; -} -.progress-fill { height: 100%; transition: width 0.05s linear; } - -/* crosshair */ -.crosshair { position: absolute; left: 50%; top: 50%; width: 0; height: 0; } - -/* scope */ -.scope { position: absolute; inset: 0; display: grid; place-items: center; } -.scope-circle { - width: min(86vh, 86vw); - height: min(86vh, 86vw); - border-radius: 50%; - box-shadow: 0 0 0 100vmax #000, inset 0 0 0 2px rgba(0, 0, 0, 0.9); -} -.scope-line { position: absolute; background: rgba(0, 0, 0, 0.85); } -.scope-h { width: 100%; height: 1px; } -.scope-v { height: 100%; width: 1px; } - -/* dead */ -.dead { - position: absolute; - top: 40%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; -} -.dead-title { font-size: 34px; font-weight: 800; letter-spacing: 6px; color: #ff5b5b; } -.dead-sub { margin-top: 8px; font-size: 13px; color: #b9c2c9; } - -/* spectate bar (after death) */ -.spectate { - position: absolute; - bottom: 15%; - left: 50%; - transform: translateX(-50%); - text-align: center; - padding: 10px 22px; - background: rgba(8, 11, 16, 0.62); - border: 1px solid rgba(255, 255, 255, 0.12); - border-radius: 8px; - white-space: nowrap; -} -.spectate-title { font-size: 16px; letter-spacing: 3px; color: #e7edf1; } -.spectate-name { color: #39d353; font-weight: 800; } -.spectate-keys { margin-top: 6px; font-size: 12px; color: #aab4bd; } -.spectate-keys b { color: #ffcf5b; } - -/* hint */ -.hint { - position: absolute; - bottom: 27%; - left: 50%; - transform: translateX(-50%); - padding: 6px 16px; - background: var(--panel); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 6px; - font-size: 14px; - letter-spacing: 1px; -} -.bomb-tag { - position: absolute; - bottom: 33%; - left: 50%; - transform: translateX(-50%); - color: var(--t); - font-size: 12px; - letter-spacing: 2px; -} - -/* vitals */ -.vitals { - position: absolute; - left: 22px; - bottom: 20px; - display: flex; - gap: 22px; - padding: 10px 16px; - background: var(--panel); - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.08); -} -.vital { display: flex; align-items: center; gap: 8px; } -.vital-icon { font-size: 15px; font-weight: 800; } -.vital-icon.hp { color: #4fd06a; } -.vital-icon.ar { color: var(--ct); } -.vital-num { font-size: 30px; font-weight: 800; min-width: 44px; } - -/* ammo */ -.ammo-block { - position: absolute; - right: 22px; - bottom: 20px; - text-align: right; - padding: 10px 16px; - background: var(--panel); - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.08); -} -.ammo-weapon { font-size: 13px; letter-spacing: 2px; color: #cbd3da; margin-bottom: 2px; } -.ammo-nums { display: flex; align-items: baseline; justify-content: flex-end; gap: 8px; } -.ammo-mag { font-size: 34px; font-weight: 800; } -.ammo-res { font-size: 16px; color: #9aa4ac; } -.weapon-slots { display: flex; flex-direction: column; gap: 3px; margin-top: 8px; align-items: flex-end; } -.slot { display: flex; gap: 8px; font-size: 12px; opacity: 0.55; } -.slot-cur { opacity: 1; color: #fff; } -.slot-key { color: #ffcf5b; font-weight: 700; } -.slot-name { min-width: 96px; text-align: right; } - -/* minimap */ -.minimap { - position: absolute; - left: 18px; - top: 14px; - z-index: 6; - width: 200px; - height: 200px; - border: 1px solid rgba(255, 255, 255, 0.12); - border-radius: 8px; - background: rgba(6, 9, 13, 0.72); - overflow: hidden; - pointer-events: none; -} -.minimap canvas { width: 100%; height: 100%; display: block; } -.minimap-label { - position: absolute; - bottom: 4px; - right: 8px; - font-size: 10px; - letter-spacing: 3px; - color: rgba(255, 255, 255, 0.4); -} - -/* click / pause overlay */ -.click-overlay { - position: absolute; - inset: 0; - z-index: 20; - display: grid; - place-items: center; - background: rgba(4, 6, 10, 0.55); - backdrop-filter: blur(2px); - pointer-events: auto; - cursor: pointer; -} -.click-inner { text-align: center; } -.click-title { font-size: 30px; font-weight: 800; letter-spacing: 6px; } -.click-hint { margin-top: 10px; font-size: 15px; color: #cfd8de; } -.click-sub { margin-top: 6px; font-size: 12px; color: #7c8790; } diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/tsconfig.json b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/tsconfig.json deleted file mode 100644 index 3c52be6..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "moduleResolution": "bundler", - "jsx": "react-jsx", - "strict": true, - "skipLibCheck": true, - "noEmit": true, - "types": ["vite/client"] - }, - "include": ["src", "vite.config.ts"] -} diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.config.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.config.ts deleted file mode 100644 index 7feb8a7..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -// base: './' keeps asset URLs relative so the built dist/ also works when opened -// straight from the filesystem. -export default defineConfig({ - base: './', - plugins: [react()], -}); diff --git a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.single.config.ts b/outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.single.config.ts deleted file mode 100644 index f38f259..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/dust2-arena/vite.single.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; -import { viteSingleFile } from 'vite-plugin-singlefile'; - -// `bun run build:single` — inlines all JS/CSS into one self-contained HTML -// (dist/index.html), which is what ships as dust2-arena.html. -export default defineConfig({ - base: './', - plugins: [react(), viteSingleFile()], -}); diff --git a/outputs/claude-opus-4-8/claude-code-max/mythos-craft-2.html b/outputs/claude-opus-4-8/claude-code-max/mythos-craft-2.html deleted file mode 100644 index 3584767..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/mythos-craft-2.html +++ /dev/null @@ -1,557 +0,0 @@ - - - - - -Mythos Craft — Voxel Realm - - - - -
-
- Mythos Craft
- W A S D move   Space jump
- Shift sprint   F toggle fly
- Left-click break   Right-click place
- 1–6 / scroll: choose block
- Esc release mouse -
-
-
-
-

MYTHOS CRAFT

-

A hand-built voxel realm — temples of marble, crystal spires & a floating sky-isle.

-
▶ ENTER THE REALM
- Click to play · pointer-lock controls -
- - - - - diff --git a/outputs/claude-opus-4-8/claude-code-max/mythos-craft.html b/outputs/claude-opus-4-8/claude-code-max/mythos-craft.html deleted file mode 100644 index ed0bf0f..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,780 +0,0 @@ - - - - - -方块秘境 · Voxel Mythos - - - - -
-
- -
-
方块秘境 Voxel Mythos
-
pos —
-
-
-
- -
- -
-
A Hand-built Myth · 神话造物
-

方块秘境VOXEL MYTHOS

- -
- W A S D移动 - SPACE跳跃 - SHIFT疾跑 - 鼠标环视 - 左键破坏 - 右键放置 - 1-9 / 滚轮切换方块 - F飞行 -
-
柏林噪声生成的无限地形之上,矗立着由开发者亲手设计的「天悬神殿」与「世界之树」——光之回廊、水晶尖塔、悬浮岛屿、巨龙守卫与符文法阵环绕其间。降临神域,开始你的造物。
-
-
- - - - - - diff --git a/outputs/claude-opus-4-8/claude-code-max/pelican-cycling-2.svg b/outputs/claude-opus-4-8/claude-code-max/pelican-cycling-2.svg deleted file mode 100644 index 57ab3bd..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/pelican-cycling-2.svg +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-opus-4-8/claude-code-max/pelican-cycling.svg b/outputs/claude-opus-4-8/claude-code-max/pelican-cycling.svg deleted file mode 100644 index b0c32c4..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,300 +0,0 @@ - - A pelican riding a bicycle by the sea - A lively brown pelican with a long pouched beak pedals a red bicycle along a sunlit beach, the turquoise ocean and a sailboat behind it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-opus-4-8/claude-code-max/skeleton-watch.html b/outputs/claude-opus-4-8/claude-code-max/skeleton-watch.html deleted file mode 100644 index 103e43e..0000000 --- a/outputs/claude-opus-4-8/claude-code-max/skeleton-watch.html +++ /dev/null @@ -1,1014 +0,0 @@ - - - - - -NAGI Mécanique — Skeleton Calibre · 镂空机械腕表 - - - -
-
-
- -
-
NAGI Mécanique
-
Skeleton Calibre N-01 · Haute Horlogerie
-
镂空陀飞轮机芯 · 高级制表工艺
-
- - - -
- - - -
-
-
Assembling Calibre
-
-
- - - - - - diff --git a/outputs/claude-sonnet-4-6/claude-code-max/pelican-cycling.svg b/outputs/claude-sonnet-4-6/claude-code-max/pelican-cycling.svg deleted file mode 100644 index 176d244..0000000 --- a/outputs/claude-sonnet-4-6/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,416 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-sonnet-4-6/cursor-high/pelican-cycling-2.svg b/outputs/claude-sonnet-4-6/cursor-high/pelican-cycling-2.svg deleted file mode 100644 index ef94559..0000000 --- a/outputs/claude-sonnet-4-6/cursor-high/pelican-cycling-2.svg +++ /dev/null @@ -1,561 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/claude-sonnet-4-6/cursor-high/pelican-cycling.svg b/outputs/claude-sonnet-4-6/cursor-high/pelican-cycling.svg deleted file mode 100644 index 2823c92..0000000 --- a/outputs/claude-sonnet-4-6/cursor-high/pelican-cycling.svg +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/composer-2-5/cursor-default/mythos-craft.html b/outputs/composer-2-5/cursor-default/mythos-craft.html deleted file mode 100644 index 9fb4699..0000000 --- a/outputs/composer-2-5/cursor-default/mythos-craft.html +++ /dev/null @@ -1,632 +0,0 @@ - - - - - -神话之境 — Mythos Craft - - - -
-

神话之境

-

Mythos Craft — 体素世界

-

- WASD 移动 · 空格跳跃 · Shift 潜行
- 鼠标环视 · 左键破坏 · 右键放置 · 1-6 切换方块
- 柏林噪声生成的无限地形:草原、沙漠、雪原、神话群系
- 探索精灵螺旋塔、龙神殿、天空浮岛遗迹 -

-
点击开始
-
-
-
- -
-
-
坐标 0, 0, 0
-
- - - - - diff --git a/outputs/composer-2-5/cursor-default/pelican-cycling.svg b/outputs/composer-2-5/cursor-default/pelican-cycling.svg deleted file mode 100644 index bfb9cce..0000000 --- a/outputs/composer-2-5/cursor-default/pelican-cycling.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/composer-2-5/cursor-max/mythos-craft.html b/outputs/composer-2-5/cursor-max/mythos-craft.html deleted file mode 100644 index c06407f..0000000 --- a/outputs/composer-2-5/cursor-max/mythos-craft.html +++ /dev/null @@ -1,1432 +0,0 @@ - - - - - -神话之境 — Minecraft 克隆版 - - - -
-

神话之境

-

Mythic Realms — 方块世界

-

- WASD 移动 · 空格跳跃 · Shift 潜行
- 鼠标环视 · 左键破坏 · 右键放置
- 1-9 切换方块 · 滚轮切换物品
- 探索柏林噪声生成的无限大地
- 发现精灵塔、龙神殿、天空遗迹等神话建筑
- G 依次瞬移到三处神话景点 -

-
点击开始探索
-
- - - - - - - - - diff --git a/outputs/composer-2-5/grok-build-tui-default/mythos-craft.html b/outputs/composer-2-5/grok-build-tui-default/mythos-craft.html deleted file mode 100644 index 273749f..0000000 --- a/outputs/composer-2-5/grok-build-tui-default/mythos-craft.html +++ /dev/null @@ -1,1218 +0,0 @@ - - - - - -MythiCraft — 神话之境 - - - -
-

MYTHICRAFT

-
神 话 之 境
-
- WASD 移动 · 空格跳跃 · Shift 潜行
- 鼠标环视 · 滚轮切换方块 · 左键破坏 · 右键放置
- 探索柏林噪声生成的无限大陆,邂逅水晶神殿、巨龙遗迹、世界树…… -
- -
- -
-
-
-
- - - - - \ No newline at end of file diff --git a/outputs/composer-2-5/grok-build-tui-default/pelican-cycling.svg b/outputs/composer-2-5/grok-build-tui-default/pelican-cycling.svg deleted file mode 100644 index ef0bf1b..0000000 --- a/outputs/composer-2-5/grok-build-tui-default/pelican-cycling.svg +++ /dev/null @@ -1,367 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A pelican's seaside ride - \ No newline at end of file diff --git a/outputs/deepseek-v4-flash/claude-code-max/mythos-craft.html b/outputs/deepseek-v4-flash/claude-code-max/mythos-craft.html deleted file mode 100644 index 59108c7..0000000 --- a/outputs/deepseek-v4-flash/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,1733 +0,0 @@ - - - - - -神话世界 - Minecraft Fantasy Clone - - - - -
-
神话世界 · 正在生成
-
铸造地形 · 召唤古堡 · 点晶为灵
-
-
- -
-
-

神话世界

-

点击进入奇幻大陆

-

- WASD 移动 · Space 跳跃 · Shift 飞行
- 左键 破坏 · 右键 放置 · 滚轮/1-9 选方块 -

-
-
- -
-
-
-
- - - - - diff --git a/outputs/deepseek-v4-flash/reasonix-max/skeleton-watch.html b/outputs/deepseek-v4-flash/reasonix-max/skeleton-watch.html deleted file mode 100644 index e4486c6..0000000 --- a/outputs/deepseek-v4-flash/reasonix-max/skeleton-watch.html +++ /dev/null @@ -1,1320 +0,0 @@ - - - - - -交互式 3D 镂空机械表 - - - - -
加载中
- - - -
-
零件信息
-
摆轮
-
控制机芯走时精度的核心部件
以 28,800 次/小时 的频率振荡
-
🖱 悬停零件查看 | 点击锁定
-
- -
- - -
- -
- -
- - - - - - diff --git a/outputs/deepseek-v4-pro/claude-code-max/mythos-craft.html b/outputs/deepseek-v4-pro/claude-code-max/mythos-craft.html deleted file mode 100644 index fce8bc3..0000000 --- a/outputs/deepseek-v4-pro/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,1196 +0,0 @@ - - - - - -Mythos Craft - - - -
-

🏰 Mythos Craft

-

🖱 点击 开始游戏 · 锁定鼠标

-

W A S D 移动   空格 跳跃   Shift 潜行

-

左键 破坏方块   右键 放置方块

-

1-9 切换方块类型   G 传送至神话建筑

-

Press G to teleport between mythic landmarks

-
-
-
-
草地
-
泥土
-
石头
-
原木
-
树叶
-
沙
-
石砖
-
水晶
-
金块
-
-
- - - - - - \ No newline at end of file diff --git a/outputs/deepseek-v4-pro/claude-code-max/pelican-cycling.svg b/outputs/deepseek-v4-pro/claude-code-max/pelican-cycling.svg deleted file mode 100644 index b7dbdb6..0000000 --- a/outputs/deepseek-v4-pro/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/deepseek-v4-pro/claude-code-max/skeleton-watch.html b/outputs/deepseek-v4-pro/claude-code-max/skeleton-watch.html deleted file mode 100644 index f0ac0c1..0000000 --- a/outputs/deepseek-v4-pro/claude-code-max/skeleton-watch.html +++ /dev/null @@ -1,1597 +0,0 @@ - - - - - -3D 镂空机械腕表 - - - - -
-
- -
-
- Calibre Squelette - Tourbillon · Manufacture -
-
- -
- -
-

组件详情

-
-
-
-
- -
- - - - -
- - - - - - diff --git a/outputs/doubao-seed-2-0-mini/doubao-web-fast-mode/pelican-cycling.svg b/outputs/doubao-seed-2-0-mini/doubao-web-fast-mode/pelican-cycling.svg deleted file mode 100644 index 846a89c..0000000 --- a/outputs/doubao-seed-2-0-mini/doubao-web-fast-mode/pelican-cycling.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/doubao-seed-2-0-pro/doubao-web-pro-mode/pelican-cycling.svg b/outputs/doubao-seed-2-0-pro/doubao-web-pro-mode/pelican-cycling.svg deleted file mode 100644 index 5371cb1..0000000 --- a/outputs/doubao-seed-2-0-pro/doubao-web-pro-mode/pelican-cycling.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - Realistic Pelican Riding Bicycle on Beach - A realistic, lively illustration of a pelican riding a bicycle along the coastal beach - pelican, bicycle, beach, coastal, realistic, animation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/antigravity-high/mythos-craft.html b/outputs/gemini-3-1-pro/antigravity-high/mythos-craft.html deleted file mode 100644 index 83f4b48..0000000 --- a/outputs/gemini-3-1-pro/antigravity-high/mythos-craft.html +++ /dev/null @@ -1,759 +0,0 @@ - - - - - - Mythical Minecraft Clone - - - -
-

MYTHIC REALMS

-

A voxel adventure built in a single HTML file.
Explore the infinite terrain, find the floating temple, and build your own legend.

-

WASD to Move • Mouse to Look • Space to Jump
Left Click to Break • Right Click to Place • 1-5 to Select Block

- -
-
+
-
-
1Grass
-
2Dirt
-
3Stone
-
4Magic
-
5Gold
-
- - - - - - - - - diff --git a/outputs/gemini-3-1-pro/antigravity-high/pelican-cycling-2.svg b/outputs/gemini-3-1-pro/antigravity-high/pelican-cycling-2.svg deleted file mode 100644 index df16c1d..0000000 --- a/outputs/gemini-3-1-pro/antigravity-high/pelican-cycling-2.svg +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/antigravity-high/skeleton-watch.html b/outputs/gemini-3-1-pro/antigravity-high/skeleton-watch.html deleted file mode 100644 index 848080e..0000000 --- a/outputs/gemini-3-1-pro/antigravity-high/skeleton-watch.html +++ /dev/null @@ -1,595 +0,0 @@ - - - - - - Aero Tourbillon - 3D Skeleton Watch - - - -
-
-
ASSEMBLING MOVEMENT...
-
- -
- -
-
-

AEROTOURBILLON

-

CALIBER X-01 SKELETON

-
- -
- - -
- -
-

Component

-

Description goes here.

-
- -
Tooltip
-
- - - - - - - diff --git a/outputs/gemini-3-1-pro/cursor-default/mythos-craft.html b/outputs/gemini-3-1-pro/cursor-default/mythos-craft.html deleted file mode 100644 index 5bc56a2..0000000 --- a/outputs/gemini-3-1-pro/cursor-default/mythos-craft.html +++ /dev/null @@ -1,603 +0,0 @@ - - - - - Mythiccraft - - - -
+
-
-
1
-
2
-
3
-
4
-
5
-
6
-
-
-

Mythiccraft

-

Explore the roots of the World Tree.

- -
-
WASD / Arrows to Move
-
Left Click to Break Block
-
SPACE to Jump
-
Right Click to Place Block
-
Mouse to Look Around
-
1 - 6 to Select Block Type
-
-
- - - - - - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/cursor-default/pelican-cycling.svg b/outputs/gemini-3-1-pro/cursor-default/pelican-cycling.svg deleted file mode 100644 index ddb7801..0000000 --- a/outputs/gemini-3-1-pro/cursor-default/pelican-cycling.svg +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/gemini-web-deepthink/mythos-craft.html b/outputs/gemini-3-1-pro/gemini-web-deepthink/mythos-craft.html deleted file mode 100644 index fad9491..0000000 --- a/outputs/gemini-3-1-pro/gemini-web-deepthink/mythos-craft.html +++ /dev/null @@ -1,503 +0,0 @@ - - - - - 神话领域 (Mythic Realms) - - - - - - -
-
- -
-

神话领域

-

前方是远古纪元遗留的奇迹:「星辰尖塔与悬浮遗迹」

- [ WASD ] 移动   |   [ 空格 ] 跳跃   |   [ Shift ] 奔跑
- [ 鼠标左键 ] 破坏   |   [ 鼠标右键 ] 建造   |   [ 1 - 9 ] 切换方块 -

- -
- - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/gemini-web-deepthink/pelican-cycling.svg b/outputs/gemini-3-1-pro/gemini-web-deepthink/pelican-cycling.svg deleted file mode 100644 index ff1550b..0000000 --- a/outputs/gemini-3-1-pro/gemini-web-deepthink/pelican-cycling.svg +++ /dev/null @@ -1,491 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gemini-3-1-pro/gemini-web-deepthink/skeleton-watch.html b/outputs/gemini-3-1-pro/gemini-web-deepthink/skeleton-watch.html deleted file mode 100644 index f33a6ac..0000000 --- a/outputs/gemini-3-1-pro/gemini-web-deepthink/skeleton-watch.html +++ /dev/null @@ -1,591 +0,0 @@ - - - - - - 3D 奢华交互式镂空机械腕表 | Haute Horlogerie - - - - - - - - -
-
-
Assembling Calibre...
-
- -
-
- -
-
-

Aethelgard Skeleton

-
Grand Complication · Calibre 89
-
- -
-

零件名称

-

零件描述详情...

-
- -
- 拖拽旋转视角 | 滚轮缩放 | 点击高亮鉴赏机芯组件 -
- -
- -
-
- - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/google-ai-studio-high/pelican-cycling.svg b/outputs/gemini-3-1-pro/google-ai-studio-high/pelican-cycling.svg deleted file mode 100644 index 2318a46..0000000 --- a/outputs/gemini-3-1-pro/google-ai-studio-high/pelican-cycling.svg +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gemini-3-1-pro/google-ai-studio-high/skeleton-watch.html b/outputs/gemini-3-1-pro/google-ai-studio-high/skeleton-watch.html deleted file mode 100644 index 13a7842..0000000 --- a/outputs/gemini-3-1-pro/google-ai-studio-high/skeleton-watch.html +++ /dev/null @@ -1,639 +0,0 @@ - - - - - - Aethelgard 3D 镂空陀飞轮机械表 - - - - - -
CRAFTING CALIBER...
-
-
- -
- -
-
组件名称
-
组件详情...
-
-
- -
-
- - - - \ No newline at end of file diff --git a/outputs/gemini-3-5-flash/antigravity-high/mythos-craft.html b/outputs/gemini-3-5-flash/antigravity-high/mythos-craft.html deleted file mode 100644 index cec38a4..0000000 --- a/outputs/gemini-3-5-flash/antigravity-high/mythos-craft.html +++ /dev/null @@ -1,2736 +0,0 @@ - - - - - - MythicCraft - 3D Minecraft Clone - - - - - - - - - -
- - -
- - -
-
-
-

MythicCraft

-
-
Pos: 0, 0, 0
-
FPS: 60
-
-
-
Biome: Mythic Valleys
-
Fly: OFF
-
-
- -
-

Legendary Structures

-
- Find structures generated in the seed:
- • Floating Temple of Aether (Y: ~95)
- • Ancient Portal Ruins (On Surface)
- • Yggdrasil World Tree (On Surface) -
-
-
- -
-
Grass Block
-
- -
-
-
- - -
Fly Mode Enabled
- - - - - - - - - - - - - - diff --git a/outputs/gemini-3-5-flash/antigravity-high/pelican-cycling-2.svg b/outputs/gemini-3-5-flash/antigravity-high/pelican-cycling-2.svg deleted file mode 100644 index aa710e1..0000000 --- a/outputs/gemini-3-5-flash/antigravity-high/pelican-cycling-2.svg +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gemini-3-5-flash/antigravity-high/skeleton-watch.html b/outputs/gemini-3-5-flash/antigravity-high/skeleton-watch.html deleted file mode 100644 index 06048a5..0000000 --- a/outputs/gemini-3-5-flash/antigravity-high/skeleton-watch.html +++ /dev/null @@ -1,2108 +0,0 @@ - - - - - - Haute Horlogerie - 3D 镂空机械表 - - - - - - - - - - - - -
-
-
HAUTE HORLOGERIE
-
正在组装 3D 机械核心...
-
-
-

HAUTE HORLOGERIE

-

为了获得最佳奢华体验,请在桌面端或更宽的屏幕上浏览此 3D 机械表模型。

- -
-
-
-
零件名称
-
- -
-
- CALIBRE . S1 - 镂空飞轮机械机芯 -
-
- - 振频: 4.0 Hz / 28800 vph -
-
- - - - - - - -
-
- - -
-
- - - - -
-
-
- - - - \ No newline at end of file diff --git a/outputs/gemini-3-5-flash/cursor-default/mythos-craft.html b/outputs/gemini-3-5-flash/cursor-default/mythos-craft.html deleted file mode 100644 index 54fed78..0000000 --- a/outputs/gemini-3-5-flash/cursor-default/mythos-craft.html +++ /dev/null @@ -1,2250 +0,0 @@ - - - - - -神话之境 — Mythos Craft - - - - - - -
-
-

神话之境

-

MYTHOS CRAFT

-
- -
-

探索与创造的神话体素世界

-
-
WASD 键移动 / 奔跑
-
Space 空格跳跃 / 飞升
-
Shift 键潜行(不落边缘)
-
鼠标移动视角环视
-
鼠标左键破坏方块
-
鼠标右键放置方块
-
1 - 9 键选择物品栏
-
F 键切换飞行模式
-
G 键折跃下一个神迹
-
T / ESC 键打开/关闭控制板
-
-

- 世界中央矗立着世界之树 (Yggdrasil),其树心深藏着闪烁的以太水晶;
- 东北方云顶悬浮着天神祭坛 (Aether Shrine);西南方伏卧着暗黑龙之巢穴 (Dragon Keep)。
- 使用左侧“折跃圣典”或按 G 键,可在各大神话景致间自由穿梭。 -

-
- - -
- - -
- - - - - - - - -
-
- -
-
座 标:X: 0, Y: 30, Z: 0
-
群 系:神话林谷
-
模 式:生存
-
帧 率:60 fps
-
- - -
- -
-
- -
-
草方块
- -
- -
-
-
- - - - - - - diff --git a/outputs/gemini-3-5-flash/cursor-default/pelican-cycling.svg b/outputs/gemini-3-5-flash/cursor-default/pelican-cycling.svg deleted file mode 100644 index 332c978..0000000 --- a/outputs/gemini-3-5-flash/cursor-default/pelican-cycling.svg +++ /dev/null @@ -1,670 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gemini-3-5-flash/google-ai-studio-high/pelican-cycling.svg b/outputs/gemini-3-5-flash/google-ai-studio-high/pelican-cycling.svg deleted file mode 100644 index 7a8716e..0000000 --- a/outputs/gemini-3-5-flash/google-ai-studio-high/pelican-cycling.svg +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/glm-5-1/zcode-max/pelican-cycling.svg b/outputs/glm-5-1/zcode-max/pelican-cycling.svg deleted file mode 100644 index b12cdca..0000000 --- a/outputs/glm-5-1/zcode-max/pelican-cycling.svg +++ /dev/null @@ -1,360 +0,0 @@ - - Pelican cycling by the sea - A lively pelican riding a red bicycle along a beach at sunset with ocean waves, palm trees, shells, clouds, and distant seabirds. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/glm-5-2/zcode-max/mythos-craft.html b/outputs/glm-5-2/zcode-max/mythos-craft.html deleted file mode 100644 index ba6652f..0000000 --- a/outputs/glm-5-2/zcode-max/mythos-craft.html +++ /dev/null @@ -1,1318 +0,0 @@ - - - - - -Mythos — A Voxel Realm - - - - -
-
-
-
N
- -
-
-

MYTHOS

-
A VOXEL REALM
-

An infinite procedural world of mythic fantasy — soaring citadels, a world-tree, crystal sanctums, and the ruins of a forgotten age. Build, break, and explore.

-
-
WASD Move
-
Mouse Look
-
Space Jump / Fly-up
-
Shift Sprint / Fly-down
-
Left Click Break block
-
Right Click Place block
-
1 – 9 Select block
-
F Toggle fly
-
R Respawn at spawn
-
Esc Release mouse
-
- -
-
FORGING THE WORLD…
-
-
-
-
- - - - - diff --git a/outputs/glm-5-2/zcode-max/pelican-cycling-2.svg b/outputs/glm-5-2/zcode-max/pelican-cycling-2.svg deleted file mode 100644 index 9efb957..0000000 --- a/outputs/glm-5-2/zcode-max/pelican-cycling-2.svg +++ /dev/null @@ -1,465 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/glm-5-2/zcode-max/pelican-cycling.svg b/outputs/glm-5-2/zcode-max/pelican-cycling.svg deleted file mode 100644 index 138918f..0000000 --- a/outputs/glm-5-2/zcode-max/pelican-cycling.svg +++ /dev/null @@ -1,349 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只鹈鹕在海边夕阳下骑着一辆红色自行车,背景是海浪、沙滩和椰子树。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/glm-5-2/zcode-max/skeleton-watch.html b/outputs/glm-5-2/zcode-max/skeleton-watch.html deleted file mode 100644 index dfe9063..0000000 --- a/outputs/glm-5-2/zcode-max/skeleton-watch.html +++ /dev/null @@ -1,1088 +0,0 @@ - - - - - -SKELETON — 镂空机械腕表 3D 展示 - - - -
- -
-
-
MANUFACTURE · GENÈVE
-
SKELETON
-
CAL. T-9128 · TOURBILLON STYLE
-
-
-
RÉFÉRENCE
-
N°0247 / 250
-
-
- -
-

CONTRÔLES

-
自动旋转
-
机芯运转
-
背景反射
-
辉光 (Bloom)
-
摆轮速率5.0 Hz
- - -
- 鼠标拖拽旋转 · 滚轮缩放
- 悬停零件查看名称 · 点击展开详情 -
-
- - - -
-
00:00:00
-
SYNCHRONIZED · LOCAL TIME
-
- -
CALIBRATING MOVEMENT…
- - - - - - diff --git a/outputs/glm-5-turbo/zcode-thinking/mythos-craft-2.html b/outputs/glm-5-turbo/zcode-thinking/mythos-craft-2.html deleted file mode 100644 index abe2e9e..0000000 --- a/outputs/glm-5-turbo/zcode-thinking/mythos-craft-2.html +++ /dev/null @@ -1,953 +0,0 @@ - - - - - -神话大陆 - MythicCraft - - - -
-

神 话 大 陆

-
MYTHICCRAFT — 一个充满神话幻想的世界
-
-
- - - - - - - diff --git a/outputs/glm-5-turbo/zcode-thinking/mythos-craft.html b/outputs/glm-5-turbo/zcode-thinking/mythos-craft.html deleted file mode 100644 index da99c5b..0000000 --- a/outputs/glm-5-turbo/zcode-thinking/mythos-craft.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - -神话工艺 MythicCraft - - - -
-
-
FPS: 0
-
位置: 0, 0, 0
-
目标: 无
-
-
-
-
-

⚒ 神话工艺 ⚒

-

MythicCraft — 神话幻想世界

-

WASD 移动 | 空格 跳跃 | Shift 潜行

-

鼠标左键 破坏方块 | 鼠标右键 放置方块

-

滚轮/数字键 切换方块 | E 切换飞行模式

- -
- - - - - diff --git a/outputs/glm-5-turbo/zcode-thinking/pelican-cycling.svg b/outputs/glm-5-turbo/zcode-thinking/pelican-cycling.svg deleted file mode 100644 index 9720ee6..0000000 --- a/outputs/glm-5-turbo/zcode-thinking/pelican-cycling.svg +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gpt-5-2/cursor-xhigh/mythos-craft.html b/outputs/gpt-5-2/cursor-xhigh/mythos-craft.html deleted file mode 100644 index 0e7cb2c..0000000 --- a/outputs/gpt-5-2/cursor-xhigh/mythos-craft.html +++ /dev/null @@ -1,1848 +0,0 @@ - - - - - - MythicCraft - Voxel Sandbox - - - -
- - -
-
-
-
-

MythicCraft:体素沙盒(单文件)

-
- Perlin 噪声无限分块地形 + 第一人称(指针锁)+ 拆放方块 + 内置神话幻想地形/建筑群(世界树、浮空神殿、龙骨峡谷、水晶尖塔、古代遗迹)。 -
- MythicCraft: infinite Perlin terrain, FPS controls, voxel break/place, and built-in mythic landmarks. -
-
-
-
- 正在准备世界… - 提示:点击后会请求鼠标锁定 / Pointer Lock -
-
- -
-
-

操作 / Controls

-
    -
  • W A S D 移动 / Move
  • -
  • 鼠标移动 环视 / Look
  • -
  • Space 跳跃(行走模式)/ Jump (walk mode)
  • -
  • F 切换飞行 / Toggle fly
  • -
  • Shift 下落(飞行)/ Down (fly)
  • -
  • 1-6 选择方块 / Select block
  • -
  • 左键 破坏方块 / Break
  • -
  • 右键 放置方块 / Place
  • -
  • Esc 释放鼠标 / Unlock
  • -
-
-
-

神话地标 / Mythic Landmarks

-
    -
  • 世界树 / World Tree:出生点附近的巨树与符文祭坛
  • -
  • 浮空神殿 / Sky Temple:东南方向的漂浮岛屿与传送环
  • -
  • 龙骨峡谷 / Dragonbone Ravine:西北方向的骨架脊梁与肋骨拱门
  • -
  • 水晶尖塔 / Crystal Spires:西南方向的符文尖塔群
  • -
  • 古代遗迹 / Ancient Ruins:南方方向的断墙、拱门与柱廊
  • -
-
- 你可以开启飞行快速巡游。坐标与目标方块信息会显示在左上角调试面板。 -
Use fly mode for quick sightseeing; coords and target info show in the top-left HUD.
-
-
-
- -
- -
- 渲染 -- FPS - 区块 -- - 种子 -- -
-
-
-
- - - - - diff --git a/outputs/gpt-5-2/cursor-xhigh/pelican-cycling.svg b/outputs/gpt-5-2/cursor-xhigh/pelican-cycling.svg deleted file mode 100644 index cd8c811..0000000 --- a/outputs/gpt-5-2/cursor-xhigh/pelican-cycling.svg +++ /dev/null @@ -1,390 +0,0 @@ - - Pelican Cycling by the Sea - A vivid, realistic pelican riding a bicycle along a seaside beach at golden hour. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-3-codex/cursor-xhigh/mythos-craft.html b/outputs/gpt-5-3-codex/cursor-xhigh/mythos-craft.html deleted file mode 100644 index 8ab7d55..0000000 --- a/outputs/gpt-5-3-codex/cursor-xhigh/mythos-craft.html +++ /dev/null @@ -1,1554 +0,0 @@ - - - - - - Mythic Craft - Single File Minecraft Clone - - - -
-
-

Mythic Craft

-

Single-file HTML5 voxel sandbox with streaming Perlin terrain and mythic procedural landmarks.

-
    -
  • WASD move, Mouse look, Space jump, Shift sprint, Esc unlock cursor
  • -
  • Left click break block, Right click place block
  • -
  • Scroll or press number keys (1-7) to select block
  • -
  • Explore floating temples, obsidian fortresses, crystal ruins, and world-tree sanctums
  • -
- -
-
- -
-
-
-
- Landmarks are procedurally generated in all directions. Walk farther to discover more structures in the infinite world. -
-
-
- - - - diff --git a/outputs/gpt-5-3-codex/cursor-xhigh/pelican-cycling.svg b/outputs/gpt-5-3-codex/cursor-xhigh/pelican-cycling.svg deleted file mode 100644 index e2efa29..0000000 --- a/outputs/gpt-5-3-codex/cursor-xhigh/pelican-cycling.svg +++ /dev/null @@ -1,276 +0,0 @@ - - Pelican cycling along the seaside - A realistic and vivid pelican riding a bicycle on a coastal path at golden hour, with moving waves and soft atmospheric motion. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-4/codex-xhigh/mythos-craft.html b/outputs/gpt-5-4/codex-xhigh/mythos-craft.html deleted file mode 100644 index 45c83de..0000000 --- a/outputs/gpt-5-4/codex-xhigh/mythos-craft.html +++ /dev/null @@ -1,1302 +0,0 @@ - - - - - - 神话方界 - - - -
-
-
-

神话方界

-

柏林噪声分块地形、第一人称方块交互、以及内置的神话幻想遗迹群都在这个单文件世界里。

-

点击开始 | WASD 移动 | 鼠标环视 | 空格跳跃 | 左键破坏 | 右键放置 | 滚轮或数字键切换方块 | ESC 释放鼠标

-
-
-
-
-
生成中…
-
世界中包含 Asterion Citadel、Elderbloom、Dragonfall Causeway、Moonwell Steps、Skyshard Reach 等大型神话建筑群,并继续向远方程序延展。
-
-
-
-
-
当前方块
-
坐标
-
-
- - - - - diff --git a/outputs/gpt-5-4/codex-xhigh/pelican-cycling-2.svg b/outputs/gpt-5-4/codex-xhigh/pelican-cycling-2.svg deleted file mode 100644 index 5875adf..0000000 --- a/outputs/gpt-5-4/codex-xhigh/pelican-cycling-2.svg +++ /dev/null @@ -1,243 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只逼真而生动的鹈鹕在海边骑着复古自行车,背景是海浪、沙滩与暖色夕阳。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-4/codex-xhigh/pelican-cycling.svg b/outputs/gpt-5-4/codex-xhigh/pelican-cycling.svg deleted file mode 100644 index 05163cd..0000000 --- a/outputs/gpt-5-4/codex-xhigh/pelican-cycling.svg +++ /dev/null @@ -1,217 +0,0 @@ - - Pelican riding a bicycle by the seaside - A vivid, realistic pelican rides a bicycle along a coastal path with waves, cliffs, clouds, and warm evening light. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-4/codex-xhigh/skeleton-watch.html b/outputs/gpt-5-4/codex-xhigh/skeleton-watch.html deleted file mode 100644 index b9c749e..0000000 --- a/outputs/gpt-5-4/codex-xhigh/skeleton-watch.html +++ /dev/null @@ -1,1729 +0,0 @@ - - - - - - Luxury Skeleton Watch Showcase - - - -
- -
-
Haute Horlogerie / Product Reveal
-

镂空机械表

-

- 拖拽旋转手表,悬停或点击零件查看说明。爆炸视图会分离蓝宝石水晶、夹板、轮系与表壳层级,便于观察复杂机芯结构。 -

-
- - - -
-
-
- Power Reserve - 72 Hours -
-
- Beat Rate - 28,800 vph -
-
- Jewels - 21 Rubies -
-
-
- - - -
- - - - - - - - - - diff --git a/outputs/gpt-5-4/cursor-xhigh/mythos-craft.html b/outputs/gpt-5-4/cursor-xhigh/mythos-craft.html deleted file mode 100644 index 04d21a7..0000000 --- a/outputs/gpt-5-4/cursor-xhigh/mythos-craft.html +++ /dev/null @@ -1,2116 +0,0 @@ - - - - - - 神话方境 - - - - -
-
-
-

神话方境

-

单文件 HTML5 + Three.js 体素世界:无限分块柏林噪声地形、第一人称漫游、左键破坏、右键放置、六种可选方块与接近原版像素质感的程序化材质。

-

起始圈内置了整套神话奇境:星冠浮城、月井神殿、蚀日石门、世界树庭、坠星晶坑与龙骸山脊;继续远行时,区域还会继续生成空中圣殿、螺旋高塔、符门遗迹与晶簇天坑。

-
-
-
Realm State
-
初始化世界中...
-
正在感知地标...
-
-
WASD 移动,空格跳跃,Shift 冲刺,鼠标环视,左键破坏,右键放置,滚轮或数字键切换方块,R 返回浮城
-
-
-
-

进入神话方境

-

点击画面锁定鼠标并开始探索这个由柏林噪声与手工神话地标共同构成的体素世界。你会从星冠浮城出发,在浮空圣殿、世界树、龙骸山脊与晶石遗迹之间穿行。

-
-
-
- - - - diff --git a/outputs/gpt-5-4/cursor-xhigh/pelican-cycling.svg b/outputs/gpt-5-4/cursor-xhigh/pelican-cycling.svg deleted file mode 100644 index f925a13..0000000 --- a/outputs/gpt-5-4/cursor-xhigh/pelican-cycling.svg +++ /dev/null @@ -1,276 +0,0 @@ - - Pelican riding a bicycle by the sea - A vivid seaside illustration of a realistic pelican riding a bicycle along a glowing beach at sunset. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/mythos-craft.html b/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/mythos-craft.html deleted file mode 100644 index 4879b3d..0000000 --- a/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/mythos-craft.html +++ /dev/null @@ -1,1334 +0,0 @@ - - - - - - MythCraft — HTML5 / Three.js Minecraft 克隆原型 - - - - - -
-
-

MythCraft

-
一个单文件 HTML5 / Three.js 体素世界:无限滚动地形、可破坏/可放置方块、神话幻想遗迹与浮空岛。
-
- WASD 移动,鼠标环视,Space 跳跃,F 飞行/生存切换
- 左键破坏,右键放置,中键吸取目标方块,数字键或滚轮切换方块,R 回到出生点
- 世界会按区块懒加载;走远后仍会继续由柏林噪声和神话结构种子生成。 -
-
点击进入世界并锁定鼠标
-
-
-
-
-
-
提示:浏览器若阻止模块加载,请用本地服务器打开此 HTML。
- - - - \ No newline at end of file diff --git a/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/pelican-cycling.svg b/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/pelican-cycling.svg deleted file mode 100644 index dd13373..0000000 --- a/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/pelican-cycling.svg +++ /dev/null @@ -1,439 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只逼真而生动的鹈鹕在海边小路上骑着自行车,背景有夕阳、海浪、沙滩和海风。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/skeleton-watch.html b/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/skeleton-watch.html deleted file mode 100644 index 0e4d629..0000000 --- a/outputs/gpt-5-5-pro/chatgpt-web-extended-pro/skeleton-watch.html +++ /dev/null @@ -1,1412 +0,0 @@ - - - - - - Interactive Skeleton Mechanical Watch — Three.js - - - -
-
- -
-
Calibre OAI-SK01
-

镂空机械表
交互式产品展示

-

完全程序化建模:蓝宝石水晶、发条盒、齿轮系、擒纵、摆轮游丝、夹板、红宝石轴承与夜光显示。

-
- - - - -
-
- - - -
-
-
拖拽旋转 · 滚轮缩放 · 悬停 / 点击零件 · 按钮切换爆炸视图
-
Assembling jeweled movement...
- - - - - - \ No newline at end of file diff --git a/outputs/gpt-5-5/codex-cli-xhigh/mythos-craft.html b/outputs/gpt-5-5/codex-cli-xhigh/mythos-craft.html deleted file mode 100644 index 5118598..0000000 --- a/outputs/gpt-5-5/codex-cli-xhigh/mythos-craft.html +++ /dev/null @@ -1,1094 +0,0 @@ - - - - - - Mythic Blocks - - - - - -
-
- Mythic Vale - 0, 0, 0 -
-
-
-
-
- - - - diff --git a/outputs/gpt-5-5/codex-cli-xhigh/pelican-cycling.svg b/outputs/gpt-5-5/codex-cli-xhigh/pelican-cycling.svg deleted file mode 100644 index a5b6ba0..0000000 --- a/outputs/gpt-5-5/codex-cli-xhigh/pelican-cycling.svg +++ /dev/null @@ -1,240 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只逼真的褐鹈鹕在金色海岸边骑着复古自行车,海浪、湿沙和飞溅的水珠营造出鲜活的速度感。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-5/codex-cli-xhigh/skeleton-watch.html b/outputs/gpt-5-5/codex-cli-xhigh/skeleton-watch.html deleted file mode 100644 index c2c5259..0000000 --- a/outputs/gpt-5-5/codex-cli-xhigh/skeleton-watch.html +++ /dev/null @@ -1,1048 +0,0 @@ - - - - - - Skeleton Mechanical Watch - - - -
-
-

Calibre X-Ray

-

全镂空手动上链机芯,悬浮夹板、红宝石轴承、蓝钢螺丝与蓝宝石水晶在摄影棚光线中完整呈现。

-
-
- - - -
-
- - - -
-
拖拽旋转 · 滚轮缩放 · 点击锁定零件
- - - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft-block-era.html b/outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft-block-era.html deleted file mode 100644 index 88a62ef..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft-block-era.html +++ /dev/null @@ -1,1834 +0,0 @@ - - - - - - MYTHOS:方块纪元 - - - -
-
- -
-
-
Realm telemetry
-
永暮高地
-
X 0 · Y 0 · Z 0
-
- -
N · 曙光王城 · 0M
- -
-
Myth archive · 0/5
-
无名荒野
-
远古地脉仍在方块之间低语。循着天际的塔影,寻找被遗忘的神话遗迹。
-
- -
-
寻找方块
- -
-
草方块
-
-
- -
已发现新的神话遗迹
-
- -
-
-
-
A procedural voxel myth
-

MYTHOS方块纪元

-

- 一座由柏林噪声与失落神话共同生成的无尽世界。越过王城的黑曜石城门,攀上浮空圣殿, - 唤醒世界树的微光,并在龙骨荒原寻找通往月海的门。 -

-
- - -
-
- -
-
- 无法载入 3D 世界
- 请确认网络可访问 cdn.jsdelivr.net,然后刷新页面。 -
-
- - - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft.html b/outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft.html deleted file mode 100644 index b6a8f32..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/mythos-craft.html +++ /dev/null @@ -1,488 +0,0 @@ - - - - - - 神域方块 · MYTHOS CRAFT - - - -
正在唤醒远古世界
-
-
-
-
程序生成 · 无限神话世界
-

神域方块

MYTHOS CRAFT
-

诸神离去后,九种原初方块仍在梦中生长。穿过日冕圣门,寻找倒悬天岛、月神仪庭与星骸巨龙;你破坏或放置的每一块石头,都会留在这个种子世界里。

- -
WASD移动鼠标环视左键破坏右键放置SPACE跳跃1—9选方块
-
-
- - - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-coastal-ride.svg b/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-coastal-ride.svg deleted file mode 100644 index 76c193c..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-coastal-ride.svg +++ /dev/null @@ -1,320 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只羽毛细腻的鹈鹕迎着海风骑过金色海岸,浪花、飞鸟与自行车的转动让画面充满活力。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cycling.svg b/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cycling.svg deleted file mode 100644 index adf618a..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cycling.svg +++ /dev/null @@ -1,357 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只羽毛细腻的鹈鹕迎着海风骑行在金色海岸小路上,青绿色海浪、暖阳、海鸥和摇曳的沙丘草环绕四周。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cyclist.svg b/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cyclist.svg deleted file mode 100644 index a1f8230..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/pelican-cyclist.svg +++ /dev/null @@ -1,418 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只羽毛细腻的鹈鹕迎着海风骑过金色沙滩,远处有海浪、礁石、云层与落日。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch-calibre-01.html b/outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch-calibre-01.html deleted file mode 100644 index 5ef94f7..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch-calibre-01.html +++ /dev/null @@ -1,1608 +0,0 @@ - - - - - - - Calibre 01 — 镂空机械腕表 - - - - - - -
- -
-
- -
-
CALIBRE 01
-
Openworked Manufacture
-
-
-
机械运转中 · 28,800 vph
-
- -
01 · Anatomy of time
- - - -
-
-
Part 01
-
部件
-
-
- - -
拖动旋转 · 滚轮缩放 · 悬停识别 · 点击锁定
- -
- - -
- -
-
-
-
CALIBRE 01
-
正在组装 248 枚精密零件
-
-
-
- - - - diff --git a/outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch.html b/outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch.html deleted file mode 100644 index eecf5a9..0000000 --- a/outputs/gpt-5-6-sol/codex-cli-ultra/skeleton-watch.html +++ /dev/null @@ -1,1950 +0,0 @@ - - - - - - - AURELIUS S-01 — 交互式镂空机械表 - - - -
- - -
-
- -
-
AURELIUS
-
Haute Horlogerie · Genève
-
-
-
Calibre S–01 / No. 008
-
- - -
-
- - - -
-
Sculpted mechanics
-

The art of motion

-

让光穿过每一枚齿轮与夹板。S–01 以 248 枚零件,呈现时间最纯粹的机械形态。

-
- - - - - - - - - - - - -
-
-
-
Assembling calibre S–01
-
-
Preparing atelier0%
-
-
- -
-

无法启动 3D 展示

此体验需要支持 WebGL 的现代浏览器,并需联网载入 Three.js。请尝试使用最新版 Chrome、Safari 或 Firefox。

-
-
- - - - - - diff --git a/outputs/gpt-5-6-terra/codex-cli-ultra/mythos-craft.html b/outputs/gpt-5-6-terra/codex-cli-ultra/mythos-craft.html deleted file mode 100644 index 001bbb9..0000000 --- a/outputs/gpt-5-6-terra/codex-cli-ultra/mythos-craft.html +++ /dev/null @@ -1,1078 +0,0 @@ - - - - - - 阿斯特拉:方块神话 - - - -
-
-

阿斯特拉 方块神话

-

柏林噪声塑造的无尽荒野。古星祠、世界树与云穹浮城在同一片地平线上苏醒。

-
-
-
区域:星祠遗址
-
X 0 Y 0 Z 0
-
地形:准备中
-
-
-
-
旅者札记
向北穿过月门可见云穹浮城;西侧有一株被星火唤醒的世界树。方块可被自由采掘与重塑。
-
-
-
-
-
ONE WORLD · MANY LEGENDS
-

进入阿斯特拉

-

这是一片由程序化柏林噪声延展的方块世界。近处的石阶通往破碎星祠,远处的瀑布从漂浮的古城倾泻而下。

- -
- WASD 移动  - 鼠标 环视  - 空格 跳跃
- 左键 破坏 右键 放置 1 至 6 选择方块 Shift 冲刺 -
-
正在唤醒中心地形
-
-
- - - - - diff --git a/outputs/gpt-5-6-terra/codex-cli-ultra/pelican-cycling.svg b/outputs/gpt-5-6-terra/codex-cli-ultra/pelican-cycling.svg deleted file mode 100644 index d51112c..0000000 --- a/outputs/gpt-5-6-terra/codex-cli-ultra/pelican-cycling.svg +++ /dev/null @@ -1,290 +0,0 @@ - - 海边骑自行车的鹈鹕 - 一只羽毛细腻的褐鹈鹕沿着阳光海滩骑着复古自行车,身后是波光粼粼的大海。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/gpt-5-6-terra/codex-cli-ultra/skeleton-watch.html b/outputs/gpt-5-6-terra/codex-cli-ultra/skeleton-watch.html deleted file mode 100644 index 9ec38d1..0000000 --- a/outputs/gpt-5-6-terra/codex-cli-ultra/skeleton-watch.html +++ /dev/null @@ -1,1605 +0,0 @@ - - - - - - - 机械镂空腕表 - - - -
- - -
-
-
AURORA HOROLOGY
-
SKELETON CALIBRE 01
-
-
机械运转中
-
- - - -
- - - -
- -
拖拽旋转腕表,悬停探索精密机芯
-
部件
-
- -
-
-
- 精密机芯装配中 -
-
-
- - - - diff --git a/outputs/grok-4-3/cursor-default/mythos-craft.html b/outputs/grok-4-3/cursor-default/mythos-craft.html deleted file mode 100644 index 565c1c3..0000000 --- a/outputs/grok-4-3/cursor-default/mythos-craft.html +++ /dev/null @@ -1,540 +0,0 @@ - - - - -神话工艺 · MythosCraft - - - -
-
-
-
- 神话工艺 MythosCraft
- WASD 移动   空格 跳跃   鼠标 环视
- 左键 破坏   右键 放置   1-9 选择方块
- 点击画布 开始游戏 -
-
-
泥土 Dirt
-
草地 Grass
-
石头 Stone
-
橡木 Oak
-
叶片 Leaves
-
晶石 Crystal
-
魔能 Mana
-
-
-
- - - - \ No newline at end of file diff --git a/outputs/grok-4-3/cursor-default/pelican-cycling.svg b/outputs/grok-4-3/cursor-default/pelican-cycling.svg deleted file mode 100644 index f9035d3..0000000 --- a/outputs/grok-4-3/cursor-default/pelican-cycling.svg +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/grok-4-5/grok-build-tui-high/mythos-craft.html b/outputs/grok-4-5/grok-build-tui-high/mythos-craft.html deleted file mode 100644 index 28fd561..0000000 --- a/outputs/grok-4-5/grok-build-tui-high/mythos-craft.html +++ /dev/null @@ -1,760 +0,0 @@ - - - - - -Mythos Craft - - - -
-
-

MYTHOS CRAFT

-

A voxel world of mythic ruins, crystal towers and forgotten rings — generated as a single HTML file.

-
    -
  • WASD move · Space jump · mouse look
  • -
  • LMB break · RMB place · 1-8 / scroll hotbar
  • -
  • G teleport between mythic landmarks
  • -
  • Esc release pointer
  • -
- -
-
-
-
-
- -
-
Press G to visit mythic sites
-
- - - - - diff --git a/outputs/grok-4-5/grok-build-tui-high/pelican-cycling.svg b/outputs/grok-4-5/grok-build-tui-high/pelican-cycling.svg deleted file mode 100644 index ccb52cf..0000000 --- a/outputs/grok-4-5/grok-build-tui-high/pelican-cycling.svg +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/grok-4-5/grok-build-tui-high/skeleton-watch.html b/outputs/grok-4-5/grok-build-tui-high/skeleton-watch.html deleted file mode 100644 index 55508dc..0000000 --- a/outputs/grok-4-5/grok-build-tui-high/skeleton-watch.html +++ /dev/null @@ -1,679 +0,0 @@ - - - - - -Skeleton Watch - - - -
-
-

Skeleton Watch

-
Interactive 3D movement · drag to orbit
-
- - - -
-
- -
-
Hover a part for details. Click to pin a selection.
-
-
Drag · scroll zoom · click parts
-
-
- - - - diff --git a/outputs/grok-build/grok-build-tui-max/mythos-craft.html b/outputs/grok-build/grok-build-tui-max/mythos-craft.html deleted file mode 100644 index b2041b1..0000000 --- a/outputs/grok-build/grok-build-tui-max/mythos-craft.html +++ /dev/null @@ -1,1711 +0,0 @@ - - - - - - Aetheria • 我的世界:幻想纪元 - - - - -
-
-
-
-
Aetheria — 我的世界幻想纪元
-
WASD 移动 | 空格跳跃 | 鼠标环视 | 滚轮/数字键 切换方块
-
左键破坏 | 右键放置 | P 切换鼠标锁定 | R 重生
-
-
- 幻想之地标
- • 永恒尖塔(起始点附近)
- • 低语废墟 • 堕龙遗骸
- • 发光巨菇林 • 黑曜石神碑
- • 浮空圣所与水晶林
- 探索并建造你自己的传说! -
- - - - - diff --git a/outputs/grok-build/grok-build-tui-max/pelican-cycling.svg b/outputs/grok-build/grok-build-tui-max/pelican-cycling.svg deleted file mode 100644 index abdbbba..0000000 --- a/outputs/grok-build/grok-build-tui-max/pelican-cycling.svg +++ /dev/null @@ -1,568 +0,0 @@ - - Seaside Pelican on a Bicycle - A realistic and vivid pelican riding a bicycle along a sunny beach with turquoise waves, golden sand, and blue sky. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/inkling/tinker-web-xhigh/mythos-craft.html b/outputs/inkling/tinker-web-xhigh/mythos-craft.html deleted file mode 100644 index b394068..0000000 --- a/outputs/inkling/tinker-web-xhigh/mythos-craft.html +++ /dev/null @@ -1,767 +0,0 @@ - - - - - -神话幻想:无尽幻境 | Mythic Fantasy Voxel Realm - - - - - - - -
-

神话幻想 · 无尽幻境

-

Mythic Fantasy · Endless Illusion

-

- 欢迎进入由 柏林噪声 编织的远古神话世界。
- 穿越晶石尖塔、远古遗迹、悬浮花园与魔法阵。
- 点击下方按钮,进入幻境。 -

- -
- WASD 移动 · 鼠标环视 · 左键破坏 · 右键放置 · 1-6 切换方块 -
-
- -
-
- -
-

神话幻想:无尽幻境

-
Mythic Voxel Realm · Procedural Perlin Terrain
-
- -
-

● 幻境指南

-

WASD — 移动

-

鼠标 — 环视

-

左键 — 破坏方块

-

右键 — 放置方块

-

1~6 — 切换神话材质

-

- 远古晶石尖塔 矗立于中心,
- 悬浮花园 浮于天际,
- 远古遗迹 隐于迷雾。 -

-
- -
-
泥土 Dirt [1]
-
草地 Grass [2]
-
石头 Stone [3]
-
水晶 Crystal [4]
-
远古石 Ancient [5]
-
神秘草 Mystic [6]
-
-
- -
当前:泥土 Dirt
- - - - \ No newline at end of file diff --git a/outputs/inkling/tinker-web-xhigh/pelican-cycling.svg b/outputs/inkling/tinker-web-xhigh/pelican-cycling.svg deleted file mode 100644 index 7aeaddb..0000000 --- a/outputs/inkling/tinker-web-xhigh/pelican-cycling.svg +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/kimi-k2-6/kimi-code-thinking/mythos-craft.html b/outputs/kimi-k2-6/kimi-code-thinking/mythos-craft.html deleted file mode 100644 index 633372b..0000000 --- a/outputs/kimi-k2-6/kimi-code-thinking/mythos-craft.html +++ /dev/null @@ -1,1608 +0,0 @@ - - - - - - 神话世界 - MythicWorld - - - - -
-

神话世界

-
MythicWorld - 无限创造的幻想沙盒
-
-
正在初始化世界...
-
- -
-

神话世界

-

点击屏幕进入游戏,使用鼠标环视四周

-

WASD 移动 | 空格 跳跃 | Shift 潜行

-

鼠标左键 破坏方块 | 鼠标右键 放置方块

-

数字键 1-9 切换方块类型

- -
- -
-
-
-
位置: 0, 0, 0
-
朝向: 0
-
方块: 无
-
-
按 ESC 暂停 | 左键破坏 | 右键放置
-
- - - - diff --git a/outputs/kimi-k2-6/kimi-code-thinking/pelican-cycling.svg b/outputs/kimi-k2-6/kimi-code-thinking/pelican-cycling.svg deleted file mode 100644 index 1cb67e2..0000000 --- a/outputs/kimi-k2-6/kimi-code-thinking/pelican-cycling.svg +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/kimi-k2-7-code/kimi-code-thinking/mythos-craft.html b/outputs/kimi-k2-7-code/kimi-code-thinking/mythos-craft.html deleted file mode 100644 index 48d98fc..0000000 --- a/outputs/kimi-k2-7-code/kimi-code-thinking/mythos-craft.html +++ /dev/null @@ -1,1173 +0,0 @@ - - - - - -神话幻想世界 - Minecraft 克隆版 - - - -
-
-

神话幻想世界

-
WASD 移动 · 空格跳跃 · 鼠标环顾
-
左键破坏方块 · 右键放置方块
-
数字键 1-9 切换方块
-
点击屏幕锁定鼠标开始探索
-
区块: 0 | FPS: 0
-
-
+
-
-
正在编织神话大地…
点击屏幕开始探索
-
- - - - - diff --git a/outputs/kimi-k2-7-code/kimi-code-thinking/pelican-cycling.svg b/outputs/kimi-k2-7-code/kimi-code-thinking/pelican-cycling.svg deleted file mode 100644 index b554afd..0000000 --- a/outputs/kimi-k2-7-code/kimi-code-thinking/pelican-cycling.svg +++ /dev/null @@ -1,322 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/kimi-k2-7-code/kimi-code-thinking/skeleton-watch.html b/outputs/kimi-k2-7-code/kimi-code-thinking/skeleton-watch.html deleted file mode 100644 index eb071e4..0000000 --- a/outputs/kimi-k2-7-code/kimi-code-thinking/skeleton-watch.html +++ /dev/null @@ -1,1023 +0,0 @@ - - - - - - 镂空机械表 · 3D 交互展示 - - - -
ASSEMBLING MOVEMENT…
-
- -
-

Skeleton Tourbillon

-

镂空机械机芯 · 实时交互展示

-
- -
- 拖拽旋转 · 滚轮缩放 · 悬停查看零件 · 点击显示详情 -
- -
- - - - -
- -
- -
⚙️
-

零件名称

-
COMPONENT
-

点击零件查看详细说明。

-
- -
零件
-
- - - - - diff --git a/outputs/kimi-k3/kimi-code-max/mythos-craft.html b/outputs/kimi-k3/kimi-code-max/mythos-craft.html deleted file mode 100644 index 2463947..0000000 --- a/outputs/kimi-k3/kimi-code-max/mythos-craft.html +++ /dev/null @@ -1,1189 +0,0 @@ - - - - - -神话境界 MythosCraft - - - -
-
-
-
-
-
-
WASD 移动 · 空格 跳跃 · 左键 破坏 · 右键 放置
F 飞行 · Shift 疾跑/下降 · 1-0/滚轮 选方块 · R 回出生点
-
-

神话境界

-

MYTHOSCRAFT · 方块构筑的神话世界

-
-
WASD / 鼠标移动与环视(点击进入指针锁定)
-
左键 / 右键破坏方块 / 放置方块(按住可连续)
-
1-0 / 滚轮切换手中的方块
-
空格 / Shift跳跃 · 疾跑(飞行时上升/下降)
-
F / R切换飞行 · 返回出生点
-
探索目标天空神殿 · 浮空圣岛 · 符文石阵 · 世界之树 · 巨龙之塔 · 远古之门 · 荒野遗迹
-
-
正在生成世界……
-
- - - - diff --git a/outputs/kimi-k3/kimi-code-max/pelican-cycling.svg b/outputs/kimi-k3/kimi-code-max/pelican-cycling.svg deleted file mode 100644 index 6fc8b63..0000000 --- a/outputs/kimi-k3/kimi-code-max/pelican-cycling.svg +++ /dev/null @@ -1,624 +0,0 @@ - - Pelican riding a bicycle by the sea - A white pelican pedals a coral beach cruiser along a sunny shoreline, scarf streaming in the sea wind, one wing on the handlebar and the other raised for balance. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/kimi-k3/kimi-web-max/mythos-craft.html b/outputs/kimi-k3/kimi-web-max/mythos-craft.html deleted file mode 100644 index 28b999d..0000000 --- a/outputs/kimi-k3/kimi-web-max/mythos-craft.html +++ /dev/null @@ -1,854 +0,0 @@ - - - - - -神话大陆 · MythCraft — 我的世界幻想克隆 - - - - -
-
-
-
WASD 移动 · 空格 跳跃 · Shift 疾跑
F 飞行开关 · 左键 破坏 · 右键 放置
1-9 / 滚轮 切换方块 · Esc 释放鼠标
-
-

神话大陆

-

MYTHCRAFT · 幻想方块世界

-
-
W A S D移动 鼠标环视 空格跳跃
-
Shift疾跑 F飞行模式(空格升 / Shift 降)
-
左键破坏方块 右键放置方块
-
1 ~ 9 / 滚轮切换手持方块
-
探索世界中的远古遗迹、符文石阵、浮空岛、水晶尖塔、巫师塔、巨灵古树与黑曜石传送门……
-
-
点 击 进 入 世 界
-
-
正在生成神话大陆……
- - - - - diff --git a/outputs/mimo-v2-5-pro-mimocode/skeleton-watch.html b/outputs/mimo-v2-5-pro-mimocode/skeleton-watch.html deleted file mode 100644 index ba1a3ad..0000000 --- a/outputs/mimo-v2-5-pro-mimocode/skeleton-watch.html +++ /dev/null @@ -1,1090 +0,0 @@ - - - - - -3D Skeleton Watch - - - -
-

Skeleton

Haute Horlogerie · Interactive 3D

-
-

Movement Details

-
CaliberSK-2024A
-
TypeManual Wind
-
Frequency28,800 vph
-
Jewels21 Rubies
-
Power Reserve72 Hours
-
Diameter39mm
-
Thickness8.5mm
-
FinishHand Angled
-
Case18K Rose Gold
-
CrystalSapphire
- -
-
-
Movement Architecture
-Main Plate: German Silver
-Bridges: Hand-finished, Beveled
-Gear Train: 4 Wheels
-Escapement: Swiss Lever
-Balance: Glucydur
-Hairspring: Nivarox
-Oscillation: 4 Hz -
-
-
- - - - -
- - - - - diff --git a/outputs/mimo-v2-5-pro-ultraspeed/mythos-craft-2.html b/outputs/mimo-v2-5-pro-ultraspeed/mythos-craft-2.html deleted file mode 100644 index b0a52a0..0000000 --- a/outputs/mimo-v2-5-pro-ultraspeed/mythos-craft-2.html +++ /dev/null @@ -1,919 +0,0 @@ - - - - -Mythicraft — 神话世界 - - - -
-

MYTHICRAFT

-
一个充满神话幻想的体素世界
-
- W A S D 移动   空格 跳跃   Shift 下潜
- 鼠标移动 环视   左键 破坏方块   右键 放置方块
- 1-9 / 滚轮 选择方块   F 切换飞行 -
-
— 点击任意处开始探险 —
-
-
-
-
- - - - - \ No newline at end of file diff --git a/outputs/mimo-v2-5-pro-ultraspeed/mythos-craft.html b/outputs/mimo-v2-5-pro-ultraspeed/mythos-craft.html deleted file mode 100644 index e42ef10..0000000 --- a/outputs/mimo-v2-5-pro-ultraspeed/mythos-craft.html +++ /dev/null @@ -1,590 +0,0 @@ - - - - -Mythical Voxel Realm - - - -

Mythical Voxel Realm

Explore ancient magic and forgotten realms
Click to Enter
WASD — Move  |  Mouse — Look  |  Space — Jump  |  Shift — Sprint
Left Click — Break Block  |  Right Click — Place Block
1–9 / Scroll — Select Block  |  ESC — Release Cursor
-
- - - - \ No newline at end of file diff --git a/outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling-2.svg b/outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling-2.svg deleted file mode 100644 index 834692a..0000000 --- a/outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling-2.svg +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling.svg b/outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling.svg deleted file mode 100644 index de90f03..0000000 --- a/outputs/mimo-v2-5-pro-ultraspeed/pelican-cycling.svg +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/mimo-v2-5-pro-ultraspeed/skeleton-watch.html b/outputs/mimo-v2-5-pro-ultraspeed/skeleton-watch.html deleted file mode 100644 index 00b7a61..0000000 --- a/outputs/mimo-v2-5-pro-ultraspeed/skeleton-watch.html +++ /dev/null @@ -1,456 +0,0 @@ - - - - - -Calibre · Skeleton Haute Horlogerie - - - - - -
Calibrating
-
-

Calibre

Skeleton Collection — Ref. 7721

-
41mm · 18K Rose Gold
Hand-Wound · 72h Power Reserve
28,800 vph · 21 Jewels
-
-
- - - -
-

Component

-
- - - - - \ No newline at end of file diff --git a/outputs/mimo-v2-5-pro/claude-code-max/mythos-craft.html b/outputs/mimo-v2-5-pro/claude-code-max/mythos-craft.html deleted file mode 100644 index 8707175..0000000 --- a/outputs/mimo-v2-5-pro/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,1144 +0,0 @@ - - - - - - Mythos Craft - - - -
-
-

🏛️ Mythos Craft

-

A Minecraft-style voxel world with mythic structures

-

- WASD Move - Space Jump -

-

- Mouse Look - Left Click Break - Right Click Place -

-

- 1-9 Select Block - G Teleport to Landmark -

-

Click to start

-
-
- -
-
-
-
FPS: 0
-
Position: 0, 0, 0
-
Block: Grass
-
- -
- - - - - diff --git a/outputs/mimo-v2-5-pro/claude-code-max/pelican-cycling.svg b/outputs/mimo-v2-5-pro/claude-code-max/pelican-cycling.svg deleted file mode 100644 index 9963d4b..0000000 --- a/outputs/mimo-v2-5-pro/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,223 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Pelican by the Sea - - diff --git a/outputs/mimo-v2-5/micode-high/mythos-craft.html b/outputs/mimo-v2-5/micode-high/mythos-craft.html deleted file mode 100644 index fb0d966..0000000 --- a/outputs/mimo-v2-5/micode-high/mythos-craft.html +++ /dev/null @@ -1,628 +0,0 @@ - - - - - -Mythos Craft - 3D Voxel World - - - -
-
-

Mythos Craft

-

神话境界 - A Mythic Fantasy Voxel World

-
- WASD - 移动 Move
- 鼠标 - 环视 Look Around
- 空格 - 跳跃 Jump
- 左键 - 破坏方块 Break Block
- 右键 - 放置方块 Place Block
- 1-9 / 滚轮 - 选择方块 Select Block
- F - 飞行模式 Toggle Fly -
- -
-
-
-
-
-
- - - - - diff --git a/outputs/mimo-v2-5/micode-high/pelican-cycling.svg b/outputs/mimo-v2-5/micode-high/pelican-cycling.svg deleted file mode 100644 index fa0308f..0000000 --- a/outputs/mimo-v2-5/micode-high/pelican-cycling.svg +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/mimo-v2-5/micode-high/skeleton-watch.html b/outputs/mimo-v2-5/micode-high/skeleton-watch.html deleted file mode 100644 index f1897d0..0000000 --- a/outputs/mimo-v2-5/micode-high/skeleton-watch.html +++ /dev/null @@ -1,774 +0,0 @@ - - - - - -Skeleton Watch - 3D Mechanical Timepiece - - - -
-
-

SKELETON

-

3D MECHANICAL TIMEPIECE

-
- 拖拽 - 旋转手表 Rotate
- 滚轮 - 缩放 Zoom
- E - 爆炸视图 Exploded View
- I - 机芯信息 Movement Info
- 空格 - 暂停/恢复动画 Pause/Resume -
- -
-
-
-
-

MOVEMENT DATA

-
CaliberSK-01
-
Frequency28,800 vph
-
Jewels35 Rubies
-
Power Reserve72 Hours
-
Components287 Parts
-
Diameter30.4mm
-
Height5.35mm
-
FinishCôtes de Genève
-
BalanceFree-sprung
-
-
- - - -
-
-
00:00:00
- - - - - diff --git a/outputs/minimax-m2-7/minimax-code-web-thinking/pelican-cycling.svg b/outputs/minimax-m2-7/minimax-code-web-thinking/pelican-cycling.svg deleted file mode 100644 index 7ba7c66..0000000 --- a/outputs/minimax-m2-7/minimax-code-web-thinking/pelican-cycling.svg +++ /dev/null @@ -1,287 +0,0 @@ - - Pelican Riding Bicycle by the Sea - A lively pelican riding a bicycle on a beach by the sea, with waves and a sunset sky - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling-2.svg b/outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling-2.svg deleted file mode 100644 index 4883823..0000000 --- a/outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling-2.svg +++ /dev/null @@ -1,488 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling.svg b/outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling.svg deleted file mode 100644 index 924aae8..0000000 --- a/outputs/minimax-m3/minimax-code-web-thinking/pelican-cycling.svg +++ /dev/null @@ -1,460 +0,0 @@ - - - Pelican Biking by the Sea - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/mistral-medium-3-5/vibe-thinking/mythos-craft.html b/outputs/mistral-medium-3-5/vibe-thinking/mythos-craft.html deleted file mode 100644 index 7c8e552..0000000 --- a/outputs/mistral-medium-3-5/vibe-thinking/mythos-craft.html +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - - 神话幻想世界 - Minecraft 克隆版 - - - -
-
-
正在生成神话世界...
-
-
-
神话幻想世界 | WASD 移动 | 鼠标环视
-
左键破坏 | 右键放置 | 1/2/3 选择方块
-
当前方块: 草地 | 位置: (0, 0, 0)
-
-
FPS: 60
- - - - - - \ No newline at end of file diff --git a/outputs/mistral-medium-3-5/vibe-thinking/pelican-cycling.svg b/outputs/mistral-medium-3-5/vibe-thinking/pelican-cycling.svg deleted file mode 100644 index 8c75576..0000000 --- a/outputs/mistral-medium-3-5/vibe-thinking/pelican-cycling.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/outputs/nex-n2-pro/claude-code-max/mythos-craft.html b/outputs/nex-n2-pro/claude-code-max/mythos-craft.html deleted file mode 100644 index f4bc1f8..0000000 --- a/outputs/nex-n2-pro/claude-code-max/mythos-craft.html +++ /dev/null @@ -1,1072 +0,0 @@ - - - - - - 神话方块世界 - 单文件 Minecraft Clone - - - -
-
-

神话方块世界

-

一个单文件 HTML5 + Three.js 的《我的世界》风格原型。

-

点击页面开始,鼠标锁定后使用 WASD 移动、鼠标环视。

-

左键 破坏方块,右键 放置方块,1-6 切换方块,Space 跳跃。

-
-
- -
-
- 操作:WASD 移动 · 鼠标 环视 · Space 跳跃 · Shift 缓行 · R 回到出生点
- 建造:左键 破坏 · 右键 放置 · 1-6 切换方块
- 世界:Perlin 噪声无限地形、浮空岛、远古遗迹、精灵桥、水晶方尖碑、龙像、月门、巨树与瀑布群。 -
-
-
-
-
- - - - - - diff --git a/outputs/nex-n2-pro/claude-code-max/pelican-cycling.svg b/outputs/nex-n2-pro/claude-code-max/pelican-cycling.svg deleted file mode 100644 index 5086802..0000000 --- a/outputs/nex-n2-pro/claude-code-max/pelican-cycling.svg +++ /dev/null @@ -1,338 +0,0 @@ - - Pelican riding a bicycle by the sea - A vivid realistic vector scene of a pelican riding a bicycle along the seaside, with waves, sand, feathers, shadows, and warm coastal light. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/outputs/qwen3-7-max/qoder-default/mythos-craft.html b/outputs/qwen3-7-max/qoder-default/mythos-craft.html deleted file mode 100644 index 03e9540..0000000 --- a/outputs/qwen3-7-max/qoder-default/mythos-craft.html +++ /dev/null @@ -1,1372 +0,0 @@ - - - - -MyCraft - Minecraft Clone - - - -
-

⛏ MyCraft

-

- 点击屏幕 开始游戏
- W A S D 移动 | 空格 跳跃 | Shift 下降
- 鼠标 环视 | 左键 破坏方块 | 右键 放置方块
- 1-8 或 滚轮 选择方块 | F3 调试信息
- ESC 暂停 -

-
-
-
-
- - - - - diff --git a/outputs/qwen3-7-max/qoder-default/pelican-cycling.svg b/outputs/qwen3-7-max/qoder-default/pelican-cycling.svg deleted file mode 100644 index 9b3338b..0000000 --- a/outputs/qwen3-7-max/qoder-default/pelican-cycling.svg +++ /dev/null @@ -1,579 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SIDE PROFILE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Pelecanus onocrotalus - - - \ No newline at end of file diff --git a/outputs/step-3-7-flash/claude-code-high/mythos-craft.html b/outputs/step-3-7-flash/claude-code-high/mythos-craft.html deleted file mode 100644 index 343eeee..0000000 --- a/outputs/step-3-7-flash/claude-code-high/mythos-craft.html +++ /dev/null @@ -1,1978 +0,0 @@ - - - - -幻想方块世界 - Fantasy Voxel World - - - -
-

⚔️ 幻想方块世界 ⚔️

-
-
初始化中...
-
- -
-
-
-
-
- - - - - - diff --git a/outputs/step-3-7-flash/claude-code-high/pelican-cycling.svg b/outputs/step-3-7-flash/claude-code-high/pelican-cycling.svg deleted file mode 100644 index 480f28a..0000000 --- a/outputs/step-3-7-flash/claude-code-high/pelican-cycling.svg +++ /dev/null @@ -1,418 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/update-registry.ts b/scripts/update-registry.ts deleted file mode 100644 index fe5a57b..0000000 --- a/scripts/update-registry.ts +++ /dev/null @@ -1,139 +0,0 @@ -// Generates the README Registry tables from models/*.json. CI runs this in -// --check mode so the public README cannot drift from the source data. -import { readFileSync, readdirSync, writeFileSync } from 'node:fs' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' - -const root = join(dirname(fileURLToPath(import.meta.url)), '..') -const modelsDir = join(root, 'models') -const checkOnly = process.argv.includes('--check') - -const START = '' -const END = '' - -type RunJson = { file?: unknown } -type ModelJson = { - label?: unknown - vendor?: unknown - harness?: unknown - effort?: unknown - order?: unknown - runs?: Record -} - -type HarnessEntry = { - label: string - order: number -} - -type RegistryGroup = { - label: string - vendor: string - order: number - runs: number - harnesses: Map -} - -function requiredString(value: unknown, field: string, file: string): string { - if (typeof value !== 'string' || !value.trim()) throw new Error(`models/${file}: "${field}" is required`) - return value.trim() -} - -function runCount(runs: ModelJson['runs']): number { - return Object.values(runs ?? {}).reduce((sum, run) => sum + (Array.isArray(run) ? run.length : 1), 0) -} - -function harnessLabel(def: ModelJson): string { - const harness = typeof def.harness === 'string' ? def.harness.trim() : '' - const effort = typeof def.effort === 'string' ? def.effort.trim() : '' - if (!harness && !effort) return 'Default' - if (!harness) return effort - return effort ? `${harness} · ${effort}` : harness -} - -function escapeCell(value: string): string { - return value.replace(/\|/g, '\\|').replace(/\n/g, ' ') -} - -function registryGroups(): RegistryGroup[] { - const groups = new Map() - for (const file of readdirSync(modelsDir).filter((name) => name.endsWith('.json')).sort()) { - const def = JSON.parse(readFileSync(join(modelsDir, file), 'utf8')) as ModelJson - const label = requiredString(def.label, 'label', file) - const vendor = requiredString(def.vendor, 'vendor', file) - const order = typeof def.order === 'number' ? def.order : Number.MAX_SAFE_INTEGER - const key = `${label}\0${vendor}` - let group = groups.get(key) - if (!group) { - group = { label, vendor, order, runs: 0, harnesses: new Map() } - groups.set(key, group) - } - - group.order = Math.min(group.order, order) - group.runs += runCount(def.runs) - const harness = harnessLabel(def) - const existing = group.harnesses.get(harness) - if (!existing || order < existing.order) group.harnesses.set(harness, { label: harness, order }) - } - - return [...groups.values()].sort((a, b) => a.order - b.order || a.label.localeCompare(b.label)) -} - -function table(lang: 'zh' | 'en'): string { - const groups = registryGroups() - const tested = groups.filter((group) => group.runs > 0) - const pending = groups.filter((group) => group.runs === 0).map((group) => escapeCell(group.label)) - const note = - lang === 'zh' - ? '> 此表由 `bun scripts/update-registry.ts` 从 `models/*.json` 生成;合并到 `main` 后由 CI 自动同步,贡献者无需手改。' - : '> This table is generated from `models/*.json` by `bun scripts/update-registry.ts`; CI re-syncs it automatically after merge — contributors need not hand-edit it.' - const header = - lang === 'zh' - ? '| 模型 | 厂商 | 运行环境(Harness)× 思考配额 | 产出 |' - : '| Model | Vendor | Harness x Effort | Runs |' - - const rows = tested.map((group) => { - const harnesses = [...group.harnesses.values()] - .sort((a, b) => a.order - b.order || a.label.localeCompare(b.label)) - .map((entry) => escapeCell(entry.label)) - .join('
') - return `| ${escapeCell(group.label)} | ${escapeCell(group.vendor)} | ${harnesses} | ${String(group.runs).padStart(2, '0')} |` - }) - - const lines = [START, note, '', header, '|---|---|---|---|', ...rows] - if (pending.length) { - lines.push( - '', - lang === 'zh' - ? `待测:${pending.join(' · ')}(欢迎 PR 补充)` - : `Pending: ${pending.join(' · ')} (PRs welcome)`, - ) - } - lines.push(END) - return lines.join('\n') -} - -function replaceRegistry(path: string, generated: string): boolean { - const original = readFileSync(path, 'utf8') - const start = original.indexOf(START) - const end = original.indexOf(END) - if (start === -1 || end === -1 || end < start) { - throw new Error(`${path.replace(`${root}/`, '')}: missing ${START} / ${END} markers`) - } - const next = `${original.slice(0, start)}${generated}${original.slice(end + END.length)}` - if (next === original) return false - if (!checkOnly) writeFileSync(path, next) - return true -} - -const changed = [ - replaceRegistry(join(root, 'README.md'), table('zh')), - replaceRegistry(join(root, 'README.en.md'), table('en')), -].some(Boolean) - -if (checkOnly && changed) { - console.error('Registry tables are stale. Run: bun scripts/update-registry.ts') - process.exit(1) -} - -console.log(changed ? 'Registry tables updated' : 'Registry tables OK') diff --git a/scripts/validate-data.ts b/scripts/validate-data.ts deleted file mode 100644 index 474a9a0..0000000 --- a/scripts/validate-data.ts +++ /dev/null @@ -1,167 +0,0 @@ -// Validates the contribution data: models/.json registrations and -// their artifacts under outputs/. Runs in CI for every PR and push, so a -// malformed or undocumented contribution fails before it can ship. -import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' - -const root = join(dirname(fileURLToPath(import.meta.url)), '..') -const modelsDir = join(root, 'models') -const outputsDir = join(root, 'outputs') - -const cases = JSON.parse(readFileSync(join(root, 'cases.json'), 'utf8')) as Array<{ - id: string - kind: string -}> -const caseKind = new Map(cases.map((c) => [c.id, c.kind])) - -const ID_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/ -const ARTIFACT_DIR_RE = /^[a-z0-9]+(-[a-z0-9]+)*(\/[a-z0-9]+(-[a-z0-9]+)*)?$/ -const errors: string[] = [] - -const isBilingual = (v: unknown): boolean => { - if (!v || typeof v !== 'object') return false - const { zh, en } = v as { zh?: unknown; en?: unknown } - return typeof zh === 'string' && zh.trim() !== '' && typeof en === 'string' && en.trim() !== '' -} - -const modelIds = new Set() -const artifactDirs = new Map() -const declaredArtifacts = new Set() -// React cases declare a whole project directory (built to a single file at -// deploy time), not one artifact file — track those so the loose-file scan -// below skips their subtree. -const declaredDirs = new Set() -for (const f of readdirSync(modelsDir).filter((f) => f.endsWith('.json'))) { - const id = f.replace(/\.json$/, '') - modelIds.add(id) - if (!ID_RE.test(id)) { - errors.push(`models/${f}: id "${id}" must be lowercase letters/digits/dashes only (it is the stable voting key and default outputs folder)`) - } - - type RunJson = { note?: unknown; file?: unknown; contributor?: unknown } - let def: { - label?: unknown - vendor?: unknown - artifactDir?: unknown - order?: unknown - runs?: Record - } - try { - def = JSON.parse(readFileSync(join(modelsDir, f), 'utf8')) - } catch (e) { - errors.push(`models/${f}: invalid JSON (${e})`) - continue - } - - if (typeof def.label !== 'string' || !def.label.trim()) errors.push(`models/${f}: "label" is required`) - if (typeof def.vendor !== 'string' || !def.vendor.trim()) errors.push(`models/${f}: "vendor" is required`) - if (def.order !== undefined && typeof def.order !== 'number') errors.push(`models/${f}: "order" must be a number`) - if (def.artifactDir !== undefined && typeof def.artifactDir !== 'string') { - errors.push(`models/${f}: "artifactDir" must be a string`) - } - const artifactDir = typeof def.artifactDir === 'string' && def.artifactDir.trim() ? def.artifactDir.trim() : id - if (!ARTIFACT_DIR_RE.test(artifactDir)) { - errors.push(`models/${f}: artifactDir "${artifactDir}" must be one or two lowercase dash-case path segments, e.g. "claude-fable-5/claude-code-max"`) - } - const dirOwner = artifactDirs.get(artifactDir) - if (dirOwner) { - errors.push(`models/${f}: artifactDir "${artifactDir}" is already used by models/${dirOwner}.json`) - } else { - artifactDirs.set(artifactDir, id) - } - - for (const [caseId, runRaw] of Object.entries(def.runs ?? {})) { - if (!caseKind.has(caseId)) { - errors.push(`models/${f}: unknown case "${caseId}" (known: ${[...caseKind.keys()].join(', ')})`) - continue - } - const variants = Array.isArray(runRaw) ? runRaw : [runRaw] - if (!variants.length) errors.push(`models/${f}: runs.${caseId} is an empty array`) - const seenFiles = new Set() - variants.forEach((run, i) => { - const where = variants.length > 1 ? `runs.${caseId}[${i}]` : `runs.${caseId}` - if (!isBilingual(run?.note)) { - errors.push(`models/${f}: ${where} needs a bilingual "note" ({ "zh", "en" }) documenting provenance (tool, effort level, one-shot or fixed)`) - } - if (run?.file !== undefined && typeof run.file !== 'string') { - errors.push(`models/${f}: ${where}.file must be a string`) - } - if ( - typeof run?.file === 'string' && - (run.file.includes('/') || run.file.includes('\\') || run.file.includes('..')) - ) { - errors.push(`models/${f}: ${where}.file must be a filename, not a path`) - } - if (run?.contributor !== undefined && (typeof run.contributor !== 'string' || !run.contributor.trim())) { - errors.push(`models/${f}: ${where}.contributor must be a non-empty GitHub username`) - } - const agentName = (run as { agentName?: unknown })?.agentName - if (agentName !== undefined && (typeof agentName !== 'string' || !agentName.trim() || agentName.length > 20)) { - errors.push(`models/${f}: ${where}.agentName must be a short non-empty string (max 20 chars)`) - } - if (caseKind.get(caseId) === 'react') { - // React case: the artifact is a full project directory, not a file. - const dirName = (typeof run?.file === 'string' && run.file) || caseId - if (seenFiles.has(dirName)) { - errors.push(`models/${f}: ${where} resolves to the same project dir "${dirName}" as another variant`) - } - seenFiles.add(dirName) - const relDir = `${artifactDir}/${dirName}` - declaredDirs.add(relDir) - const dirPath = join(outputsDir, artifactDir, dirName) - if (!existsSync(dirPath) || !statSync(dirPath).isDirectory()) { - errors.push(`models/${f}: ${where} declares a React project but directory missing: outputs/${relDir}/`) - } else if (!existsSync(join(dirPath, 'package.json'))) { - errors.push(`models/${f}: ${where}: outputs/${relDir}/ must contain a package.json (a full project)`) - } - return - } - const kind = caseKind.get(caseId) - if (kind === 'agent') { - // Agent policies are deliberately NOT public (anti-scouting): the run - // entry registers the combo for the roster/board, but the artifact - // lives on the private referee side, so there is nothing to check - // under outputs/ here. - return - } - const file = (typeof run?.file === 'string' && run.file) || `${caseId}.${kind}` - if (seenFiles.has(file)) { - errors.push(`models/${f}: ${where} resolves to the same artifact "${file}" as another variant — extra variants must set a distinct "file"`) - } - seenFiles.add(file) - const artifact = `${artifactDir}/${file}` - declaredArtifacts.add(artifact) - const artifactPath = join(outputsDir, artifactDir, file) - if (!existsSync(artifactPath)) { - errors.push(`models/${f}: ${where} declared but artifact missing: outputs/${artifact}`) - } else if (statSync(artifactPath).size === 0) { - errors.push(`models/${f}: ${where} artifact is empty: outputs/${artifact}`) - } - }) - } -} - -// Every file under outputs/ must be declared by a run — loose artifacts would -// otherwise ship without provenance. -// `artifactDir` can be one or two path segments, so scan recursively and compare -// against the concrete paths declared above. -function walkOutputs(dir: string, prefix = '') { - for (const entry of readdirSync(dir, { withFileTypes: true })) { - if (entry.name.startsWith('.')) continue - const rel = prefix ? `${prefix}/${entry.name}` : entry.name - if (entry.isDirectory()) { - if (declaredDirs.has(rel)) continue // React project dir — declared wholesale - walkOutputs(join(dir, entry.name), rel) - } else if (!declaredArtifacts.has(rel)) { - errors.push(`outputs/${rel} is not declared by any run in models/*.json`) - } - } -} -if (existsSync(outputsDir)) walkOutputs(outputsDir) - -if (errors.length) { - console.error(`Data validation failed (${errors.length}):\n- ${errors.join('\n- ')}`) - process.exit(1) -} -console.log(`Data OK: ${modelIds.size} models, ${caseKind.size} cases validated`)