create-aura3d 3.0.0 → 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 +4 -3
- 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 +13 -0
- 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 +5 -4
- package/templates/animation-studio/public/aura-assets/luma.thumb.svg +1 -1
- package/templates/animation-studio/public/aura-assets/miko.thumb.svg +1 -1
- package/templates/{falling-blocks-starter/public/aura-assets/showcaseBlockfallCabinet.thumb.svg → animation-studio/public/aura-assets/moonGarden.thumb.svg} +1 -1
- 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/asset-contract.ts +19 -0
- package/templates/animation-studio/src/aura-assets.ts +651 -54
- 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 +6 -4
- 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 +6 -5
- package/templates/character-controller/playwright.config.ts +1 -0
- 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 +49 -4
- 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 +6 -4
- 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 +4 -3
- package/templates/cinematic-scene/src/main.ts +46 -11
- 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 +6 -4
- 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 +4 -3
- 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/route-health.spec.ts +11 -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 +4 -3
- 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 +317 -96
- 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 +5 -3
- 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 +25 -33
- package/templates/fighting-game/tests/look-floor.ts +270 -0
- package/templates/fighting-game/tests/route-health.spec.ts +23 -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 +6 -4
- 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 +4 -2
- 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 +4 -2
- 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 +4 -3
- 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 +12 -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 +4 -3
- package/templates/racing-starter/src/main.ts +169 -123
- 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/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
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD-13 T3.12/T3.13 — the shared template look floor.
|
|
3
|
+
*
|
|
4
|
+
* Every create-aura3d template's `tests/screenshot.spec.ts` calls
|
|
5
|
+
* `assertTemplateLookFloor(page, ...)` after readiness: the same five checks
|
|
6
|
+
* everywhere (PRD §6.5/T3.12):
|
|
7
|
+
*
|
|
8
|
+
* 1. non-blank — sampled WebGL pixels are lit and varied (not a uniform
|
|
9
|
+
* clear/void frame);
|
|
10
|
+
* 2. `diagnostics().look.lint` carries no `severity === "error"` finding
|
|
11
|
+
* (empty when A3D_QR_LOOKS is off — the check never silently skips);
|
|
12
|
+
* 3. `appliedLook.environment.specularIntensity > 0` — an environment map
|
|
13
|
+
* actually reached the frame;
|
|
14
|
+
* 4. `appliedLook.shadows.strength >= 0.8` when the look declares a shadow
|
|
15
|
+
* caster (a null ShadowReport means the renderer produced no shadow
|
|
16
|
+
* evidence — recorded, not failed);
|
|
17
|
+
* 5. `appliedLook.pixelRatio >= min(devicePixelRatio, tierCap)` — the
|
|
18
|
+
* renderer used the display density up to the tier cap (2).
|
|
19
|
+
*
|
|
20
|
+
* …plus the optional §T3.12 subject check: the lit-pixel bounding box of the
|
|
21
|
+
* canvas' central region must sit within `tolerance` of the expected subject
|
|
22
|
+
* bounds (default ±10% of frame).
|
|
23
|
+
*
|
|
24
|
+
* Templates that mount through `createAuraApp` surface `appliedLook`/`look`
|
|
25
|
+
* via the global `__AURA3D_LIVE_APPS__` registry — no per-template wiring.
|
|
26
|
+
* `skipAppDiagnostics` covers the bespoke-renderer template (animation-studio),
|
|
27
|
+
* which reports its stage environment through its own readiness evidence.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { expect, type Page } from "@playwright/test";
|
|
31
|
+
|
|
32
|
+
/** Normalized canvas-space bounds the lit subject mass is expected to occupy. */
|
|
33
|
+
export interface LookFloorSubjectBounds {
|
|
34
|
+
readonly x: number;
|
|
35
|
+
readonly y: number;
|
|
36
|
+
readonly width: number;
|
|
37
|
+
readonly height: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface LookFloorOptions {
|
|
41
|
+
/** Expected subject bounds in normalized canvas units. Omit to skip. */
|
|
42
|
+
readonly subject?: LookFloorSubjectBounds;
|
|
43
|
+
/** Fractional tolerance on each bound axis. Default 0.1 (±10%). */
|
|
44
|
+
readonly tolerance?: number;
|
|
45
|
+
/** Template has no `__AURA3D_LIVE_APPS__` app (bespoke renderer). */
|
|
46
|
+
readonly skipAppDiagnostics?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface LookFloorReport {
|
|
50
|
+
readonly sampledPixels: number;
|
|
51
|
+
readonly brightPixels: number;
|
|
52
|
+
readonly uniqueBuckets: number;
|
|
53
|
+
readonly subjectBounds: LookFloorSubjectBounds | null;
|
|
54
|
+
readonly appliedLook: {
|
|
55
|
+
readonly specularIntensity: number;
|
|
56
|
+
readonly shadowStrength: number | null;
|
|
57
|
+
readonly pixelRatio: number;
|
|
58
|
+
readonly renderPath: string;
|
|
59
|
+
readonly background: string | null;
|
|
60
|
+
} | null;
|
|
61
|
+
readonly lookLintErrors: readonly string[];
|
|
62
|
+
readonly devicePixelRatio: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const MIN_BRIGHT_FRACTION = 0.02;
|
|
66
|
+
const MIN_UNIQUE_BUCKETS = 8;
|
|
67
|
+
|
|
68
|
+
export async function assertTemplateLookFloor(page: Page, options: LookFloorOptions = {}): Promise<LookFloorReport> {
|
|
69
|
+
const canvas = page.locator("canvas").first();
|
|
70
|
+
await expect(canvas).toBeVisible();
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* Deterministic frame before profiling: pause every live app, rewind its
|
|
74
|
+
* runtime clock and step a fixed 45 frames at 1/60 — through `stepAsync`,
|
|
75
|
+
* not the synchronous registry `settle()`. The production renderer mounts
|
|
76
|
+
* asynchronously, so a sync step loop renders nothing while the mount is in
|
|
77
|
+
* flight and never yields for it to finish (the failure mode on software-GL
|
|
78
|
+
* runners: blank frames, `environment.intensity` still NaN in diagnostics).
|
|
79
|
+
* Awaiting each step also lets pending environment/IBL/asset promises resolve
|
|
80
|
+
* between frames, and one final dt=0 step re-renders the same simulated
|
|
81
|
+
* instant once that work has applied.
|
|
82
|
+
*/
|
|
83
|
+
const report = await page.evaluate(async (): Promise<LookFloorReport> => {
|
|
84
|
+
interface LiveApp {
|
|
85
|
+
pause?: () => void;
|
|
86
|
+
resetRuntimeClock?: () => void;
|
|
87
|
+
step?: (dt?: number) => void;
|
|
88
|
+
stepAsync?: (dt?: number) => Promise<unknown>;
|
|
89
|
+
diagnostics?: () => Record<string, unknown>;
|
|
90
|
+
}
|
|
91
|
+
const empty = (code: string): LookFloorReport => ({
|
|
92
|
+
sampledPixels: 0,
|
|
93
|
+
brightPixels: 0,
|
|
94
|
+
uniqueBuckets: 0,
|
|
95
|
+
subjectBounds: null,
|
|
96
|
+
appliedLook: null,
|
|
97
|
+
lookLintErrors: [code],
|
|
98
|
+
devicePixelRatio: globalThis.devicePixelRatio ?? 1
|
|
99
|
+
});
|
|
100
|
+
const registry = (globalThis as { __AURA3D_LIVE_APPS__?: { all?: () => readonly LiveApp[] } }).__AURA3D_LIVE_APPS__;
|
|
101
|
+
const apps = [...(registry?.all?.() ?? [])];
|
|
102
|
+
const stepApp = async (app: LiveApp, dt: number): Promise<void> => {
|
|
103
|
+
if (app.stepAsync) {
|
|
104
|
+
try {
|
|
105
|
+
await Promise.race([
|
|
106
|
+
app.stepAsync(dt),
|
|
107
|
+
new Promise((resolvePromise) => setTimeout(resolvePromise, 30_000))
|
|
108
|
+
]);
|
|
109
|
+
return;
|
|
110
|
+
} catch {
|
|
111
|
+
// synchronous step fallback below
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
app.step?.(dt);
|
|
115
|
+
};
|
|
116
|
+
/*
|
|
117
|
+
* Wall-clock bound on the settle loop: on software-GL CI runners a single
|
|
118
|
+
* stepped render of a heavy scene costs several seconds, so an unbounded
|
|
119
|
+
* 45-step loop outlives the test budget and fails with a bare timeout and
|
|
120
|
+
* no report. Cap the stepping and always take the dt=0 settle frame — a
|
|
121
|
+
* partially settled scene still yields a readable floor report.
|
|
122
|
+
*/
|
|
123
|
+
const STEP_WALLCLOCK_BUDGET_MS = 420_000;
|
|
124
|
+
const settleStartedAt = Date.now();
|
|
125
|
+
for (const app of apps) {
|
|
126
|
+
app.pause?.();
|
|
127
|
+
app.resetRuntimeClock?.();
|
|
128
|
+
for (let index = 0; index < 45; index += 1) {
|
|
129
|
+
if (Date.now() - settleStartedAt > STEP_WALLCLOCK_BUDGET_MS) break;
|
|
130
|
+
await stepApp(app, 1 / 60);
|
|
131
|
+
}
|
|
132
|
+
await stepApp(app, 0);
|
|
133
|
+
}
|
|
134
|
+
/*
|
|
135
|
+
* Renderers outside the liveApps registry (bespoke renderers, e.g.
|
|
136
|
+
* animation-studio's A3DRenderer) cannot be stepped. Two animation
|
|
137
|
+
* frames guarantee at least one full app render finished inside this
|
|
138
|
+
* evaluate task, so the readPixels below sees a real presented frame
|
|
139
|
+
* instead of a compositor-cleared buffer.
|
|
140
|
+
*/
|
|
141
|
+
if (apps.length === 0) {
|
|
142
|
+
await new Promise<void>((resolve) => {
|
|
143
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const diagnostics = apps[0]?.diagnostics?.() as
|
|
148
|
+
| { appliedLook?: { environment?: { specularIntensity?: number; background?: string }; shadows?: { strength?: number | null } | null; pixelRatio?: number; renderPath?: string }; look?: { lint?: readonly { severity?: string; code?: string }[] } }
|
|
149
|
+
| undefined;
|
|
150
|
+
const appliedLook = diagnostics?.appliedLook
|
|
151
|
+
? {
|
|
152
|
+
specularIntensity: diagnostics.appliedLook.environment?.specularIntensity ?? 0,
|
|
153
|
+
shadowStrength: diagnostics.appliedLook.shadows?.strength ?? null,
|
|
154
|
+
pixelRatio: diagnostics.appliedLook.pixelRatio ?? 0,
|
|
155
|
+
renderPath: diagnostics.appliedLook.renderPath ?? "unknown",
|
|
156
|
+
background: diagnostics.appliedLook.environment?.background ?? null
|
|
157
|
+
}
|
|
158
|
+
: null;
|
|
159
|
+
const lookLintErrors = (diagnostics?.look?.lint ?? [])
|
|
160
|
+
.filter((finding) => finding.severity === "error")
|
|
161
|
+
.map((finding) => finding.code ?? "unknown");
|
|
162
|
+
const devicePixelRatio = globalThis.devicePixelRatio ?? 1;
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
* The app's WebGL context is not preserveDrawingBuffer, so readPixels must
|
|
166
|
+
* run in the same task as the stepped render, before compositing clears the
|
|
167
|
+
* drawing buffer. That also removes the composited element screenshot that
|
|
168
|
+
* software-GL runners could not produce inside a test timeout.
|
|
169
|
+
*/
|
|
170
|
+
const target = [...document.querySelectorAll("canvas")]
|
|
171
|
+
.map((element) => ({
|
|
172
|
+
element,
|
|
173
|
+
gl: (element.getContext("webgl2") ?? element.getContext("webgl")) as WebGL2RenderingContext | WebGLRenderingContext | null
|
|
174
|
+
}))
|
|
175
|
+
.find((entry) => entry.gl !== null);
|
|
176
|
+
if (!target?.gl) return { ...empty("no-webgl-context"), appliedLook, lookLintErrors };
|
|
177
|
+
const gl = target.gl;
|
|
178
|
+
const width = gl.drawingBufferWidth;
|
|
179
|
+
const height = gl.drawingBufferHeight;
|
|
180
|
+
if (width === 0 || height === 0) return { ...empty("empty-drawing-buffer"), appliedLook, lookLintErrors };
|
|
181
|
+
// readPixels reads the currently bound framebuffer: renderers that end a
|
|
182
|
+
// frame with an offscreen target bound (shadow/post FBOs — e.g.
|
|
183
|
+
// animation-studio's bespoke renderer) would return that target's pixels
|
|
184
|
+
// instead of the canvas backbuffer. Rebind the default framebuffer first;
|
|
185
|
+
// every renderer rebinds its own targets at the start of its next frame.
|
|
186
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
187
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
188
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
189
|
+
|
|
190
|
+
const BRIGHT_LUMA = 48;
|
|
191
|
+
const stride = 4; // pixels — 16×16 sample grid
|
|
192
|
+
let sampled = 0;
|
|
193
|
+
let bright = 0;
|
|
194
|
+
const buckets = new Set<number>();
|
|
195
|
+
// Central-region lit-pixel bbox: edges carry floor/backdrop, the subject
|
|
196
|
+
// mass is what every §6.4 template frames mid-frame.
|
|
197
|
+
const x0 = Math.floor(width * 0.1);
|
|
198
|
+
const x1 = Math.floor(width * 0.9);
|
|
199
|
+
const y0 = Math.floor(height * 0.1);
|
|
200
|
+
const y1 = Math.floor(height * 0.9);
|
|
201
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
202
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
203
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
204
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
205
|
+
for (let y = 0; y < height; y += stride) {
|
|
206
|
+
for (let x = 0; x < width; x += stride) {
|
|
207
|
+
const offset = (y * width + x) * 4;
|
|
208
|
+
const r = pixels[offset] ?? 0;
|
|
209
|
+
const g = pixels[offset + 1] ?? 0;
|
|
210
|
+
const b = pixels[offset + 2] ?? 0;
|
|
211
|
+
sampled += 1;
|
|
212
|
+
buckets.add(((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4));
|
|
213
|
+
const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
214
|
+
if (luma > BRIGHT_LUMA) {
|
|
215
|
+
bright += 1;
|
|
216
|
+
if (x >= x0 && x <= x1 && y >= y0 && y <= y1) {
|
|
217
|
+
minX = Math.min(minX, x);
|
|
218
|
+
maxX = Math.max(maxX, x);
|
|
219
|
+
minY = Math.min(minY, y);
|
|
220
|
+
maxY = Math.max(maxY, y);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// readPixels rows run bottom-up; report `y` in the same top-down
|
|
226
|
+
// convention the composited-screenshot path produced so stored
|
|
227
|
+
// expectations stay comparable across the switch.
|
|
228
|
+
const subjectBounds = Number.isFinite(minX)
|
|
229
|
+
? { x: minX / width, y: 1 - maxY / height, width: (maxX - minX) / width, height: (maxY - minY) / height }
|
|
230
|
+
: null;
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
sampledPixels: sampled,
|
|
234
|
+
brightPixels: bright,
|
|
235
|
+
uniqueBuckets: buckets.size,
|
|
236
|
+
subjectBounds,
|
|
237
|
+
appliedLook,
|
|
238
|
+
lookLintErrors,
|
|
239
|
+
devicePixelRatio
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// 1. Non-blank.
|
|
244
|
+
expect(report.brightPixels / Math.max(1, report.sampledPixels)).toBeGreaterThan(MIN_BRIGHT_FRACTION);
|
|
245
|
+
expect(report.uniqueBuckets).toBeGreaterThan(MIN_UNIQUE_BUCKETS);
|
|
246
|
+
|
|
247
|
+
if (!options.skipAppDiagnostics) {
|
|
248
|
+
// 2–5. Renderer/look evidence via __AURA3D_LIVE_APPS__.
|
|
249
|
+
expect(report.appliedLook, "appliedLook diagnostics missing — is the app mounted via createAuraApp?").not.toBeNull();
|
|
250
|
+
expect(report.lookLintErrors).toEqual([]);
|
|
251
|
+
expect(report.appliedLook!.specularIntensity).toBeGreaterThan(0);
|
|
252
|
+
if (report.appliedLook!.shadowStrength !== null) {
|
|
253
|
+
expect(report.appliedLook!.shadowStrength!).toBeGreaterThanOrEqual(0.8);
|
|
254
|
+
}
|
|
255
|
+
expect(report.appliedLook!.pixelRatio).toBeGreaterThanOrEqual(Math.min(report.devicePixelRatio, 2));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// 6. Subject bounds ±10%.
|
|
259
|
+
if (options.subject) {
|
|
260
|
+
const tolerance = options.tolerance ?? 0.1;
|
|
261
|
+
const measured = `measured ${JSON.stringify(report.subjectBounds)}`;
|
|
262
|
+
expect(report.subjectBounds, "no lit subject mass in the central frame").not.toBeNull();
|
|
263
|
+
expect(Math.abs(report.subjectBounds!.x - options.subject.x), measured).toBeLessThanOrEqual(tolerance);
|
|
264
|
+
expect(Math.abs(report.subjectBounds!.y - options.subject.y), measured).toBeLessThanOrEqual(tolerance);
|
|
265
|
+
expect(Math.abs(report.subjectBounds!.width - options.subject.width), measured).toBeLessThanOrEqual(tolerance);
|
|
266
|
+
expect(Math.abs(report.subjectBounds!.height - options.subject.height), measured).toBeLessThanOrEqual(tolerance);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return report;
|
|
270
|
+
}
|
|
@@ -1,48 +1,73 @@
|
|
|
1
1
|
import { expect, test } from "@playwright/test";
|
|
2
2
|
|
|
3
3
|
test("falling-blocks starter responds to keyboard input and clears a line", async ({ page }) => {
|
|
4
|
-
test.setTimeout(
|
|
4
|
+
test.setTimeout(420_000);
|
|
5
5
|
await page.goto("/");
|
|
6
|
-
await page.waitForFunction(() => document.body.dataset.aura3dReady === "true", undefined, { timeout:
|
|
6
|
+
await page.waitForFunction(() => document.body.dataset.aura3dReady === "true", undefined, { timeout: 150_000 });
|
|
7
7
|
await page.waitForFunction(() => Boolean((window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: unknown }).__AURA3D_FALLING_BLOCKS_STARTER__));
|
|
8
8
|
|
|
9
9
|
const initial = await fallingState(page);
|
|
10
|
+
expect(initial.look.id).toBe("neon-arcade");
|
|
10
11
|
expect(initial.active?.kind).toBe("I");
|
|
11
12
|
expect(initial.active?.x).toBe(3);
|
|
12
|
-
expect(initial.
|
|
13
|
-
expect(initial.
|
|
13
|
+
expect(initial.board.rendering).toBe("instanced-model");
|
|
14
|
+
expect(initial.board.cellAsset.id).toBe("blockCell");
|
|
15
|
+
expect(initial.board.filledCells).toBeGreaterThanOrEqual(4);
|
|
16
|
+
expect(initial.flash.modelBased).toBe(true);
|
|
14
17
|
|
|
18
|
+
// Key presses are consumed per presented frame; on software-GL runners a
|
|
19
|
+
// frame can take seconds, so a fixed wall-clock settle can miss or race the
|
|
20
|
+
// input. Tap, then wait on the published state itself.
|
|
15
21
|
await tapKey(page, "ArrowRight");
|
|
16
|
-
await page.
|
|
22
|
+
await page.waitForFunction(
|
|
23
|
+
(expectedX) => ((window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly active?: { readonly x?: number } } }).__AURA3D_FALLING_BLOCKS_STARTER__?.active?.x ?? -1) === expectedX,
|
|
24
|
+
(initial.active?.x ?? 0) + 1, { timeout: 60_000 });
|
|
17
25
|
const moved = await fallingState(page);
|
|
18
26
|
expect(moved.active?.x).toBe((initial.active?.x ?? 0) + 1);
|
|
19
27
|
|
|
28
|
+
// Reset returns the active piece to spawn (x=3); wait on that real change
|
|
29
|
+
// rather than a state that was already true before the key landed.
|
|
20
30
|
await tapKey(page, "KeyR");
|
|
21
|
-
await page.
|
|
31
|
+
await page.waitForFunction(
|
|
32
|
+
() => (window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly active?: { readonly x?: number } } }).__AURA3D_FALLING_BLOCKS_STARTER__?.active?.x === 3,
|
|
33
|
+
undefined, { timeout: 60_000 });
|
|
22
34
|
await tapKey(page, "ArrowUp");
|
|
23
|
-
await page.
|
|
35
|
+
await page.waitForFunction(
|
|
36
|
+
(rotation) => ((window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly active?: { readonly rotation?: number } } }).__AURA3D_FALLING_BLOCKS_STARTER__?.active?.rotation ?? -1) !== rotation,
|
|
37
|
+
initial.active?.rotation, { timeout: 60_000 });
|
|
24
38
|
const rotated = await fallingState(page);
|
|
25
39
|
expect(rotated.active?.rotation).not.toBe(initial.active?.rotation);
|
|
26
40
|
|
|
27
41
|
await tapKey(page, "KeyR");
|
|
28
|
-
await page.
|
|
42
|
+
await page.waitForFunction(
|
|
43
|
+
() => (window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly active?: { readonly rotation?: number } } }).__AURA3D_FALLING_BLOCKS_STARTER__?.active?.rotation === 0,
|
|
44
|
+
undefined, { timeout: 60_000 });
|
|
29
45
|
await tapKey(page, "KeyC");
|
|
30
|
-
await page.
|
|
46
|
+
await page.waitForFunction(
|
|
47
|
+
() => (window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly hold?: string | null } }).__AURA3D_FALLING_BLOCKS_STARTER__?.hold === "I",
|
|
48
|
+
undefined, { timeout: 60_000 });
|
|
31
49
|
const held = await fallingState(page);
|
|
32
50
|
expect(held.hold).toBe("I");
|
|
33
51
|
expect(held.events).toEqual(expect.arrayContaining(["hold:I"]));
|
|
34
52
|
|
|
35
53
|
await tapKey(page, "KeyR");
|
|
36
|
-
await page.
|
|
54
|
+
await page.waitForFunction(
|
|
55
|
+
() => (window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly hold?: string | null } }).__AURA3D_FALLING_BLOCKS_STARTER__?.hold === null
|
|
56
|
+
|| (window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly hold?: string | null } }).__AURA3D_FALLING_BLOCKS_STARTER__?.hold === undefined,
|
|
57
|
+
undefined, { timeout: 60_000 });
|
|
37
58
|
await tapKey(page, "Space");
|
|
38
|
-
await page.
|
|
59
|
+
await page.waitForFunction(
|
|
60
|
+
() => ((window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly lines?: number } }).__AURA3D_FALLING_BLOCKS_STARTER__?.lines ?? 0) >= 1,
|
|
61
|
+
undefined, { timeout: 60_000 });
|
|
39
62
|
const cleared = await fallingState(page);
|
|
40
63
|
expect(cleared.lines).toBe(1);
|
|
41
64
|
expect(cleared.score).toBeGreaterThanOrEqual(100);
|
|
42
65
|
expect(cleared.events).toEqual(expect.arrayContaining(["hard-drop:I", "line-clear"]));
|
|
43
66
|
|
|
44
67
|
await tapKey(page, "KeyR");
|
|
45
|
-
await page.
|
|
68
|
+
await page.waitForFunction(
|
|
69
|
+
() => (window as unknown as { __AURA3D_FALLING_BLOCKS_STARTER__?: { readonly lines?: number } }).__AURA3D_FALLING_BLOCKS_STARTER__?.lines === 0,
|
|
70
|
+
undefined, { timeout: 60_000 });
|
|
46
71
|
const reset = await fallingState(page);
|
|
47
72
|
expect(reset.lines).toBe(0);
|
|
48
73
|
expect(reset.active?.kind).toBe("I");
|
|
@@ -55,10 +80,14 @@ async function fallingState(page: import("@playwright/test").Page): Promise<{
|
|
|
55
80
|
readonly active: { readonly kind: string; readonly x: number; readonly rotation: number } | null;
|
|
56
81
|
readonly hold: string | null;
|
|
57
82
|
readonly events: readonly string[];
|
|
58
|
-
readonly
|
|
59
|
-
|
|
60
|
-
readonly
|
|
83
|
+
readonly look: { readonly id: string };
|
|
84
|
+
readonly board: {
|
|
85
|
+
readonly filledCells: number;
|
|
86
|
+
readonly rendering: string;
|
|
87
|
+
readonly cellAsset: { readonly id: string; readonly url: string };
|
|
88
|
+
readonly drawCalls: number;
|
|
61
89
|
};
|
|
90
|
+
readonly flash: { readonly modelBased: boolean; readonly activeRows: readonly number[] };
|
|
62
91
|
}> {
|
|
63
92
|
return await page.evaluate(() => {
|
|
64
93
|
const state = (window as unknown as {
|
|
@@ -68,10 +97,14 @@ async function fallingState(page: import("@playwright/test").Page): Promise<{
|
|
|
68
97
|
readonly active: { readonly kind: string; readonly x: number; readonly rotation: number } | null;
|
|
69
98
|
readonly hold: string | null;
|
|
70
99
|
readonly events: readonly string[];
|
|
71
|
-
readonly
|
|
72
|
-
|
|
73
|
-
readonly
|
|
100
|
+
readonly look: { readonly id: string };
|
|
101
|
+
readonly board: {
|
|
102
|
+
readonly filledCells: number;
|
|
103
|
+
readonly rendering: string;
|
|
104
|
+
readonly cellAsset: { readonly id: string; readonly url: string };
|
|
105
|
+
readonly drawCalls: number;
|
|
74
106
|
};
|
|
107
|
+
readonly flash: { readonly modelBased: boolean; readonly activeRows: readonly number[] };
|
|
75
108
|
};
|
|
76
109
|
}).__AURA3D_FALLING_BLOCKS_STARTER__;
|
|
77
110
|
if (!state) throw new Error("Missing __AURA3D_FALLING_BLOCKS_STARTER__ state.");
|
|
@@ -2,22 +2,28 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { expect, test } from "@playwright/test";
|
|
4
4
|
|
|
5
|
-
test.setTimeout(
|
|
5
|
+
test.setTimeout(240_000);
|
|
6
6
|
|
|
7
|
-
test("Aura3D falling-blocks starter reaches ready state with
|
|
7
|
+
test("Aura3D falling-blocks starter reaches ready state with instanced board evidence", async ({ page }) => {
|
|
8
8
|
await page.goto("/");
|
|
9
|
-
await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout:
|
|
9
|
+
await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 150_000 }).toBe("true");
|
|
10
10
|
|
|
11
11
|
const drawCalls = Number(await page.locator("body").getAttribute("data-aura3d-draw-calls"));
|
|
12
12
|
const routeState = await page.evaluate(() => {
|
|
13
13
|
const value: unknown = Reflect.get(window, "__AURA3D_FALLING_BLOCKS_STARTER__");
|
|
14
14
|
const state = isRecord(value) ? value : {};
|
|
15
|
-
const
|
|
16
|
-
const
|
|
15
|
+
const look = isRecord(state.look) ? state.look : {};
|
|
16
|
+
const board = isRecord(state.board) ? state.board : {};
|
|
17
|
+
const cellAsset = isRecord(board.cellAsset) ? board.cellAsset : {};
|
|
18
|
+
const flash = isRecord(state.flash) ? state.flash : {};
|
|
17
19
|
return {
|
|
18
20
|
score: typeof state.score === "number" ? state.score : -1,
|
|
19
21
|
lines: typeof state.lines === "number" ? state.lines : -1,
|
|
20
|
-
|
|
22
|
+
lookId: typeof look.id === "string" ? look.id : "",
|
|
23
|
+
rendering: typeof board.rendering === "string" ? board.rendering : "",
|
|
24
|
+
filledCells: typeof board.filledCells === "number" ? board.filledCells : 0,
|
|
25
|
+
cellAssetId: typeof cellAsset.id === "string" ? cellAsset.id : "",
|
|
26
|
+
flashModelBased: flash.modelBased === true
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
function isRecord(recordValue: unknown): recordValue is Readonly<Record<string, unknown>> {
|
|
@@ -28,7 +34,11 @@ test("Aura3D falling-blocks starter reaches ready state with line-clear evidence
|
|
|
28
34
|
expect(drawCalls).toBeGreaterThan(0);
|
|
29
35
|
expect(routeState.score).toBeGreaterThanOrEqual(0);
|
|
30
36
|
expect(routeState.lines).toBeGreaterThanOrEqual(0);
|
|
31
|
-
expect(routeState.
|
|
37
|
+
expect(routeState.lookId).toBe("neon-arcade");
|
|
38
|
+
expect(routeState.rendering).toBe("instanced-model");
|
|
39
|
+
expect(routeState.filledCells).toBeGreaterThan(0);
|
|
40
|
+
expect(routeState.cellAssetId).toBe("blockCell");
|
|
41
|
+
expect(routeState.flashModelBased).toBe(true);
|
|
32
42
|
mkdirSync(resolve("tests/reports"), { recursive: true });
|
|
33
43
|
writeFileSync(resolve("tests/reports/route-health.json"), `${JSON.stringify({ ready: true, drawCalls, routeState }, null, 2)}\n`);
|
|
34
44
|
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { expect, test } from "@playwright/test";
|
|
4
|
+
import { assertTemplateLookFloor } from "./look-floor";
|
|
5
|
+
|
|
6
|
+
test.setTimeout(600_000);
|
|
7
|
+
|
|
8
|
+
// PRD-13 T3.12 — look floor: non-blank, look.lint error-free, appliedLook
|
|
9
|
+
// environment specular > 0, shadow strength >= 0.8, pixelRatio at tier cap,
|
|
10
|
+
// subject bounds within ±10% — plus this template's bespoke assertions.
|
|
11
|
+
test("Aura3D falling blocks starter screenshot clears the look floor", async ({ page }) => {
|
|
12
|
+
await page.goto("/");
|
|
13
|
+
await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 150_000 }).toBe("true");
|
|
14
|
+
|
|
15
|
+
const floor = await assertTemplateLookFloor(page, { subject: { x: 0.15, y: 0.15, width: 0.7, height: 0.7 } });
|
|
16
|
+
const screenshot = await page.screenshot({ fullPage: false });
|
|
17
|
+
mkdirSync(resolve("tests/reports"), { recursive: true });
|
|
18
|
+
writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
|
|
19
|
+
writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength, floor }, null, 2)}\n`);
|
|
20
|
+
expect(screenshot.byteLength).toBeGreaterThan(1000);
|
|
21
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import { auraDecodersPlugin } from "@aura3d/assets/vite";
|
|
3
|
+
|
|
4
|
+
// F-05-04 (05-PKG): ship + serve the decoder vendor tree at /aura-decoders/
|
|
5
|
+
// so compressed (KTX2/draco/meshopt) GLBs decode same-origin with correct
|
|
6
|
+
// MIME in both `vite dev` and `vite preview`/deployed builds.
|
|
7
|
+
export default defineConfig({ plugins: [auraDecodersPlugin()] });
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: Aura3D look-dev
|
|
2
|
+
|
|
3
|
+
# Captures this scene's screenshot tests on an Apple-silicon GPU runner
|
|
4
|
+
# (ANGLE Metal) and uploads the report as the `lookdev` artifact.
|
|
5
|
+
# `aura3d look capture --runner gh-actions` dispatches this workflow and
|
|
6
|
+
# downloads the artifacts; it can also be run manually from the Actions tab.
|
|
7
|
+
# No secrets are used; workflow_dispatch only — never runs forked code.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
inputs:
|
|
12
|
+
shots:
|
|
13
|
+
description: "Shot names to capture (comma-separated; the template's defaults when empty)"
|
|
14
|
+
required: false
|
|
15
|
+
default: ""
|
|
16
|
+
viewports:
|
|
17
|
+
description: "Viewport names (comma-separated; the template's defaults when empty)"
|
|
18
|
+
required: false
|
|
19
|
+
default: ""
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
capture:
|
|
26
|
+
name: Look-dev captures (macos-14, ANGLE Metal)
|
|
27
|
+
runs-on: macos-14
|
|
28
|
+
timeout-minutes: 45
|
|
29
|
+
env:
|
|
30
|
+
QRC_GPU_ARGS: "--use-angle=metal --enable-gpu --ignore-gpu-blocklist"
|
|
31
|
+
A3D_LOOKDEV_SHOTS: ${{ inputs.shots }}
|
|
32
|
+
A3D_LOOKDEV_VIEWPORTS: ${{ inputs.viewports }}
|
|
33
|
+
steps:
|
|
34
|
+
- name: Checkout
|
|
35
|
+
uses: actions/checkout@v4
|
|
36
|
+
with:
|
|
37
|
+
lfs: false
|
|
38
|
+
|
|
39
|
+
- name: Setup Node.js
|
|
40
|
+
uses: actions/setup-node@v4
|
|
41
|
+
with:
|
|
42
|
+
node-version: '22'
|
|
43
|
+
cache: 'npm'
|
|
44
|
+
|
|
45
|
+
- name: Install dependencies
|
|
46
|
+
run: npm ci
|
|
47
|
+
|
|
48
|
+
- name: Build the app
|
|
49
|
+
run: npm run build
|
|
50
|
+
|
|
51
|
+
- name: Install Playwright Chromium
|
|
52
|
+
run: npx playwright install chromium
|
|
53
|
+
|
|
54
|
+
- name: Capture screenshots
|
|
55
|
+
run: npx playwright test tests/screenshot.spec.ts --reporter=line
|
|
56
|
+
env:
|
|
57
|
+
CHROMIUM_FLAGS: ${{ env.QRC_GPU_ARGS }}
|
|
58
|
+
|
|
59
|
+
- name: Upload look-dev artifacts
|
|
60
|
+
if: always()
|
|
61
|
+
uses: actions/upload-artifact@v4
|
|
62
|
+
with:
|
|
63
|
+
name: lookdev
|
|
64
|
+
path: |
|
|
65
|
+
tests/reports/**
|
|
66
|
+
if-no-files-found: warn
|
|
67
|
+
retention-days: 30
|
|
@@ -13,6 +13,8 @@ This template demonstrates Aura3D's public game runtime APIs:
|
|
|
13
13
|
- `games.fighting.stagePreset(...)` and `games.fighting.validateStage(...)` for fighting-stage source, safe zones, combat bounds, and readiness warnings.
|
|
14
14
|
- `game.hud.*`, `game.accessibility.*`, and `ui.*` helpers for HUD, controls, and a11y evidence.
|
|
15
15
|
- `game.evidence(app, ...)` for proving the route is using runtime systems instead of a static scene.
|
|
16
|
+
- `looks.preset("arena-fight")` supplies the interior-industrial backdrop, key light, haze and post grade; only the accent rim light rides on top — no ambient/studio fill, no `.background`, no diagnostics overlay.
|
|
17
|
+
- `game.cameraDirector(...)` drives the real camera: the C-22 `app.camera` controller presents the `fighting` rig and every frame applies the director's `position`/`target`/`fov` via `setPose`.
|
|
16
18
|
|
|
17
19
|
## Source layout
|
|
18
20
|
|