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
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { camera,
|
|
1
|
+
import { camera, effects, game, gameFeel, lights, looks, scene, ui } from "@aura3d/engine";
|
|
2
|
+
// PRD-09: mounted via the shared runtime — createGame owns mount/lifecycle,
|
|
3
|
+
// the §7.7 fighting HUD theme, the §6.11 dpad-4btn touch preset,
|
|
4
|
+
// game-sfx-core cues, and the juice event map.
|
|
5
|
+
import { createGame, sfxUrl } from "@aura3d/engine/game";
|
|
2
6
|
import { assets } from "./aura-assets";
|
|
3
7
|
import {
|
|
4
8
|
animationLayer,
|
|
@@ -26,6 +30,7 @@ import {
|
|
|
26
30
|
import "./styles.css";
|
|
27
31
|
|
|
28
32
|
type Aura3DGameWindow = Window & {
|
|
33
|
+
__AURA3D_GAME__?: { readonly state?: string };
|
|
29
34
|
__AURA3D_GAME_DEBUG__?: unknown;
|
|
30
35
|
__AURA3D_GAME_EVIDENCE__?: unknown;
|
|
31
36
|
__AURA3D_GAME_RUNTIME__?: unknown;
|
|
@@ -61,7 +66,6 @@ ui.html(
|
|
|
61
66
|
<section class="hud__panel hud__panel--meta" aria-label="Runtime evidence">
|
|
62
67
|
<span id="hud-round">Round 1 - 99</span>
|
|
63
68
|
<span id="hud-frame">Frame 0</span>
|
|
64
|
-
<span id="hud-camera">Camera zoom 1.00</span>
|
|
65
69
|
<span id="hud-assets">Typed assets ${typedFighterAssetCount}/2</span>
|
|
66
70
|
<span id="hud-stage">Stage ${fightingStage.id}</span>
|
|
67
71
|
<span id="hud-replay">Replay ready</span>
|
|
@@ -79,43 +83,59 @@ const hudRivalHealth = ui.text("#hud-rival-health");
|
|
|
79
83
|
const hudPlayerMeter = ui.text("#hud-player-meter");
|
|
80
84
|
const hudRound = ui.text("#hud-round");
|
|
81
85
|
const hudFrame = ui.text("#hud-frame");
|
|
82
|
-
const hudCamera = ui.text("#hud-camera");
|
|
83
86
|
const hudAssets = ui.text("#hud-assets");
|
|
84
87
|
const hudStage = ui.text("#hud-stage");
|
|
85
88
|
const hudReplay = ui.text("#hud-replay");
|
|
86
89
|
const replayButton = ui.button("#hud-replay-button");
|
|
87
90
|
const pauseButton = ui.button("#hud-pause-button");
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
game
|
|
93
|
-
game
|
|
94
|
-
game
|
|
95
|
-
game
|
|
96
|
-
game
|
|
97
|
-
|
|
92
|
+
// Descriptor literals replace the deprecated game.hud.* / game.accessibility.*
|
|
93
|
+
// helpers — same evidence shape, no factory call.
|
|
94
|
+
const hudBindings = [
|
|
95
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "health", id: "hud:player:health", label: "Player health", source: "combat", targetId: "player", valuePath: "combat.actors.player.health", maxPath: "rules.maxHealth", format: "percent", a11yLabel: "player health" },
|
|
96
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "health", id: "hud:rival:health", label: "Rival health", source: "combat", targetId: "rival", valuePath: "combat.actors.rival.health", maxPath: "rules.maxHealth", format: "percent", a11yLabel: "rival health" },
|
|
97
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "meter", id: "hud:player:meter", label: "Player meter", source: "combat", targetId: "player", valuePath: "combat.actors.player.meter", maxPath: "rules.maxMeter", format: "percent", a11yLabel: "player super meter value" },
|
|
98
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "timer", id: "hud:round:timer", label: "Round timer", source: "app-state", valuePath: "round.timeRemaining", format: "clock", a11yLabel: "round timer" },
|
|
99
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "combo", id: "hud:player:combo", label: "Player combo", source: "combat", targetId: "player", valuePath: "combat.player.combo", format: "number", a11yLabel: "player combo" },
|
|
100
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "round", id: "hud:round:index", label: "Round", source: "app-state", valuePath: "round.index", format: "number", a11yLabel: "round index" },
|
|
101
|
+
{ kind: "aura-game-hud-binding", owner: "app", binding: "debug-toggle", id: "hud:debug:toggle", label: "Runtime evidence", source: "app-state", valuePath: "debug.visible", format: "boolean", a11yLabel: "runtime evidence toggle", debugOnly: true }
|
|
102
|
+
] as const;
|
|
98
103
|
|
|
99
104
|
const accessibilitySources = [
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
{
|
|
106
|
+
kind: "aura-game-accessibility-source", feature: "label", id: "a11y:hud:label", owner: "app",
|
|
102
107
|
label: "Live fighting game HUD with health, timer, stage, assets, and replay status.",
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
108
|
+
targetId: "hud", role: "status", actions: [], source: "dom",
|
|
109
|
+
evidence: "App owns an aria-live label for this gameplay target."
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
kind: "aura-game-accessibility-source", feature: "focus", id: "a11y:hud-controls:focus", owner: "app",
|
|
113
|
+
label: "HUD controls", targetId: "hud-controls",
|
|
114
|
+
actions: ["#hud-replay-button", "#hud-pause-button"], source: "dom",
|
|
115
|
+
evidence: "Focus is scoped to the replay and pause controls."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
kind: "aura-game-accessibility-source", feature: "reduced-motion", id: "a11y:reduced-motion", owner: "app",
|
|
119
|
+
label: "reduced motion", actions: [], source: "media-query",
|
|
120
|
+
evidence: reducedMotion ? "prefers-reduced-motion is enabled." : "prefers-reduced-motion is not set."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
kind: "aura-game-accessibility-source", feature: "reduced-flash", id: "a11y:reduced-flash", owner: "app",
|
|
124
|
+
label: "reduced flash", actions: [], source: "media-query",
|
|
125
|
+
evidence: reducedFlash ? "Reduced flash enabled via reduced-motion preference." : "Reduced flash not required."
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
kind: "aura-game-accessibility-source", feature: "high-contrast", id: "a11y:high-contrast", owner: "app",
|
|
129
|
+
label: "high contrast", actions: [], source: "media-query",
|
|
130
|
+
evidence: highContrast ? "prefers-contrast: more is enabled." : "prefers-contrast: more is not set."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
kind: "aura-game-accessibility-source", feature: "pause-controls", id: "a11y:pause-controls", owner: "app",
|
|
134
|
+
label: "pause controls", targetId: "hud-controls",
|
|
135
|
+
actions: ["pause", "Escape"], source: "app-state",
|
|
136
|
+
evidence: "Pause/resume through the pause action or Escape; resume via pause or Enter."
|
|
137
|
+
}
|
|
138
|
+
] as const;
|
|
119
139
|
|
|
120
140
|
const inputOptions = {
|
|
121
141
|
actions: {
|
|
@@ -129,29 +149,65 @@ const inputOptions = {
|
|
|
129
149
|
gamepad: true
|
|
130
150
|
} as const;
|
|
131
151
|
|
|
152
|
+
const LOOK_ID = "arena-fight" as const;
|
|
132
153
|
const arena = scene()
|
|
133
|
-
|
|
154
|
+
// The arena-fight look supplies the interior-industrial backdrop, key light,
|
|
155
|
+
// haze and post grade; only the accent rim spot rides on top of it.
|
|
156
|
+
.add(looks.preset(LOOK_ID))
|
|
134
157
|
.addMany(fightingStage.nodes)
|
|
135
|
-
//
|
|
136
|
-
//
|
|
158
|
+
// Both library rigs are metre-scale humanoids (~1.8 m) matched to the 1.7 m
|
|
159
|
+
// fighter colliders — full scale for both, no per-model correction needed.
|
|
137
160
|
.add(createFighterNode("player", PLAYER_FIGHTER_ASSET, "Player fighter", playerStart, 1, "#45f5bb", typedFighterAssets, 1))
|
|
138
|
-
.add(createFighterNode("rival", RIVAL_FIGHTER_ASSET, "Rival fighter", rivalStart, -1, "#ffca5f", typedFighterAssets,
|
|
161
|
+
.add(createFighterNode("rival", RIVAL_FIGHTER_ASSET, "Rival fighter", rivalStart, -1, "#ffca5f", typedFighterAssets, 1))
|
|
139
162
|
.addMany([
|
|
140
163
|
effects.bloom({ intensity: 0.32 }),
|
|
141
|
-
lights.studio({ intensity: 1.15 }),
|
|
142
164
|
lights.directional({ name: "rim light", color: "#80ffd4", intensity: 0.7 }).position(0, 4, 3)
|
|
143
165
|
])
|
|
144
166
|
.camera(camera.perspective({ position: [0, 1.75, 5.8], target: [0, 0.85, 0], fov: 42 }));
|
|
145
167
|
|
|
146
|
-
const
|
|
147
|
-
|
|
168
|
+
const fightingGame = createGame({
|
|
169
|
+
id: "fighting-game",
|
|
170
|
+
target: "#app",
|
|
171
|
+
autoStart: true,
|
|
172
|
+
diagnostics: { overlay: false, performancePanel: false },
|
|
148
173
|
input: inputOptions,
|
|
149
174
|
loop: { fixedDt: 1 / 60 },
|
|
150
|
-
scene: arena
|
|
175
|
+
scene: () => arena,
|
|
176
|
+
hud: { theme: "fighting", widgets: [] },
|
|
177
|
+
touch: {
|
|
178
|
+
preset: "dpad-4btn",
|
|
179
|
+
bindings: { left: "left", right: "right", block: "guard", light: "light", heavy: "heavy", special: "special", jump: "jump" }
|
|
180
|
+
},
|
|
181
|
+
sound: {
|
|
182
|
+
cues: {
|
|
183
|
+
hit: { id: "hit", asset: { url: sfxUrl("impact.flesh.medium.00") }, volume: 0.7 },
|
|
184
|
+
blocked: { id: "blocked", asset: { url: sfxUrl("impact.metal.light.00") }, volume: 0.6 },
|
|
185
|
+
special: { id: "special", asset: { url: sfxUrl("impact.energy.heavy.00") }, volume: 0.8 },
|
|
186
|
+
dash: { id: "dash", asset: { url: sfxUrl("vehicle.boost") }, volume: 0.35 },
|
|
187
|
+
"replay-start": { id: "replay-start", asset: { url: sfxUrl("ui.confirm.00") }, volume: 0.5 }
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
juice: {
|
|
191
|
+
hit: { hitStop: 0.045, shake: 0.32, punch: { fovDeg: 1.8, ms: 160 }, rumble: { strong: 0.5, ms: 140 } },
|
|
192
|
+
blocked: { shake: 0.14, rumble: { weak: 0.4, ms: 100 } },
|
|
193
|
+
special: { hitStop: 0.06, punch: { fovDeg: 2.4, ms: 260 }, flash: { color: "#45f5bb", peak: 0.2, ms: 240 }, rumble: { strong: 0.7, ms: 260 } },
|
|
194
|
+
dash: { punch: { fovDeg: 1.1, ms: 120 } }
|
|
195
|
+
},
|
|
196
|
+
qualityRebuild: { flags: ["game"] },
|
|
197
|
+
evidence: {
|
|
198
|
+
schema: 1,
|
|
199
|
+
sections: {
|
|
200
|
+
fightingGame: () => ({
|
|
201
|
+
replay: gameWindow.__AURA3D_GAME_REPLAY__ ?? { status: "unbound" },
|
|
202
|
+
debug: gameWindow.__AURA3D_GAME_DEBUG__ ?? { status: "unbound" },
|
|
203
|
+
source: gameWindow.__AURA3D_GAME_SOURCE__ ?? { status: "unbound" }
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
}
|
|
151
207
|
});
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const input =
|
|
208
|
+
const app = fightingGame.app;
|
|
209
|
+
fightingGame.start();
|
|
210
|
+
const input = fightingGame.input;
|
|
155
211
|
if (!input) throw new Error("create-aura3d fighting-game template failed to create runtime-owned input.");
|
|
156
212
|
const replayInput = game.input({ ...inputOptions, autoListen: false, gamepad: false });
|
|
157
213
|
const openingReplay = game.inputReplay(
|
|
@@ -188,6 +244,13 @@ const director = game.cameraDirector({
|
|
|
188
244
|
});
|
|
189
245
|
const playerNode = app.nodes.require("player");
|
|
190
246
|
const rivalNode = app.nodes.require("rival");
|
|
247
|
+
// F-08-1: the fighting rig owns the presented camera — it frames both
|
|
248
|
+
// fighters from the runtime actor positions (flag-off mounts the no-op stub
|
|
249
|
+
// controller; the scene camera spec is the fallback).
|
|
250
|
+
// F-08-2/F-08-5: fighting feel preset + GameFeel attach through app.time.
|
|
251
|
+
app.camera?.use(camera.rigs.fighting({ fighters: ["player", "rival"] }));
|
|
252
|
+
const feel = gameFeel.create({ app, time: app.time });
|
|
253
|
+
app.feel?.preset("fighting");
|
|
191
254
|
const playerAnimation = createFighterAnimationController("player", typedFighterAssets[PLAYER_FIGHTER_ASSET]);
|
|
192
255
|
const rivalAnimation = createFighterAnimationController("rival", typedFighterAssets[RIVAL_FIGHTER_ASSET]);
|
|
193
256
|
|
|
@@ -204,10 +267,13 @@ gameWindow.__AURA3D_GAME_SOURCE__ = {
|
|
|
204
267
|
template: "fighting-game",
|
|
205
268
|
package: "create-aura3d",
|
|
206
269
|
publicEngineApi: true,
|
|
270
|
+
look: { id: LOOK_ID, category: "studio", biome: "interior-industrial" },
|
|
207
271
|
lifecycle: {
|
|
208
|
-
kind:
|
|
209
|
-
usesCreateGameApp:
|
|
210
|
-
|
|
272
|
+
kind: "createGame",
|
|
273
|
+
usesCreateGameApp: false,
|
|
274
|
+
usesCreateGame: true,
|
|
275
|
+
beaconGlobal: "__AURA3D_GAME__",
|
|
276
|
+
evidenceGlobal: "__AURA3D_GAME_EVIDENCE__"
|
|
211
277
|
},
|
|
212
278
|
typedAssetPattern: "src/aura-assets.ts",
|
|
213
279
|
typedAssetKeys: REQUIRED_FIGHTER_ASSETS,
|
|
@@ -239,6 +305,7 @@ let playerClip: FighterClip = "idle";
|
|
|
239
305
|
let rivalClip: FighterClip = "idle";
|
|
240
306
|
|
|
241
307
|
ui.onClick(replayButton, () => {
|
|
308
|
+
void fightingGame.sound?.cue("replay-start");
|
|
242
309
|
replayActive = true;
|
|
243
310
|
replayHitCount = 0;
|
|
244
311
|
replayDriver.reset();
|
|
@@ -248,13 +315,11 @@ ui.onClick(replayButton, () => {
|
|
|
248
315
|
|
|
249
316
|
ui.onClick(pauseButton, () => setPaused(!paused));
|
|
250
317
|
|
|
251
|
-
|
|
318
|
+
app.onFrame(({ dt }) => {
|
|
252
319
|
const activeInput = replayActive ? replayInput : input;
|
|
253
320
|
if (replayActive) {
|
|
254
321
|
replayDriver.step(dt);
|
|
255
322
|
if (replayDriver.snapshot().complete) replayActive = false;
|
|
256
|
-
} else {
|
|
257
|
-
input.update(dt);
|
|
258
323
|
}
|
|
259
324
|
|
|
260
325
|
if (activeInput.pressed("pause")) setPaused(!paused);
|
|
@@ -272,6 +337,8 @@ gameApp.onFrame(({ dt }) => {
|
|
|
272
337
|
if (activeInput.pressed("dash")) {
|
|
273
338
|
playerBody.dash([playerBody.facing, 0, 0], 8);
|
|
274
339
|
runtimeEffects.dashTrail(playerBody.position, { ownerId: "player", intensity: 0.55 });
|
|
340
|
+
fightingGame.juice.fire("dash");
|
|
341
|
+
void fightingGame.sound?.cue("dash");
|
|
275
342
|
}
|
|
276
343
|
|
|
277
344
|
aiCooldown -= dt;
|
|
@@ -294,7 +361,11 @@ gameApp.onFrame(({ dt }) => {
|
|
|
294
361
|
: undefined;
|
|
295
362
|
if (playerAttack) {
|
|
296
363
|
combat.beginAttack("player", playerAttack);
|
|
297
|
-
if (playerAttack.id.includes("special"))
|
|
364
|
+
if (playerAttack.id.includes("special")) {
|
|
365
|
+
runtimeEffects.auraBurst(playerBody.position, { ownerId: "player", intensity: 0.7 });
|
|
366
|
+
fightingGame.juice.fire("special");
|
|
367
|
+
void fightingGame.sound?.cue("special");
|
|
368
|
+
}
|
|
298
369
|
}
|
|
299
370
|
|
|
300
371
|
playerBody.update(dt);
|
|
@@ -313,13 +384,21 @@ gameApp.onFrame(({ dt }) => {
|
|
|
313
384
|
totalHitCount += 1;
|
|
314
385
|
if (replayActive || replayDriver.snapshot().frame > 0) replayHitCount += 1;
|
|
315
386
|
}
|
|
387
|
+
fightingGame.juice.fire(event.type);
|
|
388
|
+
void fightingGame.sound?.cue(event.type);
|
|
389
|
+
// F-08-6: combat outcomes emit on the feel bus — the preset's hitStop
|
|
390
|
+
// spec freezes gameplay through app.time (auto hit-stop).
|
|
391
|
+
app.feel?.emit(event.type === "hit" ? "hit-light" : "block", { strength: event.type === "hit" ? 0.6 : 0.3 });
|
|
316
392
|
if (event.targetId === "player") playerBody.applyKnockback([event.attackerId === "rival" ? -2.2 : 2.2, 1.5, 0]);
|
|
317
393
|
if (event.targetId === "rival") rivalBody.applyKnockback([event.attackerId === "player" ? 2.2 : -2.2, 1.5, 0]);
|
|
318
394
|
}
|
|
319
395
|
}
|
|
320
396
|
|
|
321
397
|
runtimeEffects.update(dt);
|
|
322
|
-
|
|
398
|
+
feel.update(dt * 1000);
|
|
399
|
+
// The fighting rig presents the frame; the director still decays impact
|
|
400
|
+
// impulses queued above so its shake bookkeeping stays bounded.
|
|
401
|
+
director.update(dt, [
|
|
323
402
|
{ id: "player", position: playerBody.position },
|
|
324
403
|
{ id: "rival", position: rivalBody.position }
|
|
325
404
|
]);
|
|
@@ -358,7 +437,6 @@ gameApp.onFrame(({ dt }) => {
|
|
|
358
437
|
ui.setText(hudPlayerMeter, `${Math.round(player.meter)}%`);
|
|
359
438
|
ui.setText(hudRound, `Round 1 - ${Math.ceil(roundTime)}`);
|
|
360
439
|
ui.setText(hudFrame, `Frame ${app.runtime.frame}`);
|
|
361
|
-
ui.setText(hudCamera, `Camera zoom ${cameraFrame.zoom.toFixed(2)}`);
|
|
362
440
|
ui.setText(
|
|
363
441
|
hudAssets,
|
|
364
442
|
missingFighterAssets.length === 0
|
|
@@ -385,7 +463,11 @@ gameApp.onFrame(({ dt }) => {
|
|
|
385
463
|
totalHitCount,
|
|
386
464
|
liveInputEvents: input.recorded()
|
|
387
465
|
};
|
|
388
|
-
gameWindow.__AURA3D_GAME_RUNTIME__ =
|
|
466
|
+
gameWindow.__AURA3D_GAME_RUNTIME__ = {
|
|
467
|
+
kind: "createGame",
|
|
468
|
+
beacon: gameWindow.__AURA3D_GAME__ ?? { state: "unbound" },
|
|
469
|
+
frame: app.runtime.frame
|
|
470
|
+
};
|
|
389
471
|
gameWindow.__AURA3D_GAME_DEBUG__ = game.debug.overlay({
|
|
390
472
|
runtime: app.runtime,
|
|
391
473
|
input: activeInput,
|
|
@@ -423,8 +505,8 @@ function setPaused(next: boolean): void {
|
|
|
423
505
|
paused = next;
|
|
424
506
|
ui.setPressed(pauseButton, paused);
|
|
425
507
|
ui.setText(pauseButton, paused ? "Resume" : "Pause");
|
|
426
|
-
if (paused)
|
|
427
|
-
else
|
|
508
|
+
if (paused) app.pause();
|
|
509
|
+
else app.resume();
|
|
428
510
|
}
|
|
429
511
|
|
|
430
512
|
function syncFighterAnimation(controller: ReturnType<typeof createFighterAnimationController>, clip: FighterClip, dt: number): void {
|
|
@@ -6,38 +6,30 @@ test("input replay produces runtime evidence and a hit declaration", async ({ pa
|
|
|
6
6
|
await page.goto("/");
|
|
7
7
|
await page.waitForFunction(() => Boolean((window as any).__AURA3D_GAME_SOURCE__?.readiness));
|
|
8
8
|
await page.getByRole("button", { name: "Run replay" }).click();
|
|
9
|
-
await page.waitForFunction(() =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
await page.waitForFunction(() => {
|
|
10
|
+
const evidence = (window as any).__AURA3D_GAME_EVIDENCE__;
|
|
11
|
+
const runtime = (window as any).__AURA3D_GAME_RUNTIME__;
|
|
12
|
+
const replay = (window as any).__AURA3D_GAME_REPLAY__;
|
|
13
|
+
const source = (window as any).__AURA3D_GAME_SOURCE__;
|
|
14
|
+
return Boolean(
|
|
15
|
+
runtime?.kind === "createGame" &&
|
|
16
|
+
runtime.frame > 0 &&
|
|
17
|
+
typeof runtime.beacon?.state === "string" &&
|
|
18
|
+
evidence?.systems?.mutableNodes &&
|
|
19
|
+
evidence.systems.inputPlan &&
|
|
20
|
+
evidence.systems.physicsPlan &&
|
|
21
|
+
evidence.systems.collisionPlan &&
|
|
22
|
+
evidence.systems.animationPlan &&
|
|
23
|
+
evidence.systems.effectsPlan &&
|
|
24
|
+
evidence.systems.cameraPlan &&
|
|
25
|
+
evidence.systems.stagePlan &&
|
|
26
|
+
replay?.hitCount > 0 &&
|
|
27
|
+
source?.readiness?.sourceOnly === false &&
|
|
28
|
+
source.readiness.placeholderMode === false &&
|
|
29
|
+
source.readiness.proofMode === "typed-assets" &&
|
|
30
|
+
Array.isArray(source.readiness.missingTypedAssets) &&
|
|
31
|
+
source.readiness.missingTypedAssets.length === 0 &&
|
|
32
|
+
source.readiness.publicEngineApis?.includes("games.fighting.stagePreset")
|
|
33
|
+
);
|
|
24
34
|
});
|
|
25
|
-
expect(runtime.frame).toBeGreaterThan(0);
|
|
26
|
-
expect(runtime.loop.frame).toBeGreaterThan(0);
|
|
27
|
-
expect(evidence.systems.mutableNodes).toBeTruthy();
|
|
28
|
-
expect(evidence.systems.inputPlan).toBeTruthy();
|
|
29
|
-
expect(evidence.systems.physicsPlan).toBeTruthy();
|
|
30
|
-
expect(evidence.systems.collisionPlan).toBeTruthy();
|
|
31
|
-
expect(evidence.systems.animationPlan).toBeTruthy();
|
|
32
|
-
expect(evidence.systems.effectsPlan).toBeTruthy();
|
|
33
|
-
expect(evidence.systems.cameraPlan).toBeTruthy();
|
|
34
|
-
expect(evidence.systems.stagePlan).toBeTruthy();
|
|
35
|
-
expect(replay.hitCount).toBeGreaterThan(0);
|
|
36
|
-
// Certified heroes ship as typed fighter assets (humanoid-a + creature), so
|
|
37
|
-
// the route runs in typed-assets proof mode instead of source placeholders.
|
|
38
|
-
expect(source.readiness.sourceOnly).toBe(false);
|
|
39
|
-
expect(source.readiness.placeholderMode).toBe(false);
|
|
40
|
-
expect(source.readiness.proofMode).toBe("typed-assets");
|
|
41
|
-
expect(source.readiness.missingTypedAssets ?? []).toEqual([]);
|
|
42
|
-
expect(source.readiness.publicEngineApis).toContain("games.fighting.stagePreset");
|
|
43
35
|
});
|
|
@@ -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
|
+
}
|