create-aura3d 3.0.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-skills.d.ts +38 -0
- package/dist/agent-skills.d.ts.map +1 -0
- package/dist/agent-skills.js +103 -0
- package/dist/agent-skills.js.map +1 -0
- package/dist/cli.js +32 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -10
- package/dist/index.js.map +1 -1
- package/dist/showcase-spec-artifacts.d.ts +1 -1
- package/dist/showcase-spec-game-geometry-extractor.js +8 -11
- package/dist/showcase-spec-game-geometry-extractor.js.map +1 -1
- package/dist/template-hdri.d.ts +12 -0
- package/dist/template-hdri.d.ts.map +1 -0
- package/dist/template-hdri.js +49 -0
- package/dist/template-hdri.js.map +1 -0
- package/hdri/ATTRIBUTION.md +8 -0
- package/hdri/autumn_field_puresky_1k.hdr +0 -0
- package/hdri/kloppenheim_06_puresky_1k.hdr +0 -0
- package/hdri/night-2k.hdr +0 -0
- package/hdri/studio_small_08_1k.hdr +0 -0
- package/package.json +14 -10
- package/skills/agent-files/AGENTS.md +3 -0
- package/skills/aura3d-animation-studio/SKILL.md +153 -0
- package/skills/aura3d-animation-studio/references/shot-looks.md +26 -0
- package/skills/aura3d-art-direction/SKILL.md +84 -0
- package/skills/aura3d-art-direction/references/failure-gallery.md +64 -0
- package/skills/aura3d-art-direction/references/framing-and-shots.md +45 -0
- package/skills/aura3d-art-direction/references/look-recipes.md +32 -0
- package/skills/aura3d-art-direction/references/quality-bar.md +103 -0
- package/skills/aura3d-art-direction/references/reference-frames.md +82 -0
- package/skills/aura3d-assets/SKILL.md +132 -0
- package/skills/aura3d-assets/references/preview-under-look.md +26 -0
- package/skills/aura3d-browser-game/SKILL.md +127 -0
- package/skills/aura3d-browser-game/references/genre-looks.md +52 -0
- package/skills/aura3d-character-animation/SKILL.md +129 -0
- package/skills/aura3d-character-animation/references/stage-and-lighting.md +31 -0
- package/skills/aura3d-core/SKILL.md +121 -0
- package/skills/aura3d-core/references/boundaries.md +91 -0
- package/skills/aura3d-evidence-review/SKILL.md +106 -0
- package/skills/aura3d-game-art/SKILL.md +118 -0
- package/skills/aura3d-game-art/references/sheet-check.mjs +58 -0
- package/skills/aura3d-game-art/references/sprite-palettes.md +25 -0
- package/skills/aura3d-materials-environments/SKILL.md +139 -0
- package/skills/aura3d-performance/SKILL.md +97 -0
- package/skills/aura3d-retexture/SKILL.md +115 -0
- package/skills/aura3d-retexture/references/geometry-hash.mjs +89 -0
- package/skills/aura3d-scene-authoring/SKILL.md +132 -0
- package/skills/aura3d-scene-authoring/references/look-by-family.md +28 -0
- package/skills/aura3d-threejs-migration/SKILL.md +125 -0
- package/skills/aura3d-threejs-migration/references/look-mapping.md +27 -0
- package/skills/llms.txt +117 -0
- package/skills/manifest.json +163 -0
- package/skills/meshy-cli/SKILL.md +133 -0
- package/templates/animation-channel/.claude/CLAUDE.md +3 -0
- package/templates/animation-channel/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/animation-channel/AGENTS.md +3 -0
- package/templates/animation-channel/package.json +3 -2
- package/templates/animation-channel/src/main.ts +5 -6
- package/templates/animation-channel/src/render-plan.ts +5 -3
- package/templates/animation-channel/tests/look-floor.ts +270 -0
- package/templates/animation-channel/tests/route-health.spec.ts +1 -1
- package/templates/animation-channel/tests/screenshot.spec.ts +10 -5
- package/templates/animation-channel/vite.config.ts +7 -0
- package/templates/animation-studio/.claude/CLAUDE.md +3 -0
- package/templates/animation-studio/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/animation-studio/AGENTS.md +2 -70
- package/templates/animation-studio/package.json +4 -3
- package/templates/animation-studio/scripts/build-clip-library.ts +6 -5
- package/templates/animation-studio/scripts/resolve-asset.ts +7 -4
- package/templates/animation-studio/src/scene-player.ts +6 -6
- package/templates/animation-studio/src/set-templates.ts +13 -9
- package/templates/animation-studio/tests/look-floor.ts +270 -0
- package/templates/animation-studio/tests/route-health.spec.ts +2 -2
- package/templates/animation-studio/tests/screenshot.spec.ts +18 -10
- package/templates/animation-studio/vite.config.ts +2 -0
- package/templates/architecture-interior/.claude/CLAUDE.md +3 -0
- package/templates/architecture-interior/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/architecture-interior/AGENTS.md +3 -0
- package/templates/architecture-interior/README.md +16 -0
- package/templates/architecture-interior/aura.assets.json +24 -0
- package/templates/architecture-interior/package.json +24 -0
- package/templates/architecture-interior/public/aura-assets/kenneyModularDungeonRoomSmall.a7e74a5f.glb +0 -0
- package/templates/architecture-interior/src/aura-assets.ts +16 -0
- package/templates/architecture-interior/src/main.ts +23 -0
- package/templates/architecture-interior/tests/look-floor.ts +270 -0
- package/templates/{three-compat-architecture-interior → architecture-interior}/tests/route-health.spec.ts +3 -3
- package/templates/architecture-interior/tests/screenshot.spec.ts +21 -0
- package/templates/architecture-interior/vite.config.ts +7 -0
- package/templates/arena-shooter/.claude/CLAUDE.md +3 -0
- package/templates/arena-shooter/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/arena-shooter/AGENTS.md +3 -0
- package/templates/arena-shooter/README.md +45 -0
- package/templates/arena-shooter/aura.assets.json +62 -0
- package/templates/arena-shooter/index.html +32 -0
- package/templates/arena-shooter/package.json +23 -0
- package/templates/arena-shooter/playwright.config.ts +15 -0
- package/templates/arena-shooter/public/aura-assets/craft_miner.de323205.glb +0 -0
- package/templates/arena-shooter/public/aura-assets/craft_racer.bce8cb3d.glb +0 -0
- package/templates/arena-shooter/public/aura-assets/meteor_detailed.f30379ab.glb +0 -0
- package/templates/arena-shooter/src/aura-assets.ts +56 -0
- package/templates/arena-shooter/src/main.ts +616 -0
- package/templates/arena-shooter/tests/look-floor.ts +270 -0
- package/templates/arena-shooter/tests/playable.spec.ts +56 -0
- package/templates/arena-shooter/tests/route-health.spec.ts +87 -0
- package/templates/arena-shooter/tests/screenshot.spec.ts +22 -0
- package/templates/arena-shooter/tsconfig.json +15 -0
- package/templates/arena-shooter/vite.config.ts +7 -0
- package/templates/asset-inspector/.claude/CLAUDE.md +3 -0
- package/templates/asset-inspector/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/asset-inspector/AGENTS.md +3 -0
- package/templates/asset-inspector/README.md +13 -0
- package/templates/asset-inspector/aura.assets.json +24 -0
- package/templates/{three-compat-custom-threejs-migration → asset-inspector}/package.json +5 -3
- package/templates/asset-inspector/public/aura-assets/kenneyCarKitSedanSports.2889c428.glb +0 -0
- package/templates/asset-inspector/src/aura-assets.ts +16 -0
- package/templates/asset-inspector/src/main.ts +23 -0
- package/templates/asset-inspector/tests/look-floor.ts +270 -0
- package/templates/{three-compat-character-viewer → asset-inspector}/tests/route-health.spec.ts +3 -3
- package/templates/asset-inspector/tests/screenshot.spec.ts +21 -0
- package/templates/asset-inspector/vite.config.ts +7 -0
- package/templates/character-controller/.claude/CLAUDE.md +3 -0
- package/templates/character-controller/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/character-controller/AGENTS.md +3 -0
- package/templates/character-controller/README.md +7 -1
- package/templates/character-controller/aura.assets.json +29 -22
- package/templates/character-controller/index.html +4 -5
- package/templates/character-controller/package.json +5 -4
- package/templates/character-controller/public/aura-assets/auraclash-player-rig.glb +0 -0
- package/templates/character-controller/src/aura-assets.ts +25 -7
- package/templates/character-controller/src/main.ts +190 -47
- package/templates/character-controller/tests/certified-rig.spec.ts +2 -2
- package/templates/character-controller/tests/look-floor.ts +270 -0
- package/templates/character-controller/tests/route-health.spec.ts +31 -6
- package/templates/character-controller/tests/screenshot.spec.ts +17 -5
- package/templates/character-controller/vite.config.ts +7 -0
- package/templates/character-viewer/.claude/CLAUDE.md +3 -0
- package/templates/character-viewer/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/character-viewer/AGENTS.md +3 -0
- package/templates/character-viewer/README.md +13 -0
- package/templates/character-viewer/aura.assets.json +24 -0
- package/templates/{three-compat-asset-inspector → character-viewer}/package.json +5 -3
- package/templates/character-viewer/public/aura-assets/kenneyMiniForestCharacterArcher.0fd0f92e.glb +0 -0
- package/templates/character-viewer/src/aura-assets.ts +16 -0
- package/templates/character-viewer/src/main.ts +21 -0
- package/templates/character-viewer/tests/look-floor.ts +270 -0
- package/templates/{three-compat-custom-threejs-migration → character-viewer}/tests/route-health.spec.ts +3 -3
- package/templates/character-viewer/tests/screenshot.spec.ts +21 -0
- package/templates/character-viewer/vite.config.ts +7 -0
- package/templates/cinematic-scene/.claude/CLAUDE.md +3 -0
- package/templates/cinematic-scene/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/cinematic-scene/AGENTS.md +3 -0
- package/templates/cinematic-scene/README.md +11 -2
- package/templates/cinematic-scene/package.json +3 -2
- package/templates/cinematic-scene/src/main.ts +30 -7
- package/templates/cinematic-scene/tests/look-floor.ts +270 -0
- package/templates/cinematic-scene/tests/route-health.spec.ts +31 -3
- package/templates/cinematic-scene/tests/screenshot.spec.ts +34 -45
- package/templates/cinematic-scene/vite.config.ts +7 -0
- package/templates/custom-scene/.claude/CLAUDE.md +3 -0
- package/templates/custom-scene/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/custom-scene/AGENTS.md +3 -0
- package/templates/custom-scene/README.md +13 -0
- package/templates/custom-scene/aura.assets.json +24 -0
- package/templates/{three-compat-character-viewer → custom-scene}/package.json +5 -3
- package/templates/custom-scene/public/aura-assets/kenneyPirateKitShipMedium.279ea019.glb +0 -0
- package/templates/custom-scene/src/aura-assets.ts +16 -0
- package/templates/custom-scene/src/main.ts +23 -0
- package/templates/custom-scene/tests/look-floor.ts +270 -0
- package/templates/{three-compat-asset-inspector → custom-scene}/tests/route-health.spec.ts +3 -3
- package/templates/custom-scene/tests/screenshot.spec.ts +21 -0
- package/templates/custom-scene/vite.config.ts +7 -0
- package/templates/episode-builder/.claude/CLAUDE.md +3 -0
- package/templates/episode-builder/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/episode-builder/AGENTS.md +3 -0
- package/templates/episode-builder/package.json +3 -2
- package/templates/episode-builder/src/main.ts +5 -3
- package/templates/episode-builder/src/render-plan.ts +5 -3
- package/templates/episode-builder/tests/look-floor.ts +270 -0
- package/templates/episode-builder/tests/screenshot.spec.ts +10 -4
- package/templates/episode-builder/vite.config.ts +7 -0
- package/templates/falling-blocks-starter/.claude/CLAUDE.md +3 -0
- package/templates/falling-blocks-starter/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/falling-blocks-starter/AGENTS.md +3 -0
- package/templates/falling-blocks-starter/README.md +10 -1
- package/templates/falling-blocks-starter/aura.assets.json +40 -23
- package/templates/falling-blocks-starter/package.json +3 -2
- package/templates/falling-blocks-starter/public/aura-assets/quaternius-cube-crate.glb +0 -0
- package/templates/falling-blocks-starter/public/aura-assets/quaternius-wall-modular.glb +0 -0
- package/templates/falling-blocks-starter/src/aura-assets.ts +33 -10
- package/templates/falling-blocks-starter/src/main.ts +316 -117
- package/templates/falling-blocks-starter/tests/look-floor.ts +270 -0
- package/templates/falling-blocks-starter/tests/playable.spec.ts +51 -18
- package/templates/falling-blocks-starter/tests/route-health.spec.ts +17 -7
- package/templates/falling-blocks-starter/tests/screenshot.spec.ts +21 -0
- package/templates/falling-blocks-starter/vite.config.ts +7 -0
- package/templates/fighting-game/.claude/CLAUDE.md +3 -0
- package/templates/fighting-game/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/fighting-game/AGENTS.md +3 -0
- package/templates/fighting-game/README.md +2 -0
- package/templates/fighting-game/aura.assets.json +56 -46
- package/templates/fighting-game/package.json +4 -2
- package/templates/fighting-game/public/aura-assets/auraclash-player-rig.glb +0 -0
- package/templates/fighting-game/public/aura-assets/auraclash-rival-rig.glb +0 -0
- package/templates/fighting-game/src/aura-assets.ts +54 -20
- package/templates/fighting-game/src/game/fighters.ts +57 -12
- package/templates/fighting-game/src/main.ts +135 -53
- package/templates/fighting-game/tests/certified-rig.spec.ts +1 -1
- package/templates/fighting-game/tests/gameplay-smoke.spec.ts +2 -8
- package/templates/fighting-game/tests/look-floor.ts +270 -0
- package/templates/fighting-game/tests/route-health.spec.ts +12 -4
- package/templates/fighting-game/tests/screenshot.spec.ts +10 -4
- package/templates/fighting-game/vite.config.ts +7 -0
- package/templates/large-scene/.claude/CLAUDE.md +3 -0
- package/templates/large-scene/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/large-scene/AGENTS.md +3 -0
- package/templates/large-scene/README.md +13 -0
- package/templates/large-scene/aura.assets.json +40 -0
- package/templates/{three-compat-architecture-interior → large-scene}/package.json +5 -3
- package/templates/large-scene/public/aura-assets/kenneyMiniForestRocksHigh.226728a0.glb +0 -0
- package/templates/large-scene/public/aura-assets/kenneyMiniForestTree.0075d505.glb +0 -0
- package/templates/large-scene/src/aura-assets.ts +28 -0
- package/templates/large-scene/src/main.ts +43 -0
- package/templates/large-scene/tests/look-floor.ts +270 -0
- package/templates/large-scene/tests/route-health.spec.ts +16 -0
- package/templates/large-scene/tests/screenshot.spec.ts +21 -0
- package/templates/large-scene/vite.config.ts +7 -0
- package/templates/material-authoring/.claude/CLAUDE.md +3 -0
- package/templates/material-authoring/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/material-authoring/AGENTS.md +3 -0
- package/templates/material-authoring/README.md +15 -0
- package/templates/material-authoring/aura.assets.json +24 -0
- package/templates/material-authoring/package.json +24 -0
- package/templates/material-authoring/public/aura-assets/kenneyCarKitSedanSports.2889c428.glb +0 -0
- package/templates/material-authoring/src/aura-assets.ts +16 -0
- package/templates/material-authoring/src/main.ts +78 -0
- package/templates/material-authoring/tests/look-floor.ts +270 -0
- package/templates/material-authoring/tests/route-health.spec.ts +16 -0
- package/templates/material-authoring/tests/screenshot.spec.ts +21 -0
- package/templates/material-authoring/vite.config.ts +7 -0
- package/templates/mini-game/.claude/CLAUDE.md +3 -0
- package/templates/mini-game/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/mini-game/AGENTS.md +3 -0
- package/templates/mini-game/README.md +9 -6
- package/templates/mini-game/aura.assets.json +177 -36
- package/templates/mini-game/package.json +3 -1
- package/templates/mini-game/public/aura-assets/kaykit-barbarian.glb +0 -0
- package/templates/mini-game/public/aura-assets/kenneyPlatformerKitKey.2e930961.glb +0 -0
- package/templates/mini-game/public/aura-assets/kenneyPlatformerKitStar.a102a1b9.glb +0 -0
- package/templates/mini-game/public/aura-assets/quaternius-crate.glb +0 -0
- package/templates/mini-game/public/aura-assets/quaternius-cube-crate.glb +0 -0
- package/templates/mini-game/src/aura-assets.ts +140 -32
- package/templates/mini-game/src/main.ts +204 -71
- package/templates/mini-game/tests/certified-rig.spec.ts +2 -2
- package/templates/mini-game/tests/look-floor.ts +270 -0
- package/templates/mini-game/tests/playable.spec.ts +23 -2
- package/templates/mini-game/tests/route-health.spec.ts +2 -2
- package/templates/mini-game/tests/screenshot.spec.ts +44 -53
- package/templates/mini-game/vite.config.ts +7 -0
- package/templates/postprocess-scene/.claude/CLAUDE.md +3 -0
- package/templates/postprocess-scene/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/postprocess-scene/AGENTS.md +3 -0
- package/templates/postprocess-scene/README.md +17 -0
- package/templates/postprocess-scene/aura.assets.json +38 -0
- package/templates/postprocess-scene/package.json +24 -0
- package/templates/postprocess-scene/public/aura-assets/showcaseLuma.ef389217.glb +0 -0
- package/templates/postprocess-scene/public/aura-assets/showcaseMiko.fcdc2b75.glb +0 -0
- package/templates/postprocess-scene/src/aura-assets.ts +28 -0
- package/templates/postprocess-scene/src/main.ts +29 -0
- package/templates/postprocess-scene/tests/look-floor.ts +270 -0
- package/templates/postprocess-scene/tests/route-health.spec.ts +16 -0
- package/templates/postprocess-scene/tests/screenshot.spec.ts +21 -0
- package/templates/postprocess-scene/vite.config.ts +7 -0
- package/templates/premium-product-viewer/.claude/CLAUDE.md +3 -0
- package/templates/premium-product-viewer/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/premium-product-viewer/AGENTS.md +3 -0
- package/templates/premium-product-viewer/README.md +18 -0
- package/templates/premium-product-viewer/aura.assets.json +24 -0
- package/templates/premium-product-viewer/package.json +24 -0
- package/templates/premium-product-viewer/public/aura-assets/khronosToyCar.01a60862.glb +0 -0
- package/templates/premium-product-viewer/src/aura-assets.ts +16 -0
- package/templates/premium-product-viewer/src/main.ts +33 -0
- package/templates/premium-product-viewer/tests/look-floor.ts +270 -0
- package/templates/premium-product-viewer/tests/route-health.spec.ts +16 -0
- package/templates/premium-product-viewer/tests/screenshot.spec.ts +21 -0
- package/templates/premium-product-viewer/vite.config.ts +7 -0
- package/templates/product-viewer/.claude/CLAUDE.md +3 -0
- package/templates/product-viewer/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/product-viewer/AGENTS.md +3 -0
- package/templates/product-viewer/README.md +10 -8
- package/templates/product-viewer/package.json +3 -1
- package/templates/product-viewer/src/aura-assets.ts +1 -1
- package/templates/product-viewer/src/main.ts +78 -19
- package/templates/product-viewer/tests/look-floor.ts +270 -0
- package/templates/product-viewer/tests/route-health.spec.ts +19 -1
- package/templates/product-viewer/tests/screenshot.spec.ts +35 -41
- package/templates/product-viewer/vite.config.ts +7 -0
- package/templates/prompt-animation-channel/.claude/CLAUDE.md +3 -0
- package/templates/prompt-animation-channel/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/prompt-animation-channel/AGENTS.md +3 -0
- package/templates/prompt-animation-channel/package.json +3 -2
- package/templates/prompt-animation-channel/src/main.ts +5 -3
- package/templates/prompt-animation-channel/src/render-plan.ts +5 -3
- package/templates/prompt-animation-channel/tests/look-floor.ts +270 -0
- package/templates/prompt-animation-channel/tests/route-health.spec.ts +1 -1
- package/templates/prompt-animation-channel/tests/screenshot.spec.ts +10 -4
- package/templates/prompt-animation-channel/tests/storyboard-playback.spec.ts +1 -1
- package/templates/prompt-animation-channel/vite.config.ts +7 -0
- package/templates/racing-starter/.claude/CLAUDE.md +3 -0
- package/templates/racing-starter/.github/workflows/aura3d-lookdev.yml +67 -0
- package/templates/racing-starter/AGENTS.md +3 -0
- package/templates/racing-starter/README.md +8 -6
- package/templates/racing-starter/package.json +3 -2
- package/templates/racing-starter/src/main.ts +168 -146
- package/templates/racing-starter/tests/geometry-certification.json +34 -0
- package/templates/racing-starter/tests/look-floor.ts +270 -0
- package/templates/racing-starter/tests/playable.spec.ts +63 -80
- package/templates/racing-starter/tests/route-health.spec.ts +14 -12
- package/templates/racing-starter/tests/screenshot.spec.ts +21 -0
- package/templates/racing-starter/vite.config.ts +7 -0
- package/templates/character-controller/public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb +0 -0
- package/templates/character-controller/public/aura-assets/showcaseWalkAnimatedGirl.thumb.svg +0 -1
- package/templates/falling-blocks-starter/public/aura-assets/showcaseBlockfallCabinet.679d52fe.glb +0 -0
- package/templates/falling-blocks-starter/public/aura-assets/showcaseBlockfallCabinet.thumb.svg +0 -1
- package/templates/fighting-game/public/aura-assets/showcaseRunnerRobot.252b3a16.glb +0 -0
- package/templates/fighting-game/public/aura-assets/showcaseRunnerRobot.thumb.svg +0 -1
- package/templates/fighting-game/public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb +0 -0
- package/templates/fighting-game/public/aura-assets/showcaseWalkAnimatedGirl.thumb.svg +0 -1
- package/templates/mini-game/public/aura-assets/showcaseKenneyOobiPlatformerHero.3f821141.glb +0 -0
- package/templates/mini-game/public/aura-assets/showcaseKenneyOobiPlatformerHero.thumb.svg +0 -1
- package/templates/three-compat-architecture-interior/aura.assets.json +0 -7
- package/templates/three-compat-architecture-interior/src/aura-assets.ts +0 -3
- package/templates/three-compat-architecture-interior/src/main.ts +0 -27
- package/templates/three-compat-architecture-interior/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-asset-inspector/aura.assets.json +0 -7
- package/templates/three-compat-asset-inspector/src/aura-assets.ts +0 -3
- package/templates/three-compat-asset-inspector/src/main.ts +0 -17
- package/templates/three-compat-asset-inspector/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-character-viewer/aura.assets.json +0 -7
- package/templates/three-compat-character-viewer/src/aura-assets.ts +0 -3
- package/templates/three-compat-character-viewer/src/main.ts +0 -17
- package/templates/three-compat-character-viewer/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-custom-threejs-migration/aura.assets.json +0 -7
- package/templates/three-compat-custom-threejs-migration/src/aura-assets.ts +0 -3
- package/templates/three-compat-custom-threejs-migration/src/main.ts +0 -16
- package/templates/three-compat-custom-threejs-migration/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-large-scene/aura.assets.json +0 -7
- package/templates/three-compat-large-scene/package.json +0 -22
- package/templates/three-compat-large-scene/src/aura-assets.ts +0 -3
- package/templates/three-compat-large-scene/src/main.ts +0 -31
- package/templates/three-compat-large-scene/tests/route-health.spec.ts +0 -16
- package/templates/three-compat-large-scene/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-material-authoring/aura.assets.json +0 -7
- package/templates/three-compat-material-authoring/package.json +0 -22
- package/templates/three-compat-material-authoring/src/aura-assets.ts +0 -3
- package/templates/three-compat-material-authoring/src/main.ts +0 -33
- package/templates/three-compat-material-authoring/tests/route-health.spec.ts +0 -16
- package/templates/three-compat-material-authoring/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-postprocess-scene/aura.assets.json +0 -7
- package/templates/three-compat-postprocess-scene/package.json +0 -22
- package/templates/three-compat-postprocess-scene/src/aura-assets.ts +0 -3
- package/templates/three-compat-postprocess-scene/src/main.ts +0 -17
- package/templates/three-compat-postprocess-scene/tests/route-health.spec.ts +0 -16
- package/templates/three-compat-postprocess-scene/tests/screenshot.spec.ts +0 -15
- package/templates/three-compat-premium-product-viewer/aura.assets.json +0 -7
- package/templates/three-compat-premium-product-viewer/package.json +0 -22
- package/templates/three-compat-premium-product-viewer/src/aura-assets.ts +0 -3
- package/templates/three-compat-premium-product-viewer/src/main.ts +0 -18
- package/templates/three-compat-premium-product-viewer/tests/route-health.spec.ts +0 -16
- package/templates/three-compat-premium-product-viewer/tests/screenshot.spec.ts +0 -15
- /package/templates/{three-compat-architecture-interior → architecture-interior}/index.html +0 -0
- /package/templates/{three-compat-architecture-interior → architecture-interior}/playwright.config.ts +0 -0
- /package/templates/{three-compat-architecture-interior → architecture-interior}/tsconfig.json +0 -0
- /package/templates/{three-compat-asset-inspector → asset-inspector}/index.html +0 -0
- /package/templates/{three-compat-asset-inspector → asset-inspector}/playwright.config.ts +0 -0
- /package/templates/{three-compat-asset-inspector → asset-inspector}/tsconfig.json +0 -0
- /package/templates/{three-compat-character-viewer → character-viewer}/index.html +0 -0
- /package/templates/{three-compat-character-viewer → character-viewer}/playwright.config.ts +0 -0
- /package/templates/{three-compat-character-viewer → character-viewer}/tsconfig.json +0 -0
- /package/templates/{three-compat-custom-threejs-migration → custom-scene}/index.html +0 -0
- /package/templates/{three-compat-custom-threejs-migration → custom-scene}/playwright.config.ts +0 -0
- /package/templates/{three-compat-custom-threejs-migration → custom-scene}/tsconfig.json +0 -0
- /package/templates/{three-compat-large-scene → large-scene}/index.html +0 -0
- /package/templates/{three-compat-large-scene → large-scene}/playwright.config.ts +0 -0
- /package/templates/{three-compat-large-scene → large-scene}/tsconfig.json +0 -0
- /package/templates/{three-compat-material-authoring → material-authoring}/index.html +0 -0
- /package/templates/{three-compat-material-authoring → material-authoring}/playwright.config.ts +0 -0
- /package/templates/{three-compat-material-authoring → material-authoring}/tsconfig.json +0 -0
- /package/templates/{three-compat-postprocess-scene → postprocess-scene}/index.html +0 -0
- /package/templates/{three-compat-postprocess-scene → postprocess-scene}/playwright.config.ts +0 -0
- /package/templates/{three-compat-postprocess-scene → postprocess-scene}/tsconfig.json +0 -0
- /package/templates/{three-compat-premium-product-viewer → premium-product-viewer}/index.html +0 -0
- /package/templates/{three-compat-premium-product-viewer → premium-product-viewer}/playwright.config.ts +0 -0
- /package/templates/{three-compat-premium-product-viewer → premium-product-viewer}/tsconfig.json +0 -0
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
camera,
|
|
3
|
-
createAuraApp,
|
|
4
3
|
game,
|
|
5
|
-
|
|
4
|
+
gameFeel,
|
|
5
|
+
instances,
|
|
6
|
+
looks,
|
|
6
7
|
material,
|
|
7
8
|
model,
|
|
8
|
-
primitives,
|
|
9
9
|
scene,
|
|
10
|
-
type
|
|
10
|
+
type AuraColor,
|
|
11
|
+
type AuraNodeInput,
|
|
12
|
+
type AuraRuntimeNodeHandle,
|
|
13
|
+
type AuraTransformSpec
|
|
11
14
|
} from "@aura3d/engine";
|
|
15
|
+
// PRD-09: mounted via the shared runtime — createGame owns mount/lifecycle,
|
|
16
|
+
// the §7.7 arcade-neon HUD theme, the §6.11 dpad-2btn touch preset,
|
|
17
|
+
// game-sfx-core cues, and the juice event map (no route-local hit-stop).
|
|
18
|
+
import { createGame, sfxUrl } from "@aura3d/engine/game";
|
|
12
19
|
import { assets } from "./aura-assets";
|
|
13
20
|
|
|
14
21
|
declare global {
|
|
@@ -19,6 +26,8 @@ declare global {
|
|
|
19
26
|
|
|
20
27
|
type Piece = "I" | "J" | "L" | "O" | "S" | "T" | "Z";
|
|
21
28
|
type Cell = Piece | null;
|
|
29
|
+
type Board = readonly (readonly Cell[])[];
|
|
30
|
+
type KitState = ReturnType<typeof falling.snapshot>;
|
|
22
31
|
|
|
23
32
|
interface FallingBlocksStarterEvidence {
|
|
24
33
|
readonly frame: number;
|
|
@@ -29,28 +38,53 @@ interface FallingBlocksStarterEvidence {
|
|
|
29
38
|
readonly hold: Piece | null;
|
|
30
39
|
readonly gameOver: boolean;
|
|
31
40
|
readonly events: readonly string[];
|
|
32
|
-
readonly
|
|
33
|
-
|
|
34
|
-
readonly
|
|
35
|
-
readonly
|
|
41
|
+
readonly look: { readonly id: string; readonly category: string };
|
|
42
|
+
readonly board: {
|
|
43
|
+
readonly width: number;
|
|
44
|
+
readonly height: number;
|
|
45
|
+
readonly visibleRows: number;
|
|
46
|
+
readonly filledCells: number;
|
|
47
|
+
readonly rendering: "instanced-model";
|
|
48
|
+
readonly cellAsset: { readonly id: string; readonly url: string; readonly metres: readonly [number, number, number] };
|
|
49
|
+
readonly drawCalls: number;
|
|
36
50
|
};
|
|
51
|
+
readonly flash: { readonly modelBased: boolean; readonly activeRows: readonly number[] };
|
|
37
52
|
readonly evidence: unknown;
|
|
38
53
|
}
|
|
39
54
|
|
|
55
|
+
const LOOK_ID = "neon-arcade" as const;
|
|
40
56
|
const boardWidth = 10;
|
|
41
57
|
const boardHeight = 22;
|
|
42
58
|
const hiddenRows = 2;
|
|
59
|
+
const visibleRows = boardHeight - hiddenRows;
|
|
43
60
|
const cellSize = 0.24;
|
|
44
61
|
const boardOrigin = { x: -1.2, y: -2.18 };
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
const boardTop = boardOrigin.y + visibleRows * cellSize;
|
|
63
|
+
const boardCenterY = (boardOrigin.y + boardTop) / 2;
|
|
64
|
+
|
|
65
|
+
// quaternius-cube-crate is a 2.021 m cube vs the retired 1.082 m block; the
|
|
66
|
+
// scale literals below were authored against the old cube, so RENORM keeps
|
|
67
|
+
// every rendered size identical. CELL_SCALE brings the crate to one
|
|
68
|
+
// 0.24 m board cell; the slight fill reduction keeps a visible bevel gap.
|
|
69
|
+
const RENORM = 1.082 / assets.quaterniusCubeCrate.bounds[1];
|
|
70
|
+
const bs = (n: number) => n * RENORM;
|
|
71
|
+
const CELL_SCALE = (cellSize / 2) * RENORM;
|
|
72
|
+
const CELL_FILL_SCALE = 0.112 * RENORM;
|
|
73
|
+
const FLASH_MS = 280;
|
|
74
|
+
|
|
75
|
+
// Per-piece colours stay inside the neon-arcade palette family: the cyan
|
|
76
|
+
// accent plus its complementary saturated neon hues over the dark base.
|
|
77
|
+
const pieceColors: Record<Piece, AuraColor> = {
|
|
78
|
+
I: "#4de8ff",
|
|
79
|
+
J: "#7d9dd4",
|
|
80
|
+
L: "#f4a259",
|
|
81
|
+
O: "#ffd166",
|
|
82
|
+
S: "#4ce8b0",
|
|
51
83
|
T: "#b987d0",
|
|
52
|
-
Z: "#
|
|
84
|
+
Z: "#ff5d7d"
|
|
53
85
|
};
|
|
86
|
+
const FRAME_COLOR: AuraColor = "#232c4d";
|
|
87
|
+
const FRAME_ACCENT: AuraColor = "#4de8ff";
|
|
54
88
|
const activeShapes: Record<Piece, readonly (readonly { readonly x: number; readonly y: number }[])[]> = {
|
|
55
89
|
I: [
|
|
56
90
|
[{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 3, y: 1 }],
|
|
@@ -67,7 +101,7 @@ const activeShapes: Record<Piece, readonly (readonly { readonly x: number; reado
|
|
|
67
101
|
L: [
|
|
68
102
|
[{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }],
|
|
69
103
|
[{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }, { x: 2, y: 2 }],
|
|
70
|
-
[{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x:
|
|
104
|
+
[{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 1, y: 2 }],
|
|
71
105
|
[{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }]
|
|
72
106
|
],
|
|
73
107
|
O: [
|
|
@@ -89,14 +123,14 @@ const activeShapes: Record<Piece, readonly (readonly { readonly x: number; reado
|
|
|
89
123
|
[{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }]
|
|
90
124
|
],
|
|
91
125
|
Z: [
|
|
92
|
-
[{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x:
|
|
126
|
+
[{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }],
|
|
93
127
|
[{ x: 2, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 1, y: 2 }],
|
|
94
128
|
[{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }, { x: 2, y: 2 }],
|
|
95
129
|
[{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }]
|
|
96
130
|
]
|
|
97
131
|
};
|
|
98
132
|
|
|
99
|
-
const
|
|
133
|
+
const inputOptions = {
|
|
100
134
|
actions: {
|
|
101
135
|
left: ["KeyA", "ArrowLeft"],
|
|
102
136
|
right: ["KeyD", "ArrowRight"],
|
|
@@ -108,7 +142,7 @@ const input = game.input({
|
|
|
108
142
|
reset: ["KeyR"]
|
|
109
143
|
},
|
|
110
144
|
bufferMs: 100
|
|
111
|
-
}
|
|
145
|
+
} as const;
|
|
112
146
|
|
|
113
147
|
const falling = game.fallingBlocks({
|
|
114
148
|
width: boardWidth,
|
|
@@ -119,35 +153,85 @@ const falling = game.fallingBlocks({
|
|
|
119
153
|
lockDelayFrames: 18
|
|
120
154
|
});
|
|
121
155
|
const routeEvents = game.eventLog({ label: "falling blocks starter events", maxEvents: 18 });
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
game
|
|
126
|
-
|
|
127
|
-
|
|
156
|
+
// HUD bindings as descriptor literals (the deprecated game.hud.* helpers are
|
|
157
|
+
// replaced by the createGame `hud` option + evidence channel sections).
|
|
158
|
+
const hudBindings = [
|
|
159
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "score", id: "hud:score", label: "score", source: "app-state", valuePath: "appState.score", format: "number", a11yLabel: "score" },
|
|
160
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "objective", id: "hud:objective", label: "objective", source: "app-state", valuePath: "appState.objective", format: "text", a11yLabel: "current objective" },
|
|
161
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "event-log", id: "hud:event-log", label: "event log", source: "app-state", valuePath: "appState.events", format: "text", a11yLabel: "game event log", debugOnly: true }
|
|
162
|
+
] as const;
|
|
128
163
|
|
|
129
164
|
setupPracticeBoard();
|
|
130
165
|
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
166
|
+
const blockfallGame = createGame({
|
|
167
|
+
id: "falling-blocks-starter",
|
|
168
|
+
target: "#app",
|
|
134
169
|
diagnostics: { overlay: true, performancePanel: true },
|
|
135
|
-
scene: buildScene()
|
|
170
|
+
scene: () => buildScene(falling.snapshot().board),
|
|
171
|
+
input: inputOptions,
|
|
172
|
+
hud: { theme: "arcade-neon", widgets: [] },
|
|
173
|
+
touch: {
|
|
174
|
+
preset: "dpad-2btn",
|
|
175
|
+
bindings: { left: "left", right: "right", dash: "softDrop", jump: "rotateRight", attack: "hardDrop" }
|
|
176
|
+
},
|
|
177
|
+
sound: {
|
|
178
|
+
cues: {
|
|
179
|
+
move: { id: "move", asset: { url: sfxUrl("ui.toggle.00") }, volume: 0.3 },
|
|
180
|
+
rotate: { id: "rotate", asset: { url: sfxUrl("ui.toggle.01") }, volume: 0.35 },
|
|
181
|
+
"hard-drop": { id: "hard-drop", asset: { url: sfxUrl("impact.wood.medium.00") }, volume: 0.6 },
|
|
182
|
+
"line-clear": { id: "line-clear", asset: { url: sfxUrl("pickup.coin.00") }, volume: 0.8 },
|
|
183
|
+
"game-over": { id: "game-over", asset: { url: sfxUrl("stinger.lose.00") }, volume: 0.8 }
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
juice: {
|
|
187
|
+
"hard-drop": { hitStop: 0.03, shake: 0.25, rumble: { strong: 0.4, ms: 120 } },
|
|
188
|
+
"line-clear": { flash: { color: "#5ed7df", peak: 0.22, ms: 240 }, punch: { fovDeg: 1.8, ms: 220 }, rumble: { weak: 0.5, ms: 200 } },
|
|
189
|
+
"game-over": { flash: { color: "#d88791", peak: 0.3, ms: 400 }, vignette: { amount: 0.6, ms: 900 } }
|
|
190
|
+
},
|
|
191
|
+
qualityRebuild: { flags: ["game"] },
|
|
192
|
+
evidence: {
|
|
193
|
+
schema: 1,
|
|
194
|
+
sections: { fallingBlocksStarter: () => window.__AURA3D_FALLING_BLOCKS_STARTER__ ?? { status: "unbound" } }
|
|
195
|
+
}
|
|
136
196
|
});
|
|
197
|
+
const app = blockfallGame.app;
|
|
198
|
+
blockfallGame.start();
|
|
199
|
+
const input = blockfallGame.input;
|
|
200
|
+
if (!input) throw new Error("create-aura3d falling-blocks-starter failed to create runtime-owned input.");
|
|
137
201
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
202
|
+
// Runtime handles are re-required after every setScene rebuild because the
|
|
203
|
+
// instanced settled board is mount-time data, not a mutable runtime spec.
|
|
204
|
+
let activeNodes: AuraRuntimeNodeHandle[] = [];
|
|
205
|
+
let flashNodes: AuraRuntimeNodeHandle[] = [];
|
|
206
|
+
let holdNode: AuraRuntimeNodeHandle | undefined;
|
|
207
|
+
mountRuntimeHandles();
|
|
143
208
|
const hudRoot = createHud();
|
|
144
209
|
let objective = "Clear the prepared line. Move, rotate, hold, or hard drop.";
|
|
145
210
|
let tickAccumulator = 0;
|
|
211
|
+
let settledSignature = settledCellsSignature(falling.snapshot().board);
|
|
212
|
+
let previousBoard: Board = falling.snapshot().board;
|
|
213
|
+
let flashRows: { readonly rows: readonly number[]; readonly until: number } = { rows: [], until: 0 };
|
|
214
|
+
let activeKind: Piece | null = null;
|
|
215
|
+
let holdKind: Piece | null = null;
|
|
146
216
|
|
|
147
|
-
|
|
148
|
-
|
|
217
|
+
// F-08-1: a static rig presents the board framing, pitched ~10° about X off
|
|
218
|
+
// the authored spec (flag-off mounts the no-op stub controller; that spec
|
|
219
|
+
// stays the fallback). F-08-5: feel bus + GameFeel attach through app.time.
|
|
220
|
+
app.camera?.use(
|
|
221
|
+
camera.rigs.static({
|
|
222
|
+
position: [0.35, boardCenterY + 0.81, 4.6],
|
|
223
|
+
target: [0, boardCenterY, 0],
|
|
224
|
+
orthographicSize: 2.9
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
const feel = gameFeel.create({ app, time: app.time });
|
|
228
|
+
app.feel?.preset("puzzle");
|
|
229
|
+
|
|
230
|
+
app.onFrame(({ dt }) => {
|
|
231
|
+
feel.update(dt * 1000);
|
|
149
232
|
if (input.pressed("reset")) {
|
|
150
233
|
setupPracticeBoard();
|
|
234
|
+
flashRows = { rows: [], until: 0 };
|
|
151
235
|
routeEvents.push({ type: "reset", label: "reset" });
|
|
152
236
|
objective = "Clear the prepared line. Move, rotate, hold, or hard drop.";
|
|
153
237
|
}
|
|
@@ -166,36 +250,19 @@ app.onFrame(({ dt }: { readonly dt: number }) => {
|
|
|
166
250
|
}
|
|
167
251
|
|
|
168
252
|
const state = falling.snapshot();
|
|
253
|
+
rebuildSettledCells(state);
|
|
169
254
|
renderBoard(state);
|
|
170
255
|
renderHud(state);
|
|
171
256
|
publishEvidence(state);
|
|
257
|
+
previousBoard = state.board;
|
|
172
258
|
});
|
|
173
259
|
|
|
174
260
|
renderBoard(falling.snapshot());
|
|
175
261
|
renderHud(falling.snapshot());
|
|
176
262
|
publishEvidence(falling.snapshot());
|
|
177
263
|
|
|
178
|
-
// Keep browser evidence deterministic on software GPUs without replacing real
|
|
179
|
-
// keyboard input. The input controller receives each DOM event first; this
|
|
180
|
-
// handler then advances the same app.onFrame gameplay callback and presents one
|
|
181
|
-
// completed frame. Generated apps outside WebDriver retain continuous playback.
|
|
182
|
-
if (evidenceMode) {
|
|
183
|
-
await app.ready();
|
|
184
|
-
// Complete one real production frame for the exact-installed visual gate.
|
|
185
|
-
// Software renderers may take seconds to drain this typed GLB scene, so keep
|
|
186
|
-
// later input-contract reads free of synchronous GPU submissions.
|
|
187
|
-
await app.stepAsync(0);
|
|
188
|
-
const advanceFromKeyboard = () => {
|
|
189
|
-
// Advance the real input and gameplay callback. The playable test reads
|
|
190
|
-
// simulation-owned evidence; rendering again for every key transition only
|
|
191
|
-
// blocks the browser main thread without adding gameplay coverage.
|
|
192
|
-
app.advance(1 / 60);
|
|
193
|
-
};
|
|
194
|
-
window.addEventListener("keydown", advanceFromKeyboard);
|
|
195
|
-
window.addEventListener("keyup", advanceFromKeyboard);
|
|
196
|
-
}
|
|
197
264
|
|
|
198
|
-
function recordKitEvents(state:
|
|
265
|
+
function recordKitEvents(state: KitState): void {
|
|
199
266
|
for (const event of state.events) {
|
|
200
267
|
routeEvents.push({
|
|
201
268
|
type: event.type,
|
|
@@ -203,10 +270,21 @@ function recordKitEvents(state: ReturnType<typeof falling.snapshot>): void {
|
|
|
203
270
|
severity: event.type === "line-clear" ? "success" : event.type === "game-over" ? "warning" : "info",
|
|
204
271
|
frame: event.frame
|
|
205
272
|
});
|
|
206
|
-
if (event.type === "line-clear")
|
|
273
|
+
if (event.type === "line-clear") {
|
|
274
|
+
objective = `Line clear. ${state.lines} line cleared. Press R to replay.`;
|
|
275
|
+
// The kit reports the count, not the rows: the cleared rows are exactly
|
|
276
|
+
// the rows that were full in the previous snapshot's board.
|
|
277
|
+
const cleared = fullRows(previousBoard).filter((row) => row >= hiddenRows);
|
|
278
|
+
flashRows = { rows: cleared, until: performance.now() + FLASH_MS };
|
|
279
|
+
}
|
|
207
280
|
if (event.type === "hold") objective = "Held piece. Press R or continue.";
|
|
208
281
|
if (event.type === "rotate") objective = "Rotation accepted.";
|
|
209
282
|
if (event.type === "move") objective = "Move accepted.";
|
|
283
|
+
if (event.type === "move" || event.type === "rotate") void blockfallGame.sound?.cue(event.type);
|
|
284
|
+
if (event.type === "hard-drop" || event.type === "line-clear" || event.type === "game-over") {
|
|
285
|
+
blockfallGame.juice.fire(event.type);
|
|
286
|
+
void blockfallGame.sound?.cue(event.type);
|
|
287
|
+
}
|
|
210
288
|
}
|
|
211
289
|
}
|
|
212
290
|
|
|
@@ -224,85 +302,207 @@ function createPracticeBoard(): Cell[][] {
|
|
|
224
302
|
return board;
|
|
225
303
|
}
|
|
226
304
|
|
|
227
|
-
function buildScene() {
|
|
305
|
+
function buildScene(board: Board) {
|
|
228
306
|
const nodes: AuraNodeInput[] = [
|
|
229
|
-
|
|
230
|
-
|
|
307
|
+
// Modular wall panel stands in for the arcade cabinet silhouette
|
|
308
|
+
// (library approximation, #481 mapping); scale keeps the old height.
|
|
309
|
+
model(assets.quaterniusWallModular, { name: "typed arcade cabinet", castShadow: true })
|
|
310
|
+
.position(1.9, 0.2, -0.7)
|
|
231
311
|
.scale(0.2),
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
...boardCellNodes(),
|
|
312
|
+
// Dark glossy board backing sourced from the same typed block GLB.
|
|
313
|
+
model(assets.quaterniusCubeCrate, { name: "board glossy backplate", material: material.pbr({ color: "#0b0e18", roughness: 0.18, metalness: 0.55 }) })
|
|
314
|
+
.position(0, boardCenterY, -0.16)
|
|
315
|
+
.scale([bs(1.42), bs(2.5), bs(0.03)]),
|
|
316
|
+
...boardFrameNodes(),
|
|
317
|
+
...settledCellsNode(board),
|
|
239
318
|
...activeCellNodes(),
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
.
|
|
319
|
+
...flashRowNodes(),
|
|
320
|
+
model(assets.quaterniusCubeCrate, { name: "hold preview", material: material.neon({ color: "#b987d0", emissive: "#b987d0", emissiveIntensity: 0.5 }) })
|
|
321
|
+
.position(-2.05, 1.92, 0.1)
|
|
322
|
+
.scale(bs(0.09))
|
|
243
323
|
.runtime(game.runtimeNode("hold-preview", { tags: ["hold", "runtime"] }))
|
|
244
324
|
];
|
|
245
325
|
|
|
326
|
+
// The neon-arcade look supplies the night-city sky gradient, key light,
|
|
327
|
+
// fog and grade — no ambient fill, background override or debug overlay.
|
|
246
328
|
return scene()
|
|
247
|
-
.
|
|
329
|
+
.add(looks.preset(LOOK_ID))
|
|
248
330
|
.addMany(nodes)
|
|
249
|
-
.
|
|
250
|
-
.add(lights.directional({ name: "blockfall key", position: [3.8, 6.2, 5], intensity: 1.15, color: "#ffffff" }))
|
|
251
|
-
.camera(camera.perspective({ position: [0.25, 1.2, 7.2], target: [0.1, 0.1, 0], fov: 38 }));
|
|
331
|
+
.camera(camera.orthographic({ position: [0.35, 0.75, 4.6], target: [0, boardCenterY, 0], orthographicSize: 2.9 }));
|
|
252
332
|
}
|
|
253
333
|
|
|
254
|
-
function
|
|
255
|
-
const
|
|
334
|
+
function boardFrameNodes(): AuraNodeInput[] {
|
|
335
|
+
const rail = material.pbr({ color: FRAME_COLOR, roughness: 0.3, metalness: 0.5, emissive: FRAME_ACCENT, emissiveIntensity: 0.22 });
|
|
336
|
+
const railThickness = 0.045; // 0.09 m rails around the 2.4 × 4.8 m well
|
|
337
|
+
const railHeight = (visibleRows * cellSize) / 2 + railThickness;
|
|
338
|
+
return [
|
|
339
|
+
model(assets.quaterniusCubeCrate, { name: "board frame left rail", material: rail })
|
|
340
|
+
.position(boardOrigin.x - railThickness, boardCenterY, 0)
|
|
341
|
+
.scale([bs(railThickness), bs(railHeight), bs(0.09)]),
|
|
342
|
+
model(assets.quaterniusCubeCrate, { name: "board frame right rail", material: rail })
|
|
343
|
+
.position(-boardOrigin.x + railThickness, boardCenterY, 0)
|
|
344
|
+
.scale([bs(railThickness), bs(railHeight), bs(0.09)]),
|
|
345
|
+
model(assets.quaterniusCubeCrate, { name: "board frame bottom rail", material: rail })
|
|
346
|
+
.position(0, boardOrigin.y - railThickness, 0)
|
|
347
|
+
.scale([bs(0.69), bs(railThickness), bs(0.09)]),
|
|
348
|
+
model(assets.quaterniusCubeCrate, { name: "board frame top rail", material: rail })
|
|
349
|
+
.position(0, boardTop + railThickness, 0)
|
|
350
|
+
.scale([bs(0.69), bs(railThickness), bs(0.09)])
|
|
351
|
+
];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// The settled board renders as ONE instanced bevelled-cube mesh: every filled
|
|
355
|
+
// cell is an instance of the typed block GLB tinted to its piece colour.
|
|
356
|
+
function settledCellsNode(board: Board): AuraNodeInput[] {
|
|
357
|
+
const transforms: AuraTransformSpec[] = [];
|
|
358
|
+
const colors: AuraColor[] = [];
|
|
256
359
|
for (let y = hiddenRows; y < boardHeight; y += 1) {
|
|
257
360
|
for (let x = 0; x < boardWidth; x += 1) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
);
|
|
361
|
+
const cell = board[y]?.[x];
|
|
362
|
+
if (!cell) continue;
|
|
363
|
+
const [px, py] = cellPosition(x, y);
|
|
364
|
+
transforms.push({ position: [px, py, 0], scale: CELL_FILL_SCALE });
|
|
365
|
+
colors.push(pieceColors[cell]);
|
|
264
366
|
}
|
|
265
367
|
}
|
|
266
|
-
|
|
368
|
+
if (transforms.length === 0) {
|
|
369
|
+
// instances.* requires at least one transform; park a scale-0 dummy.
|
|
370
|
+
transforms.push({ position: [0, -50, 0], scale: 0 });
|
|
371
|
+
colors.push("#141828");
|
|
372
|
+
}
|
|
373
|
+
return [
|
|
374
|
+
instances.model(assets.quaterniusCubeCrate, {
|
|
375
|
+
name: "settled board cells",
|
|
376
|
+
transforms,
|
|
377
|
+
colors,
|
|
378
|
+
material: material.pbr({ color: "#ffffff", roughness: 0.22, metalness: 0.3 }),
|
|
379
|
+
instancingAware: true
|
|
380
|
+
})
|
|
381
|
+
];
|
|
267
382
|
}
|
|
268
383
|
|
|
269
384
|
function activeCellNodes(): AuraNodeInput[] {
|
|
270
385
|
return Array.from({ length: 4 }, (_, index) =>
|
|
271
|
-
|
|
272
|
-
.position(
|
|
273
|
-
.scale(
|
|
386
|
+
model(assets.quaterniusCubeCrate, { name: `active piece cell ${index}`, material: material.neon({ color: "#4de8ff", emissive: "#4de8ff", emissiveIntensity: 0.45 }) })
|
|
387
|
+
.position(0, -50, 0.14)
|
|
388
|
+
.scale(CELL_SCALE)
|
|
274
389
|
.runtime(game.runtimeNode(`active-cell-${index}`, { tags: ["active-cell", "runtime"] }))
|
|
275
390
|
);
|
|
276
391
|
}
|
|
277
392
|
|
|
278
|
-
|
|
393
|
+
// Line-clear flash is a model surface, not a particle pool: four instanced-GLB
|
|
394
|
+
// bars stretch across the board and pulse emissive while a clear animates.
|
|
395
|
+
function flashRowNodes(): AuraNodeInput[] {
|
|
396
|
+
return Array.from({ length: 4 }, (_, index) =>
|
|
397
|
+
model(assets.quaterniusCubeCrate, { name: `line clear flash ${index}`, material: material.neon({ color: FRAME_ACCENT, emissive: FRAME_ACCENT, emissiveIntensity: 1.6 }) })
|
|
398
|
+
.position(0, -50, 0.16)
|
|
399
|
+
.scale([bs(0.66), CELL_FILL_SCALE, bs(0.05)])
|
|
400
|
+
.runtime(game.runtimeNode(`flash-row-${index}`, { tags: ["flash", "runtime"] }))
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function mountRuntimeHandles(): void {
|
|
405
|
+
activeNodes = Array.from({ length: 4 }, (_, index) => app.nodes.require(`active-cell-${index}`));
|
|
406
|
+
flashNodes = Array.from({ length: 4 }, (_, index) => app.nodes.require(`flash-row-${index}`));
|
|
407
|
+
holdNode = app.nodes.require("hold-preview");
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// The instanced settled mesh is mount-time data: rebuild the scene only when
|
|
411
|
+
// the settled board signature changes (lock, line clear, reset) — never on
|
|
412
|
+
// per-frame motion of the active piece.
|
|
413
|
+
function rebuildSettledCells(state: KitState): void {
|
|
414
|
+
const signature = settledCellsSignature(state.board);
|
|
415
|
+
if (signature === settledSignature) return;
|
|
416
|
+
try {
|
|
417
|
+
app.setScene(buildScene(state.board));
|
|
418
|
+
} catch {
|
|
419
|
+
// Frame submission can be pending during a mid-frame rebuild; retry on the
|
|
420
|
+
// next frame instead of tearing down the gameplay callback.
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
settledSignature = signature;
|
|
424
|
+
mountRuntimeHandles();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function settledCellsSignature(board: Board): string {
|
|
428
|
+
const cells: string[] = [];
|
|
279
429
|
for (let y = hiddenRows; y < boardHeight; y += 1) {
|
|
280
430
|
for (let x = 0; x < boardWidth; x += 1) {
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
node.setVisible(Boolean(cell)).setPosition(...cellPosition(x, y), 0);
|
|
431
|
+
const cell = board[y]?.[x];
|
|
432
|
+
if (cell) cells.push(`${x}:${y}:${cell}`);
|
|
284
433
|
}
|
|
285
434
|
}
|
|
435
|
+
return cells.join("|");
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function fullRows(board: Board): number[] {
|
|
439
|
+
const rows: number[] = [];
|
|
440
|
+
for (let y = hiddenRows; y < boardHeight; y += 1) {
|
|
441
|
+
if (board[y]?.every((cell) => cell !== null)) rows.push(y);
|
|
442
|
+
}
|
|
443
|
+
return rows;
|
|
444
|
+
}
|
|
286
445
|
|
|
287
|
-
|
|
446
|
+
function filledCellCount(board: Board): number {
|
|
447
|
+
let count = 0;
|
|
448
|
+
for (let y = hiddenRows; y < boardHeight; y += 1) {
|
|
449
|
+
for (let x = 0; x < boardWidth; x += 1) {
|
|
450
|
+
if (board[y]?.[x]) count += 1;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return count;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function renderBoard(state: KitState): void {
|
|
288
457
|
if (state.active) {
|
|
289
|
-
const
|
|
290
|
-
|
|
458
|
+
const kind = state.active.kind;
|
|
459
|
+
if (kind !== activeKind) {
|
|
460
|
+
const activeMaterial = material.neon({ color: pieceColors[kind], emissive: pieceColors[kind], emissiveIntensity: 0.45 });
|
|
461
|
+
activeNodes.forEach((node) => node.setMaterial(activeMaterial));
|
|
462
|
+
activeKind = kind;
|
|
463
|
+
}
|
|
464
|
+
const cells = activeShapes[kind][state.active.rotation] ?? activeShapes[kind][0];
|
|
465
|
+
activeNodes.forEach((node, index) => {
|
|
466
|
+
const cell = cells[index];
|
|
467
|
+
if (!cell) {
|
|
468
|
+
node.setVisible(false);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
291
471
|
const x = state.active!.x + cell.x;
|
|
292
472
|
const y = state.active!.y + cell.y;
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
.setPosition(...cellPosition(x, y), 0.14)
|
|
296
|
-
.setScale([cellSize * 0.94, cellSize * 0.94, 0.16]);
|
|
473
|
+
const [px, py] = cellPosition(x, y);
|
|
474
|
+
node.setVisible(y >= hiddenRows).setPosition(px, py, 0.14).setScale(CELL_SCALE);
|
|
297
475
|
});
|
|
476
|
+
} else {
|
|
477
|
+
activeNodes.forEach((node) => node.setVisible(false));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const flashing = performance.now() < flashRows.until;
|
|
481
|
+
flashNodes.forEach((node, index) => {
|
|
482
|
+
const row = flashRows.rows[index];
|
|
483
|
+
if (!flashing || row === undefined) {
|
|
484
|
+
node.setVisible(false);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const [, py] = cellPosition(0, row);
|
|
488
|
+
node.setVisible(true).setPosition(0, py, 0.16);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
if (state.hold) {
|
|
492
|
+
if (state.hold !== holdKind) {
|
|
493
|
+
holdKind = state.hold;
|
|
494
|
+
holdNode?.setMaterial(material.neon({ color: pieceColors[holdKind], emissive: pieceColors[holdKind], emissiveIntensity: 0.5 }));
|
|
495
|
+
}
|
|
496
|
+
holdNode?.setVisible(true);
|
|
497
|
+
} else {
|
|
498
|
+
holdNode?.setVisible(false);
|
|
298
499
|
}
|
|
299
|
-
holdNode.setVisible(Boolean(state.hold));
|
|
300
500
|
}
|
|
301
501
|
|
|
302
502
|
function cellPosition(x: number, y: number): [number, number] {
|
|
303
503
|
return [
|
|
304
504
|
boardOrigin.x + (x + 0.5) * cellSize,
|
|
305
|
-
boardOrigin.y + (
|
|
505
|
+
boardOrigin.y + (visibleRows - (y - hiddenRows) - 0.5) * cellSize
|
|
306
506
|
];
|
|
307
507
|
}
|
|
308
508
|
|
|
@@ -317,8 +517,8 @@ function createHud(): HTMLElement {
|
|
|
317
517
|
"min-width:310px",
|
|
318
518
|
"font:600 13px/1.35 Inter, system-ui, sans-serif",
|
|
319
519
|
"color:#f5fbff",
|
|
320
|
-
"background:rgba(
|
|
321
|
-
"border:1px solid rgba(
|
|
520
|
+
"background:rgba(8,10,22,0.72)",
|
|
521
|
+
"border:1px solid rgba(77,232,255,0.34)",
|
|
322
522
|
"border-radius:8px",
|
|
323
523
|
"padding:12px",
|
|
324
524
|
"pointer-events:none"
|
|
@@ -327,7 +527,7 @@ function createHud(): HTMLElement {
|
|
|
327
527
|
return root;
|
|
328
528
|
}
|
|
329
529
|
|
|
330
|
-
function renderHud(state:
|
|
530
|
+
function renderHud(state: KitState): void {
|
|
331
531
|
hudRoot.innerHTML = [
|
|
332
532
|
`<strong>Aura3D Falling Blocks Starter</strong>`,
|
|
333
533
|
`<div>Score ${state.score} | Lines ${state.lines} | Level ${state.level}</div>`,
|
|
@@ -337,11 +537,11 @@ function renderHud(state: ReturnType<typeof falling.snapshot>): void {
|
|
|
337
537
|
].join("");
|
|
338
538
|
}
|
|
339
539
|
|
|
340
|
-
function publishEvidence(state:
|
|
540
|
+
function publishEvidence(state: KitState): void {
|
|
341
541
|
const evidence = app.evidence({
|
|
342
542
|
input,
|
|
343
543
|
events: routeEvents,
|
|
344
|
-
hud,
|
|
544
|
+
hud: hudBindings,
|
|
345
545
|
appState: {
|
|
346
546
|
score: state.score,
|
|
347
547
|
objective,
|
|
@@ -353,6 +553,7 @@ function publishEvidence(state: ReturnType<typeof falling.snapshot>): void {
|
|
|
353
553
|
},
|
|
354
554
|
source: { expectsGame: true }
|
|
355
555
|
});
|
|
556
|
+
const diagnostics = app.diagnostics();
|
|
356
557
|
window.__AURA3D_FALLING_BLOCKS_STARTER__ = {
|
|
357
558
|
frame: state.frame,
|
|
358
559
|
score: state.score,
|
|
@@ -362,19 +563,17 @@ function publishEvidence(state: ReturnType<typeof falling.snapshot>): void {
|
|
|
362
563
|
hold: state.hold,
|
|
363
564
|
gameOver: state.gameOver,
|
|
364
565
|
events: routeEvents.events().map((event: { readonly label: string }) => event.label),
|
|
365
|
-
|
|
566
|
+
look: { id: LOOK_ID, category: "studio" },
|
|
567
|
+
board: {
|
|
568
|
+
width: boardWidth,
|
|
569
|
+
height: boardHeight,
|
|
570
|
+
visibleRows,
|
|
571
|
+
filledCells: filledCellCount(state.board),
|
|
572
|
+
rendering: "instanced-model",
|
|
573
|
+
cellAsset: { id: "quaterniusCubeCrate", url: assets.quaterniusCubeCrate.url, metres: assets.quaterniusCubeCrate.bounds },
|
|
574
|
+
drawCalls: diagnostics.drawCalls
|
|
575
|
+
},
|
|
576
|
+
flash: { modelBased: true, activeRows: performance.now() < flashRows.until ? flashRows.rows : [] },
|
|
366
577
|
evidence
|
|
367
578
|
};
|
|
368
579
|
}
|
|
369
|
-
|
|
370
|
-
function createLineClearProof(): FallingBlocksStarterEvidence["lineClearProof"] {
|
|
371
|
-
const proof = game.fallingBlocks({ width: boardWidth, height: boardHeight, hiddenRows, seed: 7, gravityFrames: 999 });
|
|
372
|
-
proof.setBoard(createPracticeBoard());
|
|
373
|
-
proof.setActive({ kind: "I", x: 3, y: boardHeight - 3, rotation: 0 });
|
|
374
|
-
const cleared = proof.hardDrop();
|
|
375
|
-
return {
|
|
376
|
-
lines: cleared.lines,
|
|
377
|
-
events: cleared.events.map((event) => event.piece ? `${event.type}:${event.piece}` : event.type),
|
|
378
|
-
checksum: cleared.checksum
|
|
379
|
-
};
|
|
380
|
-
}
|