skillui 1.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 (59) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.js +202 -0
  3. package/dist/extractors/components.d.ts +11 -0
  4. package/dist/extractors/components.js +455 -0
  5. package/dist/extractors/framework.d.ts +4 -0
  6. package/dist/extractors/framework.js +126 -0
  7. package/dist/extractors/tokens/computed.d.ts +7 -0
  8. package/dist/extractors/tokens/computed.js +249 -0
  9. package/dist/extractors/tokens/css.d.ts +3 -0
  10. package/dist/extractors/tokens/css.js +510 -0
  11. package/dist/extractors/tokens/http-css.d.ts +14 -0
  12. package/dist/extractors/tokens/http-css.js +1689 -0
  13. package/dist/extractors/tokens/tailwind.d.ts +3 -0
  14. package/dist/extractors/tokens/tailwind.js +353 -0
  15. package/dist/extractors/tokens/tokens-file.d.ts +3 -0
  16. package/dist/extractors/tokens/tokens-file.js +229 -0
  17. package/dist/extractors/ultra/animations.d.ts +21 -0
  18. package/dist/extractors/ultra/animations.js +530 -0
  19. package/dist/extractors/ultra/components-dom.d.ts +13 -0
  20. package/dist/extractors/ultra/components-dom.js +152 -0
  21. package/dist/extractors/ultra/interactions.d.ts +14 -0
  22. package/dist/extractors/ultra/interactions.js +225 -0
  23. package/dist/extractors/ultra/layout.d.ts +14 -0
  24. package/dist/extractors/ultra/layout.js +126 -0
  25. package/dist/extractors/ultra/pages.d.ts +16 -0
  26. package/dist/extractors/ultra/pages.js +231 -0
  27. package/dist/font-resolver.d.ts +10 -0
  28. package/dist/font-resolver.js +280 -0
  29. package/dist/modes/dir.d.ts +6 -0
  30. package/dist/modes/dir.js +213 -0
  31. package/dist/modes/repo.d.ts +6 -0
  32. package/dist/modes/repo.js +76 -0
  33. package/dist/modes/ultra.d.ts +22 -0
  34. package/dist/modes/ultra.js +285 -0
  35. package/dist/modes/url.d.ts +14 -0
  36. package/dist/modes/url.js +161 -0
  37. package/dist/normalizer.d.ts +11 -0
  38. package/dist/normalizer.js +867 -0
  39. package/dist/screenshot.d.ts +9 -0
  40. package/dist/screenshot.js +94 -0
  41. package/dist/types-ultra.d.ts +157 -0
  42. package/dist/types-ultra.js +4 -0
  43. package/dist/types.d.ts +182 -0
  44. package/dist/types.js +4 -0
  45. package/dist/writers/animations-md.d.ts +17 -0
  46. package/dist/writers/animations-md.js +313 -0
  47. package/dist/writers/components-md.d.ts +8 -0
  48. package/dist/writers/components-md.js +151 -0
  49. package/dist/writers/design-md.d.ts +7 -0
  50. package/dist/writers/design-md.js +704 -0
  51. package/dist/writers/interactions-md.d.ts +8 -0
  52. package/dist/writers/interactions-md.js +146 -0
  53. package/dist/writers/layout-md.d.ts +8 -0
  54. package/dist/writers/layout-md.js +120 -0
  55. package/dist/writers/skill.d.ts +12 -0
  56. package/dist/writers/skill.js +1006 -0
  57. package/dist/writers/tokens-json.d.ts +11 -0
  58. package/dist/writers/tokens-json.js +164 -0
  59. package/package.json +78 -0
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runDirMode = runDirMode;
4
+ const framework_1 = require("../extractors/framework");
5
+ const tailwind_1 = require("../extractors/tokens/tailwind");
6
+ const css_1 = require("../extractors/tokens/css");
7
+ const tokens_file_1 = require("../extractors/tokens/tokens-file");
8
+ const components_1 = require("../extractors/components");
9
+ const normalizer_1 = require("../normalizer");
10
+ /**
11
+ * DIR mode: scan a local project directory and extract design tokens.
12
+ */
13
+ async function runDirMode(projectDir, nameOverride) {
14
+ // Step 1: Detect frameworks
15
+ const frameworks = (0, framework_1.detectFrameworks)(projectDir);
16
+ const projectName = (0, framework_1.getProjectName)(projectDir, nameOverride);
17
+ // Step 2: Detect project libraries (icons, state, animations)
18
+ const libraries = (0, components_1.detectProjectLibraries)(projectDir);
19
+ // Step 3: Extract raw tokens from all sources (priority order)
20
+ const tailwindTokens = (0, tailwind_1.extractTailwindTokens)(projectDir);
21
+ const tokensFileTokens = (0, tokens_file_1.extractTokensFile)(projectDir);
22
+ const cssTokens = (0, css_1.extractCSSTokens)(projectDir);
23
+ // Merge all raw tokens
24
+ const merged = mergeRawTokens([tailwindTokens, tokensFileTokens, cssTokens]);
25
+ // Step 4: Extract components
26
+ const components = (0, components_1.extractComponents)(projectDir);
27
+ // Step 5: Scan component files for additional color/font tokens
28
+ for (const comp of components) {
29
+ extractComponentTokens(comp, merged);
30
+ }
31
+ // Step 6: Collect animation tokens from components
32
+ for (const comp of components) {
33
+ if (comp.hasAnimation) {
34
+ for (const detail of comp.animationDetails) {
35
+ if (detail.startsWith('framer-motion')) {
36
+ merged.animations.push({
37
+ name: 'framer-motion',
38
+ type: 'framer-motion',
39
+ value: detail,
40
+ source: comp.filePath,
41
+ });
42
+ }
43
+ else if (detail.startsWith('spring:')) {
44
+ merged.animations.push({
45
+ name: 'spring-config',
46
+ type: 'spring',
47
+ value: detail.replace('spring: ', ''),
48
+ source: comp.filePath,
49
+ });
50
+ }
51
+ else if (detail.startsWith('tw-animate-')) {
52
+ merged.animations.push({
53
+ name: detail.replace('tw-', ''),
54
+ type: 'css-keyframe',
55
+ value: detail,
56
+ source: comp.filePath,
57
+ });
58
+ }
59
+ }
60
+ }
61
+ }
62
+ // Step 7: Normalize into clean DesignProfile
63
+ return (0, normalizer_1.normalize)(projectName, frameworks, merged, components, libraries);
64
+ }
65
+ function mergeRawTokens(sources) {
66
+ const merged = {
67
+ colors: [],
68
+ fonts: [],
69
+ spacingValues: [],
70
+ shadows: [],
71
+ cssVariables: [],
72
+ breakpoints: [],
73
+ borderRadii: [],
74
+ gradients: [],
75
+ fontVarMap: {},
76
+ animations: [],
77
+ darkModeVars: [],
78
+ zIndexValues: [],
79
+ containerMaxWidth: null,
80
+ fontSources: [],
81
+ pageSections: [],
82
+ transitionDurations: [],
83
+ transitionEasings: [],
84
+ };
85
+ for (const src of sources) {
86
+ // Merge colors, deduplicating by hex value
87
+ for (const color of src.colors) {
88
+ const existing = merged.colors.find(c => c.value === color.value);
89
+ if (existing) {
90
+ existing.frequency += color.frequency;
91
+ if (color.name && !existing.name)
92
+ existing.name = color.name;
93
+ }
94
+ else {
95
+ merged.colors.push({ ...color });
96
+ }
97
+ }
98
+ // Merge fonts
99
+ for (const font of src.fonts) {
100
+ if (font.family && !merged.fonts.find(f => f.family === font.family && f.size === font.size)) {
101
+ merged.fonts.push({ ...font });
102
+ }
103
+ }
104
+ // Merge spacing
105
+ merged.spacingValues.push(...src.spacingValues);
106
+ // Merge shadows
107
+ for (const shadow of src.shadows) {
108
+ if (!merged.shadows.find(s => s.value === shadow.value)) {
109
+ merged.shadows.push({ ...shadow });
110
+ }
111
+ }
112
+ // Merge CSS variables
113
+ for (const v of src.cssVariables) {
114
+ if (!merged.cssVariables.find(cv => cv.name === v.name)) {
115
+ merged.cssVariables.push({ ...v });
116
+ }
117
+ }
118
+ // Merge breakpoints (prefer tailwind over css)
119
+ for (const bp of src.breakpoints) {
120
+ if (!merged.breakpoints.find(b => b.value === bp.value)) {
121
+ merged.breakpoints.push({ ...bp });
122
+ }
123
+ }
124
+ // Merge border radii
125
+ if (src.borderRadii) {
126
+ for (const r of src.borderRadii) {
127
+ if (!merged.borderRadii.includes(r))
128
+ merged.borderRadii.push(r);
129
+ }
130
+ }
131
+ // Merge gradients
132
+ if (src.gradients) {
133
+ merged.gradients.push(...src.gradients);
134
+ }
135
+ // Merge font var map
136
+ if (src.fontVarMap) {
137
+ Object.assign(merged.fontVarMap, src.fontVarMap);
138
+ }
139
+ // Merge animations
140
+ if (src.animations) {
141
+ merged.animations.push(...src.animations);
142
+ }
143
+ // Merge dark mode vars
144
+ if (src.darkModeVars) {
145
+ for (const dmv of src.darkModeVars) {
146
+ if (!merged.darkModeVars.find(d => d.variable === dmv.variable)) {
147
+ merged.darkModeVars.push(dmv);
148
+ }
149
+ }
150
+ }
151
+ // Merge z-index values
152
+ if (src.zIndexValues) {
153
+ for (const z of src.zIndexValues) {
154
+ if (!merged.zIndexValues.includes(z))
155
+ merged.zIndexValues.push(z);
156
+ }
157
+ }
158
+ // Container max-width: prefer explicit
159
+ if (src.containerMaxWidth && !merged.containerMaxWidth) {
160
+ merged.containerMaxWidth = src.containerMaxWidth;
161
+ }
162
+ // Merge font sources
163
+ if (src.fontSources) {
164
+ for (const fs of src.fontSources) {
165
+ if (!merged.fontSources.find(f => f.family === fs.family && f.src === fs.src)) {
166
+ merged.fontSources.push(fs);
167
+ }
168
+ }
169
+ }
170
+ // Merge page sections
171
+ if (src.pageSections) {
172
+ for (const ps of src.pageSections) {
173
+ if (!merged.pageSections.find(p => p.type === ps.type)) {
174
+ merged.pageSections.push(ps);
175
+ }
176
+ }
177
+ }
178
+ // Merge transition durations/easings
179
+ if (src.transitionDurations) {
180
+ for (const d of src.transitionDurations) {
181
+ if (!merged.transitionDurations.includes(d))
182
+ merged.transitionDurations.push(d);
183
+ }
184
+ }
185
+ if (src.transitionEasings) {
186
+ for (const e of src.transitionEasings) {
187
+ if (!merged.transitionEasings.includes(e))
188
+ merged.transitionEasings.push(e);
189
+ }
190
+ }
191
+ }
192
+ return merged;
193
+ }
194
+ function extractComponentTokens(comp, tokens) {
195
+ if (comp.jsxSnippet) {
196
+ const hexMatches = comp.jsxSnippet.matchAll(/#([0-9a-fA-F]{3,6})\b/g);
197
+ for (const m of hexMatches) {
198
+ let hex = m[0].toLowerCase();
199
+ if (hex.length === 4) {
200
+ const [, r, g, b] = hex.split('');
201
+ hex = `#${r}${r}${g}${g}${b}${b}`;
202
+ }
203
+ const existing = tokens.colors.find(c => c.value === hex);
204
+ if (existing) {
205
+ existing.frequency++;
206
+ }
207
+ else {
208
+ tokens.colors.push({ value: hex, frequency: 1, source: 'component' });
209
+ }
210
+ }
211
+ }
212
+ }
213
+ //# sourceMappingURL=dir.js.map
@@ -0,0 +1,6 @@
1
+ import { DesignProfile } from '../types';
2
+ /**
3
+ * REPO mode: clone a git repo into a temp directory, then run dir mode.
4
+ */
5
+ export declare function runRepoMode(repoUrl: string, nameOverride?: string): Promise<DesignProfile>;
6
+ //# sourceMappingURL=repo.d.ts.map
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runRepoMode = runRepoMode;
37
+ const tmp = __importStar(require("tmp"));
38
+ const dir_1 = require("./dir");
39
+ /**
40
+ * REPO mode: clone a git repo into a temp directory, then run dir mode.
41
+ */
42
+ async function runRepoMode(repoUrl, nameOverride) {
43
+ // Import simple-git
44
+ const { simpleGit } = await Promise.resolve().then(() => __importStar(require('simple-git')));
45
+ const git = simpleGit();
46
+ // Create temp directory
47
+ const tmpDir = tmp.dirSync({ unsafeCleanup: true, prefix: 'skillui-' });
48
+ const cloneDir = tmpDir.name;
49
+ try {
50
+ process.stdout.write(' Cloning...');
51
+ await git.clone(repoUrl, cloneDir, ['--depth', '1', '--single-branch']);
52
+ console.log(' \u2713');
53
+ // Derive project name from repo URL if not overridden
54
+ const derivedName = nameOverride || deriveRepoName(repoUrl);
55
+ // Run dir mode on the cloned repo
56
+ const profile = await (0, dir_1.runDirMode)(cloneDir, derivedName);
57
+ return profile;
58
+ }
59
+ finally {
60
+ // Cleanup temp directory
61
+ try {
62
+ tmpDir.removeCallback();
63
+ }
64
+ catch {
65
+ // Best effort cleanup
66
+ }
67
+ }
68
+ }
69
+ function deriveRepoName(url) {
70
+ // Handle GitHub URLs: https://github.com/org/repo or git@github.com:org/repo.git
71
+ const match = url.match(/\/([^\/]+?)(?:\.git)?$/);
72
+ if (match)
73
+ return match[1];
74
+ return 'project';
75
+ }
76
+ //# sourceMappingURL=repo.js.map
@@ -0,0 +1,22 @@
1
+ import { DesignProfile } from '../types';
2
+ import { UltraOptions, UltraResult } from '../types-ultra';
3
+ /**
4
+ * Ultra mode orchestrator.
5
+ *
6
+ * Runs AFTER the normal url mode pipeline. Adds:
7
+ * - screens/pages/ — full-page screenshots per crawled page
8
+ * - screens/sections/ — clipped section screenshots per page
9
+ * - screens/states/ — hover/focus state screenshots per interactive element
10
+ * - screens/scroll/ — 7 scroll-journey screenshots + video first frames
11
+ * - references/LAYOUT.md
12
+ * - references/INTERACTIONS.md
13
+ * - references/COMPONENTS.md
14
+ * - references/ANIMATIONS.md ← NEW: cinematic animation documentation
15
+ * - tokens/colors.json
16
+ * - tokens/spacing.json
17
+ * - tokens/typography.json
18
+ *
19
+ * All existing outputs remain untouched.
20
+ */
21
+ export declare function runUltraMode(url: string, profile: DesignProfile, skillDir: string, opts: UltraOptions): Promise<UltraResult>;
22
+ //# sourceMappingURL=ultra.d.ts.map
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runUltraMode = runUltraMode;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const pages_1 = require("../extractors/ultra/pages");
40
+ const interactions_1 = require("../extractors/ultra/interactions");
41
+ const layout_1 = require("../extractors/ultra/layout");
42
+ const components_dom_1 = require("../extractors/ultra/components-dom");
43
+ const animations_1 = require("../extractors/ultra/animations");
44
+ const layout_md_1 = require("../writers/layout-md");
45
+ const interactions_md_1 = require("../writers/interactions-md");
46
+ const components_md_1 = require("../writers/components-md");
47
+ const animations_md_1 = require("../writers/animations-md");
48
+ const tokens_json_1 = require("../writers/tokens-json");
49
+ /**
50
+ * Ultra mode orchestrator.
51
+ *
52
+ * Runs AFTER the normal url mode pipeline. Adds:
53
+ * - screens/pages/ — full-page screenshots per crawled page
54
+ * - screens/sections/ — clipped section screenshots per page
55
+ * - screens/states/ — hover/focus state screenshots per interactive element
56
+ * - screens/scroll/ — 7 scroll-journey screenshots + video first frames
57
+ * - references/LAYOUT.md
58
+ * - references/INTERACTIONS.md
59
+ * - references/COMPONENTS.md
60
+ * - references/ANIMATIONS.md ← NEW: cinematic animation documentation
61
+ * - tokens/colors.json
62
+ * - tokens/spacing.json
63
+ * - tokens/typography.json
64
+ *
65
+ * All existing outputs remain untouched.
66
+ */
67
+ async function runUltraMode(url, profile, skillDir, opts) {
68
+ // Ensure all output directories exist
69
+ fs.mkdirSync(path.join(skillDir, 'screens', 'pages'), { recursive: true });
70
+ fs.mkdirSync(path.join(skillDir, 'screens', 'sections'), { recursive: true });
71
+ fs.mkdirSync(path.join(skillDir, 'screens', 'states'), { recursive: true });
72
+ fs.mkdirSync(path.join(skillDir, 'screens', 'scroll'), { recursive: true });
73
+ fs.mkdirSync(path.join(skillDir, 'references'), { recursive: true });
74
+ fs.mkdirSync(path.join(skillDir, 'tokens'), { recursive: true });
75
+ let hasPlaywright = false;
76
+ try {
77
+ require.resolve('playwright');
78
+ hasPlaywright = true;
79
+ }
80
+ catch { /* not installed */ }
81
+ if (!hasPlaywright) {
82
+ process.stdout.write('\n ⚠ Playwright not installed — ultra visual features skipped\n');
83
+ process.stdout.write(' Run: npm install playwright && npx playwright install chromium\n\n');
84
+ (0, tokens_json_1.writeTokensJson)(profile, skillDir);
85
+ writeStubs(skillDir);
86
+ const emptyAnim = emptyAnimResult();
87
+ return { pageScreenshots: [], sectionScreenshots: [], interactions: [], layouts: [], domComponents: [], animations: emptyAnim };
88
+ }
89
+ // ── Step 1: Animation extraction (scroll journey + keyframes + libraries) ──
90
+ process.stdout.write(' Extracting animations & scroll journey...');
91
+ const animations = await (0, animations_1.captureAnimations)(url, skillDir);
92
+ console.log(` ✓ (${animations.keyframes.length} keyframes · ${animations.scrollFrames.length} scroll frames · ${animations.libraries.length} libs)`);
93
+ // ── Step 2: Multi-page screenshots + section clips ─────────────────────
94
+ process.stdout.write(` Crawling ${opts.screens} pages...`);
95
+ const { pages, sections } = await (0, pages_1.capturePageScreenshots)(url, skillDir, opts.screens);
96
+ console.log(` ✓ (${pages.length} pages · ${sections.length} sections)`);
97
+ // ── Step 3: Micro-interactions ────────────────────────────────────────
98
+ process.stdout.write(' Capturing interactions...');
99
+ const interactions = await (0, interactions_1.captureInteractions)(url, skillDir);
100
+ console.log(` ✓ (${interactions.length} components)`);
101
+ // ── Step 4: Layout extraction ──────────────────────────────────────────
102
+ process.stdout.write(' Extracting layout...');
103
+ const layouts = await (0, layout_1.extractLayouts)(url);
104
+ console.log(` ✓ (${layouts.length} containers)`);
105
+ // ── Step 5: DOM component detection ───────────────────────────────────
106
+ process.stdout.write(' Detecting DOM components...');
107
+ const domComponents = await (0, components_dom_1.detectDOMComponents)(url);
108
+ console.log(` ✓ (${domComponents.length} patterns)`);
109
+ // ── Step 6: Write all reference files ─────────────────────────────────
110
+ process.stdout.write(' Writing extended outputs...');
111
+ const refsDir = path.join(skillDir, 'references');
112
+ // ANIMATIONS.md — cinematic motion documentation
113
+ const animMd = (0, animations_md_1.generateAnimationsMd)(animations, profile);
114
+ fs.writeFileSync(path.join(refsDir, 'ANIMATIONS.md'), animMd, 'utf-8');
115
+ // LAYOUT.md
116
+ const layoutMd = (0, layout_md_1.generateLayoutMd)(layouts, profile);
117
+ fs.writeFileSync(path.join(refsDir, 'LAYOUT.md'), layoutMd, 'utf-8');
118
+ // INTERACTIONS.md
119
+ const interactionsMd = (0, interactions_md_1.generateInteractionsMd)(interactions, profile);
120
+ fs.writeFileSync(path.join(refsDir, 'INTERACTIONS.md'), interactionsMd, 'utf-8');
121
+ // COMPONENTS.md
122
+ const componentsMd = (0, components_md_1.generateComponentsMd)(domComponents, profile);
123
+ fs.writeFileSync(path.join(refsDir, 'COMPONENTS.md'), componentsMd, 'utf-8');
124
+ // Token JSON files
125
+ (0, tokens_json_1.writeTokensJson)(profile, skillDir);
126
+ // VISUAL_GUIDE.md — master visual reference embedding all screenshots
127
+ const visualGuideMd = generateVisualGuideMd(profile, pages, sections, animations);
128
+ fs.writeFileSync(path.join(refsDir, 'VISUAL_GUIDE.md'), visualGuideMd, 'utf-8');
129
+ // Ultra screenshot index
130
+ writeScreensIndex(pages, sections, animations, skillDir);
131
+ console.log(' ✓');
132
+ // ── Print ultra summary ────────────────────────────────────────────────
133
+ printUltraSummary(animations);
134
+ return { pageScreenshots: pages, sectionScreenshots: sections, interactions, layouts, domComponents, animations };
135
+ }
136
+ // ── Visual Guide Generator ────────────────────────────────────────────
137
+ function generateVisualGuideMd(profile, pages, sections, anim) {
138
+ let md = `# ${profile.projectName} — Visual Guide\n\n`;
139
+ md += `> Master visual reference. Study every screenshot carefully before implementing any UI.\n`;
140
+ md += `> Match colors, layout, typography, spacing, and motion states exactly.\n\n`;
141
+ // Animation stack summary
142
+ if (anim.libraries.length > 0) {
143
+ const libs = anim.libraries.map(l => `**${l.name}**`).join(', ');
144
+ md += `**Motion Stack:** ${libs}\n\n`;
145
+ }
146
+ if (anim.webglDetected) {
147
+ md += `**WebGL/3D:** Detected (${anim.canvasCount} canvas elements) — replicate with Three.js or CSS 3D transforms\n\n`;
148
+ }
149
+ // Scroll journey — most important section
150
+ if (anim.scrollFrames.length > 0) {
151
+ md += `## Scroll Journey\n\n`;
152
+ md += `The page has cinematic scroll animations. Each screenshot below shows the exact visual state at that scroll depth.\n`;
153
+ md += `**Replicate these transitions precisely** — the design changes dramatically as you scroll.\n\n`;
154
+ for (const frame of anim.scrollFrames) {
155
+ const relPath = `../screens/scroll/${path.basename(frame.filePath)}`;
156
+ const label = frame.scrollPercent === 0 ? 'Hero — Above the fold'
157
+ : frame.scrollPercent === 100 ? 'Footer — End of page'
158
+ : `${frame.scrollPercent}% scroll depth`;
159
+ md += `### ${label}\n\n`;
160
+ md += `*Scroll position: ${frame.scrollY}px of ${frame.pageHeight}px total*\n\n`;
161
+ md += `![${label}](${relPath})\n\n`;
162
+ }
163
+ }
164
+ // Video backgrounds
165
+ if (anim.videos.some(v => v.firstFramePath)) {
166
+ md += `## Video Backgrounds\n\n`;
167
+ md += `These videos play as background elements. Use first-frame as poster image while video loads.\n\n`;
168
+ for (const v of anim.videos.filter(vv => vv.firstFramePath)) {
169
+ const relPath = `../screens/scroll/${path.basename(v.firstFramePath)}`;
170
+ md += `### Video ${v.index} (${v.role})\n\n`;
171
+ if (v.src)
172
+ md += `*Source: \`${v.src.slice(0, 80)}...\`*\n\n`;
173
+ md += `![Video ${v.index} first frame](${relPath})\n\n`;
174
+ }
175
+ }
176
+ // Page screenshots
177
+ if (pages.length > 0) {
178
+ md += `## Full Page Screenshots\n\n`;
179
+ for (const p of pages) {
180
+ const relPath = `../screens/pages/${path.basename(p.filePath)}`;
181
+ md += `### ${p.title}\n\n`;
182
+ md += `*URL: \`${p.url}\`*\n\n`;
183
+ md += `![${p.title}](${relPath})\n\n`;
184
+ }
185
+ }
186
+ // Section clips
187
+ if (sections.length > 0) {
188
+ md += `## Section Screenshots\n\n`;
189
+ md += `Clipped sections showing individual components in context.\n\n`;
190
+ for (const s of sections) {
191
+ const relPath = `../screens/sections/${path.basename(s.filePath)}`;
192
+ md += `### Section ${s.index} — \`${s.selector}\`\n\n`;
193
+ md += `*${s.width}×${s.height}px*\n\n`;
194
+ md += `![Section ${s.index}](${relPath})\n\n`;
195
+ }
196
+ }
197
+ return md;
198
+ }
199
+ // ── Helpers ───────────────────────────────────────────────────────────
200
+ function printUltraSummary(anim) {
201
+ const libs = anim.libraries.map(l => l.name).join(', ') || 'none';
202
+ console.log('');
203
+ console.log(` Animation Stack: ${libs}`);
204
+ if (anim.webglDetected)
205
+ console.log(` WebGL/3D: detected (${anim.canvasCount} canvas elements)`);
206
+ if (anim.videos.length > 0) {
207
+ const bg = anim.videos.filter(v => v.role === 'background').length;
208
+ console.log(` Video: ${anim.videos.length} elements (${bg} background)`);
209
+ }
210
+ if (anim.lottieCount > 0)
211
+ console.log(` Lottie: ${anim.lottieCount} players`);
212
+ if (anim.keyframes.length > 0)
213
+ console.log(` Keyframes: ${anim.keyframes.length} extracted`);
214
+ if (anim.scrollPatterns.length > 0)
215
+ console.log(` Scroll patterns: ${anim.scrollPatterns.length} types`);
216
+ }
217
+ function writeScreensIndex(pages, sections, anim, skillDir) {
218
+ let md = `# Screenshot Index\n\n`;
219
+ // Scroll journey (most important for animation sites)
220
+ if (anim.scrollFrames.length > 0) {
221
+ md += `## Scroll Journey\n\n`;
222
+ md += `> Shows the cinematic state at each point of the page\n\n`;
223
+ md += `| Scroll | Y Position | File |\n`;
224
+ md += `|--------|-----------|------|\n`;
225
+ for (const f of anim.scrollFrames) {
226
+ md += `| ${f.scrollPercent}% | ${f.scrollY}px | \`${f.filePath}\` |\n`;
227
+ }
228
+ md += `\n`;
229
+ }
230
+ // Video frames
231
+ if (anim.videos.some(v => v.firstFramePath)) {
232
+ md += `## Video First Frames\n\n`;
233
+ for (const v of anim.videos) {
234
+ if (v.firstFramePath) {
235
+ md += `- Video ${v.index} (${v.role}): \`${v.firstFramePath}\`\n`;
236
+ }
237
+ }
238
+ md += `\n`;
239
+ }
240
+ if (pages.length > 0) {
241
+ md += `## Pages\n\n`;
242
+ md += `| Page | URL | File |\n`;
243
+ md += `|------|-----|------|\n`;
244
+ for (const p of pages) {
245
+ md += `| ${p.title} | \`${p.url}\` | \`${p.filePath}\` |\n`;
246
+ }
247
+ md += `\n`;
248
+ }
249
+ if (sections.length > 0) {
250
+ md += `## Sections\n\n`;
251
+ md += `| Page | Section | File |\n`;
252
+ md += `|------|---------|------|\n`;
253
+ for (const s of sections) {
254
+ md += `| ${s.page} | #${s.index} (${s.selector}) | \`${s.filePath}\` |\n`;
255
+ }
256
+ md += `\n`;
257
+ }
258
+ fs.writeFileSync(path.join(skillDir, 'screens', 'INDEX.md'), md, 'utf-8');
259
+ }
260
+ function writeStubs(skillDir) {
261
+ const refsDir = path.join(skillDir, 'references');
262
+ const note = '> Install Playwright to enable: `npm install playwright && npx playwright install chromium`\n\nRun `skillui --url <url> --mode ultra` after installing.\n';
263
+ for (const file of ['ANIMATIONS.md', 'LAYOUT.md', 'INTERACTIONS.md', 'COMPONENTS.md']) {
264
+ const filePath = path.join(refsDir, file);
265
+ if (!fs.existsSync(filePath)) {
266
+ const title = file.replace('.md', '').replace(/-/g, ' ');
267
+ fs.writeFileSync(filePath, `# ${title} Reference\n\n${note}`, 'utf-8');
268
+ }
269
+ }
270
+ }
271
+ function emptyAnimResult() {
272
+ return {
273
+ keyframes: [],
274
+ scrollFrames: [],
275
+ libraries: [],
276
+ videos: [],
277
+ scrollPatterns: [],
278
+ animationVars: [],
279
+ globalTransitions: [],
280
+ canvasCount: 0,
281
+ webglDetected: false,
282
+ lottieCount: 0,
283
+ };
284
+ }
285
+ //# sourceMappingURL=ultra.js.map
@@ -0,0 +1,14 @@
1
+ import { DesignProfile } from '../types';
2
+ /**
3
+ * URL mode: crawl a live website and extract design tokens.
4
+ *
5
+ * Strategy:
6
+ * 1. ALWAYS fetch HTML + linked CSS via HTTP (no Playwright needed)
7
+ * 2. If Playwright is available, ALSO extract computed styles from live DOM
8
+ * 3. Merge both token sets for maximum coverage
9
+ */
10
+ export declare function runUrlMode(url: string, nameOverride?: string, skillDir?: string): Promise<{
11
+ profile: DesignProfile;
12
+ screenshotPath: string | null;
13
+ }>;
14
+ //# sourceMappingURL=url.d.ts.map