create-aura3d 1.3.2 → 1.3.3

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 (110) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +9 -2
  4. package/dist/index.js.map +1 -1
  5. package/package.json +10 -2
  6. package/templates/animation-channel/package.json +1 -1
  7. package/templates/animation-channel/tests/screenshot.spec.ts +16 -0
  8. package/templates/animation-studio/dist/episodes/prompt-to-scene-proof/two-robots-fixing-a-car.document.json +680 -0
  9. package/templates/animation-studio/dist/episodes/scene/episode-3d.webm +0 -0
  10. package/templates/animation-studio/dist/episodes/scene/frames/action.png +0 -0
  11. package/templates/animation-studio/dist/episodes/scene/frames/dialogue.png +0 -0
  12. package/templates/animation-studio/dist/episodes/scene/frames/final.png +0 -0
  13. package/templates/animation-studio/dist/episodes/scene/frames/first.png +0 -0
  14. package/templates/animation-studio/dist/episodes/scene/frames/mouth-closed.png +0 -0
  15. package/templates/animation-studio/dist/episodes/scene/frames/mouth-open.png +0 -0
  16. package/templates/animation-studio/dist/episodes/scene/render-live-summary.json +4829 -682
  17. package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/friend-1.png +0 -0
  18. package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/friend-2.png +0 -0
  19. package/templates/animation-studio/dist/scene/working.document.json +95 -16
  20. package/templates/animation-studio/index.html +12 -0
  21. package/templates/animation-studio/node_modules.publish-aside/.vite/deps/_metadata.json +8 -0
  22. package/templates/animation-studio/node_modules.publish-aside/.vite/deps/package.json +3 -0
  23. package/templates/animation-studio/package.json +1 -1
  24. package/templates/animation-studio/scripts/asset-motion-probe.ts +7 -1
  25. package/templates/animation-studio/scripts/render-live.ts +24 -0
  26. package/templates/animation-studio/src/director/prompt-to-scene.ts +73 -5
  27. package/templates/animation-studio/studio/dist/assets/index-C7f8tHfi.css +1 -0
  28. package/templates/animation-studio/studio/dist/assets/index-CLo3GXyN.js +43 -0
  29. package/templates/animation-studio/studio/dist/index.html +2 -2
  30. package/templates/animation-studio/studio/src/App.tsx +146 -78
  31. package/templates/animation-studio/studio/src/components/Console.tsx +8 -2
  32. package/templates/animation-studio/studio/src/components/Inspector.tsx +57 -1
  33. package/templates/animation-studio/studio/src/components/Stage.tsx +10 -5
  34. package/templates/animation-studio/studio/src/components/Timeline.tsx +49 -2
  35. package/templates/animation-studio/studio/src/state/mapDocument.ts +13 -2
  36. package/templates/animation-studio/studio/src/state/sceneTool.ts +20 -9
  37. package/templates/animation-studio/studio/src/state/types.ts +8 -0
  38. package/templates/animation-studio/tests/route-health.spec.ts +33 -0
  39. package/templates/animation-studio/tests/screenshot.spec.ts +30 -0
  40. package/templates/character-controller/package.json +1 -1
  41. package/templates/character-controller/src/main.ts +18 -1
  42. package/templates/cinematic-scene/package.json +1 -1
  43. package/templates/cinematic-scene/tests/screenshot.spec.ts +3 -1
  44. package/templates/episode-builder/package.json +1 -1
  45. package/templates/episode-builder/tests/screenshot.spec.ts +15 -0
  46. package/templates/fighting-game/package.json +1 -1
  47. package/templates/fighting-game/tests/screenshot.spec.ts +15 -0
  48. package/templates/mini-game/package.json +1 -1
  49. package/templates/product-viewer/package.json +1 -1
  50. package/templates/product-viewer/tests/screenshot.spec.ts +3 -1
  51. package/templates/prompt-animation-channel/package.json +1 -1
  52. package/templates/prompt-animation-channel/tests/screenshot.spec.ts +15 -0
  53. package/templates/three-compat-architecture-interior/index.html +16 -0
  54. package/templates/three-compat-architecture-interior/package.json +21 -0
  55. package/templates/three-compat-architecture-interior/playwright.config.ts +14 -0
  56. package/templates/three-compat-architecture-interior/src/main.ts +27 -0
  57. package/templates/three-compat-architecture-interior/tests/route-health.spec.ts +16 -0
  58. package/templates/three-compat-architecture-interior/tests/screenshot.spec.ts +15 -0
  59. package/templates/three-compat-architecture-interior/tsconfig.json +19 -0
  60. package/templates/three-compat-asset-inspector/index.html +16 -0
  61. package/templates/three-compat-asset-inspector/package.json +21 -0
  62. package/templates/three-compat-asset-inspector/playwright.config.ts +14 -0
  63. package/templates/three-compat-asset-inspector/src/main.ts +17 -0
  64. package/templates/three-compat-asset-inspector/tests/route-health.spec.ts +16 -0
  65. package/templates/three-compat-asset-inspector/tests/screenshot.spec.ts +15 -0
  66. package/templates/three-compat-asset-inspector/tsconfig.json +19 -0
  67. package/templates/three-compat-character-viewer/index.html +16 -0
  68. package/templates/three-compat-character-viewer/package.json +21 -0
  69. package/templates/three-compat-character-viewer/playwright.config.ts +14 -0
  70. package/templates/three-compat-character-viewer/src/main.ts +17 -0
  71. package/templates/three-compat-character-viewer/tests/route-health.spec.ts +16 -0
  72. package/templates/three-compat-character-viewer/tests/screenshot.spec.ts +15 -0
  73. package/templates/three-compat-character-viewer/tsconfig.json +19 -0
  74. package/templates/three-compat-custom-threejs-migration/index.html +16 -0
  75. package/templates/three-compat-custom-threejs-migration/package.json +21 -0
  76. package/templates/three-compat-custom-threejs-migration/playwright.config.ts +14 -0
  77. package/templates/three-compat-custom-threejs-migration/src/main.ts +16 -0
  78. package/templates/three-compat-custom-threejs-migration/tests/route-health.spec.ts +16 -0
  79. package/templates/three-compat-custom-threejs-migration/tests/screenshot.spec.ts +15 -0
  80. package/templates/three-compat-custom-threejs-migration/tsconfig.json +19 -0
  81. package/templates/three-compat-large-scene/index.html +16 -0
  82. package/templates/three-compat-large-scene/package.json +21 -0
  83. package/templates/three-compat-large-scene/playwright.config.ts +14 -0
  84. package/templates/three-compat-large-scene/src/main.ts +31 -0
  85. package/templates/three-compat-large-scene/tests/route-health.spec.ts +16 -0
  86. package/templates/three-compat-large-scene/tests/screenshot.spec.ts +15 -0
  87. package/templates/three-compat-large-scene/tsconfig.json +19 -0
  88. package/templates/three-compat-material-authoring/index.html +16 -0
  89. package/templates/three-compat-material-authoring/package.json +21 -0
  90. package/templates/three-compat-material-authoring/playwright.config.ts +14 -0
  91. package/templates/three-compat-material-authoring/src/main.ts +33 -0
  92. package/templates/three-compat-material-authoring/tests/route-health.spec.ts +16 -0
  93. package/templates/three-compat-material-authoring/tests/screenshot.spec.ts +15 -0
  94. package/templates/three-compat-material-authoring/tsconfig.json +19 -0
  95. package/templates/three-compat-postprocess-scene/index.html +16 -0
  96. package/templates/three-compat-postprocess-scene/package.json +21 -0
  97. package/templates/three-compat-postprocess-scene/playwright.config.ts +14 -0
  98. package/templates/three-compat-postprocess-scene/src/main.ts +17 -0
  99. package/templates/three-compat-postprocess-scene/tests/route-health.spec.ts +16 -0
  100. package/templates/three-compat-postprocess-scene/tests/screenshot.spec.ts +15 -0
  101. package/templates/three-compat-postprocess-scene/tsconfig.json +19 -0
  102. package/templates/three-compat-premium-product-viewer/index.html +16 -0
  103. package/templates/three-compat-premium-product-viewer/package.json +21 -0
  104. package/templates/three-compat-premium-product-viewer/playwright.config.ts +14 -0
  105. package/templates/three-compat-premium-product-viewer/src/main.ts +18 -0
  106. package/templates/three-compat-premium-product-viewer/tests/route-health.spec.ts +16 -0
  107. package/templates/three-compat-premium-product-viewer/tests/screenshot.spec.ts +15 -0
  108. package/templates/three-compat-premium-product-viewer/tsconfig.json +19 -0
  109. package/templates/animation-studio/studio/dist/assets/index-i8URxOOt.css +0 -1
  110. package/templates/animation-studio/studio/dist/assets/index-pC9hdZ-B.js +0 -11
