reelson 0.7.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 (105) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +15 -0
  4. package/README.md +180 -0
  5. package/bin/reelson.js +649 -0
  6. package/bin/reelson.ts +676 -0
  7. package/bin/run.js +5 -0
  8. package/demo.config.example.json +51 -0
  9. package/docs/demo.webp +0 -0
  10. package/docs/prompting.md +72 -0
  11. package/docs/style-guide.md +117 -0
  12. package/examples/demo.config.json +18 -0
  13. package/examples/todo-add-item/scenario.ts +45 -0
  14. package/examples/todo-add-item/video.json +35 -0
  15. package/music/README.md +7 -0
  16. package/package.json +68 -0
  17. package/skills/reelson-compose/SKILL.md +226 -0
  18. package/skills/reelson-compose/schemas/video.schema.json +172 -0
  19. package/skills/reelson-compose/scripts/build.js +424 -0
  20. package/skills/reelson-compose/scripts/build.ts +532 -0
  21. package/skills/reelson-compose/scripts/captions.js +24 -0
  22. package/skills/reelson-compose/scripts/captions.ts +40 -0
  23. package/skills/reelson-compose/scripts/check.js +80 -0
  24. package/skills/reelson-compose/scripts/check.ts +93 -0
  25. package/skills/reelson-compose/scripts/composition.js +163 -0
  26. package/skills/reelson-compose/scripts/composition.ts +241 -0
  27. package/skills/reelson-compose/scripts/hyperframes.js +138 -0
  28. package/skills/reelson-compose/scripts/hyperframes.ts +157 -0
  29. package/skills/reelson-compose/scripts/portrait.js +150 -0
  30. package/skills/reelson-compose/scripts/portrait.ts +218 -0
  31. package/skills/reelson-compose/scripts/project.js +238 -0
  32. package/skills/reelson-compose/scripts/project.ts +324 -0
  33. package/skills/reelson-compose/scripts/studio.js +330 -0
  34. package/skills/reelson-compose/scripts/studio.ts +394 -0
  35. package/skills/reelson-compose/scripts/timeline.js +271 -0
  36. package/skills/reelson-compose/scripts/timeline.ts +514 -0
  37. package/skills/reelson-compose/scripts/tts.js +303 -0
  38. package/skills/reelson-compose/scripts/tts.ts +371 -0
  39. package/skills/reelson-compose/scripts/verify.js +190 -0
  40. package/skills/reelson-compose/scripts/verify.ts +209 -0
  41. package/skills/reelson-compose/scripts/voice.js +178 -0
  42. package/skills/reelson-compose/scripts/voice.ts +224 -0
  43. package/skills/reelson-compose/scripts/zooms.js +259 -0
  44. package/skills/reelson-compose/scripts/zooms.ts +333 -0
  45. package/skills/reelson-compose/sections/README.md +5 -0
  46. package/skills/reelson-compose/sections/intro/minimal/section.css +27 -0
  47. package/skills/reelson-compose/sections/intro/minimal/section.html +12 -0
  48. package/skills/reelson-compose/sections/intro/minimal/section.js +16 -0
  49. package/skills/reelson-compose/sections/intro/minimal/section.json +9 -0
  50. package/skills/reelson-compose/sections/intro/poster/section.css +27 -0
  51. package/skills/reelson-compose/sections/intro/poster/section.html +14 -0
  52. package/skills/reelson-compose/sections/intro/poster/section.js +28 -0
  53. package/skills/reelson-compose/sections/intro/poster/section.json +9 -0
  54. package/skills/reelson-compose/sections/intro/split/section.css +30 -0
  55. package/skills/reelson-compose/sections/intro/split/section.html +12 -0
  56. package/skills/reelson-compose/sections/intro/split/section.js +19 -0
  57. package/skills/reelson-compose/sections/intro/split/section.json +9 -0
  58. package/skills/reelson-compose/sections/outro/compact/section.css +23 -0
  59. package/skills/reelson-compose/sections/outro/compact/section.html +10 -0
  60. package/skills/reelson-compose/sections/outro/compact/section.js +11 -0
  61. package/skills/reelson-compose/sections/outro/compact/section.json +8 -0
  62. package/skills/reelson-compose/sections/outro/endcard/section.css +25 -0
  63. package/skills/reelson-compose/sections/outro/endcard/section.html +13 -0
  64. package/skills/reelson-compose/sections/outro/endcard/section.js +13 -0
  65. package/skills/reelson-compose/sections/outro/endcard/section.json +8 -0
  66. package/skills/reelson-compose/sections/outro/wordmark/section.css +11 -0
  67. package/skills/reelson-compose/sections/outro/wordmark/section.html +5 -0
  68. package/skills/reelson-compose/sections/outro/wordmark/section.js +12 -0
  69. package/skills/reelson-compose/sections/outro/wordmark/section.json +8 -0
  70. package/skills/reelson-compose/sections/recap/compact/section.css +26 -0
  71. package/skills/reelson-compose/sections/recap/compact/section.html +8 -0
  72. package/skills/reelson-compose/sections/recap/compact/section.js +23 -0
  73. package/skills/reelson-compose/sections/recap/compact/section.json +11 -0
  74. package/skills/reelson-compose/sections/recap/steps/section.css +36 -0
  75. package/skills/reelson-compose/sections/recap/steps/section.html +8 -0
  76. package/skills/reelson-compose/sections/recap/steps/section.js +27 -0
  77. package/skills/reelson-compose/sections/recap/steps/section.json +11 -0
  78. package/skills/reelson-compose/studio/index.html +81 -0
  79. package/skills/reelson-compose/studio/studio.css +142 -0
  80. package/skills/reelson-compose/studio/studio.js +1031 -0
  81. package/skills/reelson-compose/templates/README.md +193 -0
  82. package/skills/reelson-compose/templates/classic/assets/vendor/Inter-OFL.txt +93 -0
  83. package/skills/reelson-compose/templates/classic/assets/vendor/gsap.min.js +11 -0
  84. package/skills/reelson-compose/templates/classic/assets/vendor/inter-latin-ext-wght-normal.woff2 +0 -0
  85. package/skills/reelson-compose/templates/classic/assets/vendor/inter-latin-wght-normal.woff2 +0 -0
  86. package/skills/reelson-compose/templates/classic/stage.html +447 -0
  87. package/skills/reelson-compose/templates/classic/template.json +5 -0
  88. package/skills/reelson-record/SKILL.md +220 -0
  89. package/skills/reelson-record/schemas/demo.config.schema.json +269 -0
  90. package/skills/reelson-record/scripts/capture.js +142 -0
  91. package/skills/reelson-record/scripts/capture.ts +190 -0
  92. package/skills/reelson-record/scripts/config.js +148 -0
  93. package/skills/reelson-record/scripts/config.ts +264 -0
  94. package/skills/reelson-record/scripts/cursor-overlay.js +111 -0
  95. package/skills/reelson-record/scripts/cursor-overlay.ts +122 -0
  96. package/skills/reelson-record/scripts/doctor.js +128 -0
  97. package/skills/reelson-record/scripts/doctor.ts +147 -0
  98. package/skills/reelson-record/scripts/languages.js +29 -0
  99. package/skills/reelson-record/scripts/languages.ts +41 -0
  100. package/skills/reelson-record/scripts/record.js +365 -0
  101. package/skills/reelson-record/scripts/record.ts +451 -0
  102. package/skills/reelson-record/scripts/scenario.js +356 -0
  103. package/skills/reelson-record/scripts/scenario.ts +570 -0
  104. package/skills/reelson-record/scripts/validate.js +143 -0
  105. package/skills/reelson-record/scripts/validate.ts +179 -0
