design-brain-memory 0.9.2 → 0.9.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 (124) hide show
  1. package/README.md +273 -0
  2. package/dist/agentBrowser.js +1 -1
  3. package/dist/agentBrowser.js.map +1 -1
  4. package/dist/aggregate.d.ts +9 -0
  5. package/dist/aggregate.js +53 -0
  6. package/dist/aggregate.js.map +1 -0
  7. package/dist/batch.d.ts +16 -0
  8. package/dist/batch.js +44 -0
  9. package/dist/batch.js.map +1 -0
  10. package/dist/cli.js +250 -216
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands.d.ts +60 -1
  13. package/dist/commands.js +323 -10
  14. package/dist/commands.js.map +1 -1
  15. package/dist/compare.d.ts +33 -0
  16. package/dist/compare.js +83 -0
  17. package/dist/compare.js.map +1 -0
  18. package/dist/componentGraph.d.ts +22 -0
  19. package/dist/componentGraph.js +106 -0
  20. package/dist/componentGraph.js.map +1 -0
  21. package/dist/contextLayer.d.ts +12 -0
  22. package/dist/contextLayer.js +263 -0
  23. package/dist/contextLayer.js.map +1 -0
  24. package/dist/cssInJs.d.ts +9 -0
  25. package/dist/cssInJs.js +124 -0
  26. package/dist/cssInJs.js.map +1 -0
  27. package/dist/extractFromUrl.d.ts +8 -0
  28. package/dist/extractFromUrl.js +104 -355
  29. package/dist/extractFromUrl.js.map +1 -1
  30. package/dist/graphView.d.ts +21 -0
  31. package/dist/graphView.js +492 -0
  32. package/dist/graphView.js.map +1 -0
  33. package/dist/index.d.ts +26 -11
  34. package/dist/index.js +17 -10
  35. package/dist/index.js.map +1 -1
  36. package/dist/knowledge.d.ts +20 -0
  37. package/dist/knowledge.js +208 -0
  38. package/dist/knowledge.js.map +1 -0
  39. package/dist/liveView.d.ts +15 -0
  40. package/dist/liveView.js +475 -0
  41. package/dist/liveView.js.map +1 -0
  42. package/dist/llm.js +1 -9
  43. package/dist/llm.js.map +1 -1
  44. package/dist/moodboard.d.ts +3 -0
  45. package/dist/moodboard.js +152 -0
  46. package/dist/moodboard.js.map +1 -0
  47. package/dist/persona.d.ts +2 -2
  48. package/dist/persona.js +82 -210
  49. package/dist/persona.js.map +1 -1
  50. package/dist/query.js +1 -6
  51. package/dist/query.js.map +1 -1
  52. package/dist/render.d.ts +2 -10
  53. package/dist/render.js +80 -175
  54. package/dist/render.js.map +1 -1
  55. package/dist/reviewChecklist.d.ts +17 -0
  56. package/dist/reviewChecklist.js +126 -0
  57. package/dist/reviewChecklist.js.map +1 -0
  58. package/dist/scan.d.ts +19 -7
  59. package/dist/scan.js +132 -374
  60. package/dist/scan.js.map +1 -1
  61. package/dist/scorecard.d.ts +53 -0
  62. package/dist/scorecard.js +325 -0
  63. package/dist/scorecard.js.map +1 -0
  64. package/dist/skillPrompt.d.ts +1 -3
  65. package/dist/skillPrompt.js +22 -148
  66. package/dist/skillPrompt.js.map +1 -1
  67. package/dist/store.d.ts +2 -2
  68. package/dist/store.js +7 -9
  69. package/dist/store.js.map +1 -1
  70. package/dist/styleDictionary.d.ts +16 -0
  71. package/dist/styleDictionary.js +89 -0
  72. package/dist/styleDictionary.js.map +1 -0
  73. package/dist/svg.d.ts +5 -0
  74. package/dist/svg.js +162 -0
  75. package/dist/svg.js.map +1 -0
  76. package/dist/systemDiff.d.ts +28 -0
  77. package/dist/systemDiff.js +107 -0
  78. package/dist/systemDiff.js.map +1 -0
  79. package/dist/tailwind.d.ts +2 -0
  80. package/dist/tailwind.js +122 -0
  81. package/dist/tailwind.js.map +1 -0
  82. package/dist/taste.d.ts +3 -2
  83. package/dist/taste.js +349 -536
  84. package/dist/taste.js.map +1 -1
  85. package/dist/tasteRenderer.d.ts +2 -3
  86. package/dist/tasteRenderer.js +123 -119
  87. package/dist/tasteRenderer.js.map +1 -1
  88. package/dist/tokenNaming.d.ts +5 -0
  89. package/dist/tokenNaming.js +229 -0
  90. package/dist/tokenNaming.js.map +1 -0
  91. package/dist/tokens.d.ts +17 -0
  92. package/dist/tokens.js +44 -0
  93. package/dist/tokens.js.map +1 -0
  94. package/dist/trends.d.ts +12 -0
  95. package/dist/trends.js +178 -0
  96. package/dist/trends.js.map +1 -0
  97. package/dist/types.d.ts +47 -101
  98. package/dist/wiki.d.ts +10 -0
  99. package/dist/wiki.js +346 -0
  100. package/dist/wiki.js.map +1 -0
  101. package/dist/writingStyle.d.ts +38 -0
  102. package/dist/writingStyle.js +224 -0
  103. package/dist/writingStyle.js.map +1 -0
  104. package/package.json +5 -4
  105. package/dist/classify.d.ts +0 -21
  106. package/dist/classify.js +0 -205
  107. package/dist/classify.js.map +0 -1
  108. package/dist/scanRenderer.d.ts +0 -2
  109. package/dist/scanRenderer.js +0 -155
  110. package/dist/scanRenderer.js.map +0 -1
  111. package/dist/tasteDiff.d.ts +0 -19
  112. package/dist/tasteDiff.js +0 -340
  113. package/dist/tasteDiff.js.map +0 -1
  114. package/dist/tasteGenerate.d.ts +0 -12
  115. package/dist/tasteGenerate.js +0 -140
  116. package/dist/tasteGenerate.js.map +0 -1
  117. package/dist/tasteRefine.d.ts +0 -13
  118. package/dist/tasteRefine.js +0 -351
  119. package/dist/tasteRefine.js.map +0 -1
  120. package/dist/theatrical.d.ts +0 -5
  121. package/dist/theatrical.js +0 -258
  122. package/dist/theatrical.js.map +0 -1
  123. package/skills/SKILL.md +0 -36
  124. package/skills/design-brain/SKILL.md +0 -77