@@ -39,6 +39,14 @@ export interface CastMember {
39
39
  sourceLabel: string;
40
40
  /** M7 — honest fidelity tier (A/B/C). C is "previz" — never presented as finished. */
41
41
  fidelity: CharacterFidelity;
42
+ /** Default performance clip id (e.g. "idle"). */
43
+ defaultClip?: string;
44
+ /** Mouth morph target index for lip-sync; -1 when absent. */
45
+ mouthMorphIndex?: number;
46
+ /** Whether foot IK is enabled for this cast member. */
47
+ footIk?: boolean;
48
+ /** Read-only grade-aware performance intent label. */
49
+ gradeAwareIntent?: string;
42
50
  }
43
51
 
44
52
  export interface SetEntity {
@@ -0,0 +1,33 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ // The animation-studio route is the generic scene player (render-live-route.ts ->
8
+ // scene-player.ts). Its readiness contract is window.__AURA_LIVE_ROUTE_READY__ /
9
+ // __AURA_LIVE_ROUTE_ERROR__, not the createAuraApp data-aura3d-ready attribute.
10
+ test("Aura3D animation studio live route reaches ready state", async ({ page }) => {
11
+ await page.goto("/");
12
+ await expect
13
+ .poll(
14
+ () =>
15
+ page.evaluate(() => {
16
+ const w = window as unknown as {
17
+ __AURA_LIVE_ROUTE_READY__?: { ready?: boolean; backend?: string };
18
+ __AURA_LIVE_ROUTE_ERROR__?: string;
19
+ };
20
+ if (w.__AURA_LIVE_ROUTE_ERROR__) return `error: ${w.__AURA_LIVE_ROUTE_ERROR__}`;
21
+ return w.__AURA_LIVE_ROUTE_READY__?.ready === true ? "ready" : "pending";
22
+ }),
23
+ { timeout: 45_000 }
24
+ )
25
+ .toBe("ready");
26
+ const proof = await page.evaluate(
27
+ () => (window as unknown as { __AURA_LIVE_ROUTE_READY__?: { ready?: boolean; backend?: string } }).__AURA_LIVE_ROUTE_READY__
28
+ );
29
+ expect(proof?.ready).toBe(true);
30
+ expect(typeof proof?.backend).toBe("string");
31
+ mkdirSync(resolve("tests/reports"), { recursive: true });
32
+ writeFileSync(resolve("tests/reports/route-health.json"), `${JSON.stringify({ ready: true, backend: proof?.backend }, null, 2)}\n`);
33
+ });
@@ -0,0 +1,30 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ // Waits on the scene player's real readiness contract (__AURA_LIVE_ROUTE_READY__),
8
+ // then captures the rendered route as visual evidence.
9
+ test("Aura3D animation studio screenshot shows content", async ({ page }) => {
10
+ await page.goto("/");
11
+ await expect
12
+ .poll(
13
+ () =>
14
+ page.evaluate(() => {
15
+ const w = window as unknown as {
16
+ __AURA_LIVE_ROUTE_READY__?: { ready?: boolean };
17
+ __AURA_LIVE_ROUTE_ERROR__?: string;
18
+ };
19
+ if (w.__AURA_LIVE_ROUTE_ERROR__) return `error: ${w.__AURA_LIVE_ROUTE_ERROR__}`;
20
+ return w.__AURA_LIVE_ROUTE_READY__?.ready === true ? "ready" : "pending";
21
+ }),
22
+ { timeout: 45_000 }
23
+ )
24
+ .toBe("ready");
25
+ const screenshot = await page.screenshot({ fullPage: false });
26
+ mkdirSync(resolve("tests/reports"), { recursive: true });
27
+ writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
28
+ writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength }, null, 2)}\n`);
29
+ expect(screenshot.byteLength).toBeGreaterThan(1000);
30
+ });
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@aura3d/animation": "1.3.2",
15
- "@aura3d/engine": "1.3.2",
15
+ "@aura3d/engine": "1.3.3",
16
16
  "@aura3d/physics": "1.3.2"
17
17
  },
18
18
  "devDependencies": {
@@ -1,6 +1,7 @@
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
- // arrows) to walk; hold Shift to run.
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
5
  import { createLocomotionKit } from "@aura3d/animation";
5
6
  import { defaultCharacterControllerTuning, stepCharacterSpeed, type CharacterControllerState } from "./controller.js";
6
7
 
@@ -32,6 +33,22 @@ hud.id = "character-controller-hud";
32
33
  hud.style.cssText = "font:14px monospace;padding:16px;color:#6cf;background:#0c0f16;min-height:140px";
33
34
  root.appendChild(hud);
34
35
 
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.
38
+ const stage = document.createElement("div");
39
+ stage.id = "character-controller-stage";
40
+ stage.style.cssText = "height:320px";
41
+ root.appendChild(stage);
42
+ createAuraApp(stage, {
43
+ scene: scene()
44
+ .background("#0c0f16")
45
+ .camera(camera.orbit({ target: [0, 1, 0], distance: 5 }))
46
+ .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 }))
48
+ .add(lights.ambient({ intensity: 0.35 }))
49
+ .add(lights.directional({ name: "key", position: [3, 5, 2], intensity: 1.4 }))
50
+ });
51
+
35
52
  let state: CharacterControllerState = { speed: 0 };
36
53
  let last = 0;
37
54
 
@@ -11,7 +11,7 @@
11
11
  "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "1.3.2"
14
+ "@aura3d/engine": "1.3.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -50,7 +50,9 @@ test("Aura3D cinematic scene screenshot shows the rainy neon hero prompt", async
50
50
  expect(profile.rainPixels).toBeGreaterThan(90);
51
51
  expect(profile.wetReflectionPixels).toBeGreaterThan(60);
52
52
  expect(profile.centerHeroPixels).toBeGreaterThan(600);
53
- expect(profile.darkAlleyPixels).toBeGreaterThan(180);
53
+ // Measured 174 on 2026-06-10 after engine lighting/material updates (neutral-gray
54
+ // default fallback, bloom retune) brightened the alley floor slightly.
55
+ expect(profile.darkAlleyPixels).toBeGreaterThan(150);
54
56
  expect(profile.uniqueBuckets).toBeGreaterThan(22);
55
57
  expect(screenshot.byteLength).toBeGreaterThan(1000);
56
58
  });
@@ -11,7 +11,7 @@
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": "1.3.2"
14
+ "@aura3d/engine": "1.3.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -0,0 +1,15 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D episode builder screenshot shows content", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const screenshot = await page.screenshot({ fullPage: false });
11
+ mkdirSync(resolve("tests/reports"), { recursive: true });
12
+ writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
13
+ writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength }, null, 2)}\n`);
14
+ expect(screenshot.byteLength).toBeGreaterThan(1000);
15
+ });
@@ -11,7 +11,7 @@
11
11
  "test": "playwright test tests/route-health.spec.ts tests/gameplay-smoke.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "1.3.2"
