skillui 1.1.2 → 1.1.3

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 (61) hide show
  1. package/dist/cli.js +105073 -194
  2. package/package.json +15 -6
  3. package/dist/cli.d.ts +0 -3
  4. package/dist/extractors/components.d.ts +0 -11
  5. package/dist/extractors/components.js +0 -455
  6. package/dist/extractors/framework.d.ts +0 -4
  7. package/dist/extractors/framework.js +0 -126
  8. package/dist/extractors/tokens/computed.d.ts +0 -7
  9. package/dist/extractors/tokens/computed.js +0 -249
  10. package/dist/extractors/tokens/css.d.ts +0 -3
  11. package/dist/extractors/tokens/css.js +0 -510
  12. package/dist/extractors/tokens/http-css.d.ts +0 -14
  13. package/dist/extractors/tokens/http-css.js +0 -1689
  14. package/dist/extractors/tokens/tailwind.d.ts +0 -3
  15. package/dist/extractors/tokens/tailwind.js +0 -353
  16. package/dist/extractors/tokens/tokens-file.d.ts +0 -3
  17. package/dist/extractors/tokens/tokens-file.js +0 -229
  18. package/dist/extractors/ultra/animations.d.ts +0 -21
  19. package/dist/extractors/ultra/animations.js +0 -527
  20. package/dist/extractors/ultra/components-dom.d.ts +0 -13
  21. package/dist/extractors/ultra/components-dom.js +0 -149
  22. package/dist/extractors/ultra/interactions.d.ts +0 -14
  23. package/dist/extractors/ultra/interactions.js +0 -222
  24. package/dist/extractors/ultra/layout.d.ts +0 -14
  25. package/dist/extractors/ultra/layout.js +0 -123
  26. package/dist/extractors/ultra/pages.d.ts +0 -16
  27. package/dist/extractors/ultra/pages.js +0 -228
  28. package/dist/font-resolver.d.ts +0 -10
  29. package/dist/font-resolver.js +0 -280
  30. package/dist/modes/dir.d.ts +0 -6
  31. package/dist/modes/dir.js +0 -213
  32. package/dist/modes/repo.d.ts +0 -6
  33. package/dist/modes/repo.js +0 -76
  34. package/dist/modes/ultra.d.ts +0 -22
  35. package/dist/modes/ultra.js +0 -281
  36. package/dist/modes/url.d.ts +0 -14
  37. package/dist/modes/url.js +0 -161
  38. package/dist/normalizer.d.ts +0 -11
  39. package/dist/normalizer.js +0 -867
  40. package/dist/playwright-loader.d.ts +0 -10
  41. package/dist/playwright-loader.js +0 -71
  42. package/dist/screenshot.d.ts +0 -9
  43. package/dist/screenshot.js +0 -94
  44. package/dist/types-ultra.d.ts +0 -157
  45. package/dist/types-ultra.js +0 -4
  46. package/dist/types.d.ts +0 -182
  47. package/dist/types.js +0 -4
  48. package/dist/writers/animations-md.d.ts +0 -17
  49. package/dist/writers/animations-md.js +0 -313
  50. package/dist/writers/components-md.d.ts +0 -8
  51. package/dist/writers/components-md.js +0 -151
  52. package/dist/writers/design-md.d.ts +0 -7
  53. package/dist/writers/design-md.js +0 -704
  54. package/dist/writers/interactions-md.d.ts +0 -8
  55. package/dist/writers/interactions-md.js +0 -146
  56. package/dist/writers/layout-md.d.ts +0 -8
  57. package/dist/writers/layout-md.js +0 -120
  58. package/dist/writers/skill.d.ts +0 -12
  59. package/dist/writers/skill.js +0 -1006
  60. package/dist/writers/tokens-json.d.ts +0 -11
  61. package/dist/writers/tokens-json.js +0 -164
