@contractspec/lib.video-gen 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/dist/browser/compositions/api-overview.js +645 -0
  2. package/dist/browser/compositions/index.js +1133 -0
  3. package/dist/browser/compositions/primitives/animated-text.js +144 -0
  4. package/dist/browser/compositions/primitives/brand-frame.js +181 -0
  5. package/dist/browser/compositions/primitives/code-block.js +226 -0
  6. package/dist/browser/compositions/primitives/index.js +656 -0
  7. package/dist/browser/compositions/primitives/progress-bar.js +59 -0
  8. package/dist/browser/compositions/primitives/terminal.js +265 -0
  9. package/dist/browser/compositions/primitives/transition.js +98 -0
  10. package/dist/browser/compositions/social-clip.js +500 -0
  11. package/dist/browser/compositions/terminal-demo.js +558 -0
  12. package/dist/browser/design/index.js +155 -0
  13. package/dist/browser/design/layouts.js +50 -0
  14. package/dist/browser/design/motion.js +43 -0
  15. package/dist/browser/design/tokens.js +28 -0
  16. package/dist/browser/design/typography.js +61 -0
  17. package/dist/browser/docs/compositions.docblock.js +182 -0
  18. package/dist/browser/docs/design.docblock.js +187 -0
  19. package/dist/browser/docs/generators.docblock.js +187 -0
  20. package/dist/browser/docs/rendering.docblock.js +197 -0
  21. package/dist/browser/docs/video-gen.docblock.js +141 -0
  22. package/dist/browser/generators/index.js +416 -0
  23. package/dist/browser/generators/scene-planner.js +205 -0
  24. package/dist/browser/generators/script-generator.js +147 -0
  25. package/dist/browser/generators/video-generator.js +414 -0
  26. package/dist/browser/index.js +1550 -0
  27. package/dist/browser/player/demo-player.js +1136 -0
  28. package/dist/browser/player/index.js +1136 -0
  29. package/dist/browser/remotion/Root.js +1189 -0
  30. package/dist/browser/remotion/index.js +1190 -0
  31. package/dist/browser/renderers/config.js +40 -0
  32. package/dist/browser/renderers/index.js +160 -0
  33. package/dist/browser/renderers/local.js +156 -0
  34. package/dist/browser/types.js +13 -0
  35. package/dist/compositions/api-overview.d.ts +16 -0
  36. package/dist/compositions/api-overview.js +640 -0
  37. package/dist/compositions/index.d.ts +7 -0
  38. package/dist/compositions/index.js +1128 -0
  39. package/dist/compositions/primitives/animated-text.d.ts +22 -0
  40. package/dist/compositions/primitives/animated-text.js +139 -0
  41. package/dist/compositions/primitives/brand-frame.d.ts +14 -0
  42. package/dist/compositions/primitives/brand-frame.js +176 -0
  43. package/dist/compositions/primitives/code-block.d.ts +18 -0
  44. package/dist/compositions/primitives/code-block.js +221 -0
  45. package/dist/compositions/primitives/index.d.ts +12 -0
  46. package/dist/compositions/primitives/index.js +651 -0
  47. package/dist/compositions/primitives/progress-bar.d.ts +12 -0
  48. package/dist/compositions/primitives/progress-bar.js +54 -0
  49. package/dist/compositions/primitives/terminal.d.ts +24 -0
  50. package/dist/compositions/primitives/terminal.js +260 -0
  51. package/dist/compositions/primitives/transition.d.ts +14 -0
  52. package/dist/compositions/primitives/transition.js +93 -0
  53. package/dist/compositions/social-clip.d.ts +16 -0
  54. package/dist/compositions/social-clip.js +495 -0
  55. package/dist/compositions/terminal-demo.d.ts +17 -0
  56. package/dist/compositions/terminal-demo.js +553 -0
  57. package/dist/design/index.d.ts +4 -0
  58. package/dist/design/index.js +150 -0
  59. package/dist/design/layouts.d.ts +69 -0
  60. package/dist/design/layouts.js +45 -0
  61. package/dist/design/motion.d.ts +72 -0
  62. package/dist/design/motion.js +38 -0
  63. package/dist/design/tokens.d.ts +31 -0
  64. package/dist/design/tokens.js +23 -0
  65. package/dist/design/typography.d.ts +61 -0
  66. package/dist/design/typography.js +56 -0
  67. package/dist/docs/compositions.docblock.d.ts +1 -0
  68. package/dist/docs/compositions.docblock.js +183 -0
  69. package/dist/docs/design.docblock.d.ts +1 -0
  70. package/dist/docs/design.docblock.js +188 -0
  71. package/dist/docs/generators.docblock.d.ts +1 -0
  72. package/dist/docs/generators.docblock.js +188 -0
  73. package/dist/docs/rendering.docblock.d.ts +1 -0
  74. package/dist/docs/rendering.docblock.js +198 -0
  75. package/dist/docs/video-gen.docblock.d.ts +1 -0
  76. package/dist/docs/video-gen.docblock.js +142 -0
  77. package/dist/generators/index.d.ts +5 -0
  78. package/dist/generators/index.js +411 -0
  79. package/dist/generators/scene-planner.d.ts +23 -0
  80. package/dist/generators/scene-planner.js +200 -0
  81. package/dist/generators/script-generator.d.ts +49 -0
  82. package/dist/generators/script-generator.js +142 -0
  83. package/dist/generators/video-generator.d.ts +20 -0
  84. package/dist/generators/video-generator.js +409 -0
  85. package/dist/index.d.ts +6 -0
  86. package/dist/index.js +1545 -0
  87. package/dist/node/compositions/api-overview.js +640 -0
  88. package/dist/node/compositions/index.js +1128 -0
  89. package/dist/node/compositions/primitives/animated-text.js +139 -0
  90. package/dist/node/compositions/primitives/brand-frame.js +176 -0
  91. package/dist/node/compositions/primitives/code-block.js +221 -0
  92. package/dist/node/compositions/primitives/index.js +651 -0
  93. package/dist/node/compositions/primitives/progress-bar.js +54 -0
  94. package/dist/node/compositions/primitives/terminal.js +260 -0
  95. package/dist/node/compositions/primitives/transition.js +93 -0
  96. package/dist/node/compositions/social-clip.js +495 -0
  97. package/dist/node/compositions/terminal-demo.js +553 -0
  98. package/dist/node/design/index.js +150 -0
  99. package/dist/node/design/layouts.js +45 -0
  100. package/dist/node/design/motion.js +38 -0
  101. package/dist/node/design/tokens.js +23 -0
  102. package/dist/node/design/typography.js +56 -0
  103. package/dist/node/docs/compositions.docblock.js +182 -0
  104. package/dist/node/docs/design.docblock.js +187 -0
  105. package/dist/node/docs/generators.docblock.js +187 -0
  106. package/dist/node/docs/rendering.docblock.js +197 -0
  107. package/dist/node/docs/video-gen.docblock.js +141 -0
  108. package/dist/node/generators/index.js +411 -0
  109. package/dist/node/generators/scene-planner.js +200 -0
  110. package/dist/node/generators/script-generator.js +142 -0
  111. package/dist/node/generators/video-generator.js +409 -0
  112. package/dist/node/index.js +1545 -0
  113. package/dist/node/player/demo-player.js +1131 -0
  114. package/dist/node/player/index.js +1131 -0
  115. package/dist/node/remotion/Root.js +1184 -0
  116. package/dist/node/remotion/index.js +1185 -0
  117. package/dist/node/renderers/config.js +35 -0
  118. package/dist/node/renderers/index.js +155 -0
  119. package/dist/node/renderers/local.js +151 -0
  120. package/dist/node/types.js +8 -0
  121. package/dist/player/demo-player.d.ts +55 -0
  122. package/dist/player/demo-player.js +1131 -0
  123. package/dist/player/index.d.ts +2 -0
  124. package/dist/player/index.js +1131 -0
  125. package/dist/remotion/Root.d.ts +2 -0
  126. package/dist/remotion/Root.js +1184 -0
  127. package/dist/remotion/index.d.ts +1 -0
  128. package/dist/remotion/index.js +1185 -0
  129. package/dist/renderers/config.d.ts +28 -0
  130. package/dist/renderers/config.js +35 -0
  131. package/dist/renderers/index.d.ts +3 -0
  132. package/dist/renderers/index.js +155 -0
  133. package/dist/renderers/local.d.ts +17 -0
  134. package/dist/renderers/local.js +151 -0
  135. package/dist/types.d.ts +63 -0
  136. package/dist/types.js +8 -0
  137. package/package.json +637 -0
