create-aura3d 1.0.8 → 1.0.10

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 (44) hide show
  1. package/dist/cli.js +0 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +4 -2
  5. package/dist/index.js.map +1 -1
  6. package/package.json +8 -4
  7. package/templates/cartoon-channel/package.json +1 -1
  8. package/templates/cartoon-studio/README.md +46 -0
  9. package/templates/cartoon-studio/index.html +13 -0
  10. package/templates/cartoon-studio/package.json +21 -0
  11. package/templates/cartoon-studio/playwright.config.ts +13 -0
  12. package/templates/cartoon-studio/src/aura-assets.ts +14 -0
  13. package/templates/cartoon-studio/src/characters.ts +28 -0
  14. package/templates/cartoon-studio/src/contract.ts +1 -0
  15. package/templates/cartoon-studio/src/episode.ts +300 -0
  16. package/templates/cartoon-studio/src/main.ts +265 -0
  17. package/templates/cartoon-studio/src/render-plan.ts +405 -0
  18. package/templates/cartoon-studio/src/sets.ts +14 -0
  19. package/templates/cartoon-studio/src/studio.ts +101 -0
  20. package/templates/cartoon-studio/tests/route-health.spec.ts +7 -0
  21. package/templates/cartoon-studio/tests/storyboard-playback.spec.ts +91 -0
  22. package/templates/cartoon-studio/tsconfig.json +12 -0
  23. package/templates/cinematic-scene/package.json +1 -1
  24. package/templates/episode-builder/README.md +46 -0
  25. package/templates/episode-builder/index.html +13 -0
  26. package/templates/episode-builder/package.json +21 -0
  27. package/templates/episode-builder/playwright.config.ts +13 -0
  28. package/templates/episode-builder/src/aura-assets.ts +14 -0
  29. package/templates/episode-builder/src/builder.ts +78 -0
  30. package/templates/episode-builder/src/characters.ts +28 -0
  31. package/templates/episode-builder/src/contract.ts +1 -0
  32. package/templates/episode-builder/src/episode.ts +300 -0
  33. package/templates/episode-builder/src/main.ts +265 -0
  34. package/templates/episode-builder/src/render-plan.ts +405 -0
  35. package/templates/episode-builder/src/sets.ts +14 -0
  36. package/templates/episode-builder/tests/route-health.spec.ts +7 -0
  37. package/templates/episode-builder/tests/storyboard-playback.spec.ts +98 -0
  38. package/templates/episode-builder/tsconfig.json +12 -0
  39. package/templates/fighting-game/package.json +1 -1
  40. package/templates/fighting-game/src/game/stage.ts +18 -4
  41. package/templates/fighting-game/src/main.ts +3 -2
  42. package/templates/mini-game/package.json +1 -1
  43. package/templates/product-viewer/package.json +1 -1
  44. package/templates/prompt-cartoon-channel/package.json +1 -1
