@codellyson/framely-cli 0.1.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 (40) hide show
  1. package/commands/compositions.js +135 -0
  2. package/commands/preview.js +889 -0
  3. package/commands/render.js +295 -0
  4. package/commands/still.js +165 -0
  5. package/index.js +93 -0
  6. package/package.json +60 -0
  7. package/studio/App.css +605 -0
  8. package/studio/App.jsx +185 -0
  9. package/studio/CompositionsView.css +399 -0
  10. package/studio/CompositionsView.jsx +327 -0
  11. package/studio/PropsEditor.css +195 -0
  12. package/studio/PropsEditor.tsx +176 -0
  13. package/studio/RenderDialog.tsx +476 -0
  14. package/studio/ShareDialog.tsx +200 -0
  15. package/studio/index.ts +19 -0
  16. package/studio/player/Player.css +199 -0
  17. package/studio/player/Player.jsx +355 -0
  18. package/studio/styles/design-system.css +592 -0
  19. package/studio/styles/dialogs.css +420 -0
  20. package/studio/templates/AnimatedGradient.jsx +99 -0
  21. package/studio/templates/InstagramStory.jsx +172 -0
  22. package/studio/templates/LowerThird.jsx +139 -0
  23. package/studio/templates/ProductShowcase.jsx +162 -0
  24. package/studio/templates/SlideTransition.jsx +211 -0
  25. package/studio/templates/SocialIntro.jsx +122 -0
  26. package/studio/templates/SubscribeAnimation.jsx +186 -0
  27. package/studio/templates/TemplateCard.tsx +58 -0
  28. package/studio/templates/TemplateFilters.tsx +97 -0
  29. package/studio/templates/TemplatePreviewDialog.tsx +196 -0
  30. package/studio/templates/TemplatesMarketplace.css +686 -0
  31. package/studio/templates/TemplatesMarketplace.tsx +172 -0
  32. package/studio/templates/TextReveal.jsx +134 -0
  33. package/studio/templates/UseTemplateDialog.tsx +154 -0
  34. package/studio/templates/index.ts +45 -0
  35. package/utils/browser.js +188 -0
  36. package/utils/codecs.js +200 -0
  37. package/utils/logger.js +35 -0
  38. package/utils/props.js +42 -0
  39. package/utils/render.js +447 -0
  40. package/utils/validate.js +148 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Compositions Command
3
+ *
4
+ * Lists all available compositions from the Framely project.
5
+ *
6
+ * Usage:
7
+ * framely compositions
8
+ * framely compositions --json
9
+ */
10
+
11
+ import chalk from 'chalk';
12
+ import ora from 'ora';
13
+ import { createBrowser, closeBrowser } from '../utils/browser.js';
14
+
15
+ /**
16
+ * Main compositions command handler.
17
+ */
18
+ export async function compositionsCommand(options) {
19
+ const spinner = ora();
20
+
21
+ try {
22
+ if (!options.json) {
23
+ console.log(chalk.cyan('\nšŸ“‹ Framely Compositions\n'));
24
+ }
25
+
26
+ // ─── Launch Browser to Fetch Compositions ───
27
+ spinner.start('Fetching compositions...');
28
+
29
+ const { browser, page } = await createBrowser({
30
+ width: 100,
31
+ height: 100,
32
+ });
33
+
34
+ // Navigate to frontend
35
+ await page.goto(options.frontendUrl, { waitUntil: 'networkidle', timeout: 30000 });
36
+
37
+ // Wait for app to be ready
38
+ try {
39
+ await page.waitForFunction('window.__ready === true || window.__FRAMELY_COMPOSITIONS', {
40
+ timeout: 10000,
41
+ });
42
+ } catch {
43
+ // May not have ready flag in some setups
44
+ }
45
+
46
+ // Get compositions from global
47
+ const compositions = await page.evaluate(() => {
48
+ // Try different possible locations
49
+ if (window.__FRAMELY_COMPOSITIONS) {
50
+ return Object.values(window.__FRAMELY_COMPOSITIONS);
51
+ }
52
+
53
+ // Try to extract from registry
54
+ if (window.__FRAMELY_ROOT) {
55
+ // This would require traversing the component tree
56
+ return [];
57
+ }
58
+
59
+ return [];
60
+ });
61
+
62
+ spinner.stop();
63
+
64
+ // If no compositions found, try the API endpoint
65
+ if (compositions.length === 0) {
66
+ try {
67
+ const parsed = new URL(options.frontendUrl);
68
+ parsed.port = String(parseInt(parsed.port || '3000', 10) + 1);
69
+ const response = await fetch(`${parsed.origin}/api/compositions`);
70
+ if (response.ok) {
71
+ const data = await response.json();
72
+ compositions.push(...(data.compositions || []));
73
+ }
74
+ } catch {
75
+ // API might not be running
76
+ }
77
+ }
78
+
79
+ // ─── Output Results ───
80
+ if (options.json) {
81
+ console.log(JSON.stringify(compositions, null, 2));
82
+ } else if (compositions.length === 0) {
83
+ console.log(chalk.yellow(' No compositions found.\n'));
84
+ console.log(chalk.gray(' Make sure the frontend is running and has registered compositions.'));
85
+ console.log(chalk.gray(' Use registerRoot() in your entry file to register compositions.\n'));
86
+ } else {
87
+ // Calculate column widths
88
+ const maxIdLength = Math.max(...compositions.map((c) => (c.id && c.id.length) || 0), 2);
89
+
90
+ // Header
91
+ console.log(
92
+ chalk.gray(' ') +
93
+ chalk.white('ID'.padEnd(maxIdLength + 2)) +
94
+ chalk.white('Resolution'.padEnd(14)) +
95
+ chalk.white('FPS'.padEnd(6)) +
96
+ chalk.white('Duration')
97
+ );
98
+ console.log(chalk.gray(' ' + '─'.repeat(maxIdLength + 40)));
99
+
100
+ // Rows
101
+ for (const comp of compositions) {
102
+ const id = (comp.id || 'unknown').padEnd(maxIdLength + 2);
103
+ const resolution = `${comp.width || '?'}x${comp.height || '?'}`.padEnd(14);
104
+ const fps = String(comp.fps || '?').padEnd(6);
105
+ const frames = comp.durationInFrames || '?';
106
+ const seconds = comp.fps ? (frames / comp.fps).toFixed(1) + 's' : '?';
107
+ const duration = `${frames} frames (${seconds})`;
108
+
109
+ console.log(
110
+ chalk.gray(' ') +
111
+ chalk.yellow(id) +
112
+ chalk.white(resolution) +
113
+ chalk.white(fps) +
114
+ chalk.gray(duration)
115
+ );
116
+ }
117
+
118
+ console.log(chalk.gray('\n ' + '─'.repeat(maxIdLength + 40)));
119
+ console.log(chalk.gray(` ${compositions.length} composition(s) found\n`));
120
+ }
121
+
122
+ await closeBrowser(browser);
123
+ process.exit(0);
124
+ } catch (error) {
125
+ spinner.fail('Failed to fetch compositions');
126
+ console.error(chalk.red(`\nError: ${error.message}\n`));
127
+
128
+ if (!options.json) {
129
+ console.log(chalk.gray(' Make sure the frontend dev server is running:'));
130
+ console.log(chalk.cyan(' framely preview\n'));
131
+ }
132
+
133
+ process.exit(1);
134
+ }
135
+ }