create-aura3d 2.0.4 → 3.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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1 -1
  3. package/package.json +2 -2
  4. package/templates/animation-channel/package.json +2 -1
  5. package/templates/animation-studio/package.json +3 -2
  6. package/templates/animation-studio/src/scene-player.ts +28 -1
  7. package/templates/character-controller/README.md +1 -1
  8. package/templates/character-controller/aura.assets.json +31 -1
  9. package/templates/character-controller/package.json +5 -4
  10. package/templates/character-controller/public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb +0 -0
  11. package/templates/character-controller/public/aura-assets/showcaseWalkAnimatedGirl.thumb.svg +1 -0
  12. package/templates/character-controller/src/aura-assets.ts +15 -1
  13. package/templates/character-controller/src/main.ts +32 -8
  14. package/templates/character-controller/tests/certified-rig.spec.ts +52 -0
  15. package/templates/cinematic-scene/package.json +2 -1
  16. package/templates/episode-builder/package.json +2 -1
  17. package/templates/falling-blocks-starter/package.json +2 -1
  18. package/templates/fighting-game/README.md +8 -7
  19. package/templates/fighting-game/aura.assets.json +62 -1
  20. package/templates/fighting-game/package.json +3 -2
  21. package/templates/fighting-game/public/aura-assets/showcaseRunnerRobot.252b3a16.glb +0 -0
  22. package/templates/fighting-game/public/aura-assets/showcaseRunnerRobot.thumb.svg +1 -0
  23. package/templates/fighting-game/public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb +0 -0
  24. package/templates/fighting-game/public/aura-assets/showcaseWalkAnimatedGirl.thumb.svg +1 -0
  25. package/templates/fighting-game/src/aura-assets.ts +36 -5
  26. package/templates/fighting-game/src/game/fighters.ts +23 -8
  27. package/templates/fighting-game/src/main.ts +21 -4
  28. package/templates/fighting-game/tests/certified-rig.spec.ts +53 -0
  29. package/templates/fighting-game/tests/gameplay-smoke.spec.ts +6 -1
  30. package/templates/mini-game/aura.assets.json +38 -14
  31. package/templates/mini-game/package.json +2 -2
  32. package/templates/mini-game/public/aura-assets/showcaseKenneyOobiPlatformerHero.3f821141.glb +0 -0
  33. package/templates/mini-game/public/aura-assets/showcaseKenneyOobiPlatformerHero.thumb.svg +1 -0
  34. package/templates/mini-game/src/aura-assets.ts +33 -7
  35. package/templates/mini-game/src/main.ts +40 -5
  36. package/templates/mini-game/tests/certified-rig.spec.ts +40 -0
  37. package/templates/product-viewer/package.json +1 -1
  38. package/templates/product-viewer/src/main.ts +9 -2
  39. package/templates/prompt-animation-channel/package.json +2 -1
  40. package/templates/racing-starter/package.json +2 -1
  41. package/templates/racing-starter/src/main.ts +31 -0
  42. package/templates/three-compat-architecture-interior/package.json +2 -1
  43. package/templates/three-compat-asset-inspector/package.json +2 -1
  44. package/templates/three-compat-character-viewer/package.json +2 -1
  45. package/templates/three-compat-custom-threejs-migration/package.json +2 -1
  46. package/templates/three-compat-large-scene/package.json +2 -1
  47. package/templates/three-compat-material-authoring/package.json +2 -1
  48. package/templates/three-compat-postprocess-scene/package.json +2 -1
  49. package/templates/three-compat-premium-product-viewer/package.json +2 -1
  50. package/templates/mini-game/public/aura-assets/player-fixture.glb +0 -0
  51. package/templates/mini-game/public/aura-assets/player.thumb.svg +0 -8
package/README.md CHANGED
@@ -47,7 +47,7 @@ npx create-aura3d@latest --help
47
47
  - **Static deploys are first-class.** Build output is a browser app you can
48
48
  deploy like any Vite project.
49
49
 
50
- Aura3D 2.0.4 scaffolds pin the packed 2.0.4 dependency graph. The historical
50
+ Aura3D 3.0.0 scaffolds pin the packed 3.0.0 dependency graph. The historical
51
51
  2.0.0 exact-tarball lifecycle receipts remain the 2.0 major-release record:
52
52
  149/149 checks against workspace source and 149/149 checks in clean projects
53
53
  that installed that packed 2.0.0 graph. Those lifecycles cover install, typecheck,
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ export function createA3DProject(options) {
42
42
  const dependencies = { ...(packageJson.dependencies ?? {}) };
43
43
  const auraDependencies = Object.keys(dependencies).filter((name) => name.startsWith("@aura3d/"));
44
44
  if (auraDependencies.length === 0) {
45
- dependencies["@aura3d/engine"] = options.packageVersion ?? "2.0.4";
45
+ dependencies["@aura3d/engine"] = options.packageVersion ?? "3.0.0";
46
46
  }
47
47
  else if (options.packageVersion) {
48
48
  for (const dependency of auraDependencies)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-aura3d",
3
- "version": "2.0.4",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-aura3d": "dist/cli.js"
@@ -54,7 +54,7 @@
54
54
  "main": "./dist/index.js",
55
55
  "types": "./dist/index.d.ts",
56
56
  "dependencies": {
57
- "@aura3d/asset-index": "2.0.4"
57
+ "@aura3d/asset-index": "3.0.0"
58
58
  },
59
59
  "description": "Start real Aura3D browser 3D apps in one command with Vite templates, typed GLB/glTF assets, route-health tests, screenshots, and deploy-ready structure.",
60
60
  "keywords": [
@@ -12,7 +12,8 @@
12
12
  "test:negative-failed-puppets": "playwright test tests/concept-2-5d.spec.ts tests/puppet-2d.spec.ts tests/image-puppet.spec.ts tests/concept-2-5d-animation.spec.ts tests/puppet-2d-animation.spec.ts tests/image-puppet-animation.spec.ts --workers=1"
13
13
  },
14
14
  "dependencies": {
15
- "@aura3d/engine": "2.0.4"
15
+ "@aura3d/engine": "3.0.0",
16
+ "@aura3d/navigation-recast": "3.0.0"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@playwright/test": "^1.52.0",
@@ -16,8 +16,9 @@
16
16
  "preview": "vite preview --host 0.0.0.0"
17
17
  },
18
18
  "dependencies": {
19
- "@aura3d/animation": "2.0.4",
20
- "@aura3d/engine": "2.0.4",
19
+ "@aura3d/animation": "3.0.0",
20
+ "@aura3d/engine": "3.0.0",
21
+ "@aura3d/navigation-recast": "3.0.0",
21
22
  "react": "^18.3.1",
22
23
  "react-dom": "^18.3.1",
23
24
  "sharp": "^0.33.5"
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  import { A3DRenderer, TextureBinding as EngineTextureBinding } from "@aura3d/engine/advanced-runtime";
17
- import { createStudioLighting, createTypedGLBActor, type TypedGLBActor } from "@aura3d/engine/production-runtime";
17
+ import { createPerformanceGovernor, createSideViewGameRenderPreset, createStudioLighting, createTypedGLBActor, type TypedGLBActor } from "@aura3d/engine/production-runtime";
18
18
  import { createCameraPathFromPreset, sampleCameraPath, type CameraPath } from "@aura3d/engine";
19
19
  // I1 clean-room correctness: import the rendering/scene PRIMITIVES from the engine's own subpaths
20
20
  // (`@aura3d/engine/rendering` / `@aura3d/engine/scene`) — the SAME copy the A3DRenderer uses — NOT
@@ -88,6 +88,13 @@ interface LiveRouteSeekProof {
88
88
  * inspectable per-seek (e.g. "miko: talk←talk [extracted] 9 bones / 0.412rad").
89
89
  */
90
90
  readonly debugOverlay: readonly string[];
91
+ /** J3 perf governor snapshot (optional so old capture scripts keep working). */
92
+ readonly governor?: {
93
+ readonly resolutionScale: number;
94
+ readonly particleScale: number;
95
+ readonly lodBias: number;
96
+ readonly shadowSize: number;
97
+ };
91
98
  readonly characters: readonly {
92
99
  readonly id: string;
93
100
  readonly clip: string;
@@ -634,7 +641,15 @@ export async function mountScenePlayer(doc: EpisodeDocument): Promise<void> {
634
641
  };
635
642
 
636
643
  // 8. Pose at episode time `t`, drive camera + lip-sync + world-state, render.
644
+ // J3 perf governor: watches wall-clock frame cost against the side-view game
645
+ // budget and degrades resolution/particles/LOD/shadows in order.
646
+ const governorBudget = createSideViewGameRenderPreset().performanceBudget;
647
+ let governor = createPerformanceGovernor("conservative");
648
+ let lastPoseAtMs = 0;
637
649
  const poseAt = (time: number, options: LiveSeekOptions = {}): LiveRouteSeekProof => {
650
+ const nowMs = performance.now();
651
+ const frameMs = lastPoseAtMs === 0 ? 1000 / 60 : Math.min(250, Math.max(0, nowMs - lastPoseAtMs));
652
+ lastPoseAtMs = nowMs;
638
653
  const shot = shotAtTime(doc, time);
639
654
  const gardenGlow = sampleWorldStateGlow(doc, time);
640
655
  applyWorldGlow(gardenGlow);
@@ -820,11 +835,23 @@ export async function mountScenePlayer(doc: EpisodeDocument): Promise<void> {
820
835
  if (debugOverlayEl && debugOverlayEnabled) {
821
836
  debugOverlayEl.textContent = `t=${time.toFixed(2)}s shot=${shot.shotId}\n${debugOverlay.join("\n")}`;
822
837
  }
838
+ governor = governor.step(
839
+ {
840
+ fps: 1000 / Math.max(1, frameMs),
841
+ frameTimeMs: frameMs,
842
+ draws: diagnostics.drawCalls,
843
+ tris: 0,
844
+ particles: 0,
845
+ shadowBytes: 0
846
+ },
847
+ governorBudget
848
+ );
823
849
  return {
824
850
  time,
825
851
  drawCalls: diagnostics.drawCalls,
826
852
  skinnedRenderItems,
827
853
  gardenGlow,
854
+ governor: { ...governor.settings },
828
855
  shot: {
829
856
  shotId: shot.shotId,
830
857
  presetId: String(shot.presetId),
@@ -32,7 +32,7 @@ npm run enable:physics
32
32
  ```
33
33
 
34
34
  The script executes
35
- `npm install @aura3d/physics@2.0.4 @aura3d/physics-rapier@2.0.4`, so the
35
+ `npm install @aura3d/physics@3.0.0 @aura3d/physics-rapier@3.0.0`, so the
36
36
  large asynchronous physical backend is added only when this physical capsule
37
37
  path is selected and never enters the default kinematic scaffold transitively.
38
38
 
@@ -3,5 +3,35 @@
3
3
  "assetBasePath": "/aura-assets/",
4
4
  "outputDir": "public/aura-assets",
5
5
  "typegen": "src/aura-assets.ts",
6
- "assets": []
6
+ "assets": [
7
+ {
8
+ "id": "showcaseWalkAnimatedGirl",
9
+ "type": "model",
10
+ "format": "glb",
11
+ "source": "public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
12
+ "outputPath": "public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
13
+ "url": "/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
14
+ "hash": "sha256-93872fc24240a071b6195d6f1339f40b09b3308dc998311252d21ebd9042d8c6",
15
+ "sizeBytes": 3791152,
16
+ "bounds": [
17
+ 86.929,
18
+ 161.836,
19
+ 37.758
20
+ ],
21
+ "materials": [
22
+ "material_0",
23
+ "material_1",
24
+ "material_0_0",
25
+ "material_0_1",
26
+ "material_0_2",
27
+ "material_0_3",
28
+ "material_0_4"
29
+ ],
30
+ "animations": [
31
+ "Take 001"
32
+ ],
33
+ "textures": [],
34
+ "thumbnailUrl": "/aura-assets/showcaseWalkAnimatedGirl.thumb.svg"
35
+ }
36
+ ]
7
37
  }
@@ -5,15 +5,16 @@
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite --host 127.0.0.1",
8
- "enable:physics": "npm install @aura3d/physics@2.0.4 @aura3d/physics-rapier@2.0.4",
8
+ "enable:physics": "npm install @aura3d/physics@3.0.0 @aura3d/physics-rapier@3.0.0",
9
9
  "typecheck": "tsc --noEmit",
10
10
  "build": "npm run typecheck && vite build",
11
11
  "preview": "vite preview --host 127.0.0.1",
12
- "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
+ "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts tests/certified-rig.spec.ts --workers=1"
13
13
  },
14
14
  "dependencies": {
15
- "@aura3d/animation": "2.0.4",
16
- "@aura3d/engine": "2.0.4"
15
+ "@aura3d/animation": "3.0.0",
16
+ "@aura3d/engine": "3.0.0",
17
+ "@aura3d/navigation-recast": "3.0.0"
17
18
  },
18
19
  "devDependencies": {
19
20
  "@playwright/test": "^1.52.0",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180"><rect width="320" height="180" fill="#101720"/><path d="M80 126 160 46l80 80-80 28z" fill="#77a7ff"/><text x="160" y="160" text-anchor="middle" font-family="Arial" font-size="18" fill="#f4f7fb">showcaseWalkAnimatedGirl 86.929x161.836x37.758</text></svg>
@@ -1,3 +1,17 @@
1
1
  import { defineAuraAssets } from "@aura3d/engine";
2
2
 
3
- export const assets = defineAuraAssets({} as const);
3
+ export const assets = defineAuraAssets({
4
+ showcaseWalkAnimatedGirl: {
5
+ type: "model",
6
+ format: "glb",
7
+ url: "/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
8
+ bounds: [86.929, 161.836, 37.758],
9
+ hash: "sha256-93872fc24240a071b6195d6f1339f40b09b3308dc998311252d21ebd9042d8c6",
10
+ metadata: {
11
+ materials: ["material_0", "material_1", "material_0_0", "material_0_1", "material_0_2", "material_0_3", "material_0_4"],
12
+ animations: ["Take 001"],
13
+ textures: [],
14
+ thumbnailUrl: "/aura-assets/showcaseWalkAnimatedGirl.thumb.svg"
15
+ }
16
+ }
17
+ } as const);
@@ -1,8 +1,10 @@
1
1
  // Character controller preview: keyboard input -> kinematic speed -> @aura3d/animation locomotion
2
2
  // kit (idle/walk/run blended by speed) -> live proof object. Hold a direction key (W/A/S/D or
3
3
  // arrows) to walk; hold Shift to run. A minimal Aura3D stage renders beneath the HUD.
4
- import { camera, createAuraApp, lights, material, primitives, scene } from "@aura3d/engine";
4
+ import { camera, createAuraApp, lights, material, model, primitives, scene } from "@aura3d/engine";
5
+ import { createPerformanceGovernor, createTopDownGameRenderPreset } from "@aura3d/engine/production-runtime";
5
6
  import { createLocomotionKit } from "@aura3d/animation";
7
+ import { assets } from "./aura-assets.js";
6
8
  import { defaultCharacterControllerTuning, stepCharacterSpeed, type CharacterControllerState } from "./controller.js";
7
9
 
8
10
  interface CharacterControllerProof {
@@ -11,6 +13,9 @@ interface CharacterControllerProof {
11
13
  moving: boolean;
12
14
  running: boolean;
13
15
  clipWeights: ReadonlyArray<{ clip: string; weight: number }>;
16
+ hero: { readonly assetId: string; readonly url: string; readonly clip: string };
17
+ debugDraw: boolean;
18
+ governor: { readonly resolutionScale: number; readonly particleScale: number; readonly lodBias: number; readonly shadowSize: number };
14
19
  }
15
20
 
16
21
  declare global {
@@ -27,14 +32,21 @@ const held = new Set<string>();
27
32
  window.addEventListener("keydown", (event) => held.add(event.code));
28
33
  window.addEventListener("keyup", (event) => held.delete(event.code));
29
34
 
35
+ // J3 scaffold surface: the engine perf governor watches frame cost against the
36
+ // top-down preset budget, and the debug key gates overlay detail in the HUD.
37
+ const governorBudget = createTopDownGameRenderPreset().performanceBudget;
38
+ let governor = createPerformanceGovernor("conservative");
39
+ let debugDraw = false;
40
+
30
41
  const root = document.getElementById("app") ?? document.body;
31
42
  const hud = document.createElement("pre");
32
43
  hud.id = "character-controller-hud";
33
44
  hud.style.cssText = "font:14px monospace;padding:16px;color:#6cf;background:#0c0f16;min-height:140px";
34
45
  root.appendChild(hud);
35
46
 
36
- // Minimal visual stage: a capsule stand-in on a floor so the route renders a real
37
- // Aura3D scene alongside the locomotion HUD proof.
47
+ // Certified hero stage: the E1 humanoid-a rig (showcaseWalkAnimatedGirl, "Take
48
+ // 001") plays its certified clip on a floor so the route renders a real Aura3D
49
+ // scene alongside the locomotion HUD proof.
38
50
  const stage = document.createElement("div");
39
51
  stage.id = "character-controller-stage";
40
52
  stage.style.cssText = "height:320px";
@@ -42,9 +54,9 @@ root.appendChild(stage);
42
54
  createAuraApp(stage, {
43
55
  scene: scene()
44
56
  .background("#0c0f16")
45
- .camera(camera.orbit({ target: [0, 1, 0], distance: 5 }))
57
+ .camera(camera.orbit({ target: [0, 0.8, 0], distance: 3.2 }))
46
58
  .add(primitives.box({ name: "floor", size: [6, 0.1, 6], position: [0, -0.05, 0], material: material.pbr({ color: "#151b27", roughness: 0.9 }), receiveShadow: true }))
47
- .add(primitives.capsule({ name: "character stand-in", size: [0.7, 1.7, 0.7], position: [0, 1.2, 0], material: material.pbr({ color: "#6cb1f0", roughness: 0.5 }), castShadow: true }))
59
+ .add(model(assets.showcaseWalkAnimatedGirl, { name: "certified hero humanoid-a" }).position(0, 0, 0).animate({ clip: "Take 001", loop: true }))
48
60
  .add(lights.ambient({ intensity: 0.35 }))
49
61
  .add(lights.directional({ name: "key", position: [3, 5, 2], intensity: 1.4 }))
50
62
  });
@@ -55,23 +67,35 @@ let last = 0;
55
67
  function frame(time: number): void {
56
68
  const dt = last === 0 ? 1 / 60 : Math.min(0.05, (time - last) / 1000);
57
69
  last = time;
70
+ if (held.has("KeyT")) {
71
+ debugDraw = !debugDraw;
72
+ held.delete("KeyT");
73
+ }
58
74
  const move = [...held].some((code) => moveKeys.has(code));
59
75
  const run = held.has("ShiftLeft") || held.has("ShiftRight");
60
76
  state = stepCharacterSpeed(state, { move, run }, dt, tuning);
61
77
  const sample = kit.sample(state.speed, dt);
78
+ governor = governor.step(
79
+ { fps: 1 / Math.max(1 / 240, dt), frameTimeMs: dt * 1000, draws: 0, tris: 0, particles: 0, shadowBytes: 0 },
80
+ governorBudget
81
+ );
62
82
  const proof: CharacterControllerProof = {
63
83
  speed: Number(state.speed.toFixed(3)),
64
84
  state: sample.state,
65
85
  moving: sample.moving,
66
86
  running: sample.running,
67
- clipWeights: sample.clipWeights.map((w) => ({ clip: w.clip, weight: Number(w.weight.toFixed(3)) }))
87
+ clipWeights: sample.clipWeights.map((w) => ({ clip: w.clip, weight: Number(w.weight.toFixed(3)) })),
88
+ hero: { assetId: assets.showcaseWalkAnimatedGirl.id, url: assets.showcaseWalkAnimatedGirl.url, clip: "Take 001" },
89
+ debugDraw,
90
+ governor: { ...governor.settings }
68
91
  };
69
92
  window.__AURA3D_CHARACTER_CONTROLLER_PROOF__ = proof;
70
93
  hud.textContent = [
71
- "Aura3D Character Controller — hold W/A/S/D (Shift = run)",
94
+ "Aura3D Character Controller — hold W/A/S/D (Shift = run, T = debug)",
72
95
  `speed: ${proof.speed}`,
73
96
  `state: ${proof.state}`,
74
- `clips: ${proof.clipWeights.map((w) => `${w.clip} ${w.weight}`).join(" ")}`
97
+ `clips: ${proof.clipWeights.map((w) => `${w.clip} ${w.weight}`).join(" ")}`,
98
+ ...(debugDraw ? [`governor: res ${proof.governor.resolutionScale} lod ${proof.governor.lodBias} shadow ${proof.governor.shadowSize}`] : [])
75
99
  ].join("\n");
76
100
  requestAnimationFrame(frame);
77
101
  }
@@ -0,0 +1,52 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { expect, test } from "@playwright/test";
5
+
6
+ test.setTimeout(60_000);
7
+
8
+ /**
9
+ * E1 certified-rig mount proof for the character-controller template.
10
+ *
11
+ * The template hero must be one of the E1-certified hero rigs
12
+ * (docs/rendering/skinning-and-morphs.md "Certified hero rigs") — currently
13
+ * the humanoid-a slot: showcaseWalkAnimatedGirl / "Take 001". The mounted
14
+ * asset id AND url assert against that roster; a capsule/placeholder swap
15
+ * regresses this spec instead of silently shipping an uncertified hero.
16
+ *
17
+ * No raw GLB URL literal lives in this file (public-example-boundary): the
18
+ * expected url is read from the template's own generated typed assets.
19
+ */
20
+ const CERTIFIED_ROSTER = ["showcaseWalkAnimatedGirl"] as const;
21
+ function certifiedHeroFromTypedAssets(): { assetId: string; url: string; clip: string } {
22
+ const source = readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "src", "aura-assets.ts"), "utf8");
23
+ for (const assetId of CERTIFIED_ROSTER) {
24
+ const pattern = new RegExp(`${assetId}:([\\s\\S]*?)\\n \\},?\\n`);
25
+ const block = pattern.exec(source)?.[1] ?? "";
26
+ const url = /url:\s*"([^"]+)"/.exec(block)?.[1];
27
+ if (url) return { assetId, url, clip: "Take 001" };
28
+ }
29
+ throw new Error(`no certified-roster hero declared in the template typed assets (roster: ${CERTIFIED_ROSTER.join(", ")})`);
30
+ }
31
+ const CERTIFIED_HERO = certifiedHeroFromTypedAssets();
32
+
33
+ test("character-controller hero mounts the certified humanoid-a rig", async ({ page }) => {
34
+ const errors: string[] = [];
35
+ page.on("pageerror", (error) => errors.push(error.message));
36
+
37
+ await page.goto("/");
38
+ await page.waitForFunction(
39
+ () => Boolean((window as unknown as { __AURA3D_CHARACTER_CONTROLLER_PROOF__?: unknown }).__AURA3D_CHARACTER_CONTROLLER_PROOF__),
40
+ undefined,
41
+ { timeout: 45_000 }
42
+ );
43
+ const hero = await page.evaluate(
44
+ () =>
45
+ (window as unknown as { __AURA3D_CHARACTER_CONTROLLER_PROOF__?: { readonly hero?: { readonly assetId?: string; readonly url?: string; readonly clip?: string } } })
46
+ .__AURA3D_CHARACTER_CONTROLLER_PROOF__?.hero
47
+ );
48
+ expect(hero?.assetId).toBe(CERTIFIED_HERO.assetId);
49
+ expect(hero?.url).toBe(CERTIFIED_HERO.url);
50
+ expect(hero?.clip).toBe(CERTIFIED_HERO.clip);
51
+ expect(errors).toEqual([]);
52
+ });
@@ -11,7 +11,8 @@
11
11
  "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "2.0.4"
14
+ "@aura3d/engine": "3.0.0",
15
+ "@aura3d/navigation-recast": "3.0.0"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@playwright/test": "^1.52.0",
@@ -11,7 +11,8 @@
11
11
  "test": "playwright test tests/route-health.spec.ts tests/storyboard-playback.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "2.0.4"
14
+ "@aura3d/engine": "3.0.0",
15
+ "@aura3d/navigation-recast": "3.0.0"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@playwright/test": "^1.52.0",
@@ -11,7 +11,8 @@
11
11
  "test": "playwright test tests/playable.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "2.0.4"
14
+ "@aura3d/engine": "3.0.0",
15
+ "@aura3d/navigation-recast": "3.0.0"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@types/node": "^22.15.30",
@@ -22,11 +22,12 @@ This template demonstrates Aura3D's public game runtime APIs:
22
22
  - `src/game/stage.ts` owns `games.fighting` stage helpers, touch controls, debug colliders, and route/build readiness declarations.
23
23
  - `src/aura-assets.ts` is the typed asset manifest generated by the Aura3D CLI.
24
24
 
25
- The scaffold does not ship invented fighter GLBs or raw model URLs. It starts
26
- with Aura3D runtime-node source placeholders so the route is playable and the
27
- combat systems are inspectable. Add real fighter assets through the Aura3D CLI
28
- to switch the placeholders to typed `model(assets.playerFighter)` and
29
- `model(assets.rivalFighter)` nodes automatically.
25
+ The scaffold ships two E1-certified hero rigs as its fighters (no invented
26
+ GLBs or raw model URLs): `model(assets.showcaseWalkAnimatedGirl)` (player,
27
+ humanoid-a) and `model(assets.showcaseRunnerRobot)` (rival, creature). If the
28
+ typed assets are ever removed, the route falls back to Aura3D runtime-node
29
+ source placeholders so it stays playable and the combat systems stay
30
+ inspectable.
30
31
 
31
32
  Controls:
32
33
 
@@ -44,8 +45,8 @@ Add fighter assets:
44
45
 
45
46
  ```bash
46
47
  npx @aura3d/cli@latest assets search "animated humanoid fighting character" --profile fighting-character --json
47
- npx @aura3d/cli@latest assets resolve "animated humanoid fighting character" --name playerFighter --profile fighting-character
48
- npx @aura3d/cli@latest assets resolve "animated humanoid fighting character" --name rivalFighter --profile fighting-character
48
+ npx @aura3d/cli@latest assets resolve "animated humanoid fighting character" --name showcaseWalkAnimatedGirl --profile fighting-character
49
+ npx @aura3d/cli@latest assets resolve "animated creature fighting character" --name showcaseRunnerRobot --profile fighting-character
49
50
  ```
50
51
 
51
52
  The CLI writes typed definitions to `src/aura-assets.ts`. The starter imports
@@ -3,5 +3,66 @@
3
3
  "assetBasePath": "/aura-assets/",
4
4
  "outputDir": "public/aura-assets",
5
5
  "typegen": "src/aura-assets.ts",
6
- "assets": []
6
+ "assets": [
7
+ {
8
+ "id": "showcaseWalkAnimatedGirl",
9
+ "type": "model",
10
+ "format": "glb",
11
+ "source": "public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
12
+ "outputPath": "public/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
13
+ "url": "/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
14
+ "hash": "sha256-93872fc24240a071b6195d6f1339f40b09b3308dc998311252d21ebd9042d8c6",
15
+ "sizeBytes": 3791152,
16
+ "bounds": [
17
+ 86.929,
18
+ 161.836,
19
+ 37.758
20
+ ],
21
+ "materials": [
22
+ "material_0",
23
+ "material_1",
24
+ "material_0_0",
25
+ "material_0_1",
26
+ "material_0_2",
27
+ "material_0_3",
28
+ "material_0_4"
29
+ ],
30
+ "animations": [
31
+ "Take 001"
32
+ ],
33
+ "textures": [],
34
+ "thumbnailUrl": "/aura-assets/showcaseWalkAnimatedGirl.thumb.svg"
35
+ },
36
+ {
37
+ "id": "showcaseRunnerRobot",
38
+ "type": "model",
39
+ "format": "glb",
40
+ "source": "public/aura-assets/showcaseRunnerRobot.252b3a16.glb",
41
+ "outputPath": "public/aura-assets/showcaseRunnerRobot.252b3a16.glb",
42
+ "url": "/aura-assets/showcaseRunnerRobot.252b3a16.glb",
43
+ "hash": "sha256-252b3a16d5a8d7fd67a4304ec8135d4fa492802a31bc2fc2d4614e130a1f4e73",
44
+ "sizeBytes": 5500216,
45
+ "bounds": [
46
+ 17.509,
47
+ 9.101,
48
+ 27.461
49
+ ],
50
+ "materials": [
51
+ "HEAD",
52
+ "EYES",
53
+ "BODY",
54
+ "HINGE",
55
+ "material",
56
+ "material_5"
57
+ ],
58
+ "animations": [
59
+ "IDLE",
60
+ "WALK",
61
+ "RUN",
62
+ "ALL"
63
+ ],
64
+ "textures": [],
65
+ "thumbnailUrl": "/aura-assets/showcaseRunnerRobot.thumb.svg"
66
+ }
67
+ ]
7
68
  }
@@ -8,10 +8,11 @@
8
8
  "typecheck": "tsc --noEmit",
9
9
  "build": "npm run typecheck && vite build",
10
10
  "preview": "vite preview --host 127.0.0.1",
11
- "test": "playwright test tests/route-health.spec.ts tests/gameplay-smoke.spec.ts --workers=1"
11
+ "test": "playwright test tests/route-health.spec.ts tests/gameplay-smoke.spec.ts tests/certified-rig.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "2.0.4"
14
+ "@aura3d/engine": "3.0.0",
15
+ "@aura3d/navigation-recast": "3.0.0"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@playwright/test": "^1.52.0",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180"><rect width="320" height="180" fill="#101720"/><path d="M80 126 160 46l80 80-80 28z" fill="#77a7ff"/><text x="160" y="160" text-anchor="middle" font-family="Arial" font-size="18" fill="#f4f7fb">showcaseRunnerRobot 17.509x14.644x3.963</text></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180"><rect width="320" height="180" fill="#101720"/><path d="M80 126 160 46l80 80-80 28z" fill="#77a7ff"/><text x="160" y="160" text-anchor="middle" font-family="Arial" font-size="18" fill="#f4f7fb">showcaseWalkAnimatedGirl 86.929x161.836x37.758</text></svg>
@@ -2,10 +2,41 @@ import { defineAuraAssets } from "@aura3d/engine";
2
2
 
3
3
  export const assets = defineAuraAssets({
4
4
  /*
5
- * Add your own fighter GLBs with the Aura3D CLI, then keep these generated
6
- * keys so src/main.ts can switch from source placeholders to typed models:
5
+ * Certified E1 hero rigs ship as the default fighters (see
6
+ * docs/rendering/skinning-and-morphs.md "Certified hero rigs"):
7
+ * - player: showcaseWalkAnimatedGirl (humanoid-a) / "Take 001"
8
+ * - rival: showcaseRunnerRobot (creature) / "WALK"
7
9
  *
8
- * npx @aura3d/cli@latest assets add ./assets/player-fighter.glb --name playerFighter
9
- * npx @aura3d/cli@latest assets add ./assets/rival-fighter.glb --name rivalFighter
10
+ * Swap in your own fighter GLBs with the Aura3D CLI and keep these keys so
11
+ * src/main.ts keeps mounting typed models instead of source placeholders:
12
+ *
13
+ * npx @aura3d/cli@latest assets add ./assets/player-fighter.glb --name showcaseWalkAnimatedGirl
14
+ * npx @aura3d/cli@latest assets add ./assets/rival-fighter.glb --name showcaseRunnerRobot
10
15
  */
11
- });
16
+ showcaseWalkAnimatedGirl: {
17
+ type: "model",
18
+ format: "glb",
19
+ url: "/aura-assets/showcaseWalkAnimatedGirl.93872fc2.glb",
20
+ bounds: [86.929, 161.836, 37.758],
21
+ hash: "sha256-93872fc24240a071b6195d6f1339f40b09b3308dc998311252d21ebd9042d8c6",
22
+ metadata: {
23
+ materials: ["material_0", "material_1", "material_0_0", "material_0_1", "material_0_2", "material_0_3", "material_0_4"],
24
+ animations: ["Take 001"],
25
+ textures: [],
26
+ thumbnailUrl: "/aura-assets/showcaseWalkAnimatedGirl.thumb.svg"
27
+ }
28
+ },
29
+ showcaseRunnerRobot: {
30
+ type: "model",
31
+ format: "glb",
32
+ url: "/aura-assets/showcaseRunnerRobot.252b3a16.glb",
33
+ bounds: [17.509, 9.101, 27.461],
34
+ hash: "sha256-252b3a16d5a8d7fd67a4304ec8135d4fa492802a31bc2fc2d4614e130a1f4e73",
35
+ metadata: {
36
+ materials: ["HEAD", "EYES", "BODY", "HINGE", "material", "material_5"],
37
+ animations: ["IDLE", "WALK", "RUN", "ALL"],
38
+ textures: [],
39
+ thumbnailUrl: "/aura-assets/showcaseRunnerRobot.thumb.svg"
40
+ }
41
+ }
42
+ } as const);