@@ -1,7 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'fs-extra';
3
3
  import { runAgentBrowserJson } from './agentBrowser.js';
4
- import { classifyMotionIntent, detectPhysics, detectAnimationGroups, classifyGsapEasing } from './classify.js';
5
4
  const DEFAULT_VIEWPORTS = [
6
5
  { label: 'desktop', width: 1440, height: 1200 },
7
6
  { label: 'tablet', width: 1024, height: 1366 },
@@ -208,6 +207,7 @@ const EXTRACTION_SCRIPT = String.raw `(() => {
208
207
  selector,
209
208
  text: normalizeWhitespace(el.textContent || '').slice(0, 90),
210
209
  className: typeof el.className === 'string' ? normalizeWhitespace(el.className) : '',
210
+ html: el.outerHTML.slice(0, 2048),
211
211
  styles: {
212
212
  color: style.color,
213
213
  backgroundColor: style.backgroundColor,
@@ -227,12 +227,46 @@ const EXTRACTION_SCRIPT = String.raw `(() => {
227
227
  const hasTransform = style.transform && style.transform !== 'none';
228
228
 
229
229
  if ((hasTransition || hasAnimation || hasTransform) && motionList.length < maxMotion) {
230
- motionList.push({
230
+ const motionEntry = {
231
231
  selector,
232
232
  transition: style.transition,
233
233
  animation: style.animation,
234
234
  transform: style.transform,
235
- });
235
+ };
236
+
237
+ if (hasTransition) {
238
+ const props = style.transitionProperty.split(',').map(s => s.trim());
239
+ const durs = style.transitionDuration.split(',').map(s => s.trim());
240
+ const funcs = style.transitionTimingFunction.split(',').map(s => s.trim());
241
+ const delays = style.transitionDelay.split(',').map(s => s.trim());
242
+ motionEntry.transitions = props.map((p, i) => ({
243
+ property: p,
244
+ duration: durs[i % durs.length] || '0s',
245
+ timingFunction: funcs[i % funcs.length] || 'ease',
246
+ delay: delays[i % delays.length] || '0s',
247
+ }));
248
+ }
249
+
250
+ if (hasAnimation) {
251
+ const names = style.animationName.split(',').map(s => s.trim());
252
+ const durs = style.animationDuration.split(',').map(s => s.trim());
253
+ const funcs = style.animationTimingFunction.split(',').map(s => s.trim());
254
+ const delays = style.animationDelay.split(',').map(s => s.trim());
255
+ const iters = style.animationIterationCount.split(',').map(s => s.trim());
256
+ const dirs = style.animationDirection.split(',').map(s => s.trim());
257
+ const fills = style.animationFillMode.split(',').map(s => s.trim());
258
+ motionEntry.animations = names.map((n, i) => ({
259
+ name: n,
260
+ duration: durs[i % durs.length] || '0s',
261
+ timingFunction: funcs[i % funcs.length] || 'ease',
262
+ delay: delays[i % delays.length] || '0s',
263
+ iterationCount: iters[i % iters.length] || '1',
264
+ direction: dirs[i % dirs.length] || 'normal',
265
+ fillMode: fills[i % fills.length] || 'none',
266
+ }));
267
+ }
268
+
269
+ motionList.push(motionEntry);
236
270
  }
237
271
  });
238
272
 
@@ -296,6 +330,35 @@ const EXTRACTION_SCRIPT = String.raw `(() => {
296
330
 
297
331
  addPseudoStateStyles();
298
332
 
333
+ const keyframeList = [];
334
+ const seenKeyframes = new Set();
335
+ const maxKeyframes = 60;
336
+
337
+ for (const sheet of Array.from(document.styleSheets)) {
338
+ let rules;
339
+ try { rules = sheet.cssRules; } catch { continue; }
340
+ if (!rules) continue;
341
+
342
+ for (const rule of Array.from(rules)) {
343
+ if (rule.constructor.name !== 'CSSKeyframesRule') continue;
344
+ const kfRule = rule;
345
+ const name = kfRule.name;
346
+ if (seenKeyframes.has(name) || keyframeList.length >= maxKeyframes) continue;
347
+ seenKeyframes.add(name);
348
+
349
+ const steps = [];
350
+ for (const kf of Array.from(kfRule.cssRules)) {
351
+ const declarations = {};
352
+ for (let i = 0; i < kf.style.length; i++) {
353
+ const prop = kf.style[i];
354
+ declarations[prop] = kf.style.getPropertyValue(prop);
355
+ }
356
+ steps.push({ offset: kf.keyText, declarations });
357
+ }
358
+ keyframeList.push({ name, steps });
359
+ }
360
+ }
361
+
299
362
  const colors = Array.from(colorMap.values()).sort((a, b) => b.count - a.count).slice(0, 70);
300
363
  const typography = Array.from(typographyMap.values()).sort((a, b) => b.count - a.count).slice(0, 90);
301
364
 
@@ -310,6 +373,7 @@ const EXTRACTION_SCRIPT = String.raw `(() => {
310
373
  typography,
311
374
  components: componentList,
312
375
  motion: motionList,
376
+ keyframes: keyframeList,
313
377
  layout: layoutList,
314
378
  cssVariables: variableMap,
315
379
  stateStyles: stateStyleList,
@@ -325,312 +389,6 @@ const PAGE_SUMMARY_SCRIPT = String.raw `(() => {
325
389
  summary: [h1, 'nav-links:' + navCount, 'ctas:' + ctaCount].filter(Boolean).join(' | '),
326
390
  };
327
391
  })();`;
328
- const ANIMATION_OBSERVER_SCRIPT = String.raw `(() => {
329
- const maxAnimations = 200;
330
- const result = {
331
- libraries: [],
332
- webAnimations: [],
333
- gsapTweens: [],
334
- lottiePlayers: [],
335
- scrollBindings: {
336
- hasScrollTrigger: false,
337
- hasIntersectionObserver: false,
338
- scrollTriggers: [],
339
- hasScrollSnap: false,
340
- hasScrollTimeline: false,
341
- },
342
- };
343
-
344
- function buildSelector(el) {
345
- if (!el || !el.tagName) return 'unknown';
346
- const tag = el.tagName.toLowerCase();
347
- if (el.id) return tag + '#' + el.id;
348
- if (typeof el.className === 'string' && el.className.trim()) {
349
- const firstClass = el.className.trim().split(/\s+/).slice(0, 2).join('.');
350
- if (firstClass) return tag + '.' + firstClass;
351
- }
352
- return tag;
353
- }
354
-
355
- /* Layer 1: Library Detection */
356
- try {
357
- if (typeof gsap !== 'undefined') {
358
- result.libraries.push({ name: 'gsap', version: typeof gsap.version === 'string' ? gsap.version : 'unknown' });
359
- }
360
- if (typeof ScrollTrigger !== 'undefined') {
361
- result.libraries.push({ name: 'scrolltrigger', version: 'detected' });
362
- result.scrollBindings.hasScrollTrigger = true;
363
- }
364
- if (typeof lottie !== 'undefined' || typeof bodymovin !== 'undefined') {
365
- result.libraries.push({ name: 'lottie', version: 'detected' });
366
- }
367
- if (document.querySelector('lottie-player, dotlottie-player')) {
368
- if (!result.libraries.some(function(l) { return l.name === 'lottie'; })) {
369
- result.libraries.push({ name: 'lottie', version: 'web-component' });
370
- }
371
- }
372
- if (document.querySelector('[data-framer-name], [data-framer-component-type]')) {
373
- result.libraries.push({ name: 'framer-motion', version: 'detected' });
374
- }
375
- } catch(e) {}
376
-
377
- /* Layer 2: Web Animations API */
378
- try {
379
- var animations = document.getAnimations();
380
- for (var ai = 0; ai < Math.min(animations.length, maxAnimations); ai++) {
381
- var anim = animations[ai];
382
- var effect = anim.effect;
383
- if (!effect || !effect.target) continue;
384
-
385
- var target = effect.target;
386
- var selector = buildSelector(target);
387
-
388
- var keyframes = [];
389
- try { keyframes = effect.getKeyframes(); } catch(e) {}
390
-
391
- var computedTiming = {};
392
- try { computedTiming = effect.getComputedTiming(); } catch(e) {}
393
-
394
- var timelineType = 'document';
395
- try {
396
- if (anim.timeline && anim.timeline.constructor) {
397
- var tlName = anim.timeline.constructor.name;
398
- if (tlName === 'ScrollTimeline') timelineType = 'scroll';
399
- else if (tlName === 'ViewTimeline') timelineType = 'view';
400
- }
401
- } catch(e) {}
402
-
403
- if (timelineType !== 'document') {
404
- result.scrollBindings.hasScrollTimeline = true;
405
- }
406
-
407
- result.webAnimations.push({
408
- selector: selector,
409
- playState: anim.playState,
410
- animationName: anim.animationName || anim.id || '',
411
- keyframes: keyframes.map(function(kf) {
412
- var props = {};
413
- for (var k in kf) {
414
- if (k !== 'offset' && k !== 'computedOffset' && k !== 'easing' && k !== 'composite') {
415
- props[k] = String(kf[k]);
416
- }
417
- }
418
- return {
419
- offset: kf.computedOffset != null ? kf.computedOffset : (kf.offset || 0),
420
- properties: props,
421
- easing: kf.easing || 'linear',
422
- };
423
- }),
424
- timing: {
425
- duration: typeof computedTiming.duration === 'number' ? computedTiming.duration : 0,
426
- delay: computedTiming.delay || 0,
427
- easing: computedTiming.easing || 'linear',
428
- iterations: computedTiming.iterations != null ? computedTiming.iterations : 1,
429
- direction: computedTiming.direction || 'normal',
430
- fillMode: computedTiming.fill || 'none',
431
- },
432
- timelineType: timelineType,
433
- });
434
- }
435
- } catch(e) {}
436
-
437
- /* Layer 3: GSAP Introspection */
438
- try {
439
- if (typeof gsap !== 'undefined' && gsap.globalTimeline) {
440
- var children = gsap.globalTimeline.getChildren(true, true, false);
441
- for (var gi = 0; gi < Math.min(children.length, maxAnimations); gi++) {
442
- var tween = children[gi];
443
- var targets = tween.targets ? tween.targets() : [];
444
- if (targets.length === 0) continue;
445
-
446
- var gsSelector = buildSelector(targets[0]);
447
- var vars = {};
448
- if (tween.vars) {
449
- for (var vk in tween.vars) {
450
- var vv = tween.vars[vk];
451
- if (typeof vv === 'number' || typeof vv === 'string') {
452
- vars[vk] = vv;
453
- }
454
- }
455
- }
456
-
457
- result.gsapTweens.push({
458
- selector: gsSelector,
459
- duration: typeof tween.duration === 'function' ? tween.duration() : 0,
460
- delay: typeof tween.delay === 'function' ? tween.delay() : 0,
461
- ease: tween.vars && tween.vars.ease ? tween.vars.ease : 'power1.out',
462
- vars: vars,
463
- startTime: typeof tween.startTime === 'function' ? tween.startTime() : 0,
464
- });
465
- }
466
- }
467
- } catch(e) {}
468
-
469
- /* Layer 4: Lottie Extraction */
470
- try {
471
- var lottieRef = (typeof lottie !== 'undefined') ? lottie : ((typeof bodymovin !== 'undefined') ? bodymovin : null);
472
- if (lottieRef && typeof lottieRef.getRegisteredAnimations === 'function') {
473
- var registered = lottieRef.getRegisteredAnimations();
474
- for (var li = 0; li < Math.min(registered.length, 20); li++) {
475
- var la = registered[li];
476
- var container = la.wrapper || la.container;
477
- result.lottiePlayers.push({
478
- selector: container ? buildSelector(container) : 'lottie-unknown',
479
- frameRate: la.frameRate || (la.animationData && la.animationData.fr) || 0,
480
- totalFrames: la.totalFrames || (la.animationData && la.animationData.op) || 0,
481
- duration: typeof la.getDuration === 'function' ? la.getDuration(false) : 0,
482
- });
483
- }
484
- }
485
-
486
- var players = document.querySelectorAll('lottie-player, dotlottie-player');
487
- for (var pi = 0; pi < Math.min(players.length, 20); pi++) {
488
- var pSelector = buildSelector(players[pi]);
489
- if (!result.lottiePlayers.some(function(l) { return l.selector === pSelector; })) {
490
- result.lottiePlayers.push({ selector: pSelector, frameRate: 0, totalFrames: 0, duration: 0 });
491
- }
492
- }
493
- } catch(e) {}
494
-
495
- /* Layer 5: Passive Scroll Detection */
496
- try {
497
- if (typeof ScrollTrigger !== 'undefined' && typeof ScrollTrigger.getAll === 'function') {
498
- var triggers = ScrollTrigger.getAll();
499
- for (var si = 0; si < Math.min(triggers.length, 50); si++) {
500
- var st = triggers[si];
501
- result.scrollBindings.scrollTriggers.push({
502
- triggerSelector: st.trigger ? buildSelector(st.trigger) : '',
503
- isActive: !!st.isActive,
504
- });
505
- }
506
- }
507
- } catch(e) {}
508
-
509
- try {
510
- var scrollSnap = window.getComputedStyle(document.documentElement).scrollSnapType;
511
- if (scrollSnap && scrollSnap !== 'none') {
512
- result.scrollBindings.hasScrollSnap = true;
513
- }
514
- } catch(e) {}
515
-
516
- return result;
517
- })();`;
518
- function convertObserverResult(raw) {
519
- const tokens = [];
520
- const libraryNames = new Set(raw.libraries.map((l) => l.name));
521
- // Convert Web Animations API results
522
- for (const wa of raw.webAnimations) {
523
- const intent = classifyMotionIntent(wa.keyframes);
524
- let library = 'css';
525
- if (libraryNames.has('framer-motion')) {
526
- library = 'framer-motion';
527
- }
528
- const token = {
529
- selector: wa.selector,
530
- library,
531
- motionIntent: intent,
532
- timing: {
533
- duration: wa.timing.duration,
534
- delay: wa.timing.delay,
535
- easing: wa.timing.easing,
536
- iterations: wa.timing.iterations === Infinity ? Infinity : wa.timing.iterations,
537
- direction: wa.timing.direction,
538
- fillMode: wa.timing.fillMode,
539
- },
540
- keyframes: wa.keyframes,
541
- trigger: wa.timelineType === 'scroll' || wa.timelineType === 'view' ? 'scroll' : 'load',
542
- };
543
- if (wa.timelineType !== 'document') {
544
- token.scrollBinding = {
545
- hasScrollTrigger: false,
546
- hasIntersectionObserver: false,
547
- scrollTimelineAxis: 'block',
548
- };
549
- }
550
- // Detect physics from keyframes
551
- const allProps = new Set();
552
- for (const kf of wa.keyframes) {
553
- for (const prop of Object.keys(kf.properties))
554
- allProps.add(prop);
555
- }
556
- if (allProps.has('transform')) {
557
- for (const fnName of ['translateX', 'translateY', 'scale', 'rotate']) {
558
- const physics = detectPhysics(wa.keyframes, fnName);
559
- if (physics) {
560
- token.physics = physics;
561
- token.motionIntent = physics.type === 'spring' ? 'spring' : 'bounce';
562
- break;
563
- }
564
- }
565
- }
566
- tokens.push(token);
567
- }
568
- // Convert GSAP tweens
569
- for (const tween of raw.gsapTweens) {
570
- const token = {
571
- selector: tween.selector,
572
- library: 'gsap',
573
- motionIntent: 'complex',
574
- timing: {
575
- duration: tween.duration * 1000,
576
- delay: tween.delay * 1000,
577
- easing: tween.ease || 'power1.out',
578
- iterations: 1,
579
- direction: 'normal',
580
- fillMode: 'none',
581
- },
582
- trigger: 'load',
583
- gsapVars: tween.vars,
584
- };
585
- const physics = classifyGsapEasing(tween.ease);
586
- if (physics) {
587
- token.physics = physics;
588
- token.motionIntent = physics.type === 'spring' ? 'spring' : 'bounce';
589
- }
590
- else {
591
- const varKeys = Object.keys(tween.vars);
592
- if (varKeys.some((k) => ['x', 'y', 'xPercent', 'yPercent'].includes(k))) {
593
- token.motionIntent = 'slide';
594
- }
595
- else if (varKeys.some((k) => ['scale', 'scaleX', 'scaleY'].includes(k))) {
596
- token.motionIntent = 'scale';
597
- }
598
- else if (varKeys.some((k) => ['rotation', 'rotationX', 'rotationY'].includes(k))) {
599
- token.motionIntent = 'rotate';
600
- }
601
- else if (varKeys.includes('opacity')) {
602
- token.motionIntent = 'fade';
603
- }
604
- }
605
- if (raw.scrollBindings.hasScrollTrigger) {
606
- const matchingTrigger = raw.scrollBindings.scrollTriggers.find((st) => st.triggerSelector === tween.selector);
607
- if (matchingTrigger) {
608
- token.trigger = 'scroll';
609
- token.scrollBinding = {
610
- triggerSelector: matchingTrigger.triggerSelector,
611
- hasScrollTrigger: true,
612
- hasIntersectionObserver: false,
613
- };
614
- }
615
- }
616
- tokens.push(token);
617
- }
618
- // Convert Lottie players
619
- for (const lp of raw.lottiePlayers) {
620
- tokens.push({
621
- selector: lp.selector,
622
- library: 'lottie',
623
- motionIntent: 'complex',
624
- trigger: 'load',
625
- lottieMetadata: {
626
- frameRate: lp.frameRate,
627
- totalFrames: lp.totalFrames,
628
- duration: lp.duration,
629
- },
630
- });
631
- }
632
- return tokens;
633
- }
634
392
  function normalizeResult(result) {
635
393
  return {
636
394
  pageTitle: result.pageTitle ?? undefined,
@@ -640,6 +398,7 @@ function normalizeResult(result) {
640
398
  typography: result.typography ?? [],
641
399
  components: result.components ?? [],
642
400
  motion: result.motion ?? [],
401
+ keyframes: result.keyframes ?? [],
643
402
  layout: result.layout ?? [],
644
403
  cssVariables: result.cssVariables ?? {},
645
404
  stateStyles: result.stateStyles ?? [],
@@ -678,6 +437,7 @@ function mergeAnalysis(all) {
678
437
  }
679
438
  const componentMap = new Map();
680
439
  const motionMap = new Map();
440
+ const keyframeMap = new Map();
681
441
  const layoutMap = new Map();
682
442
  const stateMap = new Map();
683
443
  const cssVariables = {};
@@ -690,13 +450,16 @@ function mergeAnalysis(all) {
690
450
  }
691
451
  }
692
452
  for (const motion of entry.motion) {
693
- const key = ('library' in motion && 'motionIntent' in motion)
694
- ? `${motion.selector}|${motion.library}|${motion.motionIntent}`
695
- : `${motion.selector}|${motion.transition}|${motion.animation}|${motion.transform}`;
453
+ const key = `${motion.selector}|${motion.transition}|${motion.animation}|${motion.transform}`;
696
454
  if (!motionMap.has(key)) {
697
455
  motionMap.set(key, motion);
698
456
  }
699
457
  }
458
+ for (const kf of entry.keyframes ?? []) {
459
+ if (!keyframeMap.has(kf.name)) {
460
+ keyframeMap.set(kf.name, kf);
461
+ }
462
+ }
700
463
  for (const layout of entry.layout) {
701
464
  const key = `${layout.tag}|${layout.selector}|${layout.role}`;
702
465
  if (!layoutMap.has(key)) {
@@ -718,6 +481,7 @@ function mergeAnalysis(all) {
718
481
  typography: [...typographyMap.values()].sort((a, b) => b.count - a.count).slice(0, 120),
719
482
  components: [...componentMap.values()].slice(0, 260),
720
483
  motion: [...motionMap.values()].slice(0, 260),
484
+ keyframes: [...keyframeMap.values()].slice(0, 80),
721
485
  layout: [...layoutMap.values()].slice(0, 220),
722
486
  cssVariables,
723
487
  stateStyles: [...stateMap.values()].slice(0, 300),
@@ -740,6 +504,7 @@ async function collectInteractiveStateStyles(params) {
740
504
  const snapshot = await runAgentBrowserJson(['snapshot', '-i', '-d', '2'], {
741
505
  session: params.sessionName,
742
506
  cwd: params.workingDir,
507
+ headed: params.headed,
743
508
  });
744
509
  const refs = (snapshot.data.refs ?? {});
745
510
  const refIds = Object.keys(refs).slice(0, 8);
@@ -748,10 +513,12 @@ async function collectInteractiveStateStyles(params) {
748
513
  await runAgentBrowserJson(['hover', ref], {
749
514
  session: params.sessionName,
750
515
  cwd: params.workingDir,
516
+ headed: params.headed,
751
517
  }).catch(() => undefined);
752
518
  const hoverStyles = await runAgentBrowserJson(['get', 'styles', ref], {
753
519
  session: params.sessionName,
754
520
  cwd: params.workingDir,
521
+ headed: params.headed,
755
522
  }).catch(() => undefined);
756
523
  if (hoverStyles?.success) {
757
524
  const declarations = parseStylesFromGetStyles(hoverStyles.data);
@@ -762,10 +529,12 @@ async function collectInteractiveStateStyles(params) {
762
529
  await runAgentBrowserJson(['focus', ref], {
763
530
  session: params.sessionName,
764
531
  cwd: params.workingDir,
532
+ headed: params.headed,
765
533
  }).catch(() => undefined);
766
534
  const focusStyles = await runAgentBrowserJson(['get', 'styles', ref], {
767
535
  session: params.sessionName,
768
536
  cwd: params.workingDir,
537
+ headed: params.headed,
769
538
  }).catch(() => undefined);
770
539
  if (focusStyles?.success) {
771
540
  const declarations = parseStylesFromGetStyles(focusStyles.data);
@@ -791,6 +560,7 @@ async function getCurrentUrl(params) {
791
560
  const response = await runAgentBrowserJson(['get', 'url'], {
792
561
  session: params.sessionName,
793
562
  cwd: params.workingDir,
563
+ headed: params.headed,
794
564
  }).catch(() => undefined);
795
565
  return response?.success ? response.data.url : undefined;
796
566
  }
@@ -802,6 +572,7 @@ async function collectJourney(params) {
802
572
  const snapshot = await runAgentBrowserJson(['snapshot', '-i', '-d', '2'], {
803
573
  session: params.sessionName,
804
574
  cwd: params.workingDir,
575
+ headed: params.headed,
805
576
  });
806
577
  const refs = (snapshot.data.refs ?? {});
807
578
  const clickable = Object.entries(refs)
@@ -814,6 +585,7 @@ async function collectJourney(params) {
814
585
  const clickResult = await runAgentBrowserJson(['click', ref], {
815
586
  session: params.sessionName,
816
587
  cwd: params.workingDir,
588
+ headed: params.headed,
817
589
  }).catch(() => undefined);
818
590
  if (!clickResult?.success) {
819
591
  continue;
@@ -821,10 +593,12 @@ async function collectJourney(params) {
821
593
  await runAgentBrowserJson(['wait', '1200'], {
822
594
  session: params.sessionName,
823
595
  cwd: params.workingDir,
596
+ headed: params.headed,
824
597
  }).catch(() => undefined);
825
598
  const summaryResult = await runAgentBrowserJson(['eval', PAGE_SUMMARY_SCRIPT], {
826
599
  session: params.sessionName,
827
600
  cwd: params.workingDir,
601
+ headed: params.headed,
828
602
  }).catch(() => undefined);
829
603
  const summaryData = summaryResult?.data.result ?? {};
830
604
  const toUrl = summaryData.url ?? (await getCurrentUrl(params));
@@ -837,22 +611,25 @@ async function collectJourney(params) {
837
611
  title: summaryData.title,
838
612
  summary: summaryData.summary,
839
613
  });
614
+ params.onStep?.(i + 1, toUrl);
840
615
  await runAgentBrowserJson(['back'], {
841
616
  session: params.sessionName,
842
617
  cwd: params.workingDir,
618
+ headed: params.headed,
843
619
  }).catch(() => undefined);
844
620
  await runAgentBrowserJson(['wait', '900'], {
845
621
  session: params.sessionName,
846
622
  cwd: params.workingDir,
623
+ headed: params.headed,
847
624
  }).catch(() => undefined);
848
625
  }
849
626
  }
850
627
  return steps;
851
628
  }
852
629
  export async function captureDesignFromUrl(params) {
853
- const { url, sessionName, screenshotPath, workingDir, journeySteps = 3, responsiveViewports = DEFAULT_VIEWPORTS, } = params;
630
+ const { url, sessionName, screenshotPath, workingDir, headed = false, journeySteps = 3, responsiveViewports = DEFAULT_VIEWPORTS, callbacks, } = params;
854
631
  await fs.ensureDir(path.dirname(screenshotPath));
855
- await runAgentBrowserJson(['open', url], { session: sessionName, cwd: workingDir });
632
+ await runAgentBrowserJson(['open', url], { session: sessionName, cwd: workingDir, headed });
856
633
  try {
857
634
  const captures = [];
858
635
  const responsiveSnapshots = [];
@@ -860,14 +637,17 @@ export async function captureDesignFromUrl(params) {
860
637
  await runAgentBrowserJson(['set', 'viewport', String(viewport.width), String(viewport.height)], {
861
638
  session: sessionName,
862
639
  cwd: workingDir,
640
+ headed,
863
641
  });
864
642
  await runAgentBrowserJson(['wait', '900'], {
865
643
  session: sessionName,
866
644
  cwd: workingDir,
645
+ headed,
867
646
  });
868
647
  const extraction = await runAgentBrowserJson(['eval', EXTRACTION_SCRIPT], {
869
648
  session: sessionName,
870
649
  cwd: workingDir,
650
+ headed,
871
651
  });
872
652
  if (!extraction.success) {
873
653
  throw new Error(`Extraction failed: ${extraction.error ?? 'Unknown error'}`);
@@ -875,72 +655,41 @@ export async function captureDesignFromUrl(params) {
875
655
  const normalized = normalizeResult(extraction.data.result ?? {});
876
656
  captures.push(normalized);
877
657
  responsiveSnapshots.push(toResponsiveSnapshot(viewport.label, normalized));
658
+ callbacks?.onViewportExtracted?.(viewport.label, normalized);
878
659
  }
879
660
  await runAgentBrowserJson(['set', 'viewport', '1440', '1200'], {
880
661
  session: sessionName,
881
662
  cwd: workingDir,
663
+ headed,
882
664
  }).catch(() => undefined);
883
- // Scroll through the page to trigger lazy-loaded animation libraries (GSAP, ScrollTrigger, etc.)
884
- try {
885
- const pageInfo = await runAgentBrowserJson(['eval',
886
- `({ height: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight), vh: window.innerHeight })`
887
- ], { session: sessionName, cwd: workingDir });
888
- const { height = 5000, vh = 800 } = pageInfo.data.result ?? {};
889
- const scrollSteps = Math.min(Math.ceil(height / vh), 15);
890
- const stepSize = Math.ceil(height / scrollSteps);
891
- for (let i = 1; i <= scrollSteps; i++) {
892
- await runAgentBrowserJson(['eval', `window.scrollTo({top:${i * stepSize},behavior:"instant"});true`], { session: sessionName, cwd: workingDir });
893
- await runAgentBrowserJson(['wait', '200'], { session: sessionName, cwd: workingDir });
894
- }
895
- await runAgentBrowserJson(['eval', 'window.scrollTo({top:0,behavior:"instant"});true'], { session: sessionName, cwd: workingDir });
896
- await runAgentBrowserJson(['wait', '1500'], { session: sessionName, cwd: workingDir });
897
- }
898
- catch {
899
- // Scroll is best-effort; continue to animation capture
900
- }
901
- // Run animation observer script (once, at desktop viewport)
902
- let animationTokens = [];
903
- try {
904
- const animResult = await runAgentBrowserJson(['eval', ANIMATION_OBSERVER_SCRIPT], {
905
- session: sessionName,
906
- cwd: workingDir,
907
- });
908
- if (animResult.success && animResult.data.result) {
909
- const rawAnimData = animResult.data.result;
910
- animationTokens = convertObserverResult(rawAnimData);
911
- animationTokens = detectAnimationGroups(animationTokens);
912
- }
913
- }
914
- catch {
915
- // Animation capture is best-effort; don't fail the whole extraction
916
- }
917
665
  const snapshotResult = await runAgentBrowserJson(['snapshot', '-c', '-d', '3'], {
918
666
  session: sessionName,
919
667
  cwd: workingDir,
668
+ headed,
920
669
  });
921
670
  const interactiveStates = await collectInteractiveStateStyles({
922
671
  sessionName,
923
672
  workingDir,
673
+ headed,
924
674
  });
675
+ callbacks?.onInteractiveStates?.(interactiveStates.length);
925
676
  const journey = await collectJourney({
926
677
  sessionName,
927
678
  workingDir,
679
+ headed,
928
680
  maxSteps: journeySteps,
681
+ onStep: callbacks?.onJourneyStep,
929
682
  });
930
683
  await runAgentBrowserJson(['screenshot', screenshotPath, '--full'], {
931
684
  session: sessionName,
932
685
  cwd: workingDir,
686
+ headed,
933
687
  });
934
688
  const merged = mergeAnalysis(captures);
689
+ callbacks?.onMerged?.(merged);
935
690
  const stateStyles = [...(merged.stateStyles ?? []), ...interactiveStates].slice(0, 400);
936
- // Merge: prefer new AnimationTokens, fall back to legacy MotionTokens
937
- const mergedMotion = [
938
- ...animationTokens,
939
- ...merged.motion.filter((legacyToken) => !animationTokens.some((at) => at.selector === legacyToken.selector)),
940
- ];
941
691
  return {
942
692
  ...merged,
943
- motion: mergedMotion,
944
693
  accessibilitySnapshot: snapshotResult.data.snapshot ?? undefined,
945
694
  responsiveSnapshots,
946
695
  stateStyles,
@@ -948,7 +697,7 @@ export async function captureDesignFromUrl(params) {
948
697
  };
949
698
  }
950
699
  finally {
951
- await runAgentBrowserJson(['close'], { session: sessionName, cwd: workingDir }).catch(() => undefined);
700
+ await runAgentBrowserJson(['close'], { session: sessionName, cwd: workingDir, headed }).catch(() => undefined);
952
701
  }
953
702
  }
954
703
  //# sourceMappingURL=extractFromUrl.js.map