@@ -1,527 +0,0 @@
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.captureAnimations = captureAnimations;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const playwright_loader_1 = require("../../playwright-loader");
40
- /**
41
- * Ultra mode — Full Animation Extractor
42
- *
43
- * Extracts EVERYTHING animation-related from a live website:
44
- *
45
- * 1. CSS @keyframes — complete with property values, selectors that use them,
46
- * duration/easing/delay/iteration metadata
47
- * 2. Scroll journey screenshots — 7 frames at 0/17/33/50/67/83/100% scroll depth,
48
- * showing the cinematic state at every point of the page
49
- * 3. Animation library detection — GSAP, ScrollTrigger, Lottie, Framer Motion,
50
- * AOS, Anime.js, Three.js, Canvas, WebGL, etc.
51
- * 4. Video backgrounds — src, poster, autoplay/loop/muted, first-frame capture
52
- * 5. Scroll-triggered patterns — data-aos, data-scroll, IntersectionObserver-driven,
53
- * GSAP ScrollTrigger elements
54
- * 6. CSS animation variables — --duration-*, --ease-*, --delay-*, etc.
55
- *
56
- * Requires Playwright (optional peer dependency).
57
- */
58
- async function captureAnimations(url, skillDir) {
59
- const empty = {
60
- keyframes: [],
61
- scrollFrames: [],
62
- libraries: [],
63
- videos: [],
64
- scrollPatterns: [],
65
- animationVars: [],
66
- globalTransitions: [],
67
- canvasCount: 0,
68
- webglDetected: false,
69
- lottieCount: 0,
70
- };
71
- const playwright = (0, playwright_loader_1.loadPlaywright)();
72
- if (!playwright)
73
- return empty;
74
- const scrollDir = path.join(skillDir, 'screens', 'scroll');
75
- fs.mkdirSync(scrollDir, { recursive: true });
76
- const browser = await playwright.chromium.launch({ headless: true });
77
- try {
78
- const context = await browser.newContext({
79
- viewport: { width: 1440, height: 900 },
80
- userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
81
- });
82
- const page = await context.newPage();
83
- // Disable CSS animations for initial load (avoids capturing mid-animation state)
84
- // We'll re-enable them before scroll capture
85
- await page.addInitScript(() => {
86
- // Store original to restore later
87
- window.__claudeui_originalRAF = window.requestAnimationFrame;
88
- });
89
- await page.goto(url, { waitUntil: 'networkidle', timeout: 30000 });
90
- await page.waitForTimeout(2000);
91
- // ── Phase 1: Extract CSS keyframes from document.styleSheets ──────────
92
- const keyframesRaw = await page.evaluate(() => {
93
- const result = [];
94
- for (const sheet of Array.from(document.styleSheets)) {
95
- try {
96
- const rules = Array.from(sheet.cssRules || []);
97
- for (const rule of rules) {
98
- if (rule.type === CSSRule.KEYFRAMES_RULE) {
99
- const kfRule = rule;
100
- const stops = [];
101
- for (const kf of Array.from(kfRule.cssRules)) {
102
- const kfStop = kf;
103
- const props = {};
104
- for (let i = 0; i < kfStop.style.length; i++) {
105
- const p = kfStop.style[i];
106
- props[p] = kfStop.style.getPropertyValue(p);
107
- }
108
- stops.push({ stop: kfStop.keyText, properties: props });
109
- }
110
- result.push({ name: kfRule.name, stops });
111
- }
112
- }
113
- }
114
- catch {
115
- // Cross-origin stylesheet — skip
116
- }
117
- }
118
- return result;
119
- });
120
- // ── Phase 2: Map animation-name → selector + properties ───────────────
121
- const animUsageRaw = await page.evaluate(() => {
122
- const usage = {};
123
- for (const sheet of Array.from(document.styleSheets)) {
124
- try {
125
- for (const rule of Array.from(sheet.cssRules || [])) {
126
- if (rule.type === CSSRule.STYLE_RULE) {
127
- const styleRule = rule;
128
- const name = styleRule.style.animationName;
129
- if (!name || name === 'none' || name === '')
130
- continue;
131
- // Multiple animation-names separated by commas
132
- const names = name.split(',').map((n) => n.trim());
133
- for (const n of names) {
134
- if (!n || n === 'none')
135
- continue;
136
- if (!usage[n]) {
137
- usage[n] = { selectors: [] };
138
- }
139
- usage[n].selectors.push(styleRule.selectorText?.slice(0, 80) || '');
140
- if (!usage[n].duration)
141
- usage[n].duration = styleRule.style.animationDuration || undefined;
142
- if (!usage[n].easing)
143
- usage[n].easing = styleRule.style.animationTimingFunction || undefined;
144
- if (!usage[n].delay)
145
- usage[n].delay = styleRule.style.animationDelay || undefined;
146
- if (!usage[n].iteration)
147
- usage[n].iteration = styleRule.style.animationIterationCount || undefined;
148
- if (!usage[n].fillMode)
149
- usage[n].fillMode = styleRule.style.animationFillMode || undefined;
150
- if (!usage[n].direction)
151
- usage[n].direction = styleRule.style.animationDirection || undefined;
152
- }
153
- }
154
- }
155
- }
156
- catch { /* cross-origin */ }
157
- }
158
- return usage;
159
- });
160
- // Merge keyframes + usage
161
- const keyframes = keyframesRaw.map((kf) => {
162
- const usage = animUsageRaw[kf.name] || {};
163
- return {
164
- name: kf.name,
165
- stops: kf.stops,
166
- usedBy: [...new Set(usage.selectors || [])].filter(Boolean).slice(0, 8),
167
- animDuration: usage.duration,
168
- animEasing: usage.easing,
169
- animDelay: usage.delay,
170
- animIteration: usage.iteration,
171
- animFillMode: usage.fillMode,
172
- animDirection: usage.direction,
173
- };
174
- });
175
- // ── Phase 3: CSS Animation Variables ──────────────────────────────────
176
- const animVarsRaw = await page.evaluate(() => {
177
- const vars = [];
178
- for (const sheet of Array.from(document.styleSheets)) {
179
- try {
180
- for (const rule of Array.from(sheet.cssRules || [])) {
181
- if (rule.type === CSSRule.STYLE_RULE) {
182
- const sr = rule;
183
- if (sr.selectorText !== ':root' && sr.selectorText !== 'html' && sr.selectorText !== '*')
184
- continue;
185
- for (let i = 0; i < sr.style.length; i++) {
186
- const prop = sr.style[i];
187
- if (prop.startsWith('--')) {
188
- const val = sr.style.getPropertyValue(prop).trim();
189
- // Only animation-related variables
190
- if (/duration|ease|delay|timing|animation|transition|spring|bounce|motion|speed|curve/i.test(prop)) {
191
- vars.push({ name: prop, value: val });
192
- }
193
- }
194
- }
195
- }
196
- }
197
- }
198
- catch { /* cross-origin */ }
199
- }
200
- // Also read computed styles on :root for CSS vars
201
- const rootStyle = getComputedStyle(document.documentElement);
202
- for (const prop of Array.from(rootStyle)) {
203
- if (prop.startsWith('--') && /duration|ease|delay|timing|animation|transition|spring|bounce|motion|speed|curve/i.test(prop)) {
204
- const val = rootStyle.getPropertyValue(prop).trim();
205
- if (val && !vars.find(v => v.name === prop)) {
206
- vars.push({ name: prop, value: val });
207
- }
208
- }
209
- }
210
- return vars;
211
- });
212
- const animationVars = animVarsRaw.map(v => ({
213
- name: v.name,
214
- value: v.value,
215
- category: categorizeAnimVar(v.name),
216
- }));
217
- // ── Phase 4: Detect Animation Libraries ───────────────────────────────
218
- const librariesRaw = await page.evaluate(() => {
219
- const found = [];
220
- const w = window;
221
- // GSAP
222
- if (w.gsap)
223
- found.push({ name: 'GSAP', version: w.gsap.version, type: 'animation' });
224
- if (w.ScrollTrigger)
225
- found.push({ name: 'ScrollTrigger', type: 'scroll' });
226
- if (w.ScrollSmoother)
227
- found.push({ name: 'ScrollSmoother', type: 'scroll' });
228
- // Lottie
229
- if (w.lottie || w.Lottie)
230
- found.push({ name: 'Lottie', version: (w.lottie || w.Lottie)?.version, type: 'lottie' });
231
- if (w.bodymovin)
232
- found.push({ name: 'Bodymovin (Lottie)', type: 'lottie' });
233
- // Three.js / WebGL
234
- if (w.THREE)
235
- found.push({ name: 'Three.js', version: w.THREE.REVISION, type: '3d' });
236
- if (w.PIXI)
237
- found.push({ name: 'PixiJS', version: w.PIXI.VERSION, type: '3d' });
238
- if (w.Babylon)
239
- found.push({ name: 'BabylonJS', type: '3d' });
240
- // Framer Motion
241
- if (w.Motion || w.motion)
242
- found.push({ name: 'Motion One / Framer Motion', type: 'animation' });
243
- // AOS
244
- if (w.AOS)
245
- found.push({ name: 'AOS (Animate On Scroll)', version: w.AOS.version, type: 'scroll' });
246
- // Anime.js
247
- if (w.anime)
248
- found.push({ name: 'Anime.js', version: w.anime.version, type: 'animation' });
249
- // ScrollMagic
250
- if (w.ScrollMagic)
251
- found.push({ name: 'ScrollMagic', type: 'scroll' });
252
- // Locomotive Scroll
253
- if (w.LocomotiveScroll || w.locomotiveScroll)
254
- found.push({ name: 'Locomotive Scroll', type: 'scroll' });
255
- // Velocity.js
256
- if (w.Velocity)
257
- found.push({ name: 'Velocity.js', type: 'animation' });
258
- // Popmotion
259
- if (w.popmotion)
260
- found.push({ name: 'Popmotion', type: 'physics' });
261
- // Matter.js
262
- if (w.Matter)
263
- found.push({ name: 'Matter.js (Physics)', type: 'physics' });
264
- // Web Animations API usage (check if any element has getAnimations)
265
- const hasWAAPI = typeof Element.prototype.getAnimations === 'function';
266
- const liveAnims = document.querySelectorAll('*');
267
- let wapiCount = 0;
268
- liveAnims.forEach(el => {
269
- try {
270
- const anims = el.getAnimations();
271
- if (anims.length > 0)
272
- wapiCount += anims.length;
273
- }
274
- catch { }
275
- });
276
- if (wapiCount > 0 && hasWAAPI) {
277
- found.push({ name: `Web Animations API (${wapiCount} active)`, type: 'animation' });
278
- }
279
- // Check script src tags for CDN libraries
280
- const scripts = Array.from(document.querySelectorAll('script[src]'));
281
- for (const script of scripts) {
282
- const src = script.src || '';
283
- if (/gsap/i.test(src) && !found.find(f => f.name === 'GSAP')) {
284
- found.push({ name: 'GSAP', type: 'animation', cdn: src.split('/').slice(0, 5).join('/') });
285
- }
286
- if (/lottie|bodymovin/i.test(src) && !found.find(f => f.name.includes('Lottie'))) {
287
- found.push({ name: 'Lottie', type: 'lottie', cdn: src.split('/').slice(0, 5).join('/') });
288
- }
289
- if (/three\.js|three\.min/i.test(src) && !found.find(f => f.name === 'Three.js')) {
290
- found.push({ name: 'Three.js', type: '3d', cdn: src });
291
- }
292
- if (/framer-motion|motion\.js/i.test(src)) {
293
- found.push({ name: 'Framer Motion', type: 'animation', cdn: src });
294
- }
295
- if (/aos\.js|aos\.min/i.test(src) && !found.find(f => f.name.includes('AOS'))) {
296
- found.push({ name: 'AOS', type: 'scroll', cdn: src });
297
- }
298
- }
299
- return found;
300
- });
301
- const libraries = librariesRaw;
302
- // ── Phase 5: Video detection + first-frame capture ────────────────────
303
- const videosRaw = await page.evaluate(() => {
304
- return Array.from(document.querySelectorAll('video')).map((v, i) => ({
305
- index: i + 1,
306
- src: v.src || v.querySelector('source')?.getAttribute('src') || '',
307
- poster: v.poster || '',
308
- autoplay: v.autoplay,
309
- loop: v.loop,
310
- muted: v.muted,
311
- width: Math.round(v.offsetWidth),
312
- height: Math.round(v.offsetHeight),
313
- role: v.offsetWidth > 800 ? 'background' : 'content',
314
- }));
315
- });
316
- const videos = [];
317
- for (const v of videosRaw.slice(0, 6)) {
318
- const videoEntry = { ...v, role: v.role };
319
- // Try to capture first frame
320
- try {
321
- const videoEl = page.locator('video').nth(v.index - 1);
322
- const box = await videoEl.boundingBox();
323
- if (box && box.width > 50 && box.height > 50) {
324
- const framePath = path.join(scrollDir, `video-${v.index}-frame.png`);
325
- await page.evaluate((idx) => {
326
- const vEl = document.querySelectorAll('video')[idx];
327
- if (vEl) {
328
- vEl.pause();
329
- vEl.currentTime = 0;
330
- }
331
- }, v.index - 1);
332
- await page.waitForTimeout(300);
333
- await page.screenshot({
334
- path: framePath,
335
- clip: { x: box.x, y: box.y, width: Math.min(box.width, 1440), height: Math.min(box.height, 900) },
336
- });
337
- videoEntry.firstFramePath = `screens/scroll/video-${v.index}-frame.png`;
338
- }
339
- }
340
- catch { /* video frame capture failed */ }
341
- videos.push(videoEntry);
342
- }
343
- // ── Phase 6: Detect scroll-triggered elements ─────────────────────────
344
- const scrollPatternsRaw = await page.evaluate(() => {
345
- const patterns = [];
346
- // AOS
347
- const aosEls = document.querySelectorAll('[data-aos]');
348
- const aosGroups = {};
349
- aosEls.forEach(el => {
350
- const type = el.getAttribute('data-aos') || 'unknown';
351
- aosGroups[type] = (aosGroups[type] || 0) + 1;
352
- });
353
- for (const [type, count] of Object.entries(aosGroups)) {
354
- const sample = document.querySelector(`[data-aos="${type}"]`);
355
- patterns.push({
356
- selector: `[data-aos="${type}"]`,
357
- library: 'AOS',
358
- attribute: `data-aos="${type}"`,
359
- animationType: type,
360
- duration: sample?.getAttribute('data-aos-duration') || undefined,
361
- delay: sample?.getAttribute('data-aos-delay') || undefined,
362
- easing: sample?.getAttribute('data-aos-easing') || undefined,
363
- count,
364
- });
365
- }
366
- // Locomotive Scroll
367
- const locoEls = document.querySelectorAll('[data-scroll]');
368
- if (locoEls.length > 0) {
369
- patterns.push({
370
- selector: '[data-scroll]',
371
- library: 'Locomotive Scroll',
372
- attribute: 'data-scroll',
373
- animationType: 'scroll-reveal',
374
- count: locoEls.length,
375
- });
376
- }
377
- // GSAP data attributes
378
- const gsapEls = document.querySelectorAll('[data-gsap], [data-animation], [data-parallax]');
379
- if (gsapEls.length > 0) {
380
- patterns.push({
381
- selector: '[data-gsap], [data-animation]',
382
- library: 'GSAP',
383
- attribute: 'data-gsap',
384
- animationType: 'scroll-trigger',
385
- count: gsapEls.length,
386
- });
387
- }
388
- // Intersection Observer — detect elements with opacity:0 / transform waiting to animate
389
- // (common pattern: element starts invisible, IO makes it visible)
390
- let ioCount = 0;
391
- document.querySelectorAll('[class]').forEach(el => {
392
- const s = window.getComputedStyle(el);
393
- const opacity = parseFloat(s.opacity);
394
- const transform = s.transform;
395
- const animName = s.animationName;
396
- const animPlayState = s.animationPlayState;
397
- if ((opacity < 0.1 || (transform !== 'none' && transform !== 'matrix(1, 0, 0, 1, 0, 0)')) &&
398
- animPlayState === 'paused') {
399
- ioCount++;
400
- }
401
- });
402
- if (ioCount > 0) {
403
- patterns.push({
404
- selector: '.animation-paused',
405
- library: 'CSS + IntersectionObserver',
406
- attribute: 'animation-play-state: paused',
407
- animationType: 'scroll-reveal (paused → running)',
408
- count: ioCount,
409
- });
410
- }
411
- // Sticky + parallax elements
412
- const stickyEls = document.querySelectorAll('[style*="sticky"], [class*="sticky"], [class*="parallax"]');
413
- if (stickyEls.length > 0) {
414
- patterns.push({
415
- selector: '.sticky, .parallax',
416
- library: 'CSS',
417
- attribute: 'position: sticky',
418
- animationType: 'parallax / sticky scroll',
419
- count: stickyEls.length,
420
- });
421
- }
422
- // Lottie players
423
- const lottieEls = document.querySelectorAll('lottie-player, dotlottie-player, [data-lottie]');
424
- if (lottieEls.length > 0) {
425
- patterns.push({
426
- selector: 'lottie-player',
427
- library: 'Lottie',
428
- attribute: 'lottie-player',
429
- animationType: 'vector animation',
430
- count: lottieEls.length,
431
- });
432
- }
433
- return patterns;
434
- });
435
- const scrollPatterns = scrollPatternsRaw;
436
- // ── Phase 7: Detect canvas + WebGL ─────────────────────────────────────
437
- const mediaInfo = await page.evaluate(() => {
438
- const canvases = document.querySelectorAll('canvas');
439
- let webgl = false;
440
- canvases.forEach(c => {
441
- try {
442
- if (c.getContext('webgl') || c.getContext('webgl2') || c.getContext('experimental-webgl')) {
443
- webgl = true;
444
- }
445
- }
446
- catch { }
447
- });
448
- const lotties = document.querySelectorAll('lottie-player, dotlottie-player, [data-lottie], svg[class*="lottie"]');
449
- return { canvasCount: canvases.length, webgl, lottieCount: lotties.length };
450
- });
451
- // ── Phase 8: Global transition declarations ────────────────────────────
452
- const transitionsRaw = await page.evaluate(() => {
453
- const found = [];
454
- for (const sheet of Array.from(document.styleSheets)) {
455
- try {
456
- for (const rule of Array.from(sheet.cssRules || [])) {
457
- if (rule.type === CSSRule.STYLE_RULE) {
458
- const sr = rule;
459
- const t = sr.style.transition;
460
- if (t && t !== 'none' && t !== 'all 0s ease 0s' && !t.startsWith('all 0s')) {
461
- found.push(t);
462
- }
463
- }
464
- }
465
- }
466
- catch { }
467
- }
468
- // Deduplicate and return top 20
469
- return [...new Set(found)].slice(0, 20);
470
- });
471
- // ── Phase 9: Scroll Journey Screenshots ───────────────────────────────
472
- const scrollFrames = [];
473
- const scrollPercents = [0, 17, 33, 50, 67, 83, 100];
474
- const pageHeight = await page.evaluate(() => document.documentElement.scrollHeight);
475
- for (const pct of scrollPercents) {
476
- const targetY = Math.round((pct / 100) * Math.max(0, pageHeight - 900));
477
- try {
478
- // Instant scroll to position
479
- await page.evaluate((y) => window.scrollTo({ top: y, behavior: 'instant' }), targetY);
480
- // Wait for scroll-triggered animations to fire
481
- await page.waitForTimeout(700);
482
- const fileName = `scroll-${String(pct).padStart(3, '0')}.png`;
483
- const filePath = path.join(scrollDir, fileName);
484
- await page.screenshot({
485
- path: filePath,
486
- clip: { x: 0, y: 0, width: 1440, height: 900 },
487
- });
488
- const actualY = await page.evaluate(() => window.scrollY);
489
- scrollFrames.push({
490
- scrollPercent: pct,
491
- scrollY: actualY,
492
- pageHeight,
493
- filePath: `screens/scroll/${fileName}`,
494
- });
495
- }
496
- catch { /* frame failed */ }
497
- }
498
- await page.close();
499
- return {
500
- keyframes,
501
- scrollFrames,
502
- libraries,
503
- videos,
504
- scrollPatterns,
505
- animationVars: animationVars.slice(0, 40),
506
- globalTransitions: transitionsRaw,
507
- canvasCount: mediaInfo.canvasCount,
508
- webglDetected: mediaInfo.webgl,
509
- lottieCount: mediaInfo.lottieCount,
510
- };
511
- }
512
- finally {
513
- await browser.close().catch(() => { });
514
- }
515
- }
516
- function categorizeAnimVar(name) {
517
- if (/duration|speed/i.test(name))
518
- return 'duration';
519
- if (/ease|timing|curve|bezier/i.test(name))
520
- return 'easing';
521
- if (/delay/i.test(name))
522
- return 'delay';
523
- if (/animation|keyframe/i.test(name))
524
- return 'animation';
525
- return 'other';
526
- }
527
- //# sourceMappingURL=animations.js.map
@@ -1,13 +0,0 @@
1
- import { DOMComponent } from '../../types-ultra';
2
- /**
3
- * Ultra mode — DOM Component Detector
4
- *
5
- * Detects repeated UI components by analyzing DOM structure:
6
- * - Elements with the same class pattern appearing 3+ times → component
7
- * - Groups by normalized class fingerprint
8
- * - Extracts representative HTML snippet
9
- *
10
- * Requires Playwright (optional peer dependency).
11
- */
12
- export declare function detectDOMComponents(url: string): Promise<DOMComponent[]>;
13
- //# sourceMappingURL=components-dom.d.ts.map