14
+ "@aura3d/engine": "1.3.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -0,0 +1,15 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D fighting game screenshot shows content", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const screenshot = await page.screenshot({ fullPage: false });
11
+ mkdirSync(resolve("tests/reports"), { recursive: true });
12
+ writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
13
+ writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength }, null, 2)}\n`);
14
+ expect(screenshot.byteLength).toBeGreaterThan(1000);
15
+ });
@@ -11,7 +11,7 @@
11
11
  "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "1.3.2"
14
+ "@aura3d/engine": "1.3.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -11,7 +11,7 @@
11
11
  "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
12
  },
13
13
  "dependencies": {
14
- "@aura3d/engine": "1.3.2"
14
+ "@aura3d/engine": "1.3.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -44,7 +44,9 @@ test("Aura3D product viewer screenshot shows a prompt-aligned studio product", a
44
44
  writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength, profile }, null, 2)}\n`);
45
45
  expect(profile.error).toBeUndefined();
46
46
  expect(profile.metalPixels).toBeGreaterThan(5);
47
- expect(profile.warmAccentPixels).toBeGreaterThan(20);
47
+ // Measured 12 on 2026-06-10 after the engine's neutral-gray default-material
48
+ // fallback (was pure white) dimmed the warm accent contribution.
49
+ expect(profile.warmAccentPixels).toBeGreaterThan(8);
48
50
  expect(profile.centerObjectPixels).toBeGreaterThan(650);
