@amg555/frameforge-mcp 2.3.2 → 2.3.4

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 (49) hide show
  1. package/.mcp.json +2 -4
  2. package/CHANGELOG.md +24 -1
  3. package/CLAUDE.md +104 -26
  4. package/README.md +17 -12
  5. package/SECURITY.md +1 -3
  6. package/package.json +7 -3
  7. package/plugins/video-pipeline/.claude-plugin/plugin.json +19 -0
  8. package/plugins/video-pipeline/skills/html-renderer/SKILL.md +292 -0
  9. package/plugins/video-pipeline/skills/video-pipeline/SKILL.md +308 -0
  10. package/plugins/video-pipeline/skills/video-pipeline/assets/project/ANIMATION_GUIDE.md +257 -0
  11. package/plugins/video-pipeline/skills/video-pipeline/assets/project/STORYBOARD.md +77 -0
  12. package/plugins/video-pipeline/skills/video-pipeline/assets/project/index.html +80 -0
  13. package/plugins/video-pipeline/skills/video-pipeline/assets/project/pipeline/briefings/diagram-author.md +43 -0
  14. package/plugins/video-pipeline/skills/video-pipeline/assets/project/pipeline/briefings/orchestrator.md +56 -0
  15. package/plugins/video-pipeline/skills/video-pipeline/assets/project/pipeline/briefings/scene-author.md +42 -0
  16. package/plugins/video-pipeline/skills/video-pipeline/assets/project/reel/engine.css +140 -0
  17. package/plugins/video-pipeline/skills/video-pipeline/assets/project/reel/engine.js +870 -0
  18. package/plugins/video-pipeline/skills/video-pipeline/assets/project/reel/virtual-clock.js +138 -0
  19. package/plugins/video-pipeline/skills/video-pipeline/references/mcp-tools.md +167 -0
  20. package/plugins/video-pipeline/skills/video-pipeline/references/providers.md +174 -0
  21. package/scripts/db-migrate.js +112 -0
  22. package/scripts/deep-validate.js +326 -0
  23. package/scripts/generate-initial-assets.js +342 -0
  24. package/scripts/html-renderer/new-project.mjs +408 -0
  25. package/scripts/html-renderer/transcribe.py +294 -0
  26. package/src/asset-library/README.md +2 -2
  27. package/src/asset-library/asset-library.js +1 -1
  28. package/src/cli/doctor.js +12 -5
  29. package/src/cli/make.js +52 -71
  30. package/src/cli/setup-keys.js +15 -17
  31. package/src/fact-checker/review-gate.js +5 -1
  32. package/src/harness/bin/harness.mjs +324 -0
  33. package/src/harness/lib/browser.mjs +137 -0
  34. package/src/harness/lib/capture.mjs +161 -0
  35. package/src/harness/lib/encode.mjs +89 -0
  36. package/src/harness/lib/jobs.mjs +135 -0
  37. package/src/harness/lib/pixels.mjs +137 -0
  38. package/src/harness/lib/sheets.mjs +164 -0
  39. package/src/harness/lib/verify-purity.mjs +119 -0
  40. package/src/harness/test/fixtures/broken-scene.html +27 -0
  41. package/src/harness/test/fixtures/reference-scene.html +23 -0
  42. package/src/harness/test/fixtures/sample-script.json +18 -0
  43. package/src/mcp-server/server.js +285 -144
  44. package/src/pipeline/telemetry.js +1 -0
  45. package/src/utils/log-redaction.js +5 -3
  46. package/src/video-renderer/renderer.js +12 -4
  47. package/src/worker/server-render-free.js +2 -3
  48. package/src/workflows/assets.js +20 -43
  49. package/src/workflows/ingest.js +5 -5