@@ -0,0 +1,143 @@
1
+ /**
2
+ * A small JSON Schema walker for demo.config.json and video.json — enough of
3
+ * the spec for our two schemas (type, properties, additionalProperties,
4
+ * required, enum, items, minimum/maximum, minItems/maxItems, anyOf), with
5
+ * "did you mean" hints for mistyped keys. Keys starting with `$` ($schema,
6
+ * $comment) are always allowed.
7
+ */
8
+ import { readFileSync } from 'node:fs';
9
+ export function loadSchema(path) {
10
+ return JSON.parse(readFileSync(path, 'utf8'));
11
+ }
12
+ /** Returns human-readable problems; empty when the value matches. */
13
+ export function validate(value, schema, at = '', root = schema) {
14
+ const where = at || '(root)';
15
+ if (schema.$ref) {
16
+ const name = schema.$ref.replace('#/definitions/', '');
17
+ const target = root.definitions?.[name];
18
+ if (!target) {
19
+ throw new Error(`schema: unresolved $ref ${schema.$ref}`);
20
+ }
21
+ return validate(value, target, at, root);
22
+ }
23
+ if (schema.anyOf) {
24
+ const branches = schema.anyOf.map((s) => validate(value, s, at, root));
25
+ if (branches.some((b) => b.length === 0)) {
26
+ return [];
27
+ }
28
+ // Report the branch that got furthest (fewest problems) — usually the intended one.
29
+ return branches.sort((a, b) => a.length - b.length)[0];
30
+ }
31
+ if (schema.type !== undefined) {
32
+ const types = Array.isArray(schema.type) ? schema.type : [schema.type];
33
+ if (!types.some((t) => matchesType(value, t))) {
34
+ return [`${where}: expected ${types.join(' or ')}, got ${describe(value)}`];
35
+ }
36
+ }
37
+ if (schema.enum && !schema.enum.some((e) => e === value)) {
38
+ return [`${where}: must be one of ${schema.enum.map((e) => JSON.stringify(e)).join(', ')}`];
39
+ }
40
+ const problems = [];
41
+ if (typeof value === 'number') {
42
+ if (schema.minimum !== undefined && value < schema.minimum) {
43
+ problems.push(`${where}: must be ≥ ${schema.minimum}`);
44
+ }
45
+ if (schema.exclusiveMinimum !== undefined && value <= schema.exclusiveMinimum) {
46
+ problems.push(`${where}: must be > ${schema.exclusiveMinimum}`);
47
+ }
48
+ if (schema.maximum !== undefined && value > schema.maximum) {
49
+ problems.push(`${where}: must be ≤ ${schema.maximum}`);
50
+ }
51
+ }
52
+ if (Array.isArray(value)) {
53
+ if (schema.minItems !== undefined && value.length < schema.minItems) {
54
+ problems.push(`${where}: needs at least ${schema.minItems} item(s)`);
55
+ }
56
+ if (schema.maxItems !== undefined && value.length > schema.maxItems) {
57
+ problems.push(`${where}: takes at most ${schema.maxItems} item(s)`);
58
+ }
59
+ if (schema.items) {
60
+ value.forEach((item, i) => problems.push(...validate(item, schema.items, `${at}[${i}]`, root)));
61
+ }
62
+ }
63
+ if (isObject(value)) {
64
+ for (const key of schema.required ?? []) {
65
+ if (!(key in value)) {
66
+ problems.push(`${where}: missing required "${key}"`);
67
+ }
68
+ }
69
+ const known = Object.keys(schema.properties ?? {});
70
+ for (const [key, child] of Object.entries(value)) {
71
+ if (key.startsWith('$')) {
72
+ continue;
73
+ }
74
+ const path = at ? `${at}.${key}` : key;
75
+ const propSchema = schema.properties?.[key];
76
+ if (propSchema) {
77
+ problems.push(...validate(child, propSchema, path, root));
78
+ }
79
+ else if (schema.additionalProperties === false) {
80
+ const hint = closest(key, known);
81
+ problems.push(`${path}: unknown key${hint ? ` — did you mean "${hint}"?` : ''}`);
82
+ }
83
+ else if (isObject(schema.additionalProperties)) {
84
+ problems.push(...validate(child, schema.additionalProperties, path, root));
85
+ }
86
+ }
87
+ }
88
+ return problems;
89
+ }
90
+ function matchesType(value, type) {
91
+ switch (type) {
92
+ case 'null':
93
+ return value === null;
94
+ case 'array':
95
+ return Array.isArray(value);
96
+ case 'object':
97
+ return isObject(value);
98
+ case 'integer':
99
+ return Number.isInteger(value);
100
+ case 'number':
101
+ return typeof value === 'number' && Number.isFinite(value);
102
+ default:
103
+ return typeof value === type;
104
+ }
105
+ }
106
+ function isObject(v) {
107
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
108
+ }
109
+ function describe(v) {
110
+ if (v === null) {
111
+ return 'null';
112
+ }
113
+ if (Array.isArray(v)) {
114
+ return 'array';
115
+ }
116
+ return typeof v === 'string' ? `string ${JSON.stringify(v)}` : typeof v;
117
+ }
118
+ /** The known key within edit distance 3 of `key`, if any. */
119
+ export function closest(key, known) {
120
+ let best = null;
121
+ let bestDistance = 4;
122
+ for (const candidate of known) {
123
+ const d = distance(key.toLowerCase(), candidate.toLowerCase());
124
+ if (d < bestDistance) {
125
+ best = candidate;
126
+ bestDistance = d;
127
+ }
128
+ }
129
+ return best;
130
+ }
131
+ function distance(a, b) {
132
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i);
133
+ for (let i = 1; i <= a.length; i++) {
134
+ let previous = row[0];
135
+ row[0] = i;
136
+ for (let j = 1; j <= b.length; j++) {
137
+ const current = row[j];
138
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
139
+ previous = current;
140
+ }
141
+ }
142
+ return row[b.length];
143
+ }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * A small JSON Schema walker for demo.config.json and video.json — enough of
3
+ * the spec for our two schemas (type, properties, additionalProperties,
4
+ * required, enum, items, minimum/maximum, minItems/maxItems, anyOf), with
5
+ * "did you mean" hints for mistyped keys. Keys starting with `$` ($schema,
6
+ * $comment) are always allowed.
7
+ */
8
+ import { readFileSync } from 'node:fs'
9
+
10
+ export interface Schema {
11
+ type?: string | string[]
12
+ properties?: Record<string, Schema>
13
+ additionalProperties?: boolean | Schema
14
+ required?: string[]
15
+ enum?: unknown[]
16
+ items?: Schema
17
+ minimum?: number
18
+ maximum?: number
19
+ exclusiveMinimum?: number
20
+ minItems?: number
21
+ maxItems?: number
22
+ anyOf?: Schema[]
23
+ $ref?: string
24
+ definitions?: Record<string, Schema>
25
+ description?: string
26
+ [key: string]: unknown
27
+ }
28
+
29
+ export function loadSchema(path: string): Schema {
30
+ return JSON.parse(readFileSync(path, 'utf8')) as Schema
31
+ }
32
+
33
+ /** Returns human-readable problems; empty when the value matches. */
34
+ export function validate(
35
+ value: unknown,
36
+ schema: Schema,
37
+ at = '',
38
+ root: Schema = schema,
39
+ ): string[] {
40
+ const where = at || '(root)'
41
+
42
+ if (schema.$ref) {
43
+ const name = schema.$ref.replace('#/definitions/', '')
44
+ const target = root.definitions?.[name]
45
+ if (!target) {
46
+ throw new Error(`schema: unresolved $ref ${schema.$ref}`)
47
+ }
48
+ return validate(value, target, at, root)
49
+ }
50
+
51
+ if (schema.anyOf) {
52
+ const branches = schema.anyOf.map((s) => validate(value, s, at, root))
53
+ if (branches.some((b) => b.length === 0)) {
54
+ return []
55
+ }
56
+ // Report the branch that got furthest (fewest problems) — usually the intended one.
57
+ return branches.sort((a, b) => a.length - b.length)[0]
58
+ }
59
+
60
+ if (schema.type !== undefined) {
61
+ const types = Array.isArray(schema.type) ? schema.type : [schema.type]
62
+ if (!types.some((t) => matchesType(value, t))) {
63
+ return [`${where}: expected ${types.join(' or ')}, got ${describe(value)}`]
64
+ }
65
+ }
66
+ if (schema.enum && !schema.enum.some((e) => e === value)) {
67
+ return [`${where}: must be one of ${schema.enum.map((e) => JSON.stringify(e)).join(', ')}`]
68
+ }
69
+
70
+ const problems: string[] = []
71
+ if (typeof value === 'number') {
72
+ if (schema.minimum !== undefined && value < schema.minimum) {
73
+ problems.push(`${where}: must be ≥ ${schema.minimum}`)
74
+ }
75
+ if (schema.exclusiveMinimum !== undefined && value <= schema.exclusiveMinimum) {
76
+ problems.push(`${where}: must be > ${schema.exclusiveMinimum}`)
77
+ }
78
+ if (schema.maximum !== undefined && value > schema.maximum) {
79
+ problems.push(`${where}: must be ≤ ${schema.maximum}`)
80
+ }
81
+ }
82
+
83
+ if (Array.isArray(value)) {
84
+ if (schema.minItems !== undefined && value.length < schema.minItems) {
85
+ problems.push(`${where}: needs at least ${schema.minItems} item(s)`)
86
+ }
87
+ if (schema.maxItems !== undefined && value.length > schema.maxItems) {
88
+ problems.push(`${where}: takes at most ${schema.maxItems} item(s)`)
89
+ }
90
+ if (schema.items) {
91
+ value.forEach((item, i) => problems.push(...validate(item, schema.items as Schema, `${at}[${i}]`, root)))
92
+ }
93
+ }
94
+
95
+ if (isObject(value)) {
96
+ for (const key of schema.required ?? []) {
97
+ if (!(key in value)) {
98
+ problems.push(`${where}: missing required "${key}"`)
99
+ }
100
+ }
101
+ const known = Object.keys(schema.properties ?? {})
102
+ for (const [key, child] of Object.entries(value)) {
103
+ if (key.startsWith('$')) {
104
+ continue
105
+ }
106
+ const path = at ? `${at}.${key}` : key
107
+ const propSchema = schema.properties?.[key]
108
+ if (propSchema) {
109
+ problems.push(...validate(child, propSchema, path, root))
110
+ } else if (schema.additionalProperties === false) {
111
+ const hint = closest(key, known)
112
+ problems.push(`${path}: unknown key${hint ? ` — did you mean "${hint}"?` : ''}`)
113
+ } else if (isObject(schema.additionalProperties)) {
114
+ problems.push(...validate(child, schema.additionalProperties, path, root))
115
+ }
116
+ }
117
+ }
118
+
119
+ return problems
120
+ }
121
+
122
+ function matchesType(value: unknown, type: string): boolean {
123
+ switch (type) {
124
+ case 'null':
125
+ return value === null
126
+ case 'array':
127
+ return Array.isArray(value)
128
+ case 'object':
129
+ return isObject(value)
130
+ case 'integer':
131
+ return Number.isInteger(value)
132
+ case 'number':
133
+ return typeof value === 'number' && Number.isFinite(value)
134
+ default:
135
+ return typeof value === type
136
+ }
137
+ }
138
+
139
+ function isObject(v: unknown): v is Record<string, unknown> {
140
+ return typeof v === 'object' && v !== null && !Array.isArray(v)
141
+ }
142
+
143
+ function describe(v: unknown): string {
144
+ if (v === null) {
145
+ return 'null'
146
+ }
147
+ if (Array.isArray(v)) {
148
+ return 'array'
149
+ }
150
+ return typeof v === 'string' ? `string ${JSON.stringify(v)}` : typeof v
151
+ }
152
+
153
+ /** The known key within edit distance 3 of `key`, if any. */
154
+ export function closest(key: string, known: string[]): string | null {
155
+ let best: string | null = null
156
+ let bestDistance = 4
157
+ for (const candidate of known) {
158
+ const d = distance(key.toLowerCase(), candidate.toLowerCase())
159
+ if (d < bestDistance) {
160
+ best = candidate
161
+ bestDistance = d
162
+ }
163
+ }
164
+ return best
165
+ }
166
+
167
+ function distance(a: string, b: string): number {
168
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i)
169
+ for (let i = 1; i <= a.length; i++) {
170
+ let previous = row[0]
171
+ row[0] = i
172
+ for (let j = 1; j <= b.length; j++) {
173
+ const current = row[j]
174
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1))
175
+ previous = current
176
+ }
177
+ }
178
+ return row[b.length]
179
+ }