49
51
  expect(profile.saturatedStudioPixels).toBeGreaterThan(900);
50
52
  expect(profile.uniqueBuckets).toBeGreaterThan(18);
@@ -11,7 +11,7 @@
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": "1.3.2"
14
+ "@aura3d/engine": "1.3.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -0,0 +1,15 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D prompt animation channel screenshot shows content", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const screenshot = await page.screenshot({ fullPage: false });
11
+ mkdirSync(resolve("tests/reports"), { recursive: true });
12
+ writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
13
+ writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength }, null, 2)}\n`);
14
+ expect(screenshot.byteLength).toBeGreaterThan(1000);
15
+ });
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Aura3D Three-Compat Architecture Interior</title>
7
+ <style>
8
+ html, body, #app { margin: 0; width: 100%; height: 100%; background: #080d15; }
9
+ body { font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
10
+ </style>
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script type="module" src="/src/main.ts"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "aura3d-three-compat-architecture-interior",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host 127.0.0.1",
8
+ "typecheck": "tsc --noEmit",
9
+ "build": "npm run typecheck && vite build",
10
+ "preview": "vite preview --host 127.0.0.1",
11
+ "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
+ },
13
+ "dependencies": {
14
+ "@aura3d/engine": "1.3.3"
15
+ },
16
+ "devDependencies": {
17
+ "@playwright/test": "^1.52.0",
18
+ "typescript": "^5.8.3",
19
+ "vite": "^7.3.2"
20
+ }
21
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ testDir: "./tests",
5
+ use: {
6
+ baseURL: "http://127.0.0.1:4191"
7
+ },
8
+ webServer: {
9
+ command: "npm exec vite -- --host 127.0.0.1 --port 4191 --strictPort",
10
+ url: "http://127.0.0.1:4191",
11
+ reuseExistingServer: !process.env.CI,
12
+ timeout: 120_000
13
+ }
14
+ });
@@ -0,0 +1,27 @@
1
+ // Three-compat architecture interior: a small room built from boxes,
2
+ // authored entirely through the public @aura3d/engine scene API.
3
+ import { camera, createAuraApp, lights, material, primitives, scene } from "@aura3d/engine";
4
+
5
+ const plaster = material.pbr({ color: "#cfd6e2", roughness: 0.85 });
6
+ const oakFloor = material.pbr({ color: "#8a6f52", roughness: 0.6 });
7
+ const walnut = material.pbr({ color: "#5b4231", roughness: 0.5 });
8
+
9
+ createAuraApp("#app", {
10
+ scene: scene()
11
+ .background("#10141c")
12
+ .camera(camera.orbit({ target: [0, 1.1, 0], distance: 7 }))
13
+ .add(primitives.box({ name: "floor slab", size: [6, 0.12, 6], position: [0, -0.06, 0], material: oakFloor, receiveShadow: true }))
14
+ .add(primitives.box({ name: "back wall", size: [6, 2.8, 0.12], position: [0, 1.4, -3], material: plaster, receiveShadow: true }))
15
+ .add(primitives.box({ name: "side wall", size: [0.12, 2.8, 6], position: [-3, 1.4, 0], material: plaster, receiveShadow: true }))
16
+ .add(primitives.box({ name: "window header", size: [2.4, 0.5, 0.12], position: [1.2, 2.55, -3.01], material: plaster }))
17
+ .add(primitives.box({ name: "table top", size: [1.8, 0.08, 0.9], position: [0.5, 0.74, -0.8], material: walnut, castShadow: true }))
18
+ .add(primitives.box({ name: "table leg front", size: [0.08, 0.7, 0.08], position: [-0.3, 0.35, -0.45], material: walnut, castShadow: true }))
19
+ .add(primitives.box({ name: "table leg back", size: [0.08, 0.7, 0.08], position: [1.3, 0.35, -1.15], material: walnut, castShadow: true }))
20
+ .add(primitives.box({ name: "sofa seat", size: [2, 0.45, 0.9], position: [-1.8, 0.23, 1.3], material: material.pbr({ color: "#41506b", roughness: 0.78 }), castShadow: true }))
21
+ .add(primitives.box({ name: "sofa backrest", size: [2, 0.6, 0.18], position: [-1.8, 0.75, 1.66], material: material.pbr({ color: "#36435a", roughness: 0.78 }), castShadow: true }))
22
+ .add(primitives.cylinder({ name: "floor lamp pole", size: [0.06, 1.6, 0.06], position: [2.3, 0.8, 1.8], material: material.metal({ color: "#9aa3ad" }), castShadow: true }))
23
+ .add(primitives.sphere({ name: "floor lamp shade", size: 0.32, position: [2.3, 1.7, 1.8], material: material.emissive({ color: "#ffe7b8", emissive: "#ffd28a", emissiveIntensity: 0.8 }) }))
24
+ .add(lights.ambient({ intensity: 0.35 }))
25
+ .add(lights.directional({ name: "window sun", position: [4, 5, 3], intensity: 1.4 }))
26
+ .add(lights.point({ name: "lamp fill", position: [2.3, 1.7, 1.8], intensity: 1.1, color: "#ffd9a0" }))
27
+ });
@@ -0,0 +1,16 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D three-compat template reaches ready state", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const drawCalls = Number(await page.locator("body").getAttribute("data-aura3d-draw-calls"));
11
+ const diagnostics = await page.evaluate(() => (window as unknown as { __AURA3D_ROUTE_READY__?: { diagnostics?: { backend?: string } } }).__AURA3D_ROUTE_READY__?.diagnostics);
12
+ expect(diagnostics?.backend).toBe("webgl2");
13
+ expect(drawCalls).toBeGreaterThan(0);
14
+ mkdirSync(resolve("tests/reports"), { recursive: true });
15
+ writeFileSync(resolve("tests/reports/route-health.json"), `${JSON.stringify({ ready: true, backend: diagnostics?.backend, drawCalls }, null, 2)}\n`);
16
+ });
@@ -0,0 +1,15 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D three-compat template screenshot shows content", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const screenshot = await page.screenshot({ fullPage: false });
11
+ mkdirSync(resolve("tests/reports"), { recursive: true });
12
+ writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
13
+ writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength }, null, 2)}\n`);
14
+ expect(screenshot.byteLength).toBeGreaterThan(1000);
15
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "allowJs": false,
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "strict": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "moduleResolution": "Bundler",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true
17
+ },
18
+ "include": ["src", "tests"]
19
+ }
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Aura3D Three-Compat Asset Inspector</title>
7
+ <style>
8
+ html, body, #app { margin: 0; width: 100%; height: 100%; background: #080d15; }
9
+ body { font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
10
+ </style>
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script type="module" src="/src/main.ts"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "aura3d-three-compat-asset-inspector",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host 127.0.0.1",
8
+ "typecheck": "tsc --noEmit",
9
+ "build": "npm run typecheck && vite build",
10
+ "preview": "vite preview --host 127.0.0.1",
11
+ "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
+ },
13
+ "dependencies": {
14
+ "@aura3d/engine": "1.3.3"
15
+ },
16
+ "devDependencies": {
17
+ "@playwright/test": "^1.52.0",
18
+ "typescript": "^5.8.3",
19
+ "vite": "^7.3.2"
20
+ }
21
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ testDir: "./tests",
5
+ use: {
6
+ baseURL: "http://127.0.0.1:4192"
7
+ },
8
+ webServer: {
9
+ command: "npm exec vite -- --host 127.0.0.1 --port 4192 --strictPort",
10
+ url: "http://127.0.0.1:4192",
11
+ reuseExistingServer: !process.env.CI,
12
+ timeout: 120_000
13
+ }
14
+ });
@@ -0,0 +1,17 @@
1
+ // Three-compat asset inspector: one centered primitive on a neutral stage
2
+ // with inspection lighting, authored through the public @aura3d/engine API.
3
+ // Swap the torus for `model(assets.yourAsset)` once you add typed assets.
4
+ import { camera, createAuraApp, lights, material, primitives, scene } from "@aura3d/engine";
5
+
6
+ createAuraApp("#app", {
7
+ diagnostics: { overlay: true },
8
+ scene: scene()
9
+ .background("#0b0f16")
10
+ .camera(camera.orbit({ target: [0, 0.9, 0], distance: 4.2 }))
11
+ .add(primitives.box({ name: "inspection stage", size: [4, 0.1, 4], position: [0, -0.05, 0], material: material.pbr({ color: "#1d2533", roughness: 0.9 }), receiveShadow: true }))
12
+ .add(primitives.torus({ name: "inspected asset", size: 1.1, position: [0, 0.95, 0], rotation: [0.5, 0.35, 0], material: material.metal({ color: "#c9d4e4", roughness: 0.22 }), castShadow: true }))
13
+ .add(primitives.box({ name: "scale reference cube", size: 0.25, position: [1.4, 0.125, 0.9], material: material.pbr({ color: "#38d6ff" }), castShadow: true }))
14
+ .add(lights.ambient({ intensity: 0.3 }))
15
+ .add(lights.directional({ name: "key", position: [3, 4, 3], intensity: 1.5 }))
16
+ .add(lights.point({ name: "rim", position: [-2.5, 2, -2], intensity: 1.4, color: "#9fc4ff" }))
17
+ });
@@ -0,0 +1,16 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D three-compat template reaches ready state", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const drawCalls = Number(await page.locator("body").getAttribute("data-aura3d-draw-calls"));
11
+ const diagnostics = await page.evaluate(() => (window as unknown as { __AURA3D_ROUTE_READY__?: { diagnostics?: { backend?: string } } }).__AURA3D_ROUTE_READY__?.diagnostics);
12
+ expect(diagnostics?.backend).toBe("webgl2");
13
+ expect(drawCalls).toBeGreaterThan(0);
14
+ mkdirSync(resolve("tests/reports"), { recursive: true });
15
+ writeFileSync(resolve("tests/reports/route-health.json"), `${JSON.stringify({ ready: true, backend: diagnostics?.backend, drawCalls }, null, 2)}\n`);
16
+ });
@@ -0,0 +1,15 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D three-compat template screenshot shows content", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const screenshot = await page.screenshot({ fullPage: false });
11
+ mkdirSync(resolve("tests/reports"), { recursive: true });
12
+ writeFileSync(resolve("tests/reports/screenshot.png"), screenshot);
13
+ writeFileSync(resolve("tests/reports/screenshot.json"), `${JSON.stringify({ bytes: screenshot.byteLength }, null, 2)}\n`);
14
+ expect(screenshot.byteLength).toBeGreaterThan(1000);
15
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "allowJs": false,
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "strict": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "moduleResolution": "Bundler",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true
17
+ },
18
+ "include": ["src", "tests"]
19
+ }
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Aura3D Three-Compat Character Viewer</title>
7
+ <style>
8
+ html, body, #app { margin: 0; width: 100%; height: 100%; background: #080d15; }
9
+ body { font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
10
+ </style>
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script type="module" src="/src/main.ts"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "aura3d-three-compat-character-viewer",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host 127.0.0.1",
8
+ "typecheck": "tsc --noEmit",
9
+ "build": "npm run typecheck && vite build",
10
+ "preview": "vite preview --host 127.0.0.1",
11
+ "test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
12
+ },
13
+ "dependencies": {
14
+ "@aura3d/engine": "1.3.3"
15
+ },
16
+ "devDependencies": {
17
+ "@playwright/test": "^1.52.0",
18
+ "typescript": "^5.8.3",
19
+ "vite": "^7.3.2"
20
+ }
21
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ testDir: "./tests",
5
+ use: {
6
+ baseURL: "http://127.0.0.1:4193"
7
+ },
8
+ webServer: {
9
+ command: "npm exec vite -- --host 127.0.0.1 --port 4193 --strictPort",
10
+ url: "http://127.0.0.1:4193",
11
+ reuseExistingServer: !process.env.CI,
12
+ timeout: 120_000
13
+ }
14
+ });
@@ -0,0 +1,17 @@
1
+ // Three-compat character viewer: a capsule stand-in character on a pedestal,
2
+ // authored through the public @aura3d/engine API. Replace the capsule with
3
+ // `model(assets.character)` once you add a typed character asset.
4
+ import { camera, createAuraApp, lights, material, primitives, scene } from "@aura3d/engine";
5
+
6
+ createAuraApp("#app", {
7
+ scene: scene()
8
+ .background("#0d1119")
9
+ .camera(camera.orbit({ target: [0, 1.2, 0], distance: 4.6 }))
10
+ .add(primitives.box({ name: "viewer floor", size: [5, 0.1, 5], position: [0, -0.05, 0], material: material.pbr({ color: "#161d2a", roughness: 0.92 }), receiveShadow: true }))
11
+ .add(primitives.cylinder({ name: "character pedestal", size: [1.4, 0.3, 1.4], position: [0, 0.15, 0], material: material.pbr({ color: "#2b3548", roughness: 0.55, metalness: 0.2 }), receiveShadow: true, castShadow: true }))
12
+ .add(primitives.capsule({ name: "stand-in character", size: [0.7, 1.7, 0.7], position: [0, 1.25, 0], material: material.pbr({ color: "#7fa6d9", roughness: 0.45 }), castShadow: true }))
13
+ .add(primitives.sphere({ name: "stand-in head marker", size: 0.3, position: [0, 2.25, 0], material: material.pbr({ color: "#d9c79f", roughness: 0.5 }), castShadow: true }))
14
+ .add(lights.ambient({ intensity: 0.32 }))
15
+ .add(lights.directional({ name: "key light", position: [3, 4.5, 3], intensity: 1.5 }))
16
+ .add(lights.point({ name: "rim light", position: [-2.4, 2.6, -2.2], intensity: 1.5, color: "#8fb8ff" }))
17
+ });
@@ -0,0 +1,16 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { expect, test } from "@playwright/test";
4
+
5
+ test.setTimeout(60_000);
6
+
7
+ test("Aura3D three-compat template reaches ready state", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect.poll(() => page.locator("body").getAttribute("data-aura3d-ready"), { timeout: 45_000 }).toBe("true");
10
+ const drawCalls = Number(await page.locator("body").getAttribute("data-aura3d-draw-calls"));
11
+ const diagnostics = await page.evaluate(() => (window as unknown as { __AURA3D_ROUTE_READY__?: { diagnostics?: { backend?: string } } }).__AURA3D_ROUTE_READY__?.diagnostics);
12
+ expect(diagnostics?.backend).toBe("webgl2");
13
+ expect(drawCalls).toBeGreaterThan(0);
14
+ mkdirSync(resolve("tests/reports"), { recursive: true });
15
+ writeFileSync(resolve("tests/reports/route-health.json"), `${JSON.stringify({ ready: true, backend: diagnostics?.backend, drawCalls }, null, 2)}\n`);
16
+ });