@@ -0,0 +1,342 @@
1
+ /**
2
+ * Generate Initial Asset Library
3
+ *
4
+ * Generates a starter set of composable assets. Characters are generic/neutral
5
+ * so they work for any topic — not locked to any historical period or style.
6
+ * Customise ASSET_DEFINITIONS before running for your project.
7
+ *
8
+ * Total: ~47 composable assets
9
+ *
10
+ * Usage:
11
+ * node scripts/generate-initial-assets.js [--dry-run]
12
+ */
13
+
14
+ const { AssetLibrary } = require('../src/asset-library/asset-library');
15
+
16
+ // Asset definitions — edit these to match your project's visual identity.
17
+ const ASSET_DEFINITIONS = {
18
+ characters: [
19
+ {
20
+ id: 'narrator',
21
+ description: 'Friendly narrator figure, simple flat-design illustration, neutral modern clothing',
22
+ poses: ['standing', 'running', 'sitting', 'jumping'],
23
+ emotions: ['neutral', 'happy', 'angry', 'sad', 'surprised', 'determined']
24
+ },
25
+ {
26
+ id: 'expert',
27
+ description: 'Professional expert figure, smart casual clothing, confident posture, simple flat-design illustration',
28
+ poses: ['standing', 'running', 'sitting', 'jumping'],
29
+ emotions: ['neutral', 'happy', 'angry', 'sad', 'surprised', 'relaxed']
30
+ }
31
+ ],
32
+
33
+ props: [
34
+ { id: 'spear', description: 'Stone-tipped wooden spear' },
35
+ { id: 'phone', description: 'Modern smartphone with glowing screen' },
36
+ { id: 'fire', description: 'Campfire with orange flames' },
37
+ { id: 'wheel', description: 'Simple wooden wheel' },
38
+ { id: 'car', description: 'Modern car (side view)' },
39
+ { id: 'meat', description: 'Raw meat on bone' },
40
+ { id: 'burger', description: 'Fast food hamburger' },
41
+ { id: 'cave_painting', description: 'Primitive cave wall art' },
42
+ { id: 'laptop', description: 'Modern laptop computer' },
43
+ { id: 'club', description: 'Wooden club weapon' },
44
+ { id: 'credit_card', description: 'Plastic credit card' },
45
+ { id: 'mammoth', description: 'Woolly mammoth (cartoon)' },
46
+ { id: 'clock', description: 'Modern analog clock' },
47
+ { id: 'sun', description: 'Simple sun icon' },
48
+ { id: 'moon', description: 'Crescent moon icon' }
49
+ ],
50
+
51
+ backgrounds: [
52
+ { id: 'forest', description: 'Dense prehistoric forest with tall trees' },
53
+ { id: 'cave', description: 'Dark cave entrance with rocky walls' },
54
+ { id: 'city', description: 'Modern city skyline with tall buildings' },
55
+ { id: 'savanna', description: 'African savanna with grass plains' },
56
+ { id: 'office', description: 'Modern office cubicle workspace' },
57
+ { id: 'mountain', description: 'Rocky mountain landscape' },
58
+ { id: 'beach', description: 'Sandy beach with ocean waves' },
59
+ { id: 'night', description: 'Night sky with stars' },
60
+ { id: 'desert', description: 'Sandy desert with dunes' },
61
+ { id: 'village', description: 'Primitive tribal village with huts' }
62
+ ],
63
+
64
+ effects: [
65
+ { id: 'arrow', description: 'Curved arrow pointer (SVG)' },
66
+ { id: 'question', description: 'Question mark icon (SVG)' },
67
+ { id: 'exclamation', description: 'Exclamation mark icon (SVG)' },
68
+ { id: 'vs', description: 'VS text (versus symbol, SVG)' },
69
+ { id: 'sparkle', description: 'Sparkle/star effect (SVG)' },
70
+ { id: 'lightning', description: 'Lightning bolt (SVG)' },
71
+ { id: 'heart', description: 'Heart icon (SVG)' },
72
+ { id: 'skull', description: 'Skull danger icon (SVG)' },
73
+ { id: 'checkmark', description: 'Checkmark icon (SVG)' },
74
+ { id: 'x_mark', description: 'X mark / cross (SVG)' }
75
+ ]
76
+ };
77
+
78
+ async function generateAssets(dryRun = false) {
79
+ console.log('🎨 Generating Initial Asset Library\n');
80
+ console.log('='.repeat(60));
81
+
82
+ const library = new AssetLibrary();
83
+ await library.initialize();
84
+
85
+ let totalGenerated = 0;
86
+ let totalSkipped = 0;
87
+
88
+ // Generate character identities
89
+ console.log('\n👤 CHARACTER IDENTITIES');
90
+ console.log('-'.repeat(60));
91
+
92
+ for (const char of ASSET_DEFINITIONS.characters) {
93
+ const query = {
94
+ asset_type: 'character_identity',
95
+ character_id: char.id
96
+ };
97
+
98
+ const existing = await library.findAsset(query);
99
+
100
+ if (existing) {
101
+ console.log(`⏭️ Skipping ${char.id} (already exists)`);
102
+ totalSkipped++;
103
+ } else {
104
+ console.log(`🎨 Generating ${char.id}...`);
105
+
106
+ if (!dryRun) {
107
+ try {
108
+ await library.generateAsset({
109
+ asset_type: 'character_identity',
110
+ character_id: char.id,
111
+ visual_description: char.description
112
+ });
113
+ totalGenerated++;
114
+ } catch (error) {
115
+ console.error(` ❌ Failed: ${error.message}`);
116
+ }
117
+ } else {
118
+ console.log(` [DRY RUN] Would generate: ${char.description}`);
119
+ totalGenerated++;
120
+ }
121
+ }
122
+ }
123
+
124
+ // Generate poses
125
+ console.log('\n🏃 POSES');
126
+ console.log('-'.repeat(60));
127
+
128
+ for (const char of ASSET_DEFINITIONS.characters) {
129
+ for (const pose of char.poses) {
130
+ const query = {
131
+ asset_type: 'pose',
132
+ character_id: char.id,
133
+ pose: pose
134
+ };
135
+
136
+ const existing = await library.findAsset(query);
137
+
138
+ if (existing) {
139
+ console.log(`⏭️ Skipping ${char.id}/${pose} (already exists)`);
140
+ totalSkipped++;
141
+ } else {
142
+ console.log(`🎨 Generating ${char.id}/${pose}...`);
143
+
144
+ if (!dryRun) {
145
+ try {
146
+ await library.generateAsset({
147
+ asset_type: 'pose',
148
+ character_id: char.id,
149
+ pose: pose,
150
+ visual_description: `${char.description}, ${pose} pose`
151
+ });
152
+ totalGenerated++;
153
+ } catch (error) {
154
+ console.error(` ❌ Failed: ${error.message}`);
155
+ }
156
+ } else {
157
+ console.log(` [DRY RUN] Would generate: ${char.description}, ${pose} pose`);
158
+ totalGenerated++;
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ // Generate emotions
165
+ console.log('\n😀 EMOTIONS');
166
+ console.log('-'.repeat(60));
167
+
168
+ for (const char of ASSET_DEFINITIONS.characters) {
169
+ for (const emotion of char.emotions) {
170
+ const query = {
171
+ asset_type: 'emotion',
172
+ character_id: char.id,
173
+ emotion: emotion
174
+ };
175
+
176
+ const existing = await library.findAsset(query);
177
+
178
+ if (existing) {
179
+ console.log(`⏭️ Skipping ${char.id}/${emotion} (already exists)`);
180
+ totalSkipped++;
181
+ } else {
182
+ console.log(`🎨 Generating ${char.id}/${emotion}...`);
183
+
184
+ if (!dryRun) {
185
+ try {
186
+ await library.generateAsset({
187
+ asset_type: 'emotion',
188
+ character_id: char.id,
189
+ emotion: emotion,
190
+ visual_description: `Face with ${emotion} expression, close-up`
191
+ });
192
+ totalGenerated++;
193
+ } catch (error) {
194
+ console.error(` ❌ Failed: ${error.message}`);
195
+ }
196
+ } else {
197
+ console.log(` [DRY RUN] Would generate: Face with ${emotion} expression`);
198
+ totalGenerated++;
199
+ }
200
+ }
201
+ }
202
+ }
203
+
204
+ // Generate props
205
+ console.log('\n🔧 PROPS');
206
+ console.log('-'.repeat(60));
207
+
208
+ for (const prop of ASSET_DEFINITIONS.props) {
209
+ const query = {
210
+ asset_type: 'prop',
211
+ character_id: prop.id
212
+ };
213
+
214
+ const existing = await library.findAsset(query);
215
+
216
+ if (existing) {
217
+ console.log(`⏭️ Skipping ${prop.id} (already exists)`);
218
+ totalSkipped++;
219
+ } else {
220
+ console.log(`🎨 Generating ${prop.id}...`);
221
+
222
+ if (!dryRun) {
223
+ try {
224
+ await library.generateAsset({
225
+ asset_type: 'prop',
226
+ character_id: prop.id,
227
+ visual_description: prop.description
228
+ });
229
+ totalGenerated++;
230
+ } catch (error) {
231
+ console.error(` ❌ Failed: ${error.message}`);
232
+ }
233
+ } else {
234
+ console.log(` [DRY RUN] Would generate: ${prop.description}`);
235
+ totalGenerated++;
236
+ }
237
+ }
238
+ }
239
+
240
+ // Generate backgrounds
241
+ console.log('\n🏞️ BACKGROUNDS');
242
+ console.log('-'.repeat(60));
243
+
244
+ for (const bg of ASSET_DEFINITIONS.backgrounds) {
245
+ const query = {
246
+ asset_type: 'background',
247
+ character_id: bg.id
248
+ };
249
+
250
+ const existing = await library.findAsset(query);
251
+
252
+ if (existing) {
253
+ console.log(`⏭️ Skipping ${bg.id} (already exists)`);
254
+ totalSkipped++;
255
+ } else {
256
+ console.log(`🎨 Generating ${bg.id}...`);
257
+
258
+ if (!dryRun) {
259
+ try {
260
+ await library.generateAsset({
261
+ asset_type: 'background',
262
+ character_id: bg.id,
263
+ visual_description: bg.description
264
+ });
265
+ totalGenerated++;
266
+ } catch (error) {
267
+ console.error(` ❌ Failed: ${error.message}`);
268
+ }
269
+ } else {
270
+ console.log(` [DRY RUN] Would generate: ${bg.description}`);
271
+ totalGenerated++;
272
+ }
273
+ }
274
+ }
275
+
276
+ // Generate effects
277
+ console.log('\n✨ EFFECTS');
278
+ console.log('-'.repeat(60));
279
+
280
+ for (const effect of ASSET_DEFINITIONS.effects) {
281
+ const query = {
282
+ asset_type: 'effect',
283
+ character_id: effect.id
284
+ };
285
+
286
+ const existing = await library.findAsset(query);
287
+
288
+ if (existing) {
289
+ console.log(`⏭️ Skipping ${effect.id} (already exists)`);
290
+ totalSkipped++;
291
+ } else {
292
+ console.log(`🎨 Generating ${effect.id}...`);
293
+
294
+ if (!dryRun) {
295
+ try {
296
+ await library.generateAsset({
297
+ asset_type: 'effect',
298
+ character_id: effect.id,
299
+ visual_description: effect.description
300
+ });
301
+ totalGenerated++;
302
+ } catch (error) {
303
+ console.error(` ❌ Failed: ${error.message}`);
304
+ }
305
+ } else {
306
+ console.log(` [DRY RUN] Would generate: ${effect.description}`);
307
+ totalGenerated++;
308
+ }
309
+ }
310
+ }
311
+
312
+ // Summary
313
+ console.log('\n' + '='.repeat(60));
314
+ console.log('📊 GENERATION SUMMARY');
315
+ console.log('='.repeat(60));
316
+ console.log(`Assets generated: ${totalGenerated}`);
317
+ console.log(`Assets skipped: ${totalSkipped}`);
318
+ console.log(`Total assets: ${totalGenerated + totalSkipped}`);
319
+
320
+ if (dryRun) {
321
+ console.log('\n⚠️ DRY RUN MODE - No assets were actually generated');
322
+ }
323
+
324
+ console.log('\n✅ Asset generation complete!\n');
325
+ }
326
+
327
+ // Parse command line arguments
328
+ const args = process.argv.slice(2);
329
+ const dryRun = args.includes('--dry-run');
330
+
331
+ if (dryRun) {
332
+ console.log('🔍 Running in DRY RUN mode\n');
333
+ }
334
+
335
+ // Run generation
336
+ generateAssets(dryRun)
337
+ .then(() => process.exit(0))
338
+ .catch(error => {
339
+ console.error('\n❌ Generation failed:', error.message);
340
+ console.error(error.stack);
341
+ process.exit(1);
342
+ });