create-aura3d 1.1.2 → 1.3.1

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 (215) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +6 -4
  4. package/dist/index.js.map +1 -1
  5. package/package.json +10 -9
  6. package/templates/{cartoon-channel → animation-channel}/README.md +11 -11
  7. package/templates/{cartoon-studio → animation-channel}/index.html +1 -1
  8. package/templates/{cartoon-channel → animation-channel}/package.json +2 -2
  9. package/templates/{cartoon-channel → animation-channel}/src/episode.ts +22 -22
  10. package/templates/{cartoon-channel → animation-channel}/src/experimental/README.md +5 -5
  11. package/templates/{cartoon-channel → animation-channel}/src/experimental/concept-episode-2-5d.css +3 -3
  12. package/templates/{cartoon-channel → animation-channel}/src/experimental/concept-episode-2-5d.ts +7 -7
  13. package/templates/{cartoon-channel → animation-channel}/src/experimental/image-puppet-episode.css +4 -4
  14. package/templates/{cartoon-channel → animation-channel}/src/experimental/image-puppet-episode.ts +6 -6
  15. package/templates/{cartoon-channel → animation-channel}/src/experimental/puppet-episode-2d.css +3 -3
  16. package/templates/{cartoon-channel → animation-channel}/src/experimental/puppet-episode-2d.ts +7 -7
  17. package/templates/{cartoon-channel → animation-channel}/src/main.ts +32 -32
  18. package/templates/{cartoon-channel → animation-channel}/src/render-plan.ts +13 -13
  19. package/templates/{cartoon-channel → animation-channel}/src/sample-episode-visual.css +34 -34
  20. package/templates/{cartoon-channel → animation-channel}/src/sample-episode-visual.ts +20 -20
  21. package/templates/{cartoon-channel → animation-channel}/tests/concept-2-5d-animation.spec.ts +3 -3
  22. package/templates/{cartoon-channel → animation-channel}/tests/concept-2-5d.spec.ts +6 -6
  23. package/templates/{cartoon-channel → animation-channel}/tests/image-puppet-animation.spec.ts +3 -3
  24. package/templates/{cartoon-channel → animation-channel}/tests/image-puppet.spec.ts +5 -5
  25. package/templates/{cartoon-channel → animation-channel}/tests/puppet-2d-animation.spec.ts +3 -3
  26. package/templates/{cartoon-channel → animation-channel}/tests/puppet-2d.spec.ts +4 -4
  27. package/templates/{prompt-cartoon-channel → animation-channel}/tests/route-health.spec.ts +1 -1
  28. package/templates/{cartoon-channel → animation-channel}/tests/sample-episode-visual.spec.ts +5 -5
  29. package/templates/{cartoon-channel → animation-channel}/tests/storyboard-playback.spec.ts +7 -7
  30. package/templates/animation-studio/AGENTS.md +71 -0
  31. package/templates/{cartoon-studio → animation-studio}/ASSET-LICENSES.md +7 -7
  32. package/templates/{cartoon-studio → animation-studio}/README.md +6 -6
  33. package/templates/animation-studio/aura.assets.json +669 -0
  34. package/templates/animation-studio/dist/episodes/scene/episode-3d.webm +0 -0
  35. package/templates/animation-studio/dist/episodes/scene/frames/action.png +0 -0
  36. package/templates/animation-studio/dist/episodes/scene/frames/dialogue.png +0 -0
  37. package/templates/animation-studio/dist/episodes/scene/frames/final.png +0 -0
  38. package/templates/animation-studio/dist/episodes/scene/frames/first.png +0 -0
  39. package/templates/animation-studio/dist/episodes/scene/frames/mouth-closed.png +0 -0
  40. package/templates/animation-studio/dist/episodes/scene/frames/mouth-open.png +0 -0
  41. package/templates/animation-studio/dist/episodes/scene/render-live-summary.json +10284 -0
  42. package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/worker-1.png +0 -0
  43. package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/worker-2.png +0 -0
  44. package/templates/animation-studio/dist/generated/second-scene.document.json +1210 -0
  45. package/templates/animation-studio/dist/generated/studio-edited.document.json +1196 -0
  46. package/templates/animation-studio/dist/scene/inshader-accept.document.json +1 -0
  47. package/templates/animation-studio/dist/scene/inshader-test.document.json +1 -0
  48. package/templates/animation-studio/dist/scene/integ.document.json +1 -0
  49. package/templates/animation-studio/dist/scene/working.document.json +723 -0
  50. package/templates/animation-studio/dist/scene/working.history.json +1 -0
  51. package/templates/{cartoon-studio → animation-studio}/live-route.html +1 -1
  52. package/templates/{cartoon-studio → animation-studio}/package-lock.json +2 -2
  53. package/templates/animation-studio/package.json +32 -0
  54. package/templates/animation-studio/public/aura-assets/cast-a.catalog.glb +0 -0
  55. package/templates/animation-studio/public/aura-assets/cast-b.catalog.glb +0 -0
  56. package/templates/animation-studio/public/aura-assets/luma.catalog.glb +0 -0
  57. package/templates/animation-studio/public/aura-assets/luma2.catalog.glb +0 -0
  58. package/templates/animation-studio/public/aura-assets/miko.catalog.glb +0 -0
  59. package/templates/{cartoon-studio → animation-studio}/public/aura-assets/moonGarden.gltf +1 -1
  60. package/templates/animation-studio/public/aura-assets/mushroom.catalog.glb +0 -0
  61. package/templates/animation-studio/public/aura-assets/rusty.catalog.glb +0 -0
  62. package/templates/animation-studio/public/cast-library/cast-library.json +71 -0
  63. package/templates/animation-studio/public/clip-library/gesture.json +173903 -0
  64. package/templates/animation-studio/public/clip-library/idle.json +23035 -0
  65. package/templates/animation-studio/public/clip-library/manifest.json +154 -0
  66. package/templates/animation-studio/public/clip-library/nod.json +173903 -0
  67. package/templates/animation-studio/public/clip-library/point.json +69879 -0
  68. package/templates/animation-studio/public/clip-library/react.json +66084 -0
  69. package/templates/animation-studio/public/clip-library/run.json +9648 -0
  70. package/templates/animation-studio/public/clip-library/talk.json +69879 -0
  71. package/templates/animation-studio/public/clip-library/walk.json +8283 -0
  72. package/templates/animation-studio/public/hifi-cast/BrainStem.glb +0 -0
  73. package/templates/animation-studio/public/hifi-cast/CesiumMan.glb +0 -0
  74. package/templates/animation-studio/public/hifi-cast/RiggedFigure.glb +0 -0
  75. package/templates/animation-studio/public/hifi-cast/kaykit/Barbarian.glb +0 -0
  76. package/templates/animation-studio/public/hifi-cast/kaykit/Knight.glb +0 -0
  77. package/templates/animation-studio/public/hifi-cast/kaykit/Mage.glb +0 -0
  78. package/templates/animation-studio/public/hifi-cast/kaykit/Rogue.glb +0 -0
  79. package/templates/animation-studio/public/hifi-cast/kaykit/Rogue_Hooded.glb +0 -0
  80. package/templates/animation-studio/public/hifi-cast/khronos-report.json +295 -0
  81. package/templates/animation-studio/public/hifi-cast/quaternius-report.json +449 -0
  82. package/templates/animation-studio/public/hifi-cast/rpm/cesiumman.glb +0 -0
  83. package/templates/animation-studio/public/hifi-cast/rpm/fox.glb +0 -0
  84. package/templates/animation-studio/public/hifi-cast/rpm/riggedfigure.glb +0 -0
  85. package/templates/animation-studio/public/hifi-cast/rpm-report.json +301 -0
  86. package/templates/animation-studio/scripts/anim.ts +103 -0
  87. package/templates/animation-studio/scripts/animation-scene.ts +457 -0
  88. package/templates/animation-studio/scripts/asset-motion-probe.ts +450 -0
  89. package/templates/animation-studio/scripts/asset-render-probe.ts +152 -0
  90. package/templates/animation-studio/scripts/author-office-scene.ts +65 -0
  91. package/templates/animation-studio/scripts/build-cast-library.ts +97 -0
  92. package/templates/animation-studio/scripts/build-characters.ts +1543 -0
  93. package/templates/animation-studio/scripts/build-clip-library.ts +972 -0
  94. package/templates/animation-studio/scripts/clip-decision-cli.ts +51 -0
  95. package/templates/animation-studio/scripts/determinism-check.ts +48 -0
  96. package/templates/animation-studio/scripts/generate-scene.ts +95 -0
  97. package/templates/animation-studio/scripts/hifi-cast-validate.ts +572 -0
  98. package/templates/animation-studio/scripts/motion-evidence-cli.ts +150 -0
  99. package/templates/animation-studio/scripts/motion-evidence.ts +362 -0
  100. package/templates/animation-studio/scripts/preview-server.ts +52 -0
  101. package/templates/animation-studio/scripts/regen-manifest.ts +156 -0
  102. package/templates/animation-studio/scripts/render-core.ts +360 -0
  103. package/templates/animation-studio/scripts/render-live.ts +813 -0
  104. package/templates/animation-studio/scripts/render-parallel.ts +70 -0
  105. package/templates/animation-studio/scripts/render-server.ts +119 -0
  106. package/templates/animation-studio/scripts/resolve-asset.ts +669 -0
  107. package/templates/animation-studio/scripts/skeleton-overlay-cli.ts +82 -0
  108. package/templates/animation-studio/scripts/skeleton-overlay.ts +293 -0
  109. package/templates/animation-studio/scripts/studio-tools-demo.ts +45 -0
  110. package/templates/animation-studio/scripts/texture-bake.ts +297 -0
  111. package/templates/{cartoon-studio → animation-studio}/scripts/validate-characters.ts +0 -0
  112. package/templates/animation-studio/scripts/verify-extracted-overlay-cli.ts +264 -0
  113. package/templates/animation-studio/src/animation-episode-validator.ts +97 -0
  114. package/templates/animation-studio/src/animation-performance.ts +556 -0
  115. package/templates/animation-studio/src/aura-assets.ts +71 -0
  116. package/templates/animation-studio/src/character.ts +40 -0
  117. package/templates/animation-studio/src/director/compile-episode-document.ts +45 -0
  118. package/templates/animation-studio/src/director/director-heuristics.ts +697 -0
  119. package/templates/animation-studio/src/director/prompt-to-scene.ts +369 -0
  120. package/templates/animation-studio/src/empty-document.ts +77 -0
  121. package/templates/animation-studio/src/episode-document.ts +442 -0
  122. package/templates/animation-studio/src/examples/moon-garden.example.ts +183 -0
  123. package/templates/animation-studio/src/fidelity.ts +129 -0
  124. package/templates/animation-studio/src/graph.ts +14 -0
  125. package/templates/animation-studio/src/procedural-hdri.ts +243 -0
  126. package/templates/animation-studio/src/profile.ts +97 -0
  127. package/templates/animation-studio/src/render-live-route.ts +42 -0
  128. package/templates/animation-studio/src/render-modes.ts +137 -0
  129. package/templates/animation-studio/src/scene-player.ts +867 -0
  130. package/templates/animation-studio/src/set-templates.ts +361 -0
  131. package/templates/animation-studio/src/studio/episode-document-store.ts +72 -0
  132. package/templates/animation-studio/src/studio/scene-tool-registry.ts +86 -0
  133. package/templates/animation-studio/src/studio/scene-tools.ts +169 -0
  134. package/templates/animation-studio/tests/reports/animation-studio/hifi-cast-validation.json +938 -0
  135. package/templates/animation-studio/tsconfig.json +26 -0
  136. package/templates/{cartoon-studio → animation-studio}/vite.config.ts +6 -1
  137. package/templates/character-controller/README.md +33 -0
  138. package/templates/character-controller/index.html +19 -0
  139. package/templates/character-controller/package.json +23 -0
  140. package/templates/character-controller/playwright.config.ts +14 -0
  141. package/templates/character-controller/src/controller.ts +44 -0
  142. package/templates/character-controller/src/main.ts +62 -0
  143. package/templates/character-controller/tests/route-health.spec.ts +26 -0
  144. package/templates/character-controller/tests/screenshot.spec.ts +9 -0
  145. package/templates/character-controller/tsconfig.json +15 -0
  146. package/templates/cinematic-scene/package.json +1 -1
  147. package/templates/episode-builder/README.md +4 -4
  148. package/templates/episode-builder/package.json +1 -1
  149. package/templates/episode-builder/src/aura-assets.ts +1 -1
  150. package/templates/episode-builder/src/builder.ts +4 -4
  151. package/templates/episode-builder/src/episode.ts +21 -21
  152. package/templates/episode-builder/src/main.ts +20 -20
  153. package/templates/episode-builder/src/render-plan.ts +13 -13
  154. package/templates/episode-builder/tests/storyboard-playback.spec.ts +7 -7
  155. package/templates/fighting-game/package.json +1 -1
  156. package/templates/mini-game/package.json +1 -1
  157. package/templates/product-viewer/package.json +1 -1
  158. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/README.md +5 -5
  159. package/templates/{cartoon-channel → prompt-animation-channel}/index.html +1 -1
  160. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/package.json +2 -2
  161. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/src/aura-assets.ts +1 -1
  162. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/src/episode.ts +22 -22
  163. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/src/main.ts +28 -28
  164. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/src/render-plan.ts +13 -13
  165. package/templates/{cartoon-channel → prompt-animation-channel}/tests/route-health.spec.ts +1 -1
  166. package/templates/{prompt-cartoon-channel → prompt-animation-channel}/tests/storyboard-playback.spec.ts +8 -8
  167. package/templates/cartoon-studio/aura.assets.json +0 -400
  168. package/templates/cartoon-studio/package.json +0 -33
  169. package/templates/cartoon-studio/public/aura-assets/luma.authored.glb +0 -0
  170. package/templates/cartoon-studio/public/aura-assets/miko.authored.glb +0 -0
  171. package/templates/cartoon-studio/scripts/build-characters.ts +0 -738
  172. package/templates/cartoon-studio/scripts/build-dialogue-audio.ts +0 -262
  173. package/templates/cartoon-studio/scripts/episode.ts +0 -323
  174. package/templates/cartoon-studio/scripts/render-live.ts +0 -873
  175. package/templates/cartoon-studio/src/aura-assets.ts +0 -64
  176. package/templates/cartoon-studio/src/characters.ts +0 -65
  177. package/templates/cartoon-studio/src/episode-renderer.ts +0 -605
  178. package/templates/cartoon-studio/src/episode.ts +0 -306
  179. package/templates/cartoon-studio/src/main.ts +0 -400
  180. package/templates/cartoon-studio/src/render-live-route.ts +0 -913
  181. package/templates/cartoon-studio/src/render-plan.ts +0 -567
  182. package/templates/cartoon-studio/src/review.ts +0 -99
  183. package/templates/cartoon-studio/src/studio.ts +0 -101
  184. package/templates/cartoon-studio/test-results/.last-run.json +0 -4
  185. package/templates/cartoon-studio/tests/episode-render.spec.ts +0 -44
  186. package/templates/cartoon-studio/tests/motion-quality.spec.ts +0 -45
  187. package/templates/cartoon-studio/tests/route-health.spec.ts +0 -7
  188. package/templates/cartoon-studio/tests/storyboard-playback.spec.ts +0 -99
  189. package/templates/cartoon-studio/tests/visual-review.spec.ts +0 -21
  190. package/templates/cartoon-studio/tsconfig.json +0 -14
  191. package/templates/prompt-cartoon-channel/index.html +0 -13
  192. package/templates/prompt-cartoon-channel/src/sets.ts +0 -14
  193. /package/templates/{cartoon-channel → animation-channel}/aura.assets.json +0 -0
  194. /package/templates/{cartoon-channel → animation-channel}/playwright.config.ts +0 -0
  195. /package/templates/{cartoon-channel → animation-channel}/public/aura-assets/luma.047f5e5f.glb +0 -0
  196. /package/templates/{cartoon-channel → animation-channel}/public/aura-assets/luma.thumb.svg +0 -0
  197. /package/templates/{cartoon-channel → animation-channel}/public/aura-assets/miko.047f5e5f.glb +0 -0
  198. /package/templates/{cartoon-channel → animation-channel}/public/aura-assets/miko.thumb.svg +0 -0
  199. /package/templates/{cartoon-channel → animation-channel}/public/aura-assets/moon-garden-feature-frame.png +0 -0
  200. /package/templates/{cartoon-channel → animation-channel}/src/aura-assets.ts +0 -0
  201. /package/templates/{cartoon-channel → animation-channel}/src/characters.ts +0 -0
  202. /package/templates/{cartoon-channel → animation-channel}/src/contract.ts +0 -0
  203. /package/templates/{cartoon-channel → animation-channel}/src/sets.ts +0 -0
  204. /package/templates/{cartoon-channel → animation-channel}/test-results/.last-run.json +0 -0
  205. /package/templates/{cartoon-channel → animation-channel}/tests/reports/prompt-animation/cartoon-sample-episode.png +0 -0
  206. /package/templates/{cartoon-channel → animation-channel}/tsconfig.json +0 -0
  207. /package/templates/{cartoon-studio → animation-studio}/playwright.config.ts +0 -0
  208. /package/templates/{cartoon-studio → animation-studio}/public/aura-assets/luma.thumb.svg +0 -0
  209. /package/templates/{cartoon-studio → animation-studio}/public/aura-assets/miko.thumb.svg +0 -0
  210. /package/templates/{cartoon-studio → animation-studio}/src/contract.ts +0 -0
  211. /package/templates/{prompt-cartoon-channel → prompt-animation-channel}/playwright.config.ts +0 -0
  212. /package/templates/{prompt-cartoon-channel → prompt-animation-channel}/src/characters.ts +0 -0
  213. /package/templates/{prompt-cartoon-channel → prompt-animation-channel}/src/contract.ts +0 -0
  214. /package/templates/{cartoon-studio → prompt-animation-channel}/src/sets.ts +0 -0
  215. /package/templates/{prompt-cartoon-channel → prompt-animation-channel}/tsconfig.json +0 -0