@@ -0,0 +1,188 @@
1
+ // @bun
2
+ // src/docs/design.docblock.ts
3
+ import { registerDocBlocks } from "@contractspec/lib.contracts-spec/docs";
4
+ var designDocBlocks = [
5
+ {
6
+ id: "docs.video-gen.design",
7
+ title: "Video Design System",
8
+ summary: "Design tokens, motion primitives, typography scale, and layout system optimized for programmatic video.",
9
+ kind: "reference",
10
+ visibility: "public",
11
+ route: "/docs/video-gen/design",
12
+ tags: ["video", "design-tokens", "motion", "typography", "layout"],
13
+ owners: ["@contractspec/lib.video-gen"],
14
+ body: `# Video Design System
15
+
16
+ The design layer bridges \`@contractspec/lib.design-system\` brand tokens with video-specific extensions for motion, typography, and spatial layout. All values are optimized for 1920x1080 (landscape) and scale proportionally for other formats.
17
+
18
+ \`\`\`ts
19
+ import {
20
+ defaultVideoTheme,
21
+ videoEasing,
22
+ videoDurations,
23
+ videoTypography,
24
+ videoSafeZone,
25
+ scaleSafeZone,
26
+ } from "@contractspec/lib.video-gen/design";
27
+ \`\`\`
28
+
29
+ ## Tokens
30
+
31
+ ### Brand Bridge
32
+
33
+ \`VideoThemeTokens\` extends the design-system \`ThemeTokens\` with a \`video\` namespace for video-specific colors:
34
+
35
+ \`\`\`ts
36
+ import { defaultVideoTheme } from "@contractspec/lib.video-gen/design/tokens";
37
+
38
+ // Brand tokens (from @contractspec/lib.design-system)
39
+ defaultVideoTheme.colors.primary; // brand primary
40
+ defaultVideoTheme.colors.accent; // brand accent
41
+
42
+ // Video-specific extensions
43
+ defaultVideoTheme.video.canvasBackground; // frame background
44
+ defaultVideoTheme.video.codeBackground; // "#1e1e2e"
45
+ defaultVideoTheme.video.terminalBackground; // "#0d1117"
46
+ defaultVideoTheme.video.terminalForeground; // "#c9d1d9"
47
+ defaultVideoTheme.video.highlight; // accent color
48
+ defaultVideoTheme.video.gradientStart; // primary
49
+ defaultVideoTheme.video.gradientEnd; // accent
50
+ \`\`\`
51
+
52
+ > Do not duplicate brand color values. Import and extend from \`@contractspec/lib.design-system\`.
53
+
54
+ ## Motion
55
+
56
+ ### Easing Functions
57
+
58
+ Pre-configured easing curves for use with Remotion's \`interpolate()\`:
59
+
60
+ | Key | Easing | Use Case |
61
+ |-----|--------|----------|
62
+ | \`entrance\` | \`Easing.out(Easing.exp)\` | Objects appearing |
63
+ | \`exit\` | \`Easing.in(Easing.exp)\` | Objects disappearing |
64
+ | \`emphasis\` | \`Easing.out(Easing.back(1.4))\` | Drawing attention, bounce |
65
+ | \`linear\` | \`Easing.linear\` | Progress bars, typing |
66
+ | \`gentle\` | \`Easing.bezier(0.25, 0.1, 0.25, 1)\` | Subtle movements |
67
+ | \`spring\` | \`Easing.out(Easing.back(1.7))\` | Playful movements |
68
+
69
+ \`\`\`ts
70
+ import { interpolate } from "remotion";
71
+ import { videoEasing } from "@contractspec/lib.video-gen/design/motion";
72
+
73
+ const opacity = interpolate(frame, [0, 15], [0, 1], {
74
+ easing: videoEasing.entrance,
75
+ extrapolateLeft: "clamp",
76
+ extrapolateRight: "clamp",
77
+ });
78
+ \`\`\`
79
+
80
+ ### Durations (frames at 30fps)
81
+
82
+ | Key | Frames | Seconds | Use Case |
83
+ |-----|--------|---------|----------|
84
+ | \`sceneTransition\` | 20 | 0.67s | Between scenes |
85
+ | \`textEntrance\` | 15 | 0.5s | Text slide-in |
86
+ | \`textExit\` | 12 | 0.4s | Text slide-out |
87
+ | \`codeTypingPerChar\` | 2 | 0.07s | Code typing speed |
88
+ | \`sectionPause\` | 30 | 1.0s | Pause after concept |
89
+ | \`emphasisPause\` | 15 | 0.5s | Brief emphasis |
90
+ | \`brandReveal\` | 25 | 0.83s | Logo/watermark |
91
+ | \`minScene\` | 60 | 2.0s | Minimum scene length |
92
+ | \`shortScene\` | 60 | 2.0s | Short scene |
93
+ | \`mediumScene\` | 120 | 4.0s | Medium scene |
94
+ | \`longScene\` | 240 | 8.0s | Long scene |
95
+
96
+ ### Transition Presets
97
+
98
+ \`\`\`ts
99
+ import { videoTransitions } from "@contractspec/lib.video-gen/design/motion";
100
+
101
+ // { type: "fade", durationInFrames: 20 }
102
+ videoTransitions.fade;
103
+
104
+ // { type: "slide-left", durationInFrames: 20 }
105
+ videoTransitions.slideLeft;
106
+ \`\`\`
107
+
108
+ ## Typography
109
+
110
+ ### Type Scale (1920x1080 baseline)
111
+
112
+ | Key | Size | Weight | Use Case |
113
+ |-----|------|--------|----------|
114
+ | \`title\` | 72px | 700 | Main title |
115
+ | \`heading\` | 56px | 600 | Section heading |
116
+ | \`subheading\` | 40px | 500 | Subheading |
117
+ | \`body\` | 32px | 400 | Body text |
118
+ | \`code\` | 28px | 400 | Monospace code |
119
+ | \`caption\` | 24px | 400 | Small caption |
120
+ | \`label\` | 20px | 600 | Badge / label |
121
+
122
+ ### Scaling for Other Formats
123
+
124
+ Use \`scaleTypography()\` to proportionally scale for non-landscape formats:
125
+
126
+ \`\`\`ts
127
+ import {
128
+ videoTypography,
129
+ scaleTypography,
130
+ } from "@contractspec/lib.video-gen/design/typography";
131
+
132
+ // Scale heading for 1080x1080 (square)
133
+ const squareHeading = scaleTypography(videoTypography.heading, 1080);
134
+ // -> fontSize: 32, lineHeight: 1.2, fontWeight: 600
135
+ \`\`\`
136
+
137
+ ## Layouts
138
+
139
+ ### Safe Zones
140
+
141
+ Content-safe padding for text within video frames (1920x1080 baseline):
142
+
143
+ \`\`\`ts
144
+ import {
145
+ videoSafeZone,
146
+ scaleSafeZone,
147
+ } from "@contractspec/lib.video-gen/design/layouts";
148
+
149
+ videoSafeZone.horizontal; // 120px
150
+ videoSafeZone.vertical; // 80px
151
+ videoSafeZone.contentWidth; // 1680px
152
+ videoSafeZone.contentHeight; // 920px
153
+
154
+ // Scale for portrait (1080x1920)
155
+ const portrait = scaleSafeZone({ type: "portrait", width: 1080, height: 1920 });
156
+ \`\`\`
157
+
158
+ ### Standard Positions
159
+
160
+ \`\`\`ts
161
+ import { videoPositions } from "@contractspec/lib.video-gen/design/layouts";
162
+
163
+ videoPositions.center; // { x: 960, y: 540 }
164
+ videoPositions.topLeft; // { x: 120, y: 80 }
165
+ videoPositions.bottomRight; // { x: 1800, y: 1000 } -- logos, watermarks
166
+ videoPositions.bottomCenter; // { x: 960, y: 960 } -- captions
167
+ \`\`\`
168
+
169
+ ### Format Variants
170
+
171
+ \`\`\`ts
172
+ import {
173
+ VIDEO_FORMATS,
174
+ getAllFormatVariants,
175
+ DEFAULT_FPS,
176
+ } from "@contractspec/lib.video-gen/design/layouts";
177
+
178
+ VIDEO_FORMATS.landscape; // { type: "landscape", width: 1920, height: 1080 }
179
+ VIDEO_FORMATS.portrait; // { type: "portrait", width: 1080, height: 1920 }
180
+ VIDEO_FORMATS.square; // { type: "square", width: 1080, height: 1080 }
181
+
182
+ getAllFormatVariants(); // [landscape, square, portrait]
183
+ DEFAULT_FPS; // 30
184
+ \`\`\`
185
+ `
186
+ }
187
+ ];
188
+ registerDocBlocks(designDocBlocks);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,188 @@
1
+ // @bun
2
+ // src/docs/generators.docblock.ts
3
+ import { registerDocBlocks } from "@contractspec/lib.contracts-spec/docs";
4
+ var generatorsDocBlocks = [
5
+ {
6
+ id: "docs.video-gen.generators",
7
+ title: "Video Generation Pipeline",
8
+ summary: "VideoGenerator, ScenePlanner, and ScriptGenerator -- from content brief to video project with optional LLM enhancement.",
9
+ kind: "reference",
10
+ visibility: "public",
11
+ route: "/docs/video-gen/generators",
12
+ tags: [
13
+ "video",
14
+ "generators",
15
+ "scene-planner",
16
+ "script-generator",
17
+ "llm",
18
+ "content-pipeline"
19
+ ],
20
+ owners: ["@contractspec/lib.video-gen"],
21
+ body: `# Video Generation Pipeline
22
+
23
+ The generators layer converts a \`VideoBrief\` (content brief + video config) into a fully specified \`VideoProject\` (scene graph ready for rendering). It follows the \`@contractspec/lib.content-gen\` pattern: optional LLM, deterministic fallback.
24
+
25
+ \`\`\`
26
+ VideoBrief
27
+ |
28
+ v
29
+ ScenePlanner.plan(brief) --> ScenePlan (scenes + durations)
30
+ |
31
+ v
32
+ ScriptGenerator.generate(brief) --> NarrationScript (text + segments)
33
+ |
34
+ v
35
+ VoiceProvider.synthesize(text) --> AudioTrack (optional)
36
+ |
37
+ v
38
+ VideoGenerator.generate(brief) --> VideoProject (complete scene graph)
39
+ \`\`\`
40
+
41
+ ## VideoGenerator
42
+
43
+ The main orchestrator. Wires ScenePlanner, ScriptGenerator, and optional VoiceProvider into a single pipeline.
44
+
45
+ \`\`\`ts
46
+ import { VideoGenerator } from "@contractspec/lib.video-gen/generators";
47
+ import type { VideoBrief } from "@contractspec/lib.video-gen/types";
48
+
49
+ // Minimal (deterministic, no LLM, no voice)
50
+ const generator = new VideoGenerator({ fps: 30 });
51
+
52
+ // Full (with LLM for richer scenes + voice narration)
53
+ const generator = new VideoGenerator({
54
+ llm: myLLMProvider,
55
+ voice: myVoiceProvider,
56
+ model: "gpt-4o",
57
+ temperature: 0.4,
58
+ defaultVoiceId: "rachel",
59
+ fps: 30,
60
+ });
61
+
62
+ const project = await generator.generate(brief);
63
+ \`\`\`
64
+
65
+ ### Pipeline Steps
66
+
67
+ 1. **Scene planning** -- \`ScenePlanner.plan(brief)\` breaks the brief into concrete \`PlannedScene[]\` with composition IDs, props, and durations.
68
+ 2. **Script generation** -- If \`brief.narration.enabled\`, \`ScriptGenerator.generate()\` produces a \`NarrationScript\` with per-scene text segments.
69
+ 3. **Voice synthesis** -- If a \`VoiceProvider\` is configured and narration is enabled, synthesizes audio via \`voice.synthesize()\`.
70
+ 4. **Assembly** -- Combines scenes, audio, and metadata into a \`VideoProject\`.
71
+
72
+ ### Constructor Options
73
+
74
+ | Option | Type | Default | Description |
75
+ |--------|------|---------|-------------|
76
+ | \`llm\` | \`LLMProvider\` | -- | Optional LLM for enhanced generation |
77
+ | \`voice\` | \`VoiceProvider\` | -- | Optional voice synthesis provider |
78
+ | \`model\` | \`string\` | -- | LLM model override |
79
+ | \`temperature\` | \`number\` | \`0.4\` | LLM temperature (lower = more deterministic) |
80
+ | \`defaultVoiceId\` | \`string\` | -- | Default voice for narration |
81
+ | \`fps\` | \`number\` | \`30\` | Frames per second |
82
+
83
+ ## ScenePlanner
84
+
85
+ Breaks a \`VideoBrief\` into concrete scenes mapped to registered compositions.
86
+
87
+ \`\`\`ts
88
+ import { ScenePlanner } from "@contractspec/lib.video-gen/generators";
89
+
90
+ const planner = new ScenePlanner({ fps: 30 });
91
+ const plan = await planner.plan(brief);
92
+
93
+ plan.scenes; // PlannedScene[]
94
+ plan.estimatedDurationSeconds; // total estimated duration
95
+ plan.narrationScript; // combined narration text
96
+ \`\`\`
97
+
98
+ ### Deterministic Path (no LLM)
99
+
100
+ Maps brief sections to \`SocialClip\` compositions:
101
+
102
+ | Brief Section | Scene | Duration |
103
+ |---------------|-------|----------|
104
+ | \`title\` + \`summary\` | Hook / title | 3s |
105
+ | \`problems\` | Problem statement | 4s |
106
+ | \`solutions\` | Solution showcase | 5s |
107
+ | \`metrics\` | Proof / results | 3s |
108
+ | \`callToAction\` | CTA | 2s |
109
+
110
+ If \`brief.targetDurationSeconds\` is set, all scene durations are scaled proportionally.
111
+
112
+ ### LLM-Enhanced Path
113
+
114
+ With an \`LLMProvider\`, the planner sends the brief to the LLM and requests a scene breakdown as JSON. The LLM can choose from \`ApiOverview\`, \`SocialClip\`, or \`TerminalDemo\` compositions. Falls back to deterministic on any failure.
115
+
116
+ ## ScriptGenerator
117
+
118
+ Produces narration text from a \`ContentBrief\` with style control.
119
+
120
+ \`\`\`ts
121
+ import { ScriptGenerator } from "@contractspec/lib.video-gen/generators";
122
+
123
+ const scriptGen = new ScriptGenerator({ temperature: 0.5 });
124
+ const script = await scriptGen.generate(brief.content, brief.narration);
125
+
126
+ script.fullText; // complete narration
127
+ script.segments; // NarrationSegment[] (per-scene text)
128
+ script.estimatedDurationSeconds; // at ~150 words/min
129
+ script.style; // "professional" | "casual" | "technical"
130
+ \`\`\`
131
+
132
+ ### Narration Styles
133
+
134
+ | Style | Tone |
135
+ |-------|------|
136
+ | \`professional\` | Clear, authoritative, concise |
137
+ | \`casual\` | Friendly, conversational, approachable |
138
+ | \`technical\` | Precise, detailed, accurate |
139
+
140
+ ### NarrationSegment
141
+
142
+ Each segment maps to a scene and provides timing estimates:
143
+
144
+ \`\`\`ts
145
+ interface NarrationSegment {
146
+ sceneId: string; // "intro", "problems", "solutions", "metrics", "cta"
147
+ text: string; // narration text for this segment
148
+ estimatedDurationSeconds: number; // at ~150 words/min
149
+ }
150
+ \`\`\`
151
+
152
+ ## Input Types
153
+
154
+ ### VideoBrief
155
+
156
+ \`\`\`ts
157
+ interface VideoBrief {
158
+ content: ContentBrief; // from @contractspec/lib.content-gen
159
+ format: VideoFormat; // landscape, portrait, square, or custom
160
+ targetDurationSeconds?: number; // auto-calculated if omitted
161
+ narration?: NarrationConfig; // { enabled, voiceId, language, style }
162
+ style?: VideoStyleOverrides; // colors, fonts, dark mode
163
+ compositionId?: string; // force a specific composition
164
+ }
165
+ \`\`\`
166
+
167
+ ### PlannedScene
168
+
169
+ \`\`\`ts
170
+ interface PlannedScene {
171
+ compositionId: string; // maps to a registered Remotion composition
172
+ props: Record<string, unknown>; // input props for the composition
173
+ durationInFrames: number; // scene duration
174
+ narrationText?: string; // narrator text for this scene
175
+ notes?: string; // planning notes (LLM path only)
176
+ }
177
+ \`\`\`
178
+
179
+ ## Guardrails
180
+
181
+ - Generators are **stateless** -- no side effects, no caching. Call \`generate()\` / \`plan()\` for each video.
182
+ - LLM responses are parsed as JSON; any parse failure falls back to deterministic.
183
+ - Temperature defaults are conservative (0.3-0.5) for reproducibility.
184
+ - Duration estimates use 150 words/min speaking rate.
185
+ `
186
+ }
187
+ ];
188
+ registerDocBlocks(generatorsDocBlocks);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,198 @@
1
+ // @bun
2
+ // src/docs/rendering.docblock.ts
3
+ import { registerDocBlocks } from "@contractspec/lib.contracts-spec/docs";
4
+ var renderingDocBlocks = [
5
+ {
6
+ id: "docs.video-gen.rendering",
7
+ title: "Video Rendering & Playback",
8
+ summary: "LocalRenderer for MP4 output, render configuration, quality presets, DemoPlayer for web embedding, and Remotion Studio setup.",
9
+ kind: "reference",
10
+ visibility: "public",
11
+ route: "/docs/video-gen/rendering",
12
+ tags: [
13
+ "video",
14
+ "rendering",
15
+ "remotion",
16
+ "player",
17
+ "mp4",
18
+ "quality-presets"
19
+ ],
20
+ owners: ["@contractspec/lib.video-gen"],
21
+ body: `# Video Rendering & Playback
22
+
23
+ The rendering layer wraps \`@remotion/renderer\` for MP4/WebM output and \`@remotion/player\` for interactive web embedding. It implements the \`VideoProvider\` contract from \`@contractspec/lib.contracts-integrations\`.
24
+
25
+ ## LocalRenderer
26
+
27
+ Renders a \`VideoProject\` to a video file using the local Remotion renderer. Requires **Node.js** (not Bun-compatible).
28
+
29
+ \`\`\`ts
30
+ import { LocalRenderer } from "@contractspec/lib.video-gen/renderers/local";
31
+
32
+ const renderer = new LocalRenderer({
33
+ entryPoint: "./src/remotion/index.ts",
34
+ });
35
+
36
+ const result = await renderer.render(project, {
37
+ outputPath: "out/video.mp4",
38
+ codec: "h264",
39
+ crf: 18,
40
+ });
41
+
42
+ result.outputPath; // "out/video.mp4"
43
+ result.format; // "mp4"
44
+ result.durationSeconds; // total duration
45
+ result.fileSizeBytes; // file size
46
+ result.dimensions; // { width: 1920, height: 1080 }
47
+ \`\`\`
48
+
49
+ > **Important**: Import \`LocalRenderer\` from the \`/renderers/local\` subpath, not from the main entry. It dynamically imports \`@remotion/bundler\` and \`@remotion/renderer\` which are Node.js-only.
50
+
51
+ ### Auto-Variants
52
+
53
+ Set \`autoVariants: true\` to generate landscape + square + portrait versions:
54
+
55
+ \`\`\`ts
56
+ const result = await renderer.render(project, {
57
+ outputPath: "out/video.mp4",
58
+ autoVariants: true,
59
+ });
60
+
61
+ result.variants; // [
62
+ // { outputPath: "out/video-square.mp4", dimensions: { width: 1080, height: 1080 } },
63
+ // { outputPath: "out/video-portrait.mp4", dimensions: { width: 1080, height: 1920 } },
64
+ // ]
65
+ \`\`\`
66
+
67
+ ## Render Configuration
68
+
69
+ ### Defaults
70
+
71
+ \`\`\`ts
72
+ import {
73
+ defaultRenderConfig,
74
+ resolveRenderConfig,
75
+ qualityPresets,
76
+ codecFormatMap,
77
+ } from "@contractspec/lib.video-gen/renderers/config";
78
+
79
+ defaultRenderConfig.codec; // "h264"
80
+ defaultRenderConfig.outputFormat; // "mp4"
81
+ defaultRenderConfig.crf; // 18
82
+ defaultRenderConfig.pixelFormat; // "yuv420p"
83
+ \`\`\`
84
+
85
+ ### RenderConfig Options
86
+
87
+ | Option | Type | Default | Description |
88
+ |--------|------|---------|-------------|
89
+ | \`outputPath\` | \`string\` | -- | **Required**. Output file path |
90
+ | \`codec\` | \`"h264" \\| "h265" \\| "vp8" \\| "vp9"\` | \`"h264"\` | Video codec |
91
+ | \`outputFormat\` | \`"mp4" \\| "webm" \\| "gif"\` | \`"mp4"\` | Container format |
92
+ | \`crf\` | \`number\` | \`18\` | Constant Rate Factor (lower = better quality) |
93
+ | \`pixelFormat\` | \`string\` | \`"yuv420p"\` | Pixel format |
94
+ | \`concurrency\` | \`number\` | CPU count | Rendering threads |
95
+ | \`autoVariants\` | \`boolean\` | \`false\` | Generate format variants |
96
+
97
+ ### Quality Presets
98
+
99
+ \`\`\`ts
100
+ import { resolveRenderConfig } from "@contractspec/lib.video-gen/renderers/config";
101
+
102
+ // Draft (fastest, for previews)
103
+ resolveRenderConfig({ outputPath: "out/preview.mp4" }, "draft");
104
+ // -> crf: 28, concurrency: 1
105
+
106
+ // Standard (balanced)
107
+ resolveRenderConfig({ outputPath: "out/video.mp4" }, "standard");
108
+ // -> crf: 18
109
+
110
+ // High (best quality, for final output)
111
+ resolveRenderConfig({ outputPath: "out/final.mp4" }, "high");
112
+ // -> crf: 12
113
+ \`\`\`
114
+
115
+ ### Codec-to-Format Mapping
116
+
117
+ | Codec | Format |
118
+ |-------|--------|
119
+ | \`h264\` | \`mp4\` |
120
+ | \`h265\` | \`mp4\` |
121
+ | \`vp8\` | \`webm\` |
122
+ | \`vp9\` | \`webm\` |
123
+
124
+ ## DemoPlayer (Web Embedding)
125
+
126
+ Embeddable Remotion Player for interactive video demos in React apps. Wraps \`@remotion/player\` with ContractSpec compositions.
127
+
128
+ \`\`\`tsx
129
+ import { DemoPlayer } from "@contractspec/lib.video-gen/player";
130
+
131
+ <DemoPlayer
132
+ compositionId="ApiOverview"
133
+ inputProps={{
134
+ specName: "CreateUser",
135
+ specCode: "export const createUser = defineCommand({...})",
136
+ }}
137
+ controls
138
+ autoPlay
139
+ loop
140
+ width="100%"
141
+ clickToPlay
142
+ doubleClickToFullscreen
143
+ />
144
+ \`\`\`
145
+
146
+ ### DemoPlayer Props
147
+
148
+ | Prop | Type | Default | Description |
149
+ |------|------|---------|-------------|
150
+ | \`compositionId\` | \`"ApiOverview" \\| "SocialClip" \\| "TerminalDemo"\` | -- | Composition to play |
151
+ | \`inputProps\` | composition props type | -- | Props for the selected composition |
152
+ | \`controls\` | \`boolean\` | \`true\` | Show playback controls |
153
+ | \`autoPlay\` | \`boolean\` | \`false\` | Auto-play on mount |
154
+ | \`loop\` | \`boolean\` | \`false\` | Loop playback |
155
+ | \`width\` | \`string \\| number\` | \`"100%"\` | Player width |
156
+ | \`height\` | \`string \\| number\` | \`"auto"\` | Player height |
157
+ | \`clickToPlay\` | \`boolean\` | \`true\` | Click to toggle playback |
158
+ | \`doubleClickToFullscreen\` | \`boolean\` | \`true\` | Double-click for fullscreen |
159
+
160
+ > \`@remotion/player\` is a peer dependency. Install it in your app if you use \`DemoPlayer\`.
161
+
162
+ ## Remotion Studio
163
+
164
+ The \`@contractspec/app.video-studio\` package provides a Remotion Studio entry point for previewing compositions interactively.
165
+
166
+ \`\`\`bash
167
+ # Start Remotion Studio
168
+ bun run dev:video
169
+
170
+ # Render a specific composition
171
+ npx remotion render src/index.ts ApiOverview out/api-overview.mp4
172
+
173
+ # Render all compositions
174
+ bun run render:all
175
+ \`\`\`
176
+
177
+ ### Registered Compositions
178
+
179
+ | ID | Component | Dimensions | Duration | Description |
180
+ |----|-----------|------------|----------|-------------|
181
+ | \`ApiOverview\` | \`ApiOverview\` | 1920x1080 | 450 frames (15s) | Homepage API demo |
182
+ | \`SocialClip\` | \`SocialClip\` | 1920x1080 | 300 frames (10s) | Landscape social clip |
183
+ | \`SocialClipSquare\` | \`SocialClip\` | 1080x1080 | 300 frames (10s) | Square social clip |
184
+ | \`SocialClipPortrait\` | \`SocialClip\` | 1080x1920 | 300 frames (10s) | Portrait social clip |
185
+ | \`TerminalDemo\` | \`TerminalDemo\` | 1920x1080 | 600 frames (20s) | CLI walkthrough |
186
+
187
+ All compositions run at 30fps.
188
+
189
+ ## Guardrails
190
+
191
+ - \`LocalRenderer\` requires Node.js -- do not attempt to use it in browser or Bun environments.
192
+ - Import \`LocalRenderer\` from the \`/renderers/local\` subpath to avoid bundling \`@remotion/renderer\` in browser builds.
193
+ - The \`remotion\` entry point (\`@contractspec/lib.video-gen/remotion\`) is a **side-effect module** that calls \`registerRoot()\`. Only import it from Remotion Studio or render scripts.
194
+ - Use quality presets for consistency: \`draft\` for development, \`standard\` for CI, \`high\` for releases.
195
+ `
196
+ }
197
+ ];
198
+ registerDocBlocks(renderingDocBlocks);
@@ -0,0 +1 @@
1
+ export {};