@@ -0,0 +1,101 @@
1
+ import { episode, publicCartoonAssetInstructions, typedCartoonAssetSummary } from "./episode";
2
+ import { publishReadiness, renderPlan } from "./render-plan";
3
+
4
+ export const cartoonStudioSupport = {
5
+ template: "cartoon-studio",
6
+ panels: ["timeline", "assets", "performance", "render"] as const,
7
+ timelineTracks: [
8
+ {
9
+ id: "shots",
10
+ label: "Shots",
11
+ clips: episode.shotTimeline.shots.map((shot) => ({
12
+ id: shot.shotId,
13
+ startTime: shot.startTime,
14
+ endTime: shot.endTime,
15
+ cameraMove: shot.camera.move,
16
+ transitionOut: shot.transitionOut ?? "cut"
17
+ }))
18
+ },
19
+ {
20
+ id: "dialogue",
21
+ label: "Dialogue",
22
+ clips: episode.dialogueTrack.lines.map((line) => ({
23
+ id: line.lineId,
24
+ speakerId: line.speakerId,
25
+ startTime: line.startTime,
26
+ endTime: line.endTime,
27
+ text: line.text
28
+ }))
29
+ },
30
+ {
31
+ id: "render",
32
+ label: "Render",
33
+ clips: renderPlan.items.map((item) => ({
34
+ id: item.id,
35
+ time: item.time,
36
+ outputIds: item.outputIds,
37
+ width: item.viewport.width,
38
+ height: item.viewport.height
39
+ }))
40
+ }
41
+ ],
42
+ assetLibrary: {
43
+ requiredCharacters: typedCartoonAssetSummary.requiredCharacterAssets,
44
+ optionalProps: typedCartoonAssetSummary.optionalPropAssets,
45
+ missingCharacters: typedCartoonAssetSummary.missingCharacterAssets,
46
+ commands: publicCartoonAssetInstructions
47
+ },
48
+ renderPipeline: {
49
+ outputs: renderPlan.outputs.map((output) => output.kind),
50
+ itemCount: renderPlan.items.length,
51
+ publishReadyFromCurrentEvidence: publishReadiness.ready,
52
+ issueCount: publishReadiness.issues.length
53
+ }
54
+ } as const;
55
+
56
+ export function installCartoonStudioPanel(target: HTMLElement): void {
57
+ const panel = document.createElement("section");
58
+ panel.id = "cartoon-studio-panel";
59
+ panel.style.cssText = [
60
+ "position:fixed",
61
+ "left:18px",
62
+ "top:18px",
63
+ "width:min(360px,calc(100vw - 36px))",
64
+ "display:grid",
65
+ "grid-template-columns:repeat(4,1fr)",
66
+ "gap:6px",
67
+ "padding:10px",
68
+ "border:1px solid rgba(248,255,242,0.22)",
69
+ "border-radius:8px",
70
+ "background:rgba(3,12,20,0.78)",
71
+ "color:#f8fff2",
72
+ "font:600 12px/1.2 system-ui,sans-serif",
73
+ "z-index:9"
74
+ ].join(";");
75
+
76
+ for (const name of cartoonStudioSupport.panels) {
77
+ const button = document.createElement("button");
78
+ button.type = "button";
79
+ button.textContent = name;
80
+ button.dataset.panel = name;
81
+ button.style.cssText = [
82
+ "min-width:0",
83
+ "height:30px",
84
+ "border:1px solid rgba(125,226,255,0.42)",
85
+ "border-radius:6px",
86
+ "background:rgba(24,45,63,0.84)",
87
+ "color:#f8fff2",
88
+ "font:inherit",
89
+ "text-transform:capitalize"
90
+ ].join(";");
91
+ panel.appendChild(button);
92
+ }
93
+
94
+ const status = document.createElement("div");
95
+ status.id = "cartoon-studio-status";
96
+ status.textContent = `${episode.shotTimeline.shots.length} shots | ${episode.dialogueTrack.lines.length} lines | ${renderPlan.items.length} render cues`;
97
+ status.style.cssText = "grid-column:1 / -1;color:#7de2ff;white-space:normal";
98
+ panel.appendChild(status);
99
+
100
+ target.appendChild(panel);
101
+ }
@@ -0,0 +1,7 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ test("cartoon studio route loads", async ({ page }) => {
4
+ await page.goto("/");
5
+ await expect(page.locator("#app")).toBeVisible();
6
+ });
7
+
@@ -0,0 +1,91 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ test("cartoon studio storyboard caption renders", async ({ page }) => {
4
+ await page.goto("/");
5
+ await expect(page.getByText(/Aura3D cartoon studio|moon|robot/i)).toBeVisible();
6
+ });
7
+
8
+ test("storyboard playback, character performance, caption timing, cuts, and nonblank cartoon frames are sourced", async ({
9
+ page
10
+ }) => {
11
+ await page.goto("/");
12
+
13
+ const routeProof = (await page.evaluate(() => {
14
+ const template = (window as unknown as {
15
+ __AURA3D_CARTOON_TEMPLATE__?: {
16
+ shotIds: readonly string[];
17
+ captionIds: readonly string[];
18
+ storyBible?: unknown;
19
+ studio?: unknown;
20
+ playbackProbeSamples: readonly unknown[];
21
+ sampleAt(time: number): unknown;
22
+ };
23
+ }).__AURA3D_CARTOON_TEMPLATE__;
24
+ return {
25
+ shotIds: template?.shotIds ?? [],
26
+ captionIds: template?.captionIds ?? [],
27
+ storyBible: template?.storyBible,
28
+ studio: template?.studio,
29
+ samples: [1, 21, 43].map((time) => template?.sampleAt(time)),
30
+ playbackProbeSamples: template?.playbackProbeSamples ?? [],
31
+ bodyShotCount: document.body.dataset.cartoonShotCount,
32
+ bodyCaptionCount: document.body.dataset.cartoonCaptionCount,
33
+ bodyPanels: document.body.dataset.cartoonStudioPanels
34
+ };
35
+ })) as {
36
+ shotIds: string[];
37
+ captionIds: string[];
38
+ storyBible?: {
39
+ props?: unknown[];
40
+ styleGuide?: { visualStyle?: string };
41
+ shotList?: unknown[];
42
+ };
43
+ studio?: {
44
+ panels?: readonly string[];
45
+ timelineTracks?: readonly { id: string; clips: readonly unknown[] }[];
46
+ assetLibrary?: { commands?: readonly string[] };
47
+ renderPipeline?: { itemCount?: number };
48
+ };
49
+ samples: Array<{
50
+ shotId?: string;
51
+ captionId?: string;
52
+ captionText?: string;
53
+ cameraMove?: string;
54
+ transitionOut?: string;
55
+ nodeUpdates?: Array<{ characterId?: string; action?: string; emotion?: string }>;
56
+ }>;
57
+ playbackProbeSamples: unknown[];
58
+ bodyShotCount?: string;
59
+ bodyCaptionCount?: string;
60
+ bodyPanels?: string;
61
+ };
62
+
63
+ expect(routeProof.shotIds).toEqual([
64
+ "shot-moon-garden-open",
65
+ "shot-glow-stone-teamwork",
66
+ "shot-moon-garden-finish"
67
+ ]);
68
+ expect(new Set(routeProof.samples.map((sample) => sample.shotId)).size).toBe(3);
69
+ expect(routeProof.captionIds).toHaveLength(6);
70
+ expect(routeProof.samples.every((sample) => sample.captionId && sample.captionText)).toBe(true);
71
+ expect(routeProof.samples.some((sample) => sample.cameraMove === "push-in" || sample.transitionOut === "cut")).toBe(true);
72
+ expect(routeProof.samples.flatMap((sample) => sample.nodeUpdates ?? []).some((update) => update.action === "speak")).toBe(true);
73
+ expect(routeProof.samples.flatMap((sample) => sample.nodeUpdates ?? []).some((update) => update.characterId === "miko")).toBe(true);
74
+ expect(routeProof.samples.flatMap((sample) => sample.nodeUpdates ?? []).some((update) => update.characterId === "luma")).toBe(true);
75
+ expect(routeProof.storyBible?.props?.length).toBeGreaterThanOrEqual(3);
76
+ expect(routeProof.storyBible?.styleGuide?.visualStyle).toMatch(/cartoon/i);
77
+ expect(routeProof.storyBible?.shotList).toHaveLength(3);
78
+ expect(routeProof.playbackProbeSamples).toHaveLength(3);
79
+ expect(routeProof.bodyShotCount).toBe("3");
80
+ expect(routeProof.bodyCaptionCount).toBe("6");
81
+ expect(routeProof.studio?.panels).toEqual(["timeline", "assets", "performance", "render"]);
82
+ expect(routeProof.studio?.timelineTracks?.map((track) => track.id)).toEqual(["shots", "dialogue", "render"]);
83
+ expect(routeProof.studio?.timelineTracks?.every((track) => track.clips.length > 0)).toBe(true);
84
+ expect(routeProof.studio?.assetLibrary?.commands?.some((command) => command.includes("assets validate-cartoon"))).toBe(true);
85
+ expect(routeProof.studio?.renderPipeline?.itemCount).toBeGreaterThan(0);
86
+ expect(routeProof.bodyPanels).toBe("timeline,assets,performance,render");
87
+ await expect(page.locator("#cartoon-studio-panel")).toBeVisible();
88
+
89
+ const screenshot = await page.screenshot();
90
+ expect(screenshot.byteLength).toBeGreaterThan(2048);
91
+ });
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "jsx": "react-jsx",
8
+ "types": ["vite/client"]
9
+ },
10
+ "include": ["src"]
11
+ }
12
+
@@ -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.0.5"
14
+ "@aura3d/engine": "1.0.10"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@playwright/test": "^1.52.0",
@@ -0,0 +1,46 @@
1
+ # Aura3D Episode Builder Template
2
+
3
+ This template demonstrates a guided prompt-to-episode builder on top of the
4
+ AuraVoice-to-Aura3D prompt-animation contract.
5
+
6
+ It uses:
7
+
8
+ - `compilePromptEpisodePlan(...)` for prompt-to-episode planning.
9
+ - Optional typed GLB characters from `./src/aura-assets` with primitive runtime fallbacks until assets are added.
10
+ - `createShotPlaybackPlan(...)` plus `installShotPlayback(...)` so `app.onFrame` updates nodes without recreating the app.
11
+ - `createAuraVoiceBridgePackage(...)`, `validateAuraVoiceBridgePackage(...)`, `collectPromptAnimationEvidence(...)`, and `evaluatePromptAnimationPublishReadiness(...)` for source-level AuraVoice/Aura3D handoff declarations.
12
+ - Caption HUD and caption timing proof metadata.
13
+ - Render queue metadata and three deterministic screenshot fixture records.
14
+ - Child-safe, reduced-motion, and high-contrast accessibility proof defaults.
15
+ - Primitive-mouth and typed-GLB viseme examples.
16
+ - Phoneme/viseme/dub source proof metadata for stable shot, storyboard, caption, line, and word timing ids.
17
+ - Episode format choices for short-form, standard, pilot, educational, and music-video structures.
18
+ - Wizard state that points at the compiled episode plan, beats, characters, and publish-evidence status.
19
+ - A compact builder panel for route tests and agent inspection.
20
+
21
+ Replace primitive characters with typed GLB assets by running:
22
+
23
+ ```bash
24
+ npx @aura3d/cli@latest assets add ./assets/miko.glb --name miko
25
+ npx @aura3d/cli@latest assets add ./assets/luma.glb --name luma
26
+ npx @aura3d/cli@latest assets validate-cartoon
27
+ ```
28
+
29
+ Then import `assets.miko` and `assets.luma` from `src/aura-assets.ts` and pass them to `model(assets.miko)` and `model(assets.luma)`.
30
+
31
+ The GLB path must keep typed assets:
32
+
33
+ ```ts
34
+ import { model } from "@aura3d/engine";
35
+ import { assets } from "./aura-assets";
36
+
37
+ model(assets.miko);
38
+ ```
39
+
40
+ Do not replace this with a string asset id or a raw loader.
41
+
42
+ This scaffold intentionally does not claim publish readiness from source alone.
43
+ Before closing build, route, asset, screenshot, render, or visual-quality gates,
44
+ archive the matching `npm run build`, `assets validate-cartoon`, browser
45
+ evidence, screenshot hashes, render outputs, and human or automated review
46
+ artifacts.
@@ -0,0 +1,13 @@
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 Episode Builder</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
13
+
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "aura3d-episode-builder",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host 0.0.0.0",
8
+ "typecheck": "tsc --noEmit",
9
+ "build": "npm run typecheck && vite build",
10
+ "preview": "vite preview --host 0.0.0.0",
11
+ "test": "playwright test tests/route-health.spec.ts tests/storyboard-playback.spec.ts --workers=1"
12
+ },
13
+ "dependencies": {
14
+ "@aura3d/engine": "1.0.10"
15
+ },
16
+ "devDependencies": {
17
+ "@playwright/test": "^1.52.0",
18
+ "typescript": "^5.9.3",
19
+ "vite": "^7.2.4"
20
+ }
21
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ webServer: {
5
+ command: "npm run dev -- --port 4181",
6
+ url: "http://127.0.0.1:4181",
7
+ reuseExistingServer: !process.env.CI
8
+ },
9
+ use: {
10
+ baseURL: "http://127.0.0.1:4181"
11
+ }
12
+ });
13
+
@@ -0,0 +1,14 @@
1
+ import { defineAuraAssets } from "@aura3d/engine";
2
+ import { AURAVOICE_AURA3D_PROMPT_ANIMATION_CONTRACT_ID } from "./contract";
3
+
4
+ export const assetContractId = AURAVOICE_AURA3D_PROMPT_ANIMATION_CONTRACT_ID;
5
+
6
+ export const assets = defineAuraAssets({
7
+ /*
8
+ * Add character GLBs with the Aura3D CLI, then keep these generated keys:
9
+ *
10
+ * npx @aura3d/cli@latest assets add ./assets/miko.glb --name miko
11
+ * npx @aura3d/cli@latest assets add ./assets/luma.glb --name luma
12
+ * npx @aura3d/cli@latest assets validate-cartoon
13
+ */
14
+ });
@@ -0,0 +1,78 @@
1
+ import { episode, publicCartoonAssetInstructions, typedCartoonAssetSummary } from "./episode";
2
+ import { publishReadiness } from "./render-plan";
3
+
4
+ export const episodeBuilderSupport = {
5
+ template: "episode-builder",
6
+ formats: [
7
+ { id: "short-form", label: "Short-form", targetMinutes: "1-3", beats: "3-5", locations: "single" },
8
+ { id: "standard", label: "Standard", targetMinutes: "5-7", beats: "8-12", locations: "multi" },
9
+ { id: "series-pilot", label: "Series pilot", targetMinutes: "10-15", beats: "12-20", locations: "multi" },
10
+ { id: "educational", label: "Educational", targetMinutes: "3-5", beats: "topic segments", locations: "guided" },
11
+ { id: "music-video", label: "Music video", targetMinutes: "2-4", beats: "song sections", locations: "choreographed" }
12
+ ] as const,
13
+ wizardSteps: [
14
+ { id: "prompt", label: "Prompt", complete: true },
15
+ { id: "format", label: "Format", complete: true },
16
+ { id: "characters", label: "Characters", complete: episode.episodePlan.characters.length >= 2 },
17
+ { id: "beats", label: "Beats", complete: episode.shotTimeline.shots.length >= 3 },
18
+ { id: "publish", label: "Publish", complete: publishReadiness.ready }
19
+ ] as const,
20
+ compiledEpisode: {
21
+ episodeId: episode.episodePlan.episodeId,
22
+ title: episode.episodePlan.title,
23
+ sourcePrompt: episode.episodePlan.production.sourcePrompt,
24
+ shotCount: episode.shotTimeline.shots.length,
25
+ captionCount: episode.captionTrack.cues.length,
26
+ renderQueueItems: episode.renderQueue.items.length
27
+ },
28
+ typedAssets: {
29
+ requiredCharacters: typedCartoonAssetSummary.requiredCharacterAssets,
30
+ missingCharacters: typedCartoonAssetSummary.missingCharacterAssets,
31
+ commands: publicCartoonAssetInstructions
32
+ }
33
+ } as const;
34
+
35
+ export function installEpisodeBuilderPanel(target: HTMLElement): void {
36
+ const panel = document.createElement("section");
37
+ panel.id = "episode-builder-panel";
38
+ panel.style.cssText = [
39
+ "position:fixed",
40
+ "left:18px",
41
+ "top:18px",
42
+ "width:min(390px,calc(100vw - 36px))",
43
+ "display:grid",
44
+ "gap:8px",
45
+ "padding:12px",
46
+ "border:1px solid rgba(248,255,242,0.22)",
47
+ "border-radius:8px",
48
+ "background:rgba(3,12,20,0.78)",
49
+ "color:#f8fff2",
50
+ "font:600 12px/1.25 system-ui,sans-serif",
51
+ "z-index:9"
52
+ ].join(";");
53
+
54
+ const format = document.createElement("select");
55
+ format.id = "episode-format";
56
+ format.style.cssText = "height:32px;border-radius:6px;background:#182d3f;color:#f8fff2;border:1px solid rgba(125,226,255,0.42)";
57
+ for (const option of episodeBuilderSupport.formats) {
58
+ const element = document.createElement("option");
59
+ element.value = option.id;
60
+ element.textContent = option.label;
61
+ format.appendChild(element);
62
+ }
63
+ panel.appendChild(format);
64
+
65
+ const steps = document.createElement("div");
66
+ steps.id = "episode-builder-steps";
67
+ steps.textContent = episodeBuilderSupport.wizardSteps.map((step) => `${step.label}:${step.complete ? "ready" : "needs evidence"}`).join(" | ");
68
+ steps.style.cssText = "color:#7de2ff;white-space:normal";
69
+ panel.appendChild(steps);
70
+
71
+ const compiled = document.createElement("div");
72
+ compiled.id = "episode-builder-compiled-plan";
73
+ compiled.textContent = `${episodeBuilderSupport.compiledEpisode.shotCount} shots | ${episodeBuilderSupport.compiledEpisode.captionCount} captions`;
74
+ compiled.style.cssText = "color:#f8fff2;white-space:normal";
75
+ panel.appendChild(compiled);
76
+
77
+ target.appendChild(panel);
78
+ }
@@ -0,0 +1,28 @@
1
+ import { AURAVOICE_AURA3D_PROMPT_ANIMATION_CONTRACT_ID } from "./contract";
2
+
3
+ export const characterContractId = AURAVOICE_AURA3D_PROMPT_ANIMATION_CONTRACT_ID;
4
+
5
+ export const characters = [
6
+ {
7
+ id: "miko",
8
+ name: "Miko",
9
+ palette: ["#7de2ff", "#f7ffe8"],
10
+ primitiveFallback: "round robot with antenna",
11
+ typedAssetKey: "miko",
12
+ runtimeNodeId: "miko",
13
+ primitiveMouthNodeId: "miko:mouth",
14
+ performanceChannels: ["body", "facial", "gesture", "blocking", "gaze"],
15
+ glbUpgrade: "After assets add, use model(assets.miko) and keep viseme blendshape metadata."
16
+ },
17
+ {
18
+ id: "luma",
19
+ name: "Luma",
20
+ palette: ["#ffe18e", "#40ffbf"],
21
+ primitiveFallback: "small moon-garden helper",
22
+ typedAssetKey: "luma",
23
+ runtimeNodeId: "luma",
24
+ primitiveMouthNodeId: "luma:mouth",
25
+ performanceChannels: ["body", "facial", "gesture", "blocking", "gaze"],
26
+ glbUpgrade: "After assets add, use model(assets.luma) and keep viseme blendshape metadata."
27
+ }
28
+ ];
@@ -0,0 +1 @@
1
+ export const AURAVOICE_AURA3D_PROMPT_ANIMATION_CONTRACT_ID = "auravoice-aura3d-prompt-animation/v1" as const;