@mineo71/showtime 0.2.1 → 0.4.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.
- package/CHANGELOG.md +32 -0
- package/README.md +155 -19
- package/docs/script.schema.json +395 -0
- package/package.json +1 -1
- package/skill/SKILL.md +70 -13
- package/src/audio/decode.ts +19 -0
- package/src/audio/mix.ts +72 -0
- package/src/audio/sfx.ts +55 -0
- package/src/audio/soundtrack.ts +49 -0
- package/src/audio/tts.ts +186 -0
- package/src/audio/wav.ts +96 -0
- package/src/cli/format.ts +10 -0
- package/src/cli/main.ts +125 -40
- package/src/convert.ts +48 -0
- package/src/ffmpeg.ts +21 -0
- package/src/lint.ts +128 -0
- package/src/logo.ts +20 -0
- package/src/paths.ts +19 -0
- package/src/pipeline.ts +97 -19
- package/src/render/remotion/Intro.tsx +3 -1
- package/src/render/remotion/Logo.tsx +6 -0
- package/src/render/remotion/Outro.tsx +38 -0
- package/src/render/remotion/Overlays.tsx +41 -16
- package/src/render/remotion/ShowtimeVideo.tsx +56 -18
- package/src/render/render.ts +1 -1
- package/src/runner/browser.ts +47 -6
- package/src/runner/check.ts +10 -1
- package/src/runner/events.ts +2 -0
- package/src/runner/hooks.ts +111 -0
- package/src/runner/record.ts +53 -34
- package/src/runner/steps.ts +4 -1
- package/src/script/config.ts +74 -0
- package/src/script/hash.ts +7 -1
- package/src/script/load.ts +15 -2
- package/src/script/schema.ts +115 -1
- package/src/setup.ts +13 -4
- package/src/sheet.ts +47 -0
- package/src/timeline/build.ts +113 -13
- package/src/timeline/camera.ts +34 -11
- package/src/timeline/fades.ts +3 -0
- package/src/timeline/frames.ts +15 -4
- package/src/timeline/layout.ts +70 -0
- package/src/timeline/narration.ts +160 -0
- package/src/timeline/timemap.ts +40 -5
- package/src/timeline/types.ts +44 -1
package/docs/script.schema.json
CHANGED
|
@@ -18,6 +18,31 @@
|
|
|
18
18
|
},
|
|
19
19
|
"subtitle": {
|
|
20
20
|
"type": "string"
|
|
21
|
+
},
|
|
22
|
+
"logo": {
|
|
23
|
+
"description": "SVG/PNG/JPEG/WebP shown on the intro and outro cards",
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1
|
|
26
|
+
},
|
|
27
|
+
"outro": {
|
|
28
|
+
"description": "Closing card after the video",
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"title": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1
|
|
34
|
+
},
|
|
35
|
+
"subtitle": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
},
|
|
38
|
+
"url": {
|
|
39
|
+
"type": "string"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"required": [
|
|
43
|
+
"title"
|
|
44
|
+
],
|
|
45
|
+
"additionalProperties": false
|
|
21
46
|
}
|
|
22
47
|
},
|
|
23
48
|
"additionalProperties": false
|
|
@@ -83,6 +108,71 @@
|
|
|
83
108
|
"type": "string",
|
|
84
109
|
"minLength": 1
|
|
85
110
|
}
|
|
111
|
+
},
|
|
112
|
+
"mock": {
|
|
113
|
+
"default": [],
|
|
114
|
+
"description": "Answer matching network requests with canned responses; the first match wins",
|
|
115
|
+
"type": "array",
|
|
116
|
+
"items": {
|
|
117
|
+
"type": "object",
|
|
118
|
+
"properties": {
|
|
119
|
+
"url": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"minLength": 1,
|
|
122
|
+
"description": "Playwright URL glob of the requests to answer, e.g. **/api/reports*"
|
|
123
|
+
},
|
|
124
|
+
"method": {
|
|
125
|
+
"description": "Only answer this HTTP method; others go to the network",
|
|
126
|
+
"type": "string",
|
|
127
|
+
"minLength": 1
|
|
128
|
+
},
|
|
129
|
+
"status": {
|
|
130
|
+
"default": 200,
|
|
131
|
+
"type": "integer",
|
|
132
|
+
"minimum": 100,
|
|
133
|
+
"maximum": 599
|
|
134
|
+
},
|
|
135
|
+
"json": {
|
|
136
|
+
"description": "Response body, sent as application/json"
|
|
137
|
+
},
|
|
138
|
+
"body": {
|
|
139
|
+
"description": "Raw response body",
|
|
140
|
+
"type": "string"
|
|
141
|
+
},
|
|
142
|
+
"headers": {
|
|
143
|
+
"type": "object",
|
|
144
|
+
"propertyNames": {
|
|
145
|
+
"type": "string"
|
|
146
|
+
},
|
|
147
|
+
"additionalProperties": {
|
|
148
|
+
"type": "string"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"delayMs": {
|
|
152
|
+
"description": "Wait this long before answering",
|
|
153
|
+
"type": "integer",
|
|
154
|
+
"minimum": 0,
|
|
155
|
+
"maximum": 30000
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"required": [
|
|
159
|
+
"url"
|
|
160
|
+
],
|
|
161
|
+
"additionalProperties": false
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"clock": {
|
|
165
|
+
"description": "Start the page clock at this ISO date-time; it then runs normally",
|
|
166
|
+
"type": "string"
|
|
167
|
+
},
|
|
168
|
+
"dialogs": {
|
|
169
|
+
"default": "accept",
|
|
170
|
+
"description": "How to answer alert/confirm/prompt dialogs",
|
|
171
|
+
"type": "string",
|
|
172
|
+
"enum": [
|
|
173
|
+
"accept",
|
|
174
|
+
"dismiss"
|
|
175
|
+
]
|
|
86
176
|
}
|
|
87
177
|
},
|
|
88
178
|
"required": [
|
|
@@ -90,6 +180,133 @@
|
|
|
90
180
|
],
|
|
91
181
|
"additionalProperties": false
|
|
92
182
|
},
|
|
183
|
+
"hooks": {
|
|
184
|
+
"default": {},
|
|
185
|
+
"type": "object",
|
|
186
|
+
"properties": {
|
|
187
|
+
"before": {
|
|
188
|
+
"default": [],
|
|
189
|
+
"description": "Run before every check and record, e.g. to reset demo data",
|
|
190
|
+
"type": "array",
|
|
191
|
+
"items": {
|
|
192
|
+
"anyOf": [
|
|
193
|
+
{
|
|
194
|
+
"type": "object",
|
|
195
|
+
"properties": {
|
|
196
|
+
"run": {
|
|
197
|
+
"type": "string",
|
|
198
|
+
"minLength": 1,
|
|
199
|
+
"description": "Shell command, run in the script folder"
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"required": [
|
|
203
|
+
"run"
|
|
204
|
+
],
|
|
205
|
+
"additionalProperties": false
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"type": "object",
|
|
209
|
+
"properties": {
|
|
210
|
+
"request": {
|
|
211
|
+
"type": "object",
|
|
212
|
+
"properties": {
|
|
213
|
+
"url": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"minLength": 1
|
|
216
|
+
},
|
|
217
|
+
"method": {
|
|
218
|
+
"default": "POST",
|
|
219
|
+
"type": "string",
|
|
220
|
+
"minLength": 1
|
|
221
|
+
},
|
|
222
|
+
"json": {},
|
|
223
|
+
"headers": {
|
|
224
|
+
"type": "object",
|
|
225
|
+
"propertyNames": {
|
|
226
|
+
"type": "string"
|
|
227
|
+
},
|
|
228
|
+
"additionalProperties": {
|
|
229
|
+
"type": "string"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"required": [
|
|
234
|
+
"url"
|
|
235
|
+
],
|
|
236
|
+
"additionalProperties": false
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"required": [
|
|
240
|
+
"request"
|
|
241
|
+
],
|
|
242
|
+
"additionalProperties": false
|
|
243
|
+
}
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"after": {
|
|
248
|
+
"default": [],
|
|
249
|
+
"description": "Run after every check and record, even when it failed",
|
|
250
|
+
"type": "array",
|
|
251
|
+
"items": {
|
|
252
|
+
"anyOf": [
|
|
253
|
+
{
|
|
254
|
+
"type": "object",
|
|
255
|
+
"properties": {
|
|
256
|
+
"run": {
|
|
257
|
+
"type": "string",
|
|
258
|
+
"minLength": 1,
|
|
259
|
+
"description": "Shell command, run in the script folder"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
"required": [
|
|
263
|
+
"run"
|
|
264
|
+
],
|
|
265
|
+
"additionalProperties": false
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"type": "object",
|
|
269
|
+
"properties": {
|
|
270
|
+
"request": {
|
|
271
|
+
"type": "object",
|
|
272
|
+
"properties": {
|
|
273
|
+
"url": {
|
|
274
|
+
"type": "string",
|
|
275
|
+
"minLength": 1
|
|
276
|
+
},
|
|
277
|
+
"method": {
|
|
278
|
+
"default": "POST",
|
|
279
|
+
"type": "string",
|
|
280
|
+
"minLength": 1
|
|
281
|
+
},
|
|
282
|
+
"json": {},
|
|
283
|
+
"headers": {
|
|
284
|
+
"type": "object",
|
|
285
|
+
"propertyNames": {
|
|
286
|
+
"type": "string"
|
|
287
|
+
},
|
|
288
|
+
"additionalProperties": {
|
|
289
|
+
"type": "string"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
"required": [
|
|
294
|
+
"url"
|
|
295
|
+
],
|
|
296
|
+
"additionalProperties": false
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
"required": [
|
|
300
|
+
"request"
|
|
301
|
+
],
|
|
302
|
+
"additionalProperties": false
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"additionalProperties": false
|
|
309
|
+
},
|
|
93
310
|
"setup": {
|
|
94
311
|
"default": [],
|
|
95
312
|
"type": "array",
|
|
@@ -143,6 +360,11 @@
|
|
|
143
360
|
"type": "number",
|
|
144
361
|
"minimum": 0.25,
|
|
145
362
|
"maximum": 16
|
|
363
|
+
},
|
|
364
|
+
"say": {
|
|
365
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
366
|
+
"type": "string",
|
|
367
|
+
"minLength": 1
|
|
146
368
|
}
|
|
147
369
|
},
|
|
148
370
|
"additionalProperties": false
|
|
@@ -203,6 +425,11 @@
|
|
|
203
425
|
"type": "number",
|
|
204
426
|
"minimum": 0.25,
|
|
205
427
|
"maximum": 16
|
|
428
|
+
},
|
|
429
|
+
"say": {
|
|
430
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
431
|
+
"type": "string",
|
|
432
|
+
"minLength": 1
|
|
206
433
|
}
|
|
207
434
|
},
|
|
208
435
|
"additionalProperties": false
|
|
@@ -287,6 +514,11 @@
|
|
|
287
514
|
"type": "number",
|
|
288
515
|
"minimum": 0.25,
|
|
289
516
|
"maximum": 16
|
|
517
|
+
},
|
|
518
|
+
"say": {
|
|
519
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
520
|
+
"type": "string",
|
|
521
|
+
"minLength": 1
|
|
290
522
|
}
|
|
291
523
|
},
|
|
292
524
|
"additionalProperties": false
|
|
@@ -347,6 +579,11 @@
|
|
|
347
579
|
"type": "number",
|
|
348
580
|
"minimum": 0.25,
|
|
349
581
|
"maximum": 16
|
|
582
|
+
},
|
|
583
|
+
"say": {
|
|
584
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
585
|
+
"type": "string",
|
|
586
|
+
"minLength": 1
|
|
350
587
|
}
|
|
351
588
|
},
|
|
352
589
|
"additionalProperties": false
|
|
@@ -407,6 +644,11 @@
|
|
|
407
644
|
"type": "number",
|
|
408
645
|
"minimum": 0.25,
|
|
409
646
|
"maximum": 16
|
|
647
|
+
},
|
|
648
|
+
"say": {
|
|
649
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
650
|
+
"type": "string",
|
|
651
|
+
"minLength": 1
|
|
410
652
|
}
|
|
411
653
|
},
|
|
412
654
|
"additionalProperties": false
|
|
@@ -470,6 +712,11 @@
|
|
|
470
712
|
"type": "number",
|
|
471
713
|
"minimum": 0.25,
|
|
472
714
|
"maximum": 16
|
|
715
|
+
},
|
|
716
|
+
"say": {
|
|
717
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
718
|
+
"type": "string",
|
|
719
|
+
"minLength": 1
|
|
473
720
|
}
|
|
474
721
|
},
|
|
475
722
|
"additionalProperties": false
|
|
@@ -536,6 +783,11 @@
|
|
|
536
783
|
"type": "number",
|
|
537
784
|
"minimum": 0.25,
|
|
538
785
|
"maximum": 16
|
|
786
|
+
},
|
|
787
|
+
"say": {
|
|
788
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
789
|
+
"type": "string",
|
|
790
|
+
"minLength": 1
|
|
539
791
|
}
|
|
540
792
|
},
|
|
541
793
|
"additionalProperties": false
|
|
@@ -600,6 +852,11 @@
|
|
|
600
852
|
"type": "number",
|
|
601
853
|
"minimum": 0.25,
|
|
602
854
|
"maximum": 16
|
|
855
|
+
},
|
|
856
|
+
"say": {
|
|
857
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
858
|
+
"type": "string",
|
|
859
|
+
"minLength": 1
|
|
603
860
|
}
|
|
604
861
|
},
|
|
605
862
|
"additionalProperties": false
|
|
@@ -659,6 +916,11 @@
|
|
|
659
916
|
"type": "number",
|
|
660
917
|
"minimum": 0.25,
|
|
661
918
|
"maximum": 16
|
|
919
|
+
},
|
|
920
|
+
"say": {
|
|
921
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
922
|
+
"type": "string",
|
|
923
|
+
"minLength": 1
|
|
662
924
|
}
|
|
663
925
|
},
|
|
664
926
|
"additionalProperties": false
|
|
@@ -735,6 +997,94 @@
|
|
|
735
997
|
},
|
|
736
998
|
"additionalProperties": false
|
|
737
999
|
},
|
|
1000
|
+
"audio": {
|
|
1001
|
+
"default": {},
|
|
1002
|
+
"type": "object",
|
|
1003
|
+
"properties": {
|
|
1004
|
+
"voice": {
|
|
1005
|
+
"description": "Text-to-speech for show.say",
|
|
1006
|
+
"default": {},
|
|
1007
|
+
"type": "object",
|
|
1008
|
+
"properties": {
|
|
1009
|
+
"engine": {
|
|
1010
|
+
"default": "system",
|
|
1011
|
+
"description": "system: macOS say / Linux espeak-ng; openai and elevenlabs read OPENAI_API_KEY / ELEVENLABS_API_KEY",
|
|
1012
|
+
"type": "string",
|
|
1013
|
+
"enum": [
|
|
1014
|
+
"system",
|
|
1015
|
+
"openai",
|
|
1016
|
+
"elevenlabs",
|
|
1017
|
+
"command"
|
|
1018
|
+
]
|
|
1019
|
+
},
|
|
1020
|
+
"name": {
|
|
1021
|
+
"description": "Voice name (system, openai) or voice id (elevenlabs)",
|
|
1022
|
+
"type": "string",
|
|
1023
|
+
"minLength": 1
|
|
1024
|
+
},
|
|
1025
|
+
"speed": {
|
|
1026
|
+
"default": 1,
|
|
1027
|
+
"type": "number",
|
|
1028
|
+
"minimum": 0.5,
|
|
1029
|
+
"maximum": 2
|
|
1030
|
+
},
|
|
1031
|
+
"model": {
|
|
1032
|
+
"description": "openai: gpt-4o-mini-tts by default; elevenlabs: eleven_multilingual_v2",
|
|
1033
|
+
"type": "string",
|
|
1034
|
+
"minLength": 1
|
|
1035
|
+
},
|
|
1036
|
+
"instructions": {
|
|
1037
|
+
"description": "openai only: how to speak, e.g. \"warm and confident\"",
|
|
1038
|
+
"type": "string",
|
|
1039
|
+
"minLength": 1
|
|
1040
|
+
},
|
|
1041
|
+
"command": {
|
|
1042
|
+
"description": "command engine: shell command that reads the text on stdin and writes audio to {out}",
|
|
1043
|
+
"type": "string",
|
|
1044
|
+
"minLength": 1
|
|
1045
|
+
}
|
|
1046
|
+
},
|
|
1047
|
+
"additionalProperties": false
|
|
1048
|
+
},
|
|
1049
|
+
"music": {
|
|
1050
|
+
"description": "Music bed under the whole video; ducks while the voice speaks",
|
|
1051
|
+
"type": "object",
|
|
1052
|
+
"properties": {
|
|
1053
|
+
"file": {
|
|
1054
|
+
"type": "string",
|
|
1055
|
+
"minLength": 1,
|
|
1056
|
+
"description": "Audio file, relative to the file that names it"
|
|
1057
|
+
},
|
|
1058
|
+
"volume": {
|
|
1059
|
+
"default": 0.25,
|
|
1060
|
+
"type": "number",
|
|
1061
|
+
"minimum": 0,
|
|
1062
|
+
"maximum": 1
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
"required": [
|
|
1066
|
+
"file"
|
|
1067
|
+
],
|
|
1068
|
+
"additionalProperties": false
|
|
1069
|
+
},
|
|
1070
|
+
"sounds": {
|
|
1071
|
+
"default": false,
|
|
1072
|
+
"description": "Click and keystroke sounds",
|
|
1073
|
+
"type": "boolean"
|
|
1074
|
+
},
|
|
1075
|
+
"subtitles": {
|
|
1076
|
+
"default": "file",
|
|
1077
|
+
"description": "Narration subtitles: an .srt next to the video (file), also drawn on the video (burn), or none",
|
|
1078
|
+
"type": "string",
|
|
1079
|
+
"enum": [
|
|
1080
|
+
"off",
|
|
1081
|
+
"file",
|
|
1082
|
+
"burn"
|
|
1083
|
+
]
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1086
|
+
"additionalProperties": false
|
|
1087
|
+
},
|
|
738
1088
|
"scenes": {
|
|
739
1089
|
"minItems": 1,
|
|
740
1090
|
"type": "array",
|
|
@@ -798,6 +1148,11 @@
|
|
|
798
1148
|
"type": "number",
|
|
799
1149
|
"minimum": 0.25,
|
|
800
1150
|
"maximum": 16
|
|
1151
|
+
},
|
|
1152
|
+
"say": {
|
|
1153
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1154
|
+
"type": "string",
|
|
1155
|
+
"minLength": 1
|
|
801
1156
|
}
|
|
802
1157
|
},
|
|
803
1158
|
"additionalProperties": false
|
|
@@ -858,6 +1213,11 @@
|
|
|
858
1213
|
"type": "number",
|
|
859
1214
|
"minimum": 0.25,
|
|
860
1215
|
"maximum": 16
|
|
1216
|
+
},
|
|
1217
|
+
"say": {
|
|
1218
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1219
|
+
"type": "string",
|
|
1220
|
+
"minLength": 1
|
|
861
1221
|
}
|
|
862
1222
|
},
|
|
863
1223
|
"additionalProperties": false
|
|
@@ -942,6 +1302,11 @@
|
|
|
942
1302
|
"type": "number",
|
|
943
1303
|
"minimum": 0.25,
|
|
944
1304
|
"maximum": 16
|
|
1305
|
+
},
|
|
1306
|
+
"say": {
|
|
1307
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1308
|
+
"type": "string",
|
|
1309
|
+
"minLength": 1
|
|
945
1310
|
}
|
|
946
1311
|
},
|
|
947
1312
|
"additionalProperties": false
|
|
@@ -1002,6 +1367,11 @@
|
|
|
1002
1367
|
"type": "number",
|
|
1003
1368
|
"minimum": 0.25,
|
|
1004
1369
|
"maximum": 16
|
|
1370
|
+
},
|
|
1371
|
+
"say": {
|
|
1372
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1373
|
+
"type": "string",
|
|
1374
|
+
"minLength": 1
|
|
1005
1375
|
}
|
|
1006
1376
|
},
|
|
1007
1377
|
"additionalProperties": false
|
|
@@ -1062,6 +1432,11 @@
|
|
|
1062
1432
|
"type": "number",
|
|
1063
1433
|
"minimum": 0.25,
|
|
1064
1434
|
"maximum": 16
|
|
1435
|
+
},
|
|
1436
|
+
"say": {
|
|
1437
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1438
|
+
"type": "string",
|
|
1439
|
+
"minLength": 1
|
|
1065
1440
|
}
|
|
1066
1441
|
},
|
|
1067
1442
|
"additionalProperties": false
|
|
@@ -1125,6 +1500,11 @@
|
|
|
1125
1500
|
"type": "number",
|
|
1126
1501
|
"minimum": 0.25,
|
|
1127
1502
|
"maximum": 16
|
|
1503
|
+
},
|
|
1504
|
+
"say": {
|
|
1505
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1506
|
+
"type": "string",
|
|
1507
|
+
"minLength": 1
|
|
1128
1508
|
}
|
|
1129
1509
|
},
|
|
1130
1510
|
"additionalProperties": false
|
|
@@ -1191,6 +1571,11 @@
|
|
|
1191
1571
|
"type": "number",
|
|
1192
1572
|
"minimum": 0.25,
|
|
1193
1573
|
"maximum": 16
|
|
1574
|
+
},
|
|
1575
|
+
"say": {
|
|
1576
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1577
|
+
"type": "string",
|
|
1578
|
+
"minLength": 1
|
|
1194
1579
|
}
|
|
1195
1580
|
},
|
|
1196
1581
|
"additionalProperties": false
|
|
@@ -1255,6 +1640,11 @@
|
|
|
1255
1640
|
"type": "number",
|
|
1256
1641
|
"minimum": 0.25,
|
|
1257
1642
|
"maximum": 16
|
|
1643
|
+
},
|
|
1644
|
+
"say": {
|
|
1645
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1646
|
+
"type": "string",
|
|
1647
|
+
"minLength": 1
|
|
1258
1648
|
}
|
|
1259
1649
|
},
|
|
1260
1650
|
"additionalProperties": false
|
|
@@ -1314,6 +1704,11 @@
|
|
|
1314
1704
|
"type": "number",
|
|
1315
1705
|
"minimum": 0.25,
|
|
1316
1706
|
"maximum": 16
|
|
1707
|
+
},
|
|
1708
|
+
"say": {
|
|
1709
|
+
"description": "Narration spoken from the start of this step; the video waits for it before the next narrated step",
|
|
1710
|
+
"type": "string",
|
|
1711
|
+
"minLength": 1
|
|
1317
1712
|
}
|
|
1318
1713
|
},
|
|
1319
1714
|
"additionalProperties": false
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: showtime
|
|
3
|
-
description: Use when the user wants a product demo video, walkthrough, screencast or feature recording of a web app (for a pitch, talk, README or social post). Write a showTime JSON script, rehearse it, record it and render a polished MP4 with auto-zoom, smooth cursor, captions and sped-up loading via the `showtime` CLI.
|
|
3
|
+
description: Use when the user wants a product demo video, walkthrough, screencast or feature recording of a web app (for a pitch, talk, README or social post). Write a showTime JSON script, rehearse it, record it and render a polished MP4 (or a 9:16 cut, GIF or WebP) with auto-zoom, smooth cursor, captions, narration and sped-up loading via the `showtime` CLI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# showTime — scripted demo videos
|
|
7
7
|
|
|
8
8
|
`showtime` turns a JSON script into a polished 1080p MP4. You are the director: you write the
|
|
9
9
|
script; the CLI clicks through the app, records it and edits it (zoom, cursor, ripples,
|
|
10
|
-
spotlights, captions, speed-ups, intro card).
|
|
10
|
+
spotlights, captions, speed-ups, intro card, narration, music, subtitles). One take renders as
|
|
11
|
+
16:9, 9:16 or 1:1, as MP4, GIF or WebP.
|
|
11
12
|
|
|
12
13
|
## Setup
|
|
13
14
|
|
|
@@ -33,14 +34,21 @@ showtime setup # downloads the browsers it records with
|
|
|
33
34
|
4. **Rehearse:** `showtime check demo/pitch.json`. On failure read the error, the ARIA snapshot it
|
|
34
35
|
prints and `.showtime/<name>/check/failure.png`; fix the selector or add a `wait`, repeat until
|
|
35
36
|
green.
|
|
36
|
-
5. **
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
5. **Lint:** `showtime lint demo/pitch.json` and fix every warning (long captions, pauses that
|
|
38
|
+
should be waits, zoom or spotlight on steps without a target).
|
|
39
|
+
6. **Record:** `showtime record demo/pitch.json` (runs in real time).
|
|
40
|
+
7. **Render:** `showtime render demo/pitch.json` → `demo/pitch.mp4`. For social posts add
|
|
41
|
+
`--aspect 9:16` (→ `demo/pitch-9x16.mp4`); for a README or docs `--format gif` or `--format webp`
|
|
42
|
+
(`--width` sets the size). Each is a render of the same take, never a new recording.
|
|
43
|
+
8. **QA:** `showtime frames demo/pitch.json`, then Read the contact sheet it prints first
|
|
44
|
+
(`sheet.png`: every step in one image); open single stills only to look closer. Check that zoom
|
|
45
|
+
lands on the right control, captions are legible, and pacing feels right. Run `showtime lint`
|
|
46
|
+
again: with a take it also flags captions on screen too briefly to read.
|
|
47
|
+
9. **Iterate:** edits to `show` (including `say`), `style`, `meta` or `audio` only need `render`. Edits to actions (`do`,
|
|
41
48
|
targets, text, `hold`, `app`) need `record` again — `render` refuses a stale take.
|
|
42
49
|
|
|
43
|
-
`showtime make <script>` runs check → record → render in one go.
|
|
50
|
+
`showtime make <script>` runs check → record → render in one go. Every command takes `--json`
|
|
51
|
+
and then prints exactly one JSON document on stdout.
|
|
44
52
|
|
|
45
53
|
## Long-running commands
|
|
46
54
|
|
|
@@ -48,14 +56,45 @@ showtime setup # downloads the browsers it records with
|
|
|
48
56
|
Remotion. They routinely take several minutes. In Claude Code run them with `timeout: 600000`, or
|
|
49
57
|
with `run_in_background: true` and wait for the completion notification. In Codex and other
|
|
50
58
|
agents, give the command a timeout of at least 10 minutes.
|
|
51
|
-
|
|
59
|
+
A `record` that fails or is stopped halfway leaves the previous take in place.
|
|
60
|
+
|
|
61
|
+
## Narration and sound
|
|
62
|
+
|
|
63
|
+
Give a step `"say": "…"` and a voice reads it from the start of that step. The video holds the
|
|
64
|
+
frame until the line ends before the next narrated step begins, so a line may cover several quick
|
|
65
|
+
steps. Write one short sentence per moment about the benefit, not the clicks. `showtime lint`
|
|
66
|
+
(with a take) flags lines that hold the frame for seconds (`narration-stretch`): shorten them.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
"audio": { "voice": { "engine": "system" }, "sounds": true, "subtitles": "burn" }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `voice.engine`: `system` (macOS `say`, Linux `espeak-ng`; free and offline) is the default.
|
|
73
|
+
Use `openai` or `elevenlabs` only when the user asks for a better voice and the key is in the
|
|
74
|
+
environment (`OPENAI_API_KEY` / `ELEVENLABS_API_KEY`); never write keys into the script. Those
|
|
75
|
+
engines send the narration text to the provider. `command` runs any TTS that reads stdin and
|
|
76
|
+
writes `{out}` (inserted already quoted: write it bare, e.g. `piper -m en_US.onnx -f {out}`).
|
|
77
|
+
- `music: { file, volume? }` adds a looped bed that ducks under the voice; only use files the user
|
|
78
|
+
provides.
|
|
79
|
+
- `subtitles`: `file` (default) writes `<video>.srt`; `burn` also draws them (good for 9:16, which
|
|
80
|
+
is often watched muted); `off`.
|
|
81
|
+
- `--no-audio` renders without the soundtrack. GIF, WebP and `--no-audio` leave narration out
|
|
82
|
+
(no voice needed, no pauses for it) unless subtitles are burned in.
|
|
52
83
|
|
|
53
84
|
## Side effects
|
|
54
85
|
|
|
55
86
|
`check` performs every action for real (it is a full run, just fast), and `record` repeats them.
|
|
56
87
|
Flows that create data ("New project", sign-up, checkout) can collide on the second run
|
|
57
|
-
("name already exists").
|
|
58
|
-
|
|
88
|
+
("name already exists"). Add `hooks` that reset the data: `before` hooks run at the start of every
|
|
89
|
+
`check` and `record`, `after` hooks when they end.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
"hooks": { "before": [{ "run": "npm run db:reset" }] }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
A hook is `{ "run": "<shell command, run in the script folder>" }` or
|
|
96
|
+
`{ "request": { "url": "…", "method": "POST", "json": {…} } }`. If the project has no reset command,
|
|
97
|
+
ask the user for one rather than guessing.
|
|
59
98
|
|
|
60
99
|
## Example
|
|
61
100
|
|
|
@@ -92,12 +131,24 @@ the change in `setup`; after a green `check`, reset the data before `record`.
|
|
|
92
131
|
`press {key}` · `hover {target}` · `select {target, value}` · `scroll {target} | {by}` ·
|
|
93
132
|
`wait {for} | {ms}` · `pause {ms}`
|
|
94
133
|
- **`show` (per step):** `zoom` (number, or `false`), `caption`, `spotlight`, `hold` (ms, real time),
|
|
95
|
-
`speed
|
|
134
|
+
`speed`, `say` (narration).
|
|
135
|
+
- **`audio`:** `voice` (`{ engine: system | openai | elevenlabs | command, name?, speed?, model?,
|
|
136
|
+
instructions?, command? }`), `music` (`{ file, volume? }`), `sounds` (clicks and keystrokes),
|
|
137
|
+
`subtitles` (`file` | `burn` | `off`).
|
|
96
138
|
- **`style`:** `background` (any CSS background), `chrome` (`browser` window frame | `none`), `address`
|
|
97
139
|
(address-bar text), `padding`, `radius`, `shadow`, `font`, `accent`, `autoZoom`, `autoSpeed`, `maxZoom`.
|
|
98
140
|
- **`app`:** `url`, `viewport`, `deviceScaleFactor`, `storageState` (Playwright storage-state JSON,
|
|
99
141
|
path relative to the script), `colorScheme`, `locale`, `timezoneId`, `mask` (CSS selectors to blur —
|
|
100
|
-
plain CSS only, not `text=` / `role=`)
|
|
142
|
+
plain CSS only, not `text=` / `role=`), `mock` (`[{ url: "**/api/x*", json | body, status?,
|
|
143
|
+
method?, delayMs? }]`), `clock` (ISO date-time the page clock starts at; first matching mock wins), `dialogs` (`accept` | `dismiss`).
|
|
144
|
+
Relative `goto` URLs resolve against `app.url`.
|
|
145
|
+
- **`meta`:** `title`, `subtitle` (intro card), `logo` (SVG/PNG/JPEG/WebP), `outro`
|
|
146
|
+
(`{ title, subtitle?, url? }`, closing card).
|
|
147
|
+
- **`hooks`:** `before` / `after` lists of `{ run }` or `{ request }`.
|
|
148
|
+
- **Brand file:** `showtime.config.json` in the script's folder or above holds default `style`,
|
|
149
|
+
`meta` (logo, outro) and `audio` for every script; the script's own fields win.
|
|
150
|
+
- **Render options** (`render`, `make`): `-o <file>`, `--aspect 16:9|9:16|1:1`,
|
|
151
|
+
`--format mp4|gif|webp`, `--width <px>`, `--no-audio`. `frames --aspect` reviews a crop.
|
|
101
152
|
- Output lands next to the script; working files in `.showtime/<script-name>/`.
|
|
102
153
|
|
|
103
154
|
## Direction tips
|
|
@@ -109,4 +160,10 @@ the change in `setup`; after a green `check`, reset the data before `record`.
|
|
|
109
160
|
- Never `pause` to wait for loading — use `wait {for}`; auto-speed compresses the loader.
|
|
110
161
|
- Use `setup` for cookie banners and onboarding, `app.storageState` to start logged in, `app.mask`
|
|
111
162
|
to blur personal data.
|
|
163
|
+
- Mock APIs that are slow, random or need real accounts (`app.mock`), and pin the date
|
|
164
|
+
(`app.clock`) so every take shows the same numbers and timestamps.
|
|
165
|
+
- End pitch demos with `meta.outro`: the product name and the URL to visit. Put brand colours, logo
|
|
166
|
+
and outro in `showtime.config.json` when a project has several demos.
|
|
112
167
|
- Keep the default 1440×900 viewport at `deviceScaleFactor` 2 for crisp 16:9 zooms.
|
|
168
|
+
- For a 9:16 cut, review it with `showtime frames <script> --aspect 9:16`: the camera follows each
|
|
169
|
+
target, so check that every step's target is the thing worth showing.
|