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,3 @@
1
+ import { RawTokens } from '../../types';
2
+ export declare function extractTailwindTokens(projectDir: string): RawTokens;
3
+ //# sourceMappingURL=tailwind.d.ts.map
@@ -0,0 +1,353 @@
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.extractTailwindTokens = extractTailwindTokens;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const TAILWIND_CONFIG_FILES = [
40
+ 'tailwind.config.js',
41
+ 'tailwind.config.ts',
42
+ 'tailwind.config.mjs',
43
+ 'tailwind.config.cjs',
44
+ ];
45
+ // Tailwind v3 default spacing scale (in rem, converted to px at 16px base)
46
+ const TAILWIND_DEFAULT_SPACING_PX = [
47
+ 0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96,
48
+ ];
49
+ function extractTailwindTokens(projectDir) {
50
+ const tokens = {
51
+ colors: [],
52
+ fonts: [],
53
+ spacingValues: [],
54
+ shadows: [],
55
+ cssVariables: [],
56
+ breakpoints: [],
57
+ borderRadii: [],
58
+ gradients: [],
59
+ fontVarMap: {},
60
+ animations: [],
61
+ darkModeVars: [],
62
+ zIndexValues: [],
63
+ containerMaxWidth: null,
64
+ fontSources: [],
65
+ pageSections: [],
66
+ transitionDurations: [],
67
+ transitionEasings: [],
68
+ };
69
+ const configPath = findTailwindConfig(projectDir);
70
+ if (!configPath)
71
+ return tokens;
72
+ let config;
73
+ try {
74
+ const jiti = require('jiti')(__filename, { interopDefault: true });
75
+ config = jiti(configPath);
76
+ if (config.default)
77
+ config = config.default;
78
+ }
79
+ catch {
80
+ try {
81
+ config = parseConfigFallback(configPath);
82
+ }
83
+ catch {
84
+ // Config failed to load — still add Tailwind defaults since config exists
85
+ config = null;
86
+ }
87
+ }
88
+ // If config exists but failed to parse, still add sensible defaults
89
+ if (!config) {
90
+ tokens.spacingValues.push(...TAILWIND_DEFAULT_SPACING_PX.filter(v => v > 0));
91
+ tokens.breakpoints = [
92
+ { name: 'sm', value: '640px', source: 'tailwind' },
93
+ { name: 'md', value: '768px', source: 'tailwind' },
94
+ { name: 'lg', value: '1024px', source: 'tailwind' },
95
+ { name: 'xl', value: '1280px', source: 'tailwind' },
96
+ { name: '2xl', value: '1536px', source: 'tailwind' },
97
+ ];
98
+ // Try to extract font names from config file text as fallback
99
+ extractFontsFromConfigText(configPath, tokens);
100
+ return tokens;
101
+ }
102
+ const theme = config.theme || {};
103
+ const extend = theme.extend || {};
104
+ // Extract colors
105
+ const colorSources = mergeDeep(theme.colors || {}, extend.colors || {});
106
+ flattenColors(colorSources, '', tokens.colors);
107
+ // Extract fonts and build var→name map
108
+ const fontFamilies = mergeDeep(theme.fontFamily || {}, extend.fontFamily || {});
109
+ for (const [name, value] of Object.entries(fontFamilies)) {
110
+ const familyList = Array.isArray(value) ? value : [String(value)];
111
+ const primaryFamily = familyList[0];
112
+ // Resolve CSS var references in font values
113
+ const resolved = resolveFontName(primaryFamily, name);
114
+ // Only add as a font if the config key maps to a real font name
115
+ if (!isGenericConfigKey(name)) {
116
+ tokens.fonts.push({ family: resolved, source: 'tailwind' });
117
+ }
118
+ // Always build the var map for resolving references later
119
+ tokens.fontVarMap[`var(--font-${name})`] = resolved;
120
+ tokens.fontVarMap[name] = resolved;
121
+ }
122
+ // Extract spacing — prefer explicit config, fall back to Tailwind defaults
123
+ const spacing = mergeDeep(theme.spacing || {}, extend.spacing || {});
124
+ const spacingEntries = Object.entries(spacing);
125
+ if (spacingEntries.length > 0) {
126
+ for (const [, value] of spacingEntries) {
127
+ const num = parseFloat(String(value));
128
+ if (!isNaN(num) && num > 0) {
129
+ const px = String(value).includes('rem') ? num * 16 : num;
130
+ tokens.spacingValues.push(Math.round(px));
131
+ }
132
+ }
133
+ }
134
+ // Always include Tailwind defaults as a baseline
135
+ tokens.spacingValues.push(...TAILWIND_DEFAULT_SPACING_PX.filter(v => v > 0));
136
+ // Extract border-radius
137
+ const borderRadius = mergeDeep(theme.borderRadius || {}, extend.borderRadius || {});
138
+ for (const [name, value] of Object.entries(borderRadius)) {
139
+ if (typeof value === 'string') {
140
+ tokens.borderRadii.push(value);
141
+ }
142
+ }
143
+ // Extract shadows
144
+ const boxShadow = mergeDeep(theme.boxShadow || {}, extend.boxShadow || {});
145
+ for (const [name, value] of Object.entries(boxShadow)) {
146
+ if (typeof value === 'string') {
147
+ tokens.shadows.push({ value, name });
148
+ }
149
+ }
150
+ // Extract breakpoints
151
+ const screens = mergeDeep(theme.screens || {}, extend.screens || {});
152
+ for (const [name, value] of Object.entries(screens)) {
153
+ const bp = {
154
+ name,
155
+ value: typeof value === 'string' ? value : typeof value === 'object' && value !== null && 'min' in value ? value.min : String(value),
156
+ source: 'tailwind',
157
+ };
158
+ tokens.breakpoints.push(bp);
159
+ }
160
+ if (tokens.breakpoints.length === 0) {
161
+ tokens.breakpoints = [
162
+ { name: 'sm', value: '640px', source: 'tailwind' },
163
+ { name: 'md', value: '768px', source: 'tailwind' },
164
+ { name: 'lg', value: '1024px', source: 'tailwind' },
165
+ { name: 'xl', value: '1280px', source: 'tailwind' },
166
+ { name: '2xl', value: '1536px', source: 'tailwind' },
167
+ ];
168
+ }
169
+ return tokens;
170
+ }
171
+ /**
172
+ * Resolve a CSS variable font name to a human-readable name.
173
+ * e.g. "var(--font-exo2)" → "Exo 2", or just use the config key.
174
+ */
175
+ function resolveFontName(primaryFamily, configKey) {
176
+ // If it's already a real font name, return it
177
+ if (!primaryFamily.startsWith('var(') && !primaryFamily.startsWith('--')) {
178
+ return primaryFamily.replace(/["']/g, '').trim();
179
+ }
180
+ // Try to derive from config key: "exo2" → "Exo 2", "jetbrains" → "JetBrains Mono"
181
+ return configKeyToFontName(configKey);
182
+ }
183
+ function configKeyToFontName(key) {
184
+ // Common font name mappings from Tailwind config keys
185
+ const known = {
186
+ sans: 'Sans-serif',
187
+ serif: 'Serif',
188
+ mono: 'Monospace',
189
+ display: 'Display',
190
+ body: 'Body',
191
+ exo2: 'Exo 2',
192
+ exo: 'Exo',
193
+ inter: 'Inter',
194
+ roboto: 'Roboto',
195
+ poppins: 'Poppins',
196
+ montserrat: 'Montserrat',
197
+ lato: 'Lato',
198
+ nunito: 'Nunito',
199
+ jetbrains: 'JetBrains Mono',
200
+ 'fira-code': 'Fira Code',
201
+ 'source-code': 'Source Code Pro',
202
+ 'space-grotesk': 'Space Grotesk',
203
+ 'space-mono': 'Space Mono',
204
+ doto: 'Doto',
205
+ geist: 'Geist',
206
+ 'geist-mono': 'Geist Mono',
207
+ outfit: 'Outfit',
208
+ manrope: 'Manrope',
209
+ 'dm-sans': 'DM Sans',
210
+ 'dm-mono': 'DM Mono',
211
+ sora: 'Sora',
212
+ 'ibm-plex': 'IBM Plex Sans',
213
+ 'ibm-plex-mono': 'IBM Plex Mono',
214
+ raleway: 'Raleway',
215
+ 'open-sans': 'Open Sans',
216
+ 'source-sans': 'Source Sans Pro',
217
+ ubuntu: 'Ubuntu',
218
+ 'ubuntu-mono': 'Ubuntu Mono',
219
+ barlow: 'Barlow',
220
+ overpass: 'Overpass',
221
+ rubik: 'Rubik',
222
+ karla: 'Karla',
223
+ cabin: 'Cabin',
224
+ mulish: 'Mulish',
225
+ };
226
+ const lowerKey = key.toLowerCase().replace(/_/g, '-');
227
+ if (known[lowerKey])
228
+ return known[lowerKey];
229
+ // Fallback: capitalize and add spaces before digits
230
+ return key
231
+ .replace(/[-_]/g, ' ')
232
+ .replace(/([a-z])(\d)/g, '$1 $2')
233
+ .replace(/(\d)([a-z])/g, '$1 $2')
234
+ .split(' ')
235
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
236
+ .join(' ');
237
+ }
238
+ /**
239
+ * Check if a fontFamily config key is a generic/functional name
240
+ * (e.g., "sans", "heading", "body", "display") rather than an actual font name.
241
+ * These resolve to CSS vars whose target font we can't determine statically.
242
+ */
243
+ function isGenericConfigKey(key) {
244
+ return /^(sans|serif|mono|heading|body|display|code|ui)$/i.test(key);
245
+ }
246
+ function findTailwindConfig(dir) {
247
+ for (const file of TAILWIND_CONFIG_FILES) {
248
+ const p = path.join(dir, file);
249
+ if (fs.existsSync(p))
250
+ return p;
251
+ }
252
+ return null;
253
+ }
254
+ function flattenColors(obj, prefix, out) {
255
+ for (const [key, value] of Object.entries(obj)) {
256
+ const name = prefix ? `${prefix}-${key}` : key;
257
+ if (typeof value === 'string') {
258
+ if (isColorValue(value)) {
259
+ out.push({ value: normalizeHex(value), frequency: 1, source: 'tailwind', name });
260
+ }
261
+ }
262
+ else if (typeof value === 'object' && value !== null) {
263
+ flattenColors(value, name, out);
264
+ }
265
+ }
266
+ }
267
+ function isColorValue(v) {
268
+ return /^#([0-9a-fA-F]{3,8})$/.test(v) ||
269
+ /^rgb/i.test(v) ||
270
+ /^hsl/i.test(v);
271
+ }
272
+ function normalizeHex(v) {
273
+ const match = v.match(/^#([0-9a-fA-F]{3})$/);
274
+ if (match) {
275
+ const [r, g, b] = match[1].split('');
276
+ return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
277
+ }
278
+ return v.toLowerCase();
279
+ }
280
+ function mergeDeep(a, b) {
281
+ const result = { ...a };
282
+ for (const key of Object.keys(b)) {
283
+ if (typeof b[key] === 'object' && b[key] !== null && !Array.isArray(b[key]) &&
284
+ typeof a[key] === 'object' && a[key] !== null && !Array.isArray(a[key])) {
285
+ result[key] = mergeDeep(a[key], b[key]);
286
+ }
287
+ else {
288
+ result[key] = b[key];
289
+ }
290
+ }
291
+ return result;
292
+ }
293
+ /**
294
+ * When jiti fails, try to extract font family names from the raw config text.
295
+ * Only looks within fontFamily blocks to avoid false positives from content arrays etc.
296
+ */
297
+ function extractFontsFromConfigText(configPath, tokens) {
298
+ try {
299
+ const content = fs.readFileSync(configPath, 'utf-8');
300
+ // Find the fontFamily block specifically
301
+ const fontFamilyBlock = content.match(/fontFamily\s*:\s*\{([^}]+)\}/s);
302
+ if (!fontFamilyBlock)
303
+ return;
304
+ const block = fontFamilyBlock[1];
305
+ // Match entries like: sans: [var(--font-inter), ...] or mono: ["JetBrains Mono", ...]
306
+ const entries = block.matchAll(/(\w[\w-]*)\s*:\s*\[([^\]]+)\]/g);
307
+ for (const entry of entries) {
308
+ const key = entry[1];
309
+ const valueList = entry[2];
310
+ // Check for var(--font-xxx) reference
311
+ const varMatch = valueList.match(/var\(--font-(\w[\w-]*)\)/);
312
+ if (varMatch) {
313
+ const varName = varMatch[1];
314
+ const resolved = configKeyToFontName(varName);
315
+ // Skip generic config key names like "heading", "body", "sans", "display"
316
+ // These are Tailwind key names, not font names
317
+ if (!isGenericConfigKey(key)) {
318
+ tokens.fonts.push({ family: resolved, source: 'tailwind' });
319
+ }
320
+ tokens.fontVarMap[`var(--font-${varName})`] = resolved;
321
+ tokens.fontVarMap[key] = resolved;
322
+ continue;
323
+ }
324
+ // Check for direct font name
325
+ const nameMatch = valueList.match(/["']([^"']+)["']/);
326
+ if (nameMatch) {
327
+ const fontName = nameMatch[1];
328
+ // Filter out generic CSS families
329
+ if (!/^(sans-serif|serif|monospace|system-ui|ui-|inherit)/.test(fontName)) {
330
+ tokens.fonts.push({ family: fontName, source: 'tailwind' });
331
+ tokens.fontVarMap[key] = fontName;
332
+ }
333
+ }
334
+ }
335
+ }
336
+ catch {
337
+ // Ignore read errors
338
+ }
339
+ }
340
+ function parseConfigFallback(configPath) {
341
+ const content = fs.readFileSync(configPath, 'utf-8');
342
+ const match = content.match(/module\.exports\s*=\s*(\{[\s\S]*\})/);
343
+ if (match) {
344
+ try {
345
+ return Function(`"use strict"; return (${match[1]})`)();
346
+ }
347
+ catch {
348
+ return null;
349
+ }
350
+ }
351
+ return null;
352
+ }
353
+ //# sourceMappingURL=tailwind.js.map
@@ -0,0 +1,3 @@
1
+ import { RawTokens } from '../../types';
2
+ export declare function extractTokensFile(projectDir: string): RawTokens;
3
+ //# sourceMappingURL=tokens-file.d.ts.map
@@ -0,0 +1,229 @@
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.extractTokensFile = extractTokensFile;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const TOKEN_FILE_NAMES = [
40
+ 'tokens.json',
41
+ 'design-tokens.json',
42
+ 'theme.json',
43
+ 'theme.ts',
44
+ 'theme.js',
45
+ 'tokens.ts',
46
+ 'tokens.js',
47
+ 'design-tokens.ts',
48
+ 'design-tokens.js',
49
+ ];
50
+ const TOKEN_DIRS = ['', 'src', 'src/styles', 'src/theme', 'styles', 'theme', 'config'];
51
+ function extractTokensFile(projectDir) {
52
+ const tokens = {
53
+ colors: [],
54
+ fonts: [],
55
+ spacingValues: [],
56
+ shadows: [],
57
+ cssVariables: [],
58
+ breakpoints: [],
59
+ borderRadii: [],
60
+ gradients: [],
61
+ fontVarMap: {},
62
+ animations: [],
63
+ darkModeVars: [],
64
+ zIndexValues: [],
65
+ containerMaxWidth: null,
66
+ fontSources: [],
67
+ pageSections: [],
68
+ transitionDurations: [],
69
+ transitionEasings: [],
70
+ };
71
+ for (const dir of TOKEN_DIRS) {
72
+ for (const fileName of TOKEN_FILE_NAMES) {
73
+ const filePath = path.join(projectDir, dir, fileName);
74
+ if (fs.existsSync(filePath)) {
75
+ try {
76
+ extractFromFile(filePath, tokens);
77
+ }
78
+ catch {
79
+ // Skip unreadable files
80
+ }
81
+ }
82
+ }
83
+ }
84
+ return tokens;
85
+ }
86
+ function extractFromFile(filePath, tokens) {
87
+ const ext = path.extname(filePath);
88
+ let data;
89
+ if (ext === '.json') {
90
+ data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
91
+ }
92
+ else {
93
+ // Try jiti for JS/TS
94
+ try {
95
+ const jiti = require('jiti')(__filename, { interopDefault: true });
96
+ data = jiti(filePath);
97
+ if (data.default)
98
+ data = data.default;
99
+ }
100
+ catch {
101
+ // Fallback: try regex extraction
102
+ const content = fs.readFileSync(filePath, 'utf-8');
103
+ extractWithRegex(content, tokens);
104
+ return;
105
+ }
106
+ }
107
+ if (!data || typeof data !== 'object')
108
+ return;
109
+ // Recursively extract tokens from the object
110
+ walkTokenObject(data, '', tokens);
111
+ }
112
+ function walkTokenObject(obj, prefix, tokens) {
113
+ for (const [key, value] of Object.entries(obj)) {
114
+ const fullKey = prefix ? `${prefix}.${key}` : key;
115
+ if (typeof value === 'string') {
116
+ classifyValue(fullKey, value, tokens);
117
+ }
118
+ else if (typeof value === 'number') {
119
+ // Could be spacing
120
+ if (value > 0 && value <= 200) {
121
+ tokens.spacingValues.push(value);
122
+ }
123
+ }
124
+ else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
125
+ // Design Tokens Community Group format: { value: "...", type: "..." }
126
+ if ('value' in value && typeof value.value === 'string') {
127
+ const tokenValue = value.value;
128
+ const tokenType = value.type || '';
129
+ classifyTokenValue(fullKey, tokenValue, tokenType, tokens);
130
+ }
131
+ else {
132
+ walkTokenObject(value, fullKey, tokens);
133
+ }
134
+ }
135
+ else if (Array.isArray(value)) {
136
+ // Font family arrays
137
+ if (key.toLowerCase().includes('font') && value.every(v => typeof v === 'string')) {
138
+ tokens.fonts.push({ family: value[0], source: 'tokens-file' });
139
+ }
140
+ }
141
+ }
142
+ }
143
+ function classifyValue(key, value, tokens) {
144
+ const keyLower = key.toLowerCase();
145
+ // Color
146
+ if (isColorValue(value)) {
147
+ const name = key.split('.').pop() || key;
148
+ tokens.colors.push({
149
+ value: normalizeHex(value),
150
+ frequency: 1,
151
+ source: 'tokens-file',
152
+ name,
153
+ });
154
+ return;
155
+ }
156
+ // Font
157
+ if (keyLower.includes('font') || keyLower.includes('family') || keyLower.includes('typeface')) {
158
+ tokens.fonts.push({ family: value, source: 'tokens-file' });
159
+ return;
160
+ }
161
+ // Shadow
162
+ if (keyLower.includes('shadow') || keyLower.includes('elevation')) {
163
+ tokens.shadows.push({ value, name: key.split('.').pop() });
164
+ return;
165
+ }
166
+ // Spacing
167
+ const pxMatch = value.match(/^(\d+(?:\.\d+)?)\s*(px|rem|em)?$/);
168
+ if (pxMatch && (keyLower.includes('spacing') || keyLower.includes('space') || keyLower.includes('gap') || keyLower.includes('size'))) {
169
+ let px = parseFloat(pxMatch[1]);
170
+ if (pxMatch[2] === 'rem' || pxMatch[2] === 'em')
171
+ px *= 16;
172
+ if (px > 0 && px <= 200) {
173
+ tokens.spacingValues.push(Math.round(px));
174
+ }
175
+ }
176
+ }
177
+ function classifyTokenValue(key, value, type, tokens) {
178
+ const typeLower = type.toLowerCase();
179
+ if (typeLower === 'color' || isColorValue(value)) {
180
+ const name = key.split('.').pop() || key;
181
+ tokens.colors.push({
182
+ value: normalizeHex(value),
183
+ frequency: 1,
184
+ source: 'tokens-file',
185
+ name,
186
+ });
187
+ }
188
+ else if (typeLower === 'fontfamily' || typeLower === 'fontfamilies') {
189
+ tokens.fonts.push({ family: value, source: 'tokens-file' });
190
+ }
191
+ else if (typeLower === 'fontsize' || typeLower === 'fontsizes') {
192
+ tokens.fonts.push({ family: '', size: value, source: 'tokens-file' });
193
+ }
194
+ else if (typeLower === 'spacing') {
195
+ const px = parseFloat(value);
196
+ if (!isNaN(px) && px > 0)
197
+ tokens.spacingValues.push(px);
198
+ }
199
+ else if (typeLower === 'boxshadow' || typeLower === 'shadow') {
200
+ tokens.shadows.push({ value, name: key.split('.').pop() });
201
+ }
202
+ else {
203
+ // Generic classify
204
+ classifyValue(key, value, tokens);
205
+ }
206
+ }
207
+ function extractWithRegex(content, tokens) {
208
+ // Extract hex colors
209
+ const hexMatches = content.matchAll(/#([0-9a-fA-F]{3,8})\b/g);
210
+ for (const m of hexMatches) {
211
+ tokens.colors.push({ value: normalizeHex(m[0]), frequency: 1, source: 'tokens-file' });
212
+ }
213
+ // Extract font strings
214
+ const fontMatches = content.matchAll(/['"]?(Inter|Roboto|Helvetica|Arial|Poppins|Montserrat|Open Sans|Lato|Nunito|Source Sans|JetBrains Mono|Fira Code|SF Mono|Menlo|Consolas)['"]?/gi);
215
+ for (const m of fontMatches) {
216
+ tokens.fonts.push({ family: m[1], source: 'tokens-file' });
217
+ }
218
+ }
219
+ function isColorValue(v) {
220
+ return /^#([0-9a-fA-F]{3,8})$/.test(v) || /^rgb/i.test(v) || /^hsl/i.test(v);
221
+ }
222
+ function normalizeHex(v) {
223
+ if (/^#([0-9a-fA-F]{3})$/.test(v)) {
224
+ const [r, g, b] = v.slice(1).split('');
225
+ return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
226
+ }
227
+ return v.toLowerCase().slice(0, 7);
228
+ }
229
+ //# sourceMappingURL=tokens-file.js.map
@@ -0,0 +1,21 @@
1
+ import { FullAnimationResult } from '../../types-ultra';
2
+ /**
3
+ * Ultra mode — Full Animation Extractor
4
+ *
5
+ * Extracts EVERYTHING animation-related from a live website:
6
+ *
7
+ * 1. CSS @keyframes — complete with property values, selectors that use them,
8
+ * duration/easing/delay/iteration metadata
9
+ * 2. Scroll journey screenshots — 7 frames at 0/17/33/50/67/83/100% scroll depth,
10
+ * showing the cinematic state at every point of the page
11
+ * 3. Animation library detection — GSAP, ScrollTrigger, Lottie, Framer Motion,
12
+ * AOS, Anime.js, Three.js, Canvas, WebGL, etc.
13
+ * 4. Video backgrounds — src, poster, autoplay/loop/muted, first-frame capture
14
+ * 5. Scroll-triggered patterns — data-aos, data-scroll, IntersectionObserver-driven,
15
+ * GSAP ScrollTrigger elements
16
+ * 6. CSS animation variables — --duration-*, --ease-*, --delay-*, etc.
17
+ *
18
+ * Requires Playwright (optional peer dependency).
19
+ */
20
+ export declare function captureAnimations(url: string, skillDir: string): Promise<FullAnimationResult>;
21
+ //# sourceMappingURL=animations.d.ts.map