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,567 +0,0 @@
1
- import {
2
- collectPromptAnimationEvidence,
3
- createAudioStemManifest,
4
- createAuraVoiceBridgePackage,
5
- createAuraVoiceVisemeTrack,
6
- createCaptionTimingProof,
7
- createGlbBlendshapeVisemeCue,
8
- createCartoonPerformanceCoverage,
9
- createCartoonRenderOutputPackageMetadata,
10
- createPrimitiveMouthVisemeCues,
11
- createPromptAnimationDeterministicScreenshotFixtureMetadata,
12
- evaluatePromptAnimationPublishReadiness,
13
- defineDubMap,
14
- glbVisemeBlendshapeExample,
15
- primitiveMouthVisemeExample,
16
- sampleAuraVoiceBridgeAtTime,
17
- sampleVisemeTrack,
18
- validateAuraVoiceBridgePackage
19
- } from "@aura3d/engine";
20
- import {
21
- episode,
22
- episodeAudioCues,
23
- episodeContractId,
24
- missingCartoonCharacterAssets,
25
- publicCartoonAssetInstructions,
26
- requiredCartoonCharacterAssets,
27
- typedCartoonAssetSummary,
28
- youtubeDraftMetadata
29
- } from "./episode";
30
-
31
- const frameRate = episode.episodePlan.runtime.frameRate;
32
-
33
- export const renderContractId = episodeContractId;
34
-
35
- export const renderPlan = episode.renderQueue;
36
-
37
- export const renderOutputPackage = createCartoonRenderOutputPackageMetadata({
38
- episodePlan: episode.episodePlan,
39
- shotTimeline: episode.shotTimeline,
40
- renderQueue: renderPlan,
41
- youtube: youtubeDraftMetadata,
42
- generatedAt: episode.episodePlan.generatedAt
43
- });
44
-
45
- export const audioStemManifest = createAudioStemManifest({
46
- episodeId: episode.episodePlan.episodeId,
47
- duration: episode.dialogueTrack.duration,
48
- stems: [
49
- ...episode.dialogueTrack.lines.map((line) => ({
50
- id: `audio:${line.lineId}`,
51
- role: "dialogue" as const,
52
- path: line.audioFile ?? `assets/audio/en/${line.lineId}.wav`,
53
- startTime: line.startTime,
54
- duration: line.endTime - line.startTime,
55
- language: line.language
56
- })),
57
- ...episodeAudioCues
58
- ],
59
- generatedAt: episode.episodePlan.generatedAt
60
- });
61
-
62
- export const visemeTrack = createAuraVoiceVisemeTrack({
63
- episodeId: episode.episodePlan.episodeId,
64
- language: episode.episodePlan.language,
65
- frameRate,
66
- cues: episode.dialogueTrack.lines.flatMap((line) =>
67
- createPrimitiveMouthVisemeCues({
68
- characterId: line.speakerId,
69
- speakerId: line.speakerId,
70
- lineId: line.lineId,
71
- startTime: line.startTime,
72
- endTime: line.endTime
73
- }).map((cue, cueIndex) => {
74
- const words = line.text.split(/\s+/).filter(Boolean);
75
- const wordIndex = Math.min(cueIndex, Math.max(0, words.length - 1));
76
- return createGlbBlendshapeVisemeCue({
77
- ...cue,
78
- phoneme: cue.visemeId === "m" ? "M" : "AH",
79
- phonemeId: `${line.lineId}:phoneme-${cueIndex + 1}`,
80
- word: words[wordIndex] ?? line.text,
81
- wordIndex,
82
- wordStartTime: cue.startTime,
83
- wordEndTime: cue.endTime
84
- });
85
- })
86
- ),
87
- generatedAt: episode.episodePlan.generatedAt
88
- });
89
-
90
- export const primitiveMouthRuntimeExample = {
91
- ...primitiveMouthVisemeExample,
92
- runtimeNodes: {
93
- miko: "miko:mouth",
94
- luma: "luma:mouth"
95
- }
96
- } as const;
97
-
98
- export const glbVisemeRuntimeExample = {
99
- ...glbVisemeBlendshapeExample,
100
- typedAssetExample: "import { assets } from './aura-assets'; model(assets.character)",
101
- sampleBlendshapeNames: Object.values(glbVisemeBlendshapeExample.blendshapeMap).slice(0, 6)
102
- } as const;
103
-
104
- export const captionTimingProof = createCaptionTimingProof(episode.dialogueTrack, episode.captionTrack, {
105
- frameRate,
106
- maxAllowedDriftFrames: 1
107
- });
108
-
109
- function frameDriftFrames(actual: number, expected: number) {
110
- return Math.round(Math.abs(actual - expected) * frameRate);
111
- }
112
-
113
- const visemeLineSyncChecks = episode.dialogueTrack.lines.map((line) => {
114
- const cues = visemeTrack.cues.filter((cue) => cue.lineId === line.lineId && cue.speakerId === line.speakerId);
115
- const firstCue = cues[0];
116
- const lastCue = cues[cues.length - 1];
117
- const startDriftFrames = firstCue ? frameDriftFrames(firstCue.startTime, line.startTime) : 999;
118
- const endDriftFrames = lastCue ? frameDriftFrames(lastCue.endTime, line.endTime) : 999;
119
- const sampleTime = Math.min(line.endTime - 1 / frameRate, line.startTime + 1 / frameRate);
120
- const sampledMouth = sampleVisemeTrack(visemeTrack, sampleTime, line.speakerId);
121
- return {
122
- lineId: line.lineId,
123
- speakerId: line.speakerId,
124
- characterId: line.speakerId,
125
- cueCount: cues.length,
126
- startDriftFrames,
127
- endDriftFrames,
128
- maxDriftFrames: Math.max(startDriftFrames, endDriftFrames),
129
- sampledMouthState: {
130
- time: sampleTime,
131
- frame: Math.round(sampleTime * frameRate),
132
- visemeId: sampledMouth.visemeId,
133
- mouthOpenness: sampledMouth.mouthOpenness,
134
- primitiveMouthCard: sampledMouth.primitiveMouthCard,
135
- blendshapeWeights: sampledMouth.blendshapeWeights
136
- }
137
- };
138
- });
139
-
140
- const maxVisemeLineDriftFrames = Math.max(0, ...visemeLineSyncChecks.map((check) => check.maxDriftFrames));
141
- const missingVisemeLineIds = visemeLineSyncChecks
142
- .filter((check) => check.cueCount === 0 || check.maxDriftFrames > 1)
143
- .map((check) => check.lineId);
144
-
145
- export const captionFrameSyncSourceProof = {
146
- contractId: renderContractId,
147
- sourceOnly: true,
148
- proofType: "caption-display-one-frame-source-harness",
149
- frameRate,
150
- allowedDriftFrames: 1,
151
- allowedFrameDurationSeconds: 1 / frameRate,
152
- captionDisplayWithinOneFrame: captionTimingProof.status === "pass" && captionTimingProof.maxDriftFrames <= 1,
153
- maxObservedDriftFrames: captionTimingProof.maxDriftFrames,
154
- coveredLineIds: captionTimingProof.coveredLineIds,
155
- missingLineIds: captionTimingProof.missingLineIds,
156
- sampledCaptionCues: captionTimingProof.lines.map((line) => ({
157
- lineId: line.lineId,
158
- captionCueId: line.captionId,
159
- startDriftFrames: line.startDriftFrames,
160
- endDriftFrames: line.endDriftFrames,
161
- maxDriftFrames: line.maxDriftFrames
162
- })),
163
- executionBoundary: "Source harness only; actual caption display proof requires rendered frame/video evidence."
164
- } as const;
165
-
166
- export const visemeFrameSyncSourceProof = {
167
- contractId: renderContractId,
168
- sourceOnly: true,
169
- proofType: "mouth-movement-one-frame-source-harness",
170
- frameRate,
171
- allowedDriftFrames: 1,
172
- allowedFrameDurationSeconds: 1 / frameRate,
173
- mouthMovementWithinOneFrame: missingVisemeLineIds.length === 0 && maxVisemeLineDriftFrames <= 1,
174
- maxObservedDriftFrames: maxVisemeLineDriftFrames,
175
- coveredLineIds: visemeLineSyncChecks.filter((check) => check.cueCount > 0).map((check) => check.lineId),
176
- missingLineIds: missingVisemeLineIds,
177
- sampledMouthStates: visemeLineSyncChecks.map((check) => ({
178
- lineId: check.lineId,
179
- speakerId: check.speakerId,
180
- characterId: check.characterId,
181
- ...check.sampledMouthState
182
- })),
183
- primitiveMouthRuntimeNodeIds: primitiveMouthRuntimeExample.runtimeNodes,
184
- glbBlendshapeNames: glbVisemeRuntimeExample.sampleBlendshapeNames,
185
- executionBoundary: "Source harness only; actual mouth movement proof requires rendered frame/video evidence."
186
- } as const;
187
-
188
- function shotForLine(lineId: string) {
189
- return episode.shotTimeline.shots.find((shot) => lineId.startsWith(`${shot.shotId}:line-`));
190
- }
191
-
192
- export const spanishDubMap = defineDubMap({
193
- artifact: "dub-map",
194
- contractId: episode.dialogueTrack.contractId,
195
- episodeId: episode.episodePlan.episodeId,
196
- sourceLanguage: "en",
197
- targetLanguage: "es",
198
- entries: episode.dialogueTrack.lines.map((line) => {
199
- const shot = shotForLine(line.lineId);
200
- return {
201
- originalStoryboardId: shot?.sceneId,
202
- dubbedStoryboardId: shot?.sceneId,
203
- originalStoryboardSceneId: shot?.sceneId,
204
- dubbedStoryboardSceneId: shot?.sceneId,
205
- originalLineId: line.lineId,
206
- dubbedLineId: line.lineId,
207
- originalCaptionId: `${line.lineId}:caption`,
208
- dubbedCaptionId: `${line.lineId}:caption`,
209
- originalCharacterId: line.speakerId,
210
- dubbedCharacterId: line.speakerId,
211
- originalSpeakerId: line.speakerId,
212
- dubbedSpeakerId: line.speakerId,
213
- originalLanguage: line.language,
214
- dubbedLanguage: "es",
215
- originalShotId: shot?.shotId,
216
- dubbedShotId: shot?.shotId,
217
- originalSceneId: shot?.sceneId,
218
- dubbedSceneId: shot?.sceneId
219
- };
220
- }),
221
- generatedAt: episode.episodePlan.generatedAt
222
- });
223
-
224
- const spanishLineTextBySourceText = new Map<string, string>([
225
- ["Luma, the moon lilies are losing their sparkle.", "Luma, los lirios lunares estan perdiendo su brillo."],
226
- ["Then we sweep softly and wake the glow stones.", "Entonces barremos con suavidad y despertamos las piedras brillantes."],
227
- ["I will polish the blue stones one tiny circle at a time.", "Pulire las piedras azules con circulos pequenitos."],
228
- ["And I will hum the garden's sleepy cleanup song.", "Y yo tarareare la cancion tranquila del jardin."],
229
- ["The moon lilies are twinkling again.", "Los lirios lunares vuelven a centellear."],
230
- ["Goodnight, little garden. Keep glowing.", "Buenas noches, jardin pequeno. Sigue brillando."]
231
- ]);
232
-
233
- function spanishTextForLine(text: string): string {
234
- return spanishLineTextBySourceText.get(text) ?? text;
235
- }
236
-
237
- export const spanishDubCaptionMetadata = {
238
- artifact: "alternate-language-caption-metadata",
239
- schema: "aura3d-cartoon-studio-alternate-language-captions/v1",
240
- contractId: renderContractId,
241
- episodeId: episode.episodePlan.episodeId,
242
- sourceLanguage: episode.dialogueTrack.language,
243
- targetLanguage: spanishDubMap.targetLanguage,
244
- cues: episode.captionTrack.cues.map((cue) => {
245
- const sourceLine = episode.dialogueTrack.lines.find((line) => line.lineId === cue.lineId);
246
- return {
247
- captionId: cue.captionId,
248
- lineId: cue.lineId,
249
- shotId: cue.shotId,
250
- sceneId: cue.sceneId,
251
- speakerId: cue.speakerId,
252
- sourceText: cue.text,
253
- text: spanishTextForLine(sourceLine?.text ?? cue.text),
254
- language: "es",
255
- startTime: cue.startTime,
256
- endTime: cue.endTime,
257
- lineSafe: cue.lineSafe
258
- };
259
- }),
260
- generatedAt: episode.episodePlan.generatedAt
261
- } as const;
262
-
263
- export const alternateLanguageDubMetadata = {
264
- artifact: "cartoon-alternate-language-dub-proof",
265
- schema: "aura3d-cartoon-studio-alternate-language-dub-proof/v1",
266
- contractId: renderContractId,
267
- episodeId: episode.episodePlan.episodeId,
268
- sourceLanguage: episode.dialogueTrack.language,
269
- alternateLanguageCount: 1,
270
- alternateLanguages: [
271
- {
272
- language: spanishDubMap.targetLanguage,
273
- label: "Spanish",
274
- title: "Limpieza del Jardin Lunar",
275
- dubMapArtifact: spanishDubMap.artifact,
276
- lineCount: spanishDubMap.entries.length,
277
- captionCueCount: spanishDubCaptionMetadata.cues.length,
278
- captionMetadata: spanishDubCaptionMetadata,
279
- audioStemSlots: episode.dialogueTrack.lines.map((line) => ({
280
- id: `dub-slot:es:${line.lineId}`,
281
- lineId: line.lineId,
282
- speakerId: line.speakerId,
283
- language: "es",
284
- assetRequiredBeforePublish: true
285
- })),
286
- stableIds: {
287
- shotIds: spanishDubMap.entries.every((entry) => entry.originalShotId === entry.dubbedShotId),
288
- storyboardIds: spanishDubMap.entries.every((entry) => entry.originalStoryboardId === entry.dubbedStoryboardId),
289
- sceneIds: spanishDubMap.entries.every((entry) => entry.originalSceneId === entry.dubbedSceneId),
290
- lineIds: spanishDubMap.entries.every((entry) => entry.originalLineId === entry.dubbedLineId),
291
- captionIds: spanishDubMap.entries.every((entry) => entry.originalCaptionId === entry.dubbedCaptionId),
292
- characterIds: spanishDubMap.entries.every((entry) => entry.originalCharacterId === entry.dubbedCharacterId)
293
- },
294
- publishBoundary: "Metadata-only alternate-language proof. Add licensed/typed Spanish dialogue stems before claiming a rendered Spanish dub."
295
- }
296
- ],
297
- assetPolicy: {
298
- inventsAudioAssets: false,
299
- inventsModelAssets: false,
300
- typedAssetSource: "./src/aura-assets"
301
- },
302
- generatedAt: episode.episodePlan.generatedAt
303
- } as const;
304
-
305
- export const phonemeVisemeDubSyncSourceProof = {
306
- contractId: renderContractId,
307
- sourceOnly: true,
308
- proofType: "phoneme-viseme-dub-sync-source-harness",
309
- visemeFormat: visemeTrack.format,
310
- frameRate,
311
- allowedDriftFrames: 1,
312
- phonemeFields: ["phoneme", "phonemeId", "word", "wordIndex", "wordStartTime", "wordEndTime"],
313
- sampledPhonemeVisemeCues: visemeTrack.cues.slice(0, 8).map((cue) => ({
314
- cueId: cue.id,
315
- lineId: cue.lineId,
316
- speakerId: cue.speakerId,
317
- characterId: cue.characterId,
318
- visemeId: cue.visemeId,
319
- phoneme: cue.phoneme,
320
- phonemeId: cue.phonemeId,
321
- word: cue.word,
322
- wordIndex: cue.wordIndex,
323
- wordStartTime: cue.wordStartTime,
324
- wordEndTime: cue.wordEndTime,
325
- startTime: cue.startTime,
326
- endTime: cue.endTime
327
- })),
328
- dubContinuity: {
329
- sourceLanguage: spanishDubMap.sourceLanguage,
330
- targetLanguage: spanishDubMap.targetLanguage,
331
- stableShotIds: spanishDubMap.entries.every((entry) => entry.originalShotId === entry.dubbedShotId),
332
- stableStoryboardIds: spanishDubMap.entries.every((entry) => entry.originalStoryboardId === entry.dubbedStoryboardId),
333
- stableCaptionIds: spanishDubMap.entries.every((entry) => entry.originalCaptionId === entry.dubbedCaptionId),
334
- stableLineIds: spanishDubMap.entries.every((entry) => entry.originalLineId === entry.dubbedLineId)
335
- },
336
- executionBoundary: "Source harness only; actual phoneme, viseme, and dub playback proof requires rendered frame/video evidence."
337
- } as const;
338
-
339
- export const cartoonStudioShowBibleBatchRenderPlan = {
340
- artifact: "cartoon-show-bible-batch-render-plan",
341
- schema: "aura3d-cartoon-studio-show-bible-batch-render-plan/v1",
342
- contractId: renderContractId,
343
- sourceStoryBible: {
344
- episodeId: episode.storyBible.episodeId,
345
- title: episode.storyBible.title,
346
- characterIds: episode.storyBible.characters.map((character) => character.id),
347
- locationIds: episode.storyBible.locations.map((location) => location.id),
348
- propIds: episode.storyBible.props.map((prop) => prop.id),
349
- continuityRules: episode.storyBible.continuityRules ?? []
350
- },
351
- renderJobs: [
352
- {
353
- id: "batch:moon-garden-cleanup-001",
354
- episodeId: episode.episodePlan.episodeId,
355
- title: episode.episodePlan.title,
356
- sourceStoryBibleEpisodeId: episode.storyBible.episodeId,
357
- route: renderPlan.route,
358
- outputDirectory: "dist/episodes/moon-garden-001",
359
- language: episode.episodePlan.language,
360
- shotIds: episode.shotTimeline.shots.map((shot) => shot.shotId),
361
- requiredTypedAssetKeys: typedCartoonAssetSummary.requiredCharacterAssets,
362
- command: "npm run episode:render -- --episode moon-garden-cleanup-001"
363
- },
364
- {
365
- id: "batch:moon-garden-glow-check-002",
366
- episodeId: "moon-garden-glow-check-002",
367
- title: "Moon Garden Glow Check",
368
- sourceStoryBibleEpisodeId: episode.storyBible.episodeId,
369
- route: renderPlan.route,
370
- outputDirectory: "dist/episodes/moon-garden-002",
371
- language: episode.episodePlan.language,
372
- reusedCharacterIds: episode.storyBible.characters.map((character) => character.id),
373
- reusedLocationIds: episode.storyBible.locations.map((location) => location.id),
374
- reusedPropIds: episode.storyBible.props.map((prop) => prop.id),
375
- requiredTypedAssetKeys: typedCartoonAssetSummary.requiredCharacterAssets,
376
- command: "npm run episode:render -- --episode moon-garden-glow-check-002",
377
- metadataOnly: true,
378
- publishBoundary: "Second episode job reuses the same show bible and asset slots; rendered media is produced only when the template runner is executed with real typed assets."
379
- }
380
- ],
381
- guarantees: {
382
- oneShowBible: true,
383
- multipleEpisodes: true,
384
- noInventedAssets: true,
385
- stableCharacterIds: true,
386
- stableLocationIds: true,
387
- stablePropIds: true
388
- },
389
- generatedAt: episode.episodePlan.generatedAt
390
- } as const;
391
-
392
- export const performanceCoverage = createCartoonPerformanceCoverage(episode.performance, episode.dialogueTrack);
393
-
394
- export const reviewPackagePaths = renderOutputPackage.reviewPackagePaths;
395
-
396
- export const thumbnailCapture = renderOutputPackage.thumbnailCapture;
397
-
398
- export const plannedDeterministicCaptureSources = renderPlan.items.map((item) => ({
399
- renderQueueItemId: item.id,
400
- time: item.time,
401
- frame: item.frame,
402
- ...(item.shotId ? { shotId: item.shotId } : {}),
403
- sourceSceneStateId: item.sourceSceneState?.sceneStateId,
404
- auraVoiceTimestamp: item.sourceSceneState?.auraVoiceTimestamp ?? item.time,
405
- deterministicSeed: item.sourceSceneState?.deterministicSeed
406
- }));
407
-
408
- export const sampleRenderSourceWorkflow = {
409
- contractId: renderContractId,
410
- sourceOnly: true,
411
- status: "source-workflow-ready",
412
- promptToAudioToAura3DAnimation: true,
413
- sampleEpisodeId: episode.episodePlan.episodeId,
414
- runtimeSeconds: episode.episodePlan.runtime.duration,
415
- minimumRuntimeSeconds: 60,
416
- frameRate,
417
- resolution: episode.episodePlan.runtime.resolution,
418
- shotCount: episode.shotTimeline.shots.length,
419
- speakingCharacterIds: Array.from(new Set(episode.dialogueTrack.lines.map((line) => line.speakerId))),
420
- requiredTypedAssets: requiredCartoonCharacterAssets,
421
- typedAssetSummary: typedCartoonAssetSummary,
422
- missingTypedCharacterAssets: missingCartoonCharacterAssets,
423
- assetCommands: publicCartoonAssetInstructions,
424
- audioStemRoles: audioStemManifest.stems.map((stem) => stem.role),
425
- requiresNoManualTimingEdits: true,
426
- doesNotClaimRenderedArtifacts: true,
427
- humanReviewRequired: true,
428
- captionFrameSyncSourceProof,
429
- visemeFrameSyncSourceProof,
430
- phonemeVisemeDubSyncSourceProof,
431
- artifactManifestExpectations: {
432
- video: {
433
- required: true,
434
- outputId: renderOutputPackage.outputs.mp4?.id,
435
- path: renderOutputPackage.outputs.mp4?.path,
436
- evidenceJsonFields: ["path", "sha256", "byteSize", "duration", "frameRate", "resolution", "renderQueueId"]
437
- },
438
- thumbnail: {
439
- required: true,
440
- outputId: renderOutputPackage.outputs.thumbnail?.id,
441
- path: renderOutputPackage.outputs.thumbnail?.path,
442
- sourceSceneStateId: renderOutputPackage.thumbnailCapture.sourceSceneStateId,
443
- evidenceJsonFields: ["path", "sha256", "byteSize", "width", "height", "captureTime", "shotId", "sourceSceneStateId"]
444
- },
445
- captions: {
446
- required: true,
447
- outputIds: renderOutputPackage.outputs.captions.map((output) => output.id),
448
- paths: renderOutputPackage.outputs.captions.map((output) => output.path),
449
- evidenceJsonFields: ["path", "sha256", "byteSize", "language", "cueCount", "captionTrackId"]
450
- },
451
- timeline: {
452
- required: true,
453
- outputId: renderOutputPackage.outputs.timelineJson?.id,
454
- path: renderOutputPackage.outputs.timelineJson?.path,
455
- evidenceJsonFields: ["path", "sha256", "byteSize", "shotTimelineId", "frameRate", "duration"]
456
- },
457
- audioStems: {
458
- required: true,
459
- artifact: audioStemManifest.artifact,
460
- path: "dist/render/audio-stems.json",
461
- stemCount: audioStemManifest.stems.length,
462
- evidenceJsonFields: ["path", "sha256", "byteSize", "stemCount", "dialogueStemCount", "sfxStemCount"]
463
- },
464
- evidenceJson: {
465
- required: true,
466
- outputId: renderOutputPackage.outputs.evidenceJson?.id,
467
- path: renderOutputPackage.outputs.evidenceJson?.path,
468
- evidenceJsonFields: ["path", "sha256", "byteSize", "schema", "ok", "gates", "proofs"]
469
- },
470
- youtubeDraftMetadata: {
471
- required: true,
472
- outputId: renderOutputPackage.outputs.youtubeMetadata?.id,
473
- path: renderOutputPackage.outputs.youtubeMetadata?.path,
474
- evidenceJsonFields: ["title", "description", "language", "videoPath", "thumbnailPath", "captionsPath"]
475
- }
476
- },
477
- requiredEvidenceJsonFields: [
478
- "artifacts.video",
479
- "artifacts.thumbnail",
480
- "artifacts.captions",
481
- "artifacts.timeline",
482
- "artifacts.audioStems",
483
- "artifacts.evidenceJson",
484
- "captionFrameSyncSourceProof.captionDisplayWithinOneFrame",
485
- "visemeFrameSyncSourceProof.mouthMovementWithinOneFrame",
486
- "phonemeVisemeDubSyncSourceProof.sampledPhonemeVisemeCues",
487
- "phonemeVisemeDubSyncSourceProof.dubContinuity.stableShotIds",
488
- "humanReview.status"
489
- ],
490
- remainingProofGates: [
491
- "Fresh scaffold npm run build output",
492
- "Browser route health and storyboard playback output",
493
- "Typed character GLBs added through src/aura-assets.ts",
494
- "npx @aura3d/cli@latest assets validate-cartoon output",
495
- "Actual 60-second MP4/WebM render artifact",
496
- "Actual thumbnail artifact captured from the same Aura3D scene state",
497
- "Actual captions/timeline/audio-stems/evidence JSON files with hashes",
498
- "Human visual review approval"
499
- ]
500
- } as const;
501
-
502
- export const templateEpisodePackageWorkflow = {
503
- contractId: renderContractId,
504
- sourceOnly: false,
505
- status: "template-package-runner-ready",
506
- packageDirectory: "dist/episodes/moon-garden-001",
507
- commands: [
508
- "npm run episode:plan",
509
- "npm run episode:preview",
510
- "npm run episode:render",
511
- "npm run episode:package",
512
- "npm run episode:review",
513
- "npm run episode:verify"
514
- ],
515
- requiredArtifacts: [
516
- "thumbnail.png",
517
- "captions.vtt",
518
- "captions.srt",
519
- "metadata.json",
520
- "route-proof.json",
521
- "asset-provenance.json",
522
- "render-manifest.json",
523
- "visual-acceptance.json",
524
- "review-package.md"
525
- ],
526
- renderOutputMode: "episode.webm-or-png-sequence-fallback-marker",
527
- publishBoundary: "PNG sequence fallback proves template packaging only; publish-ready claims require a real encoded WebM or MP4 plus human review."
528
- } as const;
529
-
530
- export const auraVoicePackage = createAuraVoiceBridgePackage({
531
- episodePlan: episode.episodePlan,
532
- storyboard: episode.storyboard,
533
- shotTimeline: episode.shotTimeline,
534
- dialogueTrack: episode.dialogueTrack,
535
- captionTrack: episode.captionTrack,
536
- visemes: visemeTrack,
537
- audioStems: audioStemManifest,
538
- dubMap: spanishDubMap,
539
- renderQueue: renderPlan,
540
- renderOutputPackage
541
- }, {
542
- route: "/",
543
- frameRate,
544
- maxTimingDriftFrames: 1,
545
- youtube: youtubeDraftMetadata
546
- });
547
-
548
- export const deterministicScreenshotFixtures = createPromptAnimationDeterministicScreenshotFixtureMetadata({
549
- bridgePackage: auraVoicePackage,
550
- count: 3,
551
- pathPrefix: "artifacts/screenshots/moon-garden"
552
- });
553
-
554
- export const accessibilityProofMetadata = auraVoicePackage.artifacts.episodePlan.accessibilityProof;
555
-
556
- export const bridgeIssues = validateAuraVoiceBridgePackage(auraVoicePackage);
557
-
558
- export const bridgeSampleAtThumbnail = sampleAuraVoiceBridgeAtTime(auraVoicePackage, renderOutputPackage.thumbnailCapture.time);
559
-
560
- export const promptAnimationEvidence = collectPromptAnimationEvidence({
561
- bridgePackage: auraVoicePackage,
562
- performanceCoverage,
563
- routeHealth: { status: "missing" },
564
- generatedAt: episode.episodePlan.generatedAt
565
- });
566
-
567
- export const publishReadiness = evaluatePromptAnimationPublishReadiness(promptAnimationEvidence);
@@ -1,99 +0,0 @@
1
- import { captionTimingProof, renderOutputPackage, visemeFrameSyncSourceProof } from "./render-plan";
2
- import { episode, missingCartoonCharacterAssets, publicCartoonAssetInstructions, typedCartoonAssetSummary, youtubeDraftMetadata } from "./episode";
3
-
4
- export const cartoonEpisodePackageDirectory = "dist/episodes/moon-garden-001" as const;
5
-
6
- export const requiredCartoonEpisodePackageFiles = [
7
- "episode.webm",
8
- "thumbnail.png",
9
- "captions.vtt",
10
- "captions.srt",
11
- "metadata.json",
12
- "prompt-animation-evidence.json",
13
- "route-proof.json",
14
- "asset-provenance.json",
15
- "render-manifest.json",
16
- "dub-metadata.json",
17
- "batch-render-plan.json",
18
- "motion-quality.json",
19
- "visual-acceptance.json",
20
- "review-package.md"
21
- ] as const;
22
-
23
- export const optionalCartoonEpisodePackageFiles = [
24
- "episode.mp4",
25
- "episode.png-sequence-fallback.json"
26
- ] as const;
27
-
28
- export interface CartoonEpisodeReviewInput {
29
- readonly packageDirectory?: string;
30
- readonly hasWebm: boolean;
31
- readonly hasPngSequenceFallback: boolean;
32
- readonly generatedAt: string;
33
- }
34
-
35
- export function createCartoonEpisodeReviewPackage(input: CartoonEpisodeReviewInput): string {
36
- const packageDirectory = input.packageDirectory ?? cartoonEpisodePackageDirectory;
37
- const outputMode = input.hasWebm ? "encoded-webm" : input.hasPngSequenceFallback ? "png-sequence-fallback" : "missing-render-output";
38
- const typedAssetStatus = missingCartoonCharacterAssets.length === 0 ? "typed character assets present" : "starter fallback mode";
39
- const reviewStatus = input.hasWebm && missingCartoonCharacterAssets.length === 0 ? "ready-for-human-review" : "needs-render-upgrade-before-publish";
40
-
41
- return [
42
- "# Moon Garden 001 Review Package",
43
- "",
44
- `Generated: ${input.generatedAt}`,
45
- `Episode: ${episode.episodePlan.title}`,
46
- `Package: \`${packageDirectory}\``,
47
- `Output mode: \`${outputMode}\``,
48
- `Review status: \`${reviewStatus}\``,
49
- "",
50
- "## Required Files",
51
- "",
52
- ...requiredCartoonEpisodePackageFiles.map((file) => `- [x] \`${file}\``),
53
- input.hasPngSequenceFallback ? "- [x] `episode.png-sequence-fallback.json`" : "- [ ] `episode.png-sequence-fallback.json`",
54
- "",
55
- "## Episode Summary",
56
- "",
57
- `- Runtime: ${episode.episodePlan.runtime.duration}s at ${episode.episodePlan.runtime.frameRate}fps`,
58
- `- Resolution: ${episode.episodePlan.runtime.resolution.width}x${episode.episodePlan.runtime.resolution.height}`,
59
- `- Shots: ${episode.shotTimeline.shots.length}`,
60
- `- Captions: ${episode.captionTrack.cues.length}`,
61
- `- Characters: ${episode.episodePlan.characters.map((character) => character.name).join(", ")}`,
62
- `- YouTube draft title: ${youtubeDraftMetadata.title}`,
63
- "",
64
- "## Asset Status",
65
- "",
66
- `- Status: ${typedAssetStatus}`,
67
- `- Required typed assets: ${typedCartoonAssetSummary.requiredCharacterAssets.join(", ")}`,
68
- `- Missing typed assets: ${missingCartoonCharacterAssets.length ? missingCartoonCharacterAssets.join(", ") : "none"}`,
69
- "",
70
- "Typed asset commands:",
71
- "",
72
- "```bash",
73
- ...publicCartoonAssetInstructions,
74
- "```",
75
- "",
76
- "## Timing Proof",
77
- "",
78
- `- Caption timing: ${captionTimingProof.status}`,
79
- `- Max caption drift frames: ${captionTimingProof.maxDriftFrames}`,
80
- `- Mouth source sync: ${visemeFrameSyncSourceProof.mouthMovementWithinOneFrame ? "pass" : "fail"}`,
81
- "",
82
- "## Human Review Checklist",
83
- "",
84
- "- [ ] Both characters are readable in representative frames.",
85
- "- [ ] Captions do not cover important action.",
86
- "- [ ] Mouth movement is visible during dialogue in the browser route.",
87
- "- [ ] Character body motion is more than still-image wobble.",
88
- "- [ ] No route chrome, proof panels, or debug overlays appear in encoded output.",
89
- "- [ ] Reviewer name and approval date are recorded before publish-ready claims.",
90
- "",
91
- "## Boundary",
92
- "",
93
- input.hasWebm
94
- ? "This package includes an encoded WebM output. Human review and asset readiness are still required before public publish-ready claims."
95
- : "This package uses the PNG-sequence fallback marker because no real browser video encoder was attached. It is useful for package workflow proof, but it is not publish-ready video evidence.",
96
- "",
97
- `Render package metadata source: \`${renderOutputPackage.packageId}\``
98
- ].join("\n");
99
- }