@@ -1,605 +0,0 @@
1
- import {
2
- createShotPlaybackPlan,
3
- exportCaptionTrack,
4
- sampleAuraVoiceBridgeAtTime,
5
- sampleShotPlaybackPlan
6
- } from "@aura3d/engine";
7
- import {
8
- episode,
9
- episodeAudioCues,
10
- episodeContractId,
11
- missingCartoonCharacterAssets,
12
- publicCartoonAssetInstructions,
13
- requiredCartoonCharacterAssets,
14
- typedCartoonAssetSummary,
15
- youtubeDraftMetadata
16
- } from "./episode";
17
- import {
18
- audioStemManifest,
19
- auraVoicePackage,
20
- alternateLanguageDubMetadata,
21
- bridgeIssues,
22
- captionFrameSyncSourceProof,
23
- captionTimingProof,
24
- cartoonStudioShowBibleBatchRenderPlan,
25
- deterministicScreenshotFixtures,
26
- performanceCoverage,
27
- promptAnimationEvidence,
28
- publishReadiness,
29
- renderOutputPackage,
30
- renderPlan,
31
- sampleRenderSourceWorkflow,
32
- visemeFrameSyncSourceProof,
33
- visemeTrack
34
- } from "./render-plan";
35
- import {
36
- cartoonEpisodePackageDirectory,
37
- createCartoonEpisodeReviewPackage,
38
- requiredCartoonEpisodePackageFiles
39
- } from "./review";
40
-
41
- export type CartoonEpisodePackageMode = "plan" | "preview" | "render" | "package" | "review";
42
-
43
- export interface CartoonEpisodePackageFile {
44
- readonly path: string;
45
- readonly kind: "json" | "markdown" | "text" | "png-base64" | "svg";
46
- readonly contents: string;
47
- }
48
-
49
- export interface CartoonEpisodePackageBuild {
50
- readonly packageDirectory: string;
51
- readonly mode: CartoonEpisodePackageMode;
52
- readonly files: readonly CartoonEpisodePackageFile[];
53
- readonly requiredFiles: readonly string[];
54
- readonly hasWebm: boolean;
55
- readonly hasPngSequenceFallback: boolean;
56
- readonly publishReady: boolean;
57
- }
58
-
59
- export const moonGardenEpisodePackageId = "moon-garden-001" as const;
60
-
61
- const generatedAt = new Date().toISOString();
62
-
63
- const packageShotPlaybackPlan = createShotPlaybackPlan({
64
- timeline: episode.shotTimeline,
65
- performance: episode.performance,
66
- captions: episode.captionTrack,
67
- visemes: visemeTrack,
68
- runtimeNodeByCharacterId: {
69
- miko: "miko",
70
- luma: "luma"
71
- },
72
- loop: false
73
- });
74
-
75
- export function createCartoonEpisodePlanArtifact() {
76
- return {
77
- artifact: "cartoon-episode-plan",
78
- schema: "aura3d-cartoon-studio-template-plan/v1",
79
- contractId: episodeContractId,
80
- packageId: moonGardenEpisodePackageId,
81
- generatedAt,
82
- episodePlan: episode.episodePlan,
83
- storyBible: episode.storyBible,
84
- storyboard: episode.storyboard,
85
- shotTimeline: episode.shotTimeline,
86
- dialogueTrack: episode.dialogueTrack,
87
- captionTrack: episode.captionTrack,
88
- alternateLanguageDubMetadata,
89
- batchRenderPlan: cartoonStudioShowBibleBatchRenderPlan,
90
- renderQueue: renderPlan,
91
- outputPackage: renderOutputPackage,
92
- audioStemManifest,
93
- youtubeDraftMetadata,
94
- requiredTypedAssets: requiredCartoonCharacterAssets,
95
- missingTypedAssets: missingCartoonCharacterAssets,
96
- assetCommands: publicCartoonAssetInstructions
97
- };
98
- }
99
-
100
- export function createCartoonEpisodeRouteProofArtifact() {
101
- const probeTimes = [1, 10, 21, 32, 43, 55];
102
- return {
103
- artifact: "cartoon-route-proof",
104
- schema: "aura3d-cartoon-route-proof/v1",
105
- contractId: episodeContractId,
106
- episodeId: episode.episodePlan.episodeId,
107
- generatedAt,
108
- route: renderPlan.route,
109
- routeMode: "template-preview",
110
- proofSource: "template-side package runner",
111
- appProofGlobal: "window.__AURA3D_CARTOON_TEMPLATE__",
112
- nonblankExpected: true,
113
- sourceOnly: false,
114
- shots: episode.shotTimeline.shots.map((shot) => ({
115
- shotId: shot.shotId,
116
- startTime: shot.startTime,
117
- endTime: shot.endTime,
118
- duration: shot.endTime - shot.startTime,
119
- sceneId: shot.sceneId,
120
- camera: shot.camera,
121
- characters: shot.characters
122
- })),
123
- captionIds: episode.captionTrack.cues.map((cue) => cue.captionId),
124
- visemeCueCount: visemeTrack.cues.length,
125
- performanceCoverage,
126
- typedAssets: typedCartoonAssetSummary,
127
- missingTypedAssets: missingCartoonCharacterAssets,
128
- bridgeIssues,
129
- probeSamples: probeTimes.map((time) => ({
130
- time,
131
- playback: sampleShotPlaybackPlan(packageShotPlaybackPlan, time),
132
- auraVoice: sampleAuraVoiceBridgeAtTime(auraVoicePackage, time)
133
- })),
134
- errors: []
135
- };
136
- }
137
-
138
- export function createCartoonAssetProvenanceArtifact() {
139
- return {
140
- artifact: "cartoon-asset-provenance",
141
- schema: "aura3d-cartoon-asset-provenance/v1",
142
- contractId: episodeContractId,
143
- generatedAt,
144
- typedAssets: typedCartoonAssetSummary,
145
- requiredCharacterAssets: requiredCartoonCharacterAssets,
146
- missingCharacterAssets: missingCartoonCharacterAssets,
147
- assetCommands: publicCartoonAssetInstructions,
148
- starterFallbackMode: missingCartoonCharacterAssets.length > 0,
149
- publishReady: missingCartoonCharacterAssets.length === 0,
150
- characters: episode.episodePlan.characters.map((character) => ({
151
- id: character.id,
152
- name: character.name,
153
- hasTypedAsset: !missingCartoonCharacterAssets.includes(character.id as typeof missingCartoonCharacterAssets[number]),
154
- style: character.style,
155
- voiceId: character.voiceId
156
- })),
157
- props: episode.storyBible.props.map((prop) => ({
158
- id: prop.id,
159
- name: prop.name,
160
- role: prop.role,
161
- fallback: prop.primitiveFallback
162
- })),
163
- audioCues: episodeAudioCues
164
- };
165
- }
166
-
167
- export function createCartoonRenderManifestArtifact() {
168
- const outputMode = "encoded-webm";
169
- const encodedFrameCount = episode.episodePlan.runtime.duration * episode.episodePlan.runtime.frameRate;
170
- return {
171
- artifact: "cartoon-render-manifest",
172
- schema: "aura3d-cartoon-render-manifest/v1",
173
- contractId: episodeContractId,
174
- packageId: moonGardenEpisodePackageId,
175
- generatedAt,
176
- outputMode,
177
- hasEncodedVideo: true,
178
- encodedVideo: {
179
- path: "episode.webm",
180
- codec: "vp9",
181
- frameDirectory: "frames",
182
- sourceFrameCount: generatedCartoonFrames.length,
183
- encodedFrameCount,
184
- source: "template-generated vector frames driven by the Moon Garden shot plan, encoded by the template render runner"
185
- },
186
- duration: episode.episodePlan.runtime.duration,
187
- frameRate: episode.episodePlan.runtime.frameRate,
188
- resolution: episode.episodePlan.runtime.resolution,
189
- renderQueueId: `${renderPlan.episodeId}:render-queue`,
190
- queueItems: renderPlan.items.map((item) => ({
191
- id: item.id,
192
- time: item.time,
193
- frame: item.frame,
194
- shotId: item.shotId,
195
- outputIds: item.outputIds
196
- })),
197
- outputPackage: renderOutputPackage,
198
- promptAnimationEvidence: createRenderedPromptAnimationEvidenceArtifact(),
199
- motionQuality: createCartoonMotionQualityArtifact(),
200
- publishReadiness
201
- };
202
- }
203
-
204
- export function createCartoonVisualAcceptanceArtifact() {
205
- const frameHashes = generatedCartoonFrames.map((frame) => frame.hash);
206
- return {
207
- artifact: "cartoon-visual-acceptance",
208
- schema: "aura3d-cartoon-visual-acceptance/v1",
209
- contractId: episodeContractId,
210
- generatedAt,
211
- status: "pass",
212
- ok: true,
213
- visualOk: true,
214
- publishReady: true,
215
- releaseReady: true,
216
- encodedVideoPresent: true,
217
- pngSequenceFallbackPresent: false,
218
- rejectsStillImageWobbleAsSuccess: true,
219
- notTrue3DAccepted: false,
220
- sourceOnlyAcceptedAsPublishProof: false,
221
- requiredHumanReview: true,
222
- visibleCharacterCount: 2,
223
- representativeFrameCount: 4,
224
- firstFramePath: "frames/first.png",
225
- dialogueFramePath: "frames/dialogue.png",
226
- actionFramePath: "frames/action.png",
227
- finalFramePath: "frames/final.png",
228
- frameHashChanges: Math.max(0, new Set(frameHashes).size - 1),
229
- independentRegionMotionSegments: 4,
230
- characterRegionMotionSegments: 4,
231
- bodyRegionMotionSegments: 4,
232
- mouthMotionSegments: 2,
233
- cameraMotionDeclared: true,
234
- globalOnlyMotion: false,
235
- flatLayerMotion: false,
236
- frames: [
237
- { id: "first", path: "frames/first.png", frameHash: generatedCartoonFrames[0]?.hash },
238
- { id: "dialogue", path: "frames/dialogue.png", frameHash: generatedCartoonFrames[2]?.hash },
239
- { id: "action", path: "frames/action.png", frameHash: generatedCartoonFrames[5]?.hash },
240
- { id: "final", path: "frames/final.png", frameHash: generatedCartoonFrames[generatedCartoonFrames.length - 1]?.hash }
241
- ],
242
- motionSegments: [
243
- { id: "dialogue-miko", kind: "dialogue", independentRegionMotion: true, mouthMotion: true, characterIds: ["miko"] },
244
- { id: "dialogue-luma", kind: "dialogue", independentRegionMotion: true, mouthMotion: true, characterIds: ["luma"] },
245
- { id: "teamwork-sweep", kind: "action", independentRegionMotion: true, bodyRegionMotion: true, characterIds: ["miko", "luma"] },
246
- { id: "final-celebrate", kind: "action", independentRegionMotion: true, bodyRegionMotion: true, characterIds: ["miko", "luma"] }
247
- ],
248
- checks: [
249
- {
250
- id: "caption-sync-source",
251
- passed: captionFrameSyncSourceProof.captionDisplayWithinOneFrame,
252
- evidence: {
253
- maxObservedDriftFrames: captionFrameSyncSourceProof.maxObservedDriftFrames,
254
- allowedDriftFrames: captionFrameSyncSourceProof.allowedDriftFrames
255
- }
256
- },
257
- {
258
- id: "mouth-sync-source",
259
- passed: visemeFrameSyncSourceProof.mouthMovementWithinOneFrame,
260
- evidence: {
261
- maxObservedDriftFrames: visemeFrameSyncSourceProof.maxObservedDriftFrames,
262
- coveredLineIds: visemeFrameSyncSourceProof.coveredLineIds
263
- }
264
- },
265
- {
266
- id: "typed-assets",
267
- passed: missingCartoonCharacterAssets.length === 0,
268
- evidence: {
269
- missingTypedAssets: missingCartoonCharacterAssets
270
- }
271
- },
272
- {
273
- id: "real-encoded-video",
274
- passed: true,
275
- evidence: {
276
- path: "episode.webm",
277
- source: "Template render runner encodes vector frame sequence with ffmpeg when available."
278
- }
279
- }
280
- ],
281
- representativeFrames: deterministicScreenshotFixtures,
282
- reviewerRequiredBeforePublish: true
283
- };
284
- }
285
-
286
- export function createCartoonMotionQualityArtifact() {
287
- const frameHashes = generatedCartoonFrames.map((frame) => frame.hash);
288
- return {
289
- artifact: "cartoon-motion-quality",
290
- schema: "aura3d-cartoon-motion-quality/v1",
291
- contractId: episodeContractId,
292
- generatedAt,
293
- videoPath: "episode.webm",
294
- frameRate: episode.episodePlan.runtime.frameRate,
295
- duration: episode.episodePlan.runtime.duration,
296
- sourceFrameCount: generatedCartoonFrames.length,
297
- encodedFrameCount: episode.episodePlan.runtime.duration * episode.episodePlan.runtime.frameRate,
298
- frameHashChanges: Math.max(0, new Set(frameHashes).size - 1),
299
- independentRegionMotionSegments: 4,
300
- characterRegionMotionSegments: 4,
301
- bodyRegionMotionSegments: 4,
302
- mouthMotionSegments: 2,
303
- globalMotionSegments: 0,
304
- cameraMotionDeclared: true,
305
- globalOnlyMotion: false,
306
- flatLayerMotion: false,
307
- regions: [
308
- { id: "miko:mouth", kind: "mouth", movesDuringDialogue: true },
309
- { id: "luma:mouth", kind: "mouth", movesDuringDialogue: true },
310
- { id: "miko:arms", kind: "limb", movesDuringAction: true },
311
- { id: "luma:arms", kind: "limb", movesDuringAction: true }
312
- ],
313
- rejectedEvidence: {
314
- stillImageWobbleAccepted: false,
315
- subtitleOverStillAccepted: false,
316
- sourceOnlyAccepted: false
317
- }
318
- };
319
- }
320
-
321
- export function createRenderedPromptAnimationEvidenceArtifact() {
322
- return {
323
- artifact: "prompt-animation-evidence",
324
- schema: "aura3d-rendered-prompt-animation-evidence/v1",
325
- contractId: episodeContractId,
326
- generatedAt,
327
- ok: true,
328
- routeHealth: { status: "pass", route: renderPlan.route },
329
- renderOutput: {
330
- mode: "encoded-webm",
331
- path: "episode.webm",
332
- thumbnailPath: "thumbnail.png",
333
- frameDirectory: "frames",
334
- encodedVideoPresent: true,
335
- pngSequenceFallbackPresent: false
336
- },
337
- captions: {
338
- status: captionTimingProof.status,
339
- cueCount: episode.captionTrack.cues.length,
340
- maxDriftFrames: captionTimingProof.maxDriftFrames
341
- },
342
- visemes: {
343
- status: visemeFrameSyncSourceProof.mouthMovementWithinOneFrame ? "pass" : "fail",
344
- cueCount: visemeTrack.cues.length,
345
- visibleMouthMovementRequired: true,
346
- visibleMouthMovementEvidencePath: "motion-quality.json"
347
- },
348
- motionQuality: createCartoonMotionQualityArtifact(),
349
- typedAssets: typedCartoonAssetSummary,
350
- failures: []
351
- };
352
- }
353
-
354
- export function createCartoonEpisodeMetadataArtifact() {
355
- return {
356
- artifact: "cartoon-episode-metadata",
357
- schema: "aura3d-cartoon-episode-metadata/v1",
358
- contractId: episodeContractId,
359
- generatedAt,
360
- packageId: moonGardenEpisodePackageId,
361
- title: episode.episodePlan.title,
362
- episodeId: episode.episodePlan.episodeId,
363
- duration: episode.episodePlan.runtime.duration,
364
- frameRate: episode.episodePlan.runtime.frameRate,
365
- resolution: episode.episodePlan.runtime.resolution,
366
- language: episode.episodePlan.language,
367
- youtube: youtubeDraftMetadata,
368
- outputBoundary: {
369
- webmRequiredForPublish: true,
370
- webmPresent: true,
371
- pngSequenceFallbackPresent: false,
372
- publishReady: true
373
- },
374
- thumbnail: {
375
- path: "thumbnail.png",
376
- captureSource: "browser-route-canvas",
377
- route: `${renderPlan.route}?capture=thumbnail`,
378
- sourceSceneStateId: renderOutputPackage.thumbnailCapture.sourceSceneStateId,
379
- time: renderOutputPackage.thumbnailCapture.time
380
- },
381
- renderWorkflow: {
382
- status: "encoded-video-ready",
383
- outputMode: "episode.webm",
384
- route: renderPlan.route,
385
- humanReviewRequired: true,
386
- sourceOnlyProofAccepted: false,
387
- stillImagePuppetAccepted: false,
388
- typedAssets: typedCartoonAssetSummary
389
- }
390
- };
391
- }
392
-
393
- export function createPngSequenceFallbackArtifact() {
394
- return {
395
- artifact: "png-sequence-fallback",
396
- schema: "aura3d-cartoon-png-sequence-fallback/v1",
397
- contractId: episodeContractId,
398
- generatedAt,
399
- publishReady: false,
400
- reason: "No real video encoder adapter is available in the template-local runner.",
401
- frames: renderPlan.items.map((item, index) => ({
402
- index,
403
- path: `frames/frame-${String(index + 1).padStart(4, "0")}.png`,
404
- time: item.time,
405
- frame: item.frame,
406
- shotId: item.shotId,
407
- sourceSceneStateId: item.sourceSceneState?.sceneStateId
408
- }))
409
- };
410
- }
411
-
412
- export function createCartoonEpisodePackage(mode: CartoonEpisodePackageMode = "package"): CartoonEpisodePackageBuild {
413
- const captionVtt = exportCaptionTrack(episode.captionTrack, "vtt");
414
- const captionSrt = exportCaptionTrack(episode.captionTrack, "srt");
415
- const fallback = createPngSequenceFallbackArtifact();
416
- const hasWebm = true;
417
- const hasPngSequenceFallback = false;
418
- const files: CartoonEpisodePackageFile[] = [
419
- jsonFile("episode-plan.json", createCartoonEpisodePlanArtifact()),
420
- jsonFile("metadata.json", createCartoonEpisodeMetadataArtifact()),
421
- jsonFile("route-proof.json", createCartoonEpisodeRouteProofArtifact()),
422
- jsonFile("asset-provenance.json", createCartoonAssetProvenanceArtifact()),
423
- jsonFile("render-manifest.json", createCartoonRenderManifestArtifact()),
424
- jsonFile("dub-metadata.json", alternateLanguageDubMetadata),
425
- jsonFile("batch-render-plan.json", cartoonStudioShowBibleBatchRenderPlan),
426
- jsonFile("motion-quality.json", createCartoonMotionQualityArtifact()),
427
- jsonFile("visual-acceptance.json", createCartoonVisualAcceptanceArtifact()),
428
- jsonFile("prompt-animation-evidence.json", createRenderedPromptAnimationEvidenceArtifact()),
429
- jsonFile("audio-stems.json", audioStemManifest),
430
- textFile("captions.vtt", captionVtt.text),
431
- textFile("captions.srt", captionSrt.text),
432
- markdownFile("review-package.md", createCartoonEpisodeReviewPackage({
433
- packageDirectory: cartoonEpisodePackageDirectory,
434
- hasWebm,
435
- hasPngSequenceFallback,
436
- generatedAt
437
- })),
438
- ...generatedCartoonFrames.map((frame) => svgFile(frame.svgPath, createCartoonFrameSvg(frame))),
439
- svgFile("frames/first.svg", createCartoonFrameSvg(generatedCartoonFrames[0])),
440
- svgFile("frames/dialogue.svg", createCartoonFrameSvg(generatedCartoonFrames[2])),
441
- svgFile("frames/action.svg", createCartoonFrameSvg(generatedCartoonFrames[5])),
442
- svgFile("frames/final.svg", createCartoonFrameSvg(generatedCartoonFrames[generatedCartoonFrames.length - 1]))
443
- ];
444
-
445
- return {
446
- packageDirectory: cartoonEpisodePackageDirectory,
447
- mode,
448
- files,
449
- requiredFiles: requiredCartoonEpisodePackageFiles,
450
- hasWebm,
451
- hasPngSequenceFallback,
452
- publishReady: true
453
- };
454
- }
455
-
456
- function jsonFile(path: string, value: unknown): CartoonEpisodePackageFile {
457
- return {
458
- path,
459
- kind: "json",
460
- contents: `${JSON.stringify(value, null, 2)}\n`
461
- };
462
- }
463
-
464
- function markdownFile(path: string, contents: string): CartoonEpisodePackageFile {
465
- return {
466
- path,
467
- kind: "markdown",
468
- contents: `${contents.trimEnd()}\n`
469
- };
470
- }
471
-
472
- function textFile(path: string, contents: string): CartoonEpisodePackageFile {
473
- return {
474
- path,
475
- kind: "text",
476
- contents: `${contents.trimEnd()}\n`
477
- };
478
- }
479
-
480
- function pngFile(path: string, contents: string): CartoonEpisodePackageFile {
481
- return {
482
- path,
483
- kind: "png-base64",
484
- contents
485
- };
486
- }
487
-
488
- function svgFile(path: string, contents: string): CartoonEpisodePackageFile {
489
- return {
490
- path,
491
- kind: "svg",
492
- contents
493
- };
494
- }
495
-
496
- interface GeneratedCartoonFrame {
497
- readonly index: number;
498
- readonly svgPath: string;
499
- readonly hash: string;
500
- readonly mikoX: number;
501
- readonly mikoY: number;
502
- readonly lumaX: number;
503
- readonly lumaY: number;
504
- readonly mikoArm: number;
505
- readonly lumaArm: number;
506
- readonly mikoMouth: number;
507
- readonly lumaMouth: number;
508
- readonly glow: number;
509
- readonly caption: string;
510
- }
511
-
512
- const generatedCartoonFrames: readonly GeneratedCartoonFrame[] = Array.from({ length: 30 }, (_, index) => {
513
- const phase = index / 29;
514
- const sweep = Math.sin(phase * Math.PI * 2);
515
- const bounce = Math.sin(phase * Math.PI * 4);
516
- const mikoMouth = index >= 1 && index <= 4 ? 1 + (index % 2) * 0.7 : 0.35;
517
- const lumaMouth = index >= 5 && index <= 8 ? 1 + (index % 2) * 0.7 : 0.35;
518
- return {
519
- index,
520
- svgPath: `frames/frame-${String(index + 1).padStart(4, "0")}.svg`,
521
- hash: `frame-${index}-${Math.round((sweep + 1) * 1000)}-${Math.round((bounce + 1) * 1000)}-${mikoMouth}-${lumaMouth}`,
522
- mikoX: 360 + phase * 115,
523
- mikoY: 420 + bounce * 8,
524
- lumaX: 900 - phase * 90,
525
- lumaY: 416 - bounce * 7,
526
- mikoArm: -24 + sweep * 34,
527
- lumaArm: 18 - sweep * 30,
528
- mikoMouth,
529
- lumaMouth,
530
- glow: 0.28 + phase * 0.72,
531
- caption: phase < 0.38
532
- ? "Luma, the moon lilies are losing their sparkle."
533
- : phase < 0.72
534
- ? "We sweep softly and wake the glow stones."
535
- : "The garden sparkles before bedtime."
536
- };
537
- });
538
-
539
- function createCartoonFrameSvg(frame = generatedCartoonFrames[0]): string {
540
- const mikoArmEndX = frame.mikoX + 78 + frame.mikoArm;
541
- const lumaArmEndX = frame.lumaX - 70 + frame.lumaArm;
542
- const glowOpacity = frame.glow.toFixed(2);
543
- return `<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
544
- <defs>
545
- <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
546
- <stop offset="0" stop-color="#071525"/>
547
- <stop offset="0.58" stop-color="#123a47"/>
548
- <stop offset="1" stop-color="#071019"/>
549
- </linearGradient>
550
- <filter id="softGlow"><feGaussianBlur stdDeviation="8" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
551
- </defs>
552
- <rect width="1280" height="720" fill="url(#sky)"/>
553
- <circle cx="640" cy="250" r="170" fill="none" stroke="#7de2ff" stroke-opacity="0.18" stroke-width="3"/>
554
- <g opacity="0.32">
555
- <rect x="120" y="370" width="80" height="160" fill="#1f5d68"/>
556
- <rect x="230" y="330" width="130" height="200" fill="#214c62"/>
557
- <rect x="780" y="355" width="90" height="175" fill="#1f5d68"/>
558
- <rect x="915" y="315" width="120" height="215" fill="#214c62"/>
559
- <rect x="1060" y="385" width="90" height="145" fill="#1f5d68"/>
560
- </g>
561
- <polygon points="140,590 1140,590 1005,500 275,500" fill="#102932" stroke="#53ffd2" stroke-width="5"/>
562
- <line x1="250" y1="528" x2="1030" y2="528" stroke="#ffe18e" stroke-width="5" stroke-linecap="round"/>
563
- <g filter="url(#softGlow)" opacity="${glowOpacity}">
564
- <circle cx="610" cy="510" r="24" fill="#ffe18e"/>
565
- <circle cx="675" cy="505" r="18" fill="#7de2ff"/>
566
- <circle cx="720" cy="520" r="15" fill="#40ffbf"/>
567
- </g>
568
- ${robotSvg("miko", frame.mikoX, frame.mikoY, "#7de2ff", "#f8fff2", frame.mikoArm, mikoArmEndX, frame.mikoMouth, false)}
569
- ${robotSvg("luma", frame.lumaX, frame.lumaY, "#ffe18e", "#40ffbf", frame.lumaArm, lumaArmEndX, frame.lumaMouth, true)}
570
- <rect x="220" y="632" width="840" height="52" rx="18" fill="#02080f" fill-opacity="0.82" stroke="#7de2ff" stroke-opacity="0.32"/>
571
- <text x="640" y="665" text-anchor="middle" fill="#f8fff2" font-family="Arial, sans-serif" font-size="24" font-weight="700">${escapeXml(frame.caption)}</text>
572
- </svg>`;
573
- }
574
-
575
- function robotSvg(
576
- id: string,
577
- x: number,
578
- y: number,
579
- body: string,
580
- mouth: string,
581
- armAngle: number,
582
- armEndX: number,
583
- mouthOpen: number,
584
- flip: boolean
585
- ): string {
586
- const dir = flip ? -1 : 1;
587
- const eyeX = dir * 20;
588
- const mouthHeight = 5 + mouthOpen * 10;
589
- return `<g id="${id}" transform="translate(${x.toFixed(1)} ${y.toFixed(1)})">
590
- <ellipse cx="0" cy="116" rx="58" ry="14" fill="#020711" opacity="0.38"/>
591
- <rect x="-42" y="-12" width="84" height="96" rx="36" fill="${body}" stroke="#071019" stroke-width="4"/>
592
- <circle cx="0" cy="-58" r="46" fill="${body}" stroke="#071019" stroke-width="4"/>
593
- <circle cx="${-eyeX}" cy="-66" r="6" fill="#06131c"/>
594
- <circle cx="${eyeX}" cy="-66" r="6" fill="#06131c"/>
595
- <rect x="-18" y="-43" width="36" height="${mouthHeight.toFixed(1)}" rx="5" fill="${mouth}"/>
596
- <line x1="${dir * 36}" y1="12" x2="${(armEndX - x).toFixed(1)}" y2="${(44 + armAngle * 0.2).toFixed(1)}" stroke="${body}" stroke-width="18" stroke-linecap="round"/>
597
- <line x1="${-dir * 34}" y1="18" x2="${(-dir * 92).toFixed(1)}" y2="${(42 - armAngle * 0.15).toFixed(1)}" stroke="${body}" stroke-width="18" stroke-linecap="round"/>
598
- <line x1="-22" y1="78" x2="-38" y2="128" stroke="${body}" stroke-width="20" stroke-linecap="round"/>
599
- <line x1="22" y1="78" x2="42" y2="126" stroke="${body}" stroke-width="20" stroke-linecap="round"/>
600
- </g>`;
601
- }
602
-
603
- function escapeXml(value: string): string {
604
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
605
- }