multiclone 0.0.0-stage → 0.2.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.
- package/README.md +78 -2
- package/agents/section-builder.md +37 -0
- package/commands/multiclone.md +15 -0
- package/dist/adapters/cli.js +129 -0
- package/dist/adapters/cli.js.map +1 -0
- package/dist/adapters/cliArgs.js +63 -0
- package/dist/adapters/cliArgs.js.map +1 -0
- package/dist/adapters/mcp.js +83 -0
- package/dist/adapters/mcp.js.map +1 -0
- package/dist/analyze/analyze.js +85 -0
- package/dist/analyze/analyze.js.map +1 -0
- package/dist/analyze/animations.js +340 -0
- package/dist/analyze/animations.js.map +1 -0
- package/dist/analyze/ast.js +182 -0
- package/dist/analyze/ast.js.map +1 -0
- package/dist/analyze/chunks.js +160 -0
- package/dist/analyze/chunks.js.map +1 -0
- package/dist/analyze/jobs/code.js +117 -0
- package/dist/analyze/jobs/code.js.map +1 -0
- package/dist/analyze/jobs/sections.js +356 -0
- package/dist/analyze/jobs/sections.js.map +1 -0
- package/dist/analyze/pretty.js +20 -0
- package/dist/analyze/pretty.js.map +1 -0
- package/dist/analyze/report.js +101 -0
- package/dist/analyze/report.js.map +1 -0
- package/dist/analyze/worker.js +71 -0
- package/dist/analyze/worker.js.map +1 -0
- package/dist/capture/capture.js +340 -0
- package/dist/capture/capture.js.map +1 -0
- package/dist/capture/collectors/a11y.js +92 -0
- package/dist/capture/collectors/a11y.js.map +1 -0
- package/dist/capture/collectors/animations.js +113 -0
- package/dist/capture/collectors/animations.js.map +1 -0
- package/dist/capture/collectors/breakpoints.js +31 -0
- package/dist/capture/collectors/breakpoints.js.map +1 -0
- package/dist/capture/collectors/consent.js +39 -0
- package/dist/capture/collectors/consent.js.map +1 -0
- package/dist/capture/collectors/coverage.js +121 -0
- package/dist/capture/collectors/coverage.js.map +1 -0
- package/dist/capture/collectors/dom.js +16 -0
- package/dist/capture/collectors/dom.js.map +1 -0
- package/dist/capture/collectors/fonts.js +154 -0
- package/dist/capture/collectors/fonts.js.map +1 -0
- package/dist/capture/collectors/frames.js +93 -0
- package/dist/capture/collectors/frames.js.map +1 -0
- package/dist/capture/collectors/index.js +61 -0
- package/dist/capture/collectors/index.js.map +1 -0
- package/dist/capture/collectors/interactions.js +207 -0
- package/dist/capture/collectors/interactions.js.map +1 -0
- package/dist/capture/collectors/intro.js +84 -0
- package/dist/capture/collectors/intro.js.map +1 -0
- package/dist/capture/collectors/listeners.js +84 -0
- package/dist/capture/collectors/listeners.js.map +1 -0
- package/dist/capture/collectors/motion.js +91 -0
- package/dist/capture/collectors/motion.js.map +1 -0
- package/dist/capture/collectors/network.js +288 -0
- package/dist/capture/collectors/network.js.map +1 -0
- package/dist/capture/collectors/probes.js +34 -0
- package/dist/capture/collectors/probes.js.map +1 -0
- package/dist/capture/collectors/runtime.js +38 -0
- package/dist/capture/collectors/runtime.js.map +1 -0
- package/dist/capture/collectors/scripts.js +98 -0
- package/dist/capture/collectors/scripts.js.map +1 -0
- package/dist/capture/collectors/sections.js +17 -0
- package/dist/capture/collectors/sections.js.map +1 -0
- package/dist/capture/collectors/shots.js +58 -0
- package/dist/capture/collectors/shots.js.map +1 -0
- package/dist/capture/collectors/snapshot.js +47 -0
- package/dist/capture/collectors/snapshot.js.map +1 -0
- package/dist/capture/collectors/sourcemaps.js +153 -0
- package/dist/capture/collectors/sourcemaps.js.map +1 -0
- package/dist/capture/collectors/storage.js +72 -0
- package/dist/capture/collectors/storage.js.map +1 -0
- package/dist/capture/context.js +40 -0
- package/dist/capture/context.js.map +1 -0
- package/dist/capture/hooks/candidates.js +104 -0
- package/dist/capture/hooks/candidates.js.map +1 -0
- package/dist/capture/hooks/consent.js +82 -0
- package/dist/capture/hooks/consent.js.map +1 -0
- package/dist/capture/hooks/recorders.js +507 -0
- package/dist/capture/hooks/recorders.js.map +1 -0
- package/dist/capture/hooks/sections.js +62 -0
- package/dist/capture/hooks/sections.js.map +1 -0
- package/dist/capture/hooks/styles.js +86 -0
- package/dist/capture/hooks/styles.js.map +1 -0
- package/dist/capture/probes.js +491 -0
- package/dist/capture/probes.js.map +1 -0
- package/dist/capture/report.js +115 -0
- package/dist/capture/report.js.map +1 -0
- package/dist/compare/compare.js +391 -0
- package/dist/compare/compare.js.map +1 -0
- package/dist/compare/image.js +105 -0
- package/dist/compare/image.js.map +1 -0
- package/dist/compare/probes.js +129 -0
- package/dist/compare/probes.js.map +1 -0
- package/dist/compare/report.js +99 -0
- package/dist/compare/report.js.map +1 -0
- package/dist/compare/session.js +139 -0
- package/dist/compare/session.js.map +1 -0
- package/dist/compare/shoot.js +62 -0
- package/dist/compare/shoot.js.map +1 -0
- package/dist/contracts/catalog.js +29 -0
- package/dist/contracts/catalog.js.map +1 -0
- package/dist/contracts/context.js +19 -0
- package/dist/contracts/context.js.map +1 -0
- package/dist/contracts/fields.js +16 -0
- package/dist/contracts/fields.js.map +1 -0
- package/dist/contracts/tools/analyze.js +38 -0
- package/dist/contracts/tools/analyze.js.map +1 -0
- package/dist/contracts/tools/capture.js +87 -0
- package/dist/contracts/tools/capture.js.map +1 -0
- package/dist/contracts/tools/compare.js +142 -0
- package/dist/contracts/tools/compare.js.map +1 -0
- package/dist/contracts/tools/doctor.js +23 -0
- package/dist/contracts/tools/doctor.js.map +1 -0
- package/dist/contracts/tools/inspect.js +41 -0
- package/dist/contracts/tools/inspect.js.map +1 -0
- package/dist/contracts/tools/method.js +60 -0
- package/dist/contracts/tools/method.js.map +1 -0
- package/dist/contracts/tools/mirror.js +53 -0
- package/dist/contracts/tools/mirror.js.map +1 -0
- package/dist/contracts/tools/project.js +61 -0
- package/dist/contracts/tools/project.js.map +1 -0
- package/dist/contracts/tools/session.js +195 -0
- package/dist/contracts/tools/session.js.map +1 -0
- package/dist/contracts/types.js +20 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/core/cdp.js +146 -0
- package/dist/core/cdp.js.map +1 -0
- package/dist/core/chrome.js +185 -0
- package/dist/core/chrome.js.map +1 -0
- package/dist/core/files.js +31 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/inpage.js +24 -0
- package/dist/core/inpage.js.map +1 -0
- package/dist/core/log.js +10 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/page.js +269 -0
- package/dist/core/page.js.map +1 -0
- package/dist/doctor.js +37 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domain/breakpoints.js +47 -0
- package/dist/domain/breakpoints.js.map +1 -0
- package/dist/domain/budget.js +38 -0
- package/dist/domain/budget.js.map +1 -0
- package/dist/domain/compare.js +138 -0
- package/dist/domain/compare.js.map +1 -0
- package/dist/domain/coverage.js +96 -0
- package/dist/domain/coverage.js.map +1 -0
- package/dist/domain/motion.js +142 -0
- package/dist/domain/motion.js.map +1 -0
- package/dist/domain/paths.js +55 -0
- package/dist/domain/paths.js.map +1 -0
- package/dist/domain/result.js +38 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/domain/routes.js +160 -0
- package/dist/domain/routes.js.map +1 -0
- package/dist/domain/sections.js +94 -0
- package/dist/domain/sections.js.map +1 -0
- package/dist/domain/snapshot.js +268 -0
- package/dist/domain/snapshot.js.map +1 -0
- package/dist/domain/sourcemap.js +95 -0
- package/dist/domain/sourcemap.js.map +1 -0
- package/dist/domain/stack.js +342 -0
- package/dist/domain/stack.js.map +1 -0
- package/dist/domain/tokens.js +183 -0
- package/dist/domain/tokens.js.map +1 -0
- package/dist/domain/types.js +2 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/viewports.js +45 -0
- package/dist/domain/viewports.js.map +1 -0
- package/dist/mirror/rewrite.js +56 -0
- package/dist/mirror/rewrite.js.map +1 -0
- package/dist/mirror/server.js +191 -0
- package/dist/mirror/server.js.map +1 -0
- package/dist/mirror/store.js +86 -0
- package/dist/mirror/store.js.map +1 -0
- package/dist/project/assets.js +69 -0
- package/dist/project/assets.js.map +1 -0
- package/dist/project/draft.js +860 -0
- package/dist/project/draft.js.map +1 -0
- package/dist/project/method.js +154 -0
- package/dist/project/method.js.map +1 -0
- package/dist/project/scaffold.js +142 -0
- package/dist/project/scaffold.js.map +1 -0
- package/dist/session/discover.js +53 -0
- package/dist/session/discover.js.map +1 -0
- package/dist/session/proc.js +113 -0
- package/dist/session/proc.js.map +1 -0
- package/dist/session/progress.js +83 -0
- package/dist/session/progress.js.map +1 -0
- package/dist/session/session.js +450 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/state.js +47 -0
- package/dist/session/state.js.map +1 -0
- package/dist/store/inspect.js +212 -0
- package/dist/store/inspect.js.map +1 -0
- package/dist/store/run.js +112 -0
- package/dist/store/run.js.map +1 -0
- package/dist/store/summary.js +69 -0
- package/dist/store/summary.js.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install.sh +29 -0
- package/package.json +67 -4
- package/skills/multiclone/SKILL.md +123 -0
- package/skills/multiclone/references/capture-format.md +73 -0
- package/skills/multiclone/references/fidelity.md +54 -0
- package/skills/multiclone/references/quality.md +47 -0
- package/skills/multiclone/references/stacks.md +156 -0
- package/templates/react-vite/.prettierignore +5 -0
- package/templates/react-vite/.prettierrc.json +6 -0
- package/templates/react-vite/eslint.config.js +38 -0
- package/templates/react-vite/gitignore +4 -0
- package/templates/react-vite/index.html +12 -0
- package/templates/react-vite/package.json +36 -0
- package/templates/react-vite/src/app/App.tsx +15 -0
- package/templates/react-vite/src/app/Page.tsx +11 -0
- package/templates/react-vite/src/app/routes.ts +7 -0
- package/templates/react-vite/src/components/README.md +7 -0
- package/templates/react-vite/src/content/README.md +2 -0
- package/templates/react-vite/src/hooks/useActiveSection.ts +37 -0
- package/templates/react-vite/src/hooks/useInView.ts +45 -0
- package/templates/react-vite/src/hooks/useMediaQuery.ts +15 -0
- package/templates/react-vite/src/lib/cn.ts +4 -0
- package/templates/react-vite/src/lib/math.ts +21 -0
- package/templates/react-vite/src/lib/mc.ts +13 -0
- package/templates/react-vite/src/lib/media.ts +4 -0
- package/templates/react-vite/src/main.tsx +13 -0
- package/templates/react-vite/src/providers/SmoothScroll.tsx +24 -0
- package/templates/react-vite/src/styles/base.css +42 -0
- package/templates/react-vite/src/styles/draft.css +1 -0
- package/templates/react-vite/src/styles/fonts.css +1 -0
- package/templates/react-vite/src/styles/index.css +4 -0
- package/templates/react-vite/src/styles/tokens.css +3 -0
- package/templates/react-vite/src/vite-env.d.ts +1 -0
- package/templates/react-vite/tsconfig.app.json +29 -0
- package/templates/react-vite/tsconfig.json +4 -0
- package/templates/react-vite/tsconfig.node.json +19 -0
- package/templates/react-vite/vite.config.ts +37 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/** What multiclone recognises and how to rebuild each one. Order is the report order. */
|
|
2
|
+
export const RULES = [
|
|
3
|
+
{
|
|
4
|
+
id: 'nextjs',
|
|
5
|
+
label: 'Next.js',
|
|
6
|
+
kind: 'framework',
|
|
7
|
+
globals: ['__NEXT_DATA__'],
|
|
8
|
+
url: /\/_next\//,
|
|
9
|
+
advice: 'Page data often sits in __NEXT_DATA__ or the RSC payload; mine it for typed content.',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: 'remix',
|
|
13
|
+
label: 'Remix / React Router',
|
|
14
|
+
kind: 'framework',
|
|
15
|
+
globals: ['__remixContext', '__reactRouterContext'],
|
|
16
|
+
advice: 'Route and island props live in window.__remixContext; extract them as typed content.',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'nuxt',
|
|
20
|
+
label: 'Nuxt',
|
|
21
|
+
kind: 'framework',
|
|
22
|
+
globals: ['__NUXT__'],
|
|
23
|
+
url: /\/_nuxt\//,
|
|
24
|
+
advice: 'Content is in window.__NUXT__; port Vue components to React by behaviour.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'gatsby',
|
|
28
|
+
label: 'Gatsby',
|
|
29
|
+
kind: 'framework',
|
|
30
|
+
globals: ['___gatsby'],
|
|
31
|
+
advice: 'Static React output; page-data JSON files hold the content.',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'astro',
|
|
35
|
+
label: 'Astro',
|
|
36
|
+
kind: 'framework',
|
|
37
|
+
markers: ['astro'],
|
|
38
|
+
advice: 'Mostly static HTML with islands; rebuild islands as lazy React components.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'react',
|
|
42
|
+
label: 'React',
|
|
43
|
+
kind: 'framework',
|
|
44
|
+
markers: ['react'],
|
|
45
|
+
advice: 'Component boundaries usually follow the original DOM sections.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'vue',
|
|
49
|
+
label: 'Vue',
|
|
50
|
+
kind: 'framework',
|
|
51
|
+
markers: ['vue'],
|
|
52
|
+
text: /__VUE__|vue\.runtime/,
|
|
53
|
+
advice: 'Port components to React hooks; Vue <Transition> classes map to CSS transitions.',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'svelte',
|
|
57
|
+
label: 'Svelte',
|
|
58
|
+
kind: 'framework',
|
|
59
|
+
markers: ['svelte'],
|
|
60
|
+
advice: 'Svelte transitions compile to CSS keyframes; copy them from the captured styles.',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'angular',
|
|
64
|
+
label: 'Angular',
|
|
65
|
+
kind: 'framework',
|
|
66
|
+
markers: ['angular'],
|
|
67
|
+
advice: 'Angular animations compile to WAAPI; read them from the motion map.',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'webflow',
|
|
71
|
+
label: 'Webflow',
|
|
72
|
+
kind: 'platform',
|
|
73
|
+
globals: ['Webflow'],
|
|
74
|
+
markers: ['webflow'],
|
|
75
|
+
text: /data-w-id|webflow\.js|"ix2"/,
|
|
76
|
+
advice: 'IX2 interactions are inline transforms driven by scroll and hover. Reuse the compiled Webflow CSS and rebuild interactions from the motion map.',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'framer',
|
|
80
|
+
label: 'Framer',
|
|
81
|
+
kind: 'platform',
|
|
82
|
+
markers: ['framer'],
|
|
83
|
+
url: /framerusercontent\.com/,
|
|
84
|
+
advice: 'Appear and scroll effects map to motion/react whileInView and useScroll/useTransform.',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'shopify',
|
|
88
|
+
label: 'Shopify storefront',
|
|
89
|
+
kind: 'platform',
|
|
90
|
+
globals: ['Shopify'],
|
|
91
|
+
url: /cdn\.shopify\.com/,
|
|
92
|
+
advice: 'Theme sections map one-to-one to components; product data is static in the capture.',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'wordpress',
|
|
96
|
+
label: 'WordPress',
|
|
97
|
+
kind: 'platform',
|
|
98
|
+
url: /\/wp-content\/|\/wp-includes\//,
|
|
99
|
+
advice: 'Theme CSS is usually reusable; plugins add jQuery-driven effects.',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'squarespace',
|
|
103
|
+
label: 'Squarespace',
|
|
104
|
+
kind: 'platform',
|
|
105
|
+
globals: ['Squarespace'],
|
|
106
|
+
url: /squarespace(-cdn)?\.com/,
|
|
107
|
+
advice: 'Section animations are class toggles on scroll; reproduce with IntersectionObserver.',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'wix',
|
|
111
|
+
label: 'Wix',
|
|
112
|
+
kind: 'platform',
|
|
113
|
+
globals: ['wixBiSession'],
|
|
114
|
+
url: /parastorage\.com|wixstatic\.com/,
|
|
115
|
+
advice: 'Absolute-positioned layout; rebuild responsive layout by hand from screenshots.',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: 'gsap',
|
|
119
|
+
label: 'GSAP',
|
|
120
|
+
kind: 'animation',
|
|
121
|
+
globals: ['gsap'],
|
|
122
|
+
text: /gsap\.(to|from|timeline)\(|GreenSock|_gsScope/,
|
|
123
|
+
advice: 'Use gsap (npm) in useLayoutEffect with gsap.context() cleanup. Rebuild timelines from the motion map and the captured scripts.',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'scrolltrigger',
|
|
127
|
+
label: 'GSAP ScrollTrigger',
|
|
128
|
+
kind: 'scroll',
|
|
129
|
+
globals: ['ScrollTrigger'],
|
|
130
|
+
text: /ScrollTrigger/,
|
|
131
|
+
advice: 'Pinned and scrubbed sections: register ScrollTrigger and match start/end from the motion map (where values begin and stop changing).',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: 'scrollsmoother',
|
|
135
|
+
label: 'GSAP ScrollSmoother',
|
|
136
|
+
kind: 'scroll',
|
|
137
|
+
globals: ['ScrollSmoother'],
|
|
138
|
+
text: /ScrollSmoother/,
|
|
139
|
+
advice: 'Smooth wrapper/content transform; Lenis is a free equivalent for the feel.',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 'lenis',
|
|
143
|
+
label: 'Lenis smooth scroll',
|
|
144
|
+
kind: 'scroll',
|
|
145
|
+
globals: ['lenis'],
|
|
146
|
+
text: /lenis|__lenis/i,
|
|
147
|
+
advice: 'Add lenis with a requestAnimationFrame loop; keep native scroll authoritative so CSS scroll timelines still work.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'locomotive',
|
|
151
|
+
label: 'Locomotive Scroll',
|
|
152
|
+
kind: 'scroll',
|
|
153
|
+
globals: ['LocomotiveScroll'],
|
|
154
|
+
markers: ['locomotive'],
|
|
155
|
+
text: /locomotive-scroll|LocomotiveScroll/,
|
|
156
|
+
advice: 'data-scroll-speed parallax; rebuild with Lenis + scroll-linked transforms.',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 'framer-motion',
|
|
160
|
+
label: 'Framer Motion / Motion',
|
|
161
|
+
kind: 'animation',
|
|
162
|
+
globals: ['Motion'],
|
|
163
|
+
text: /framer-motion|motion\/react|useMotionValue|animateMotionValue/,
|
|
164
|
+
advice: 'Use motion/react; spring and duration values are often visible in the bundle.',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'anime',
|
|
168
|
+
label: 'anime.js',
|
|
169
|
+
kind: 'animation',
|
|
170
|
+
globals: ['anime'],
|
|
171
|
+
text: /animejs|anime\.timeline/,
|
|
172
|
+
advice: 'Port timelines to WAAPI or motion.',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: 'aos',
|
|
176
|
+
label: 'AOS reveal on scroll',
|
|
177
|
+
kind: 'animation',
|
|
178
|
+
markers: ['aos'],
|
|
179
|
+
advice: 'Simple reveal classes; an IntersectionObserver hook plus CSS transitions is enough.',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: 'split-text',
|
|
183
|
+
label: 'Split text effects',
|
|
184
|
+
kind: 'animation',
|
|
185
|
+
markers: ['split-text'],
|
|
186
|
+
text: /SplitText|SplitType|splitting/i,
|
|
187
|
+
advice: 'Split headings into line/word/char spans in React and stagger them with CSS delays.',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: 'swiper',
|
|
191
|
+
label: 'Swiper / Splide carousel',
|
|
192
|
+
kind: 'animation',
|
|
193
|
+
globals: ['Swiper'],
|
|
194
|
+
markers: ['swiper', 'splide'],
|
|
195
|
+
advice: 'Use the same library in React or embla-carousel; copy breakpoints from the scripts.',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: 'page-transitions',
|
|
199
|
+
label: 'Barba / Swup page transitions',
|
|
200
|
+
kind: 'animation',
|
|
201
|
+
globals: ['barba', 'swup'],
|
|
202
|
+
advice: 'Landing-page-only clones can ignore cross-page transitions; keep the intro animation.',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: 'three',
|
|
206
|
+
label: 'three.js / WebGL',
|
|
207
|
+
kind: 'graphics',
|
|
208
|
+
globals: ['THREE'],
|
|
209
|
+
text: /WebGLRenderer|THREE\.REVISION|__THREE__/,
|
|
210
|
+
advice: 'Use @react-three/fiber or plain three. Shaders are in the captured scripts (search for gl_FragColor / void main); port them verbatim when possible.',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: 'ogl',
|
|
214
|
+
label: 'OGL / raw WebGL',
|
|
215
|
+
kind: 'graphics',
|
|
216
|
+
text: /gl_FragColor|precision (highp|mediump) float/,
|
|
217
|
+
advice: 'Raw shader code is present in the bundle; lift it into a small WebGL canvas component.',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
id: 'pixi',
|
|
221
|
+
label: 'PixiJS',
|
|
222
|
+
kind: 'graphics',
|
|
223
|
+
globals: ['PIXI'],
|
|
224
|
+
text: /pixi\.js|PIXI\.Application/,
|
|
225
|
+
advice: 'Use pixi.js in a canvas effect component.',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: 'spline',
|
|
229
|
+
label: 'Spline 3D',
|
|
230
|
+
kind: 'graphics',
|
|
231
|
+
markers: ['spline'],
|
|
232
|
+
url: /prod\.spline\.design|\.splinecode/,
|
|
233
|
+
advice: 'Embed the same .splinecode scene with @splinetool/react-spline.',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: 'rive',
|
|
237
|
+
label: 'Rive',
|
|
238
|
+
kind: 'media',
|
|
239
|
+
globals: ['rive'],
|
|
240
|
+
url: /\.riv(\?|$)|rive\.wasm/,
|
|
241
|
+
advice: 'Reuse the captured .riv files with @rive-app/canvas and the same state machine names.',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'lottie',
|
|
245
|
+
label: 'Lottie',
|
|
246
|
+
kind: 'media',
|
|
247
|
+
globals: ['lottie'],
|
|
248
|
+
markers: ['lottie-player'],
|
|
249
|
+
url: /\.lottie(\?|$)|lottie.*\.json/,
|
|
250
|
+
advice: 'Reuse the captured animation JSON with lottie-web or @lottiefiles/dotlottie-react.',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: 'canvas',
|
|
254
|
+
label: 'Canvas drawing',
|
|
255
|
+
kind: 'graphics',
|
|
256
|
+
advice: 'Canvas output is code, not markup: find the drawing code in the scripts and rebuild it as a canvas component. Match it with screenshots.',
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
id: 'video',
|
|
260
|
+
label: 'Video backgrounds',
|
|
261
|
+
kind: 'media',
|
|
262
|
+
advice: 'Reuse the captured video files; play only in view and respect reduced motion.',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: 'scroll-driven-css',
|
|
266
|
+
label: 'CSS scroll-driven animations',
|
|
267
|
+
kind: 'css',
|
|
268
|
+
css: ['scroll-driven-animations'],
|
|
269
|
+
text: /animation-timeline\s*:/,
|
|
270
|
+
advice: 'Pure CSS (animation-timeline: scroll()/view()). Reuse the original rules; runtime-set custom properties may need calibrating per viewport.',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: 'tailwind',
|
|
274
|
+
label: 'Tailwind CSS',
|
|
275
|
+
kind: 'css',
|
|
276
|
+
css: ['tailwind'],
|
|
277
|
+
text: /--tw-[a-z]/,
|
|
278
|
+
advice: 'The compiled stylesheet can be reused as-is with the original class names.',
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
id: 'view-transitions',
|
|
282
|
+
label: 'View transitions',
|
|
283
|
+
kind: 'css',
|
|
284
|
+
css: ['view-transitions'],
|
|
285
|
+
advice: 'document.startViewTransition with matching view-transition-name rules.',
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: 'sticky',
|
|
289
|
+
label: 'Sticky / pinned sections',
|
|
290
|
+
kind: 'css',
|
|
291
|
+
css: ['position-sticky'],
|
|
292
|
+
advice: 'Pinned sections are tall wrappers with a sticky child; match wrapper heights exactly.',
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
export function detectStack({ fingerprint, urls, texts }) {
|
|
296
|
+
const signals = [];
|
|
297
|
+
for (const rule of RULES) {
|
|
298
|
+
const evidence = [];
|
|
299
|
+
for (const name of rule.globals ?? []) {
|
|
300
|
+
if (fingerprint.globals.includes(name))
|
|
301
|
+
evidence.push(`window.${name}`);
|
|
302
|
+
}
|
|
303
|
+
for (const name of rule.markers ?? []) {
|
|
304
|
+
if (fingerprint.markers.includes(name))
|
|
305
|
+
evidence.push(`DOM marker: ${name}`);
|
|
306
|
+
}
|
|
307
|
+
for (const name of rule.css ?? []) {
|
|
308
|
+
if (fingerprint.cssFeatures.includes(name))
|
|
309
|
+
evidence.push(`stylesheet: ${name}`);
|
|
310
|
+
}
|
|
311
|
+
if (rule.url) {
|
|
312
|
+
const hit = urls.find((url) => rule.url?.test(url));
|
|
313
|
+
if (hit)
|
|
314
|
+
evidence.push(`request: ${hit}`);
|
|
315
|
+
}
|
|
316
|
+
if (rule.text) {
|
|
317
|
+
for (const [url, text] of texts) {
|
|
318
|
+
if (rule.text.test(text)) {
|
|
319
|
+
evidence.push(`code: ${url}`);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (rule.id === 'canvas' && fingerprint.canvases.length) {
|
|
325
|
+
evidence.push(`${fingerprint.canvases.length} <canvas> element(s)`);
|
|
326
|
+
}
|
|
327
|
+
if (rule.id === 'video' && fingerprint.videos.length) {
|
|
328
|
+
evidence.push(`${fingerprint.videos.length} <video> element(s)`);
|
|
329
|
+
}
|
|
330
|
+
if (evidence.length) {
|
|
331
|
+
signals.push({
|
|
332
|
+
id: rule.id,
|
|
333
|
+
label: rule.label,
|
|
334
|
+
kind: rule.kind,
|
|
335
|
+
evidence,
|
|
336
|
+
advice: rule.advice,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return signals;
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/domain/stack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { nodeStyles } from './snapshot.js';
|
|
2
|
+
class Counter {
|
|
3
|
+
#map = new Map();
|
|
4
|
+
add(value, weight = 1) {
|
|
5
|
+
if (value === undefined || value === '' || weight <= 0)
|
|
6
|
+
return;
|
|
7
|
+
this.#map.set(value, (this.#map.get(value) ?? 0) + weight);
|
|
8
|
+
}
|
|
9
|
+
top(limit, minUses = 1, order = 'uses') {
|
|
10
|
+
const entries = [...this.#map]
|
|
11
|
+
.filter(([, uses]) => uses >= minUses)
|
|
12
|
+
.map(([value, uses]) => ({ value, uses: Math.round(uses) }))
|
|
13
|
+
.sort((a, b) => b.uses - a.uses || a.value.localeCompare(b.value))
|
|
14
|
+
.slice(0, limit);
|
|
15
|
+
return order === 'px'
|
|
16
|
+
? entries.sort((a, b) => px(a.value) - px(b.value) || a.value.localeCompare(b.value))
|
|
17
|
+
: entries;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const px = (value) => {
|
|
21
|
+
const number = Number.parseFloat(value);
|
|
22
|
+
return Number.isFinite(number) ? number : Number.MAX_SAFE_INTEGER;
|
|
23
|
+
};
|
|
24
|
+
const transparent = (value) => /^(transparent|rgba\(0, 0, 0, 0\))$/.test(value);
|
|
25
|
+
const isZero = (value) => /^(0px|0|auto|normal|none)$/.test(value);
|
|
26
|
+
/** Splits multi-value timing strings like `opacity 0.3s ease, transform 0.6s cubic-bezier(…)`. */
|
|
27
|
+
export function timingParts(transition) {
|
|
28
|
+
const durations = [];
|
|
29
|
+
const easings = [];
|
|
30
|
+
for (const part of transition.split(/,(?![^(]*\))/)) {
|
|
31
|
+
for (const match of part.matchAll(/(cubic-bezier\([^)]*\)|steps\([^)]*\)|linear\([^)]*\)|ease-in-out|ease-in|ease-out|ease|linear)|(\d*\.?\d+m?s)/g)) {
|
|
32
|
+
if (match[1])
|
|
33
|
+
easings.push(match[1]);
|
|
34
|
+
else if (match[2] && match[2] !== '0s')
|
|
35
|
+
durations.push(match[2]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { durations, easings };
|
|
39
|
+
}
|
|
40
|
+
/** Design scales from computed styles of laid-out, visible elements in the main document. */
|
|
41
|
+
export function extractTokens(snapshot, extraEasings = []) {
|
|
42
|
+
const text = new Counter();
|
|
43
|
+
const background = new Counter();
|
|
44
|
+
const border = new Counter();
|
|
45
|
+
const families = new Counter();
|
|
46
|
+
const sizes = new Counter();
|
|
47
|
+
const weights = new Counter();
|
|
48
|
+
const lineHeights = new Counter();
|
|
49
|
+
const letterSpacings = new Counter();
|
|
50
|
+
const spacing = new Counter();
|
|
51
|
+
const radii = new Counter();
|
|
52
|
+
const shadows = new Counter();
|
|
53
|
+
const containers = new Counter();
|
|
54
|
+
const zIndices = new Counter();
|
|
55
|
+
const easings = new Counter();
|
|
56
|
+
const durations = new Counter();
|
|
57
|
+
const doc = snapshot.documents[0];
|
|
58
|
+
if (doc) {
|
|
59
|
+
const textLength = new Map();
|
|
60
|
+
for (const node of doc.nodes) {
|
|
61
|
+
if (node.t === 3 && node.text)
|
|
62
|
+
textLength.set(node.p, (textLength.get(node.p) ?? 0) + node.text.trim().length);
|
|
63
|
+
}
|
|
64
|
+
for (const node of doc.nodes) {
|
|
65
|
+
if (node.t !== 1 || !node.box || !node.s)
|
|
66
|
+
continue;
|
|
67
|
+
const [, , width, height] = node.box;
|
|
68
|
+
if (width <= 0 || height <= 0)
|
|
69
|
+
continue;
|
|
70
|
+
const style = nodeStyles(snapshot, node);
|
|
71
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0')
|
|
72
|
+
continue;
|
|
73
|
+
const chars = textLength.get(node.i) ?? 0;
|
|
74
|
+
if (chars > 0) {
|
|
75
|
+
const weight = Math.min(chars, 400);
|
|
76
|
+
text.add(style.color, weight);
|
|
77
|
+
families.add(style['font-family']?.split(',')[0]?.replace(/["']/g, '').trim(), weight);
|
|
78
|
+
sizes.add(style['font-size'], weight);
|
|
79
|
+
weights.add(style['font-weight'], weight);
|
|
80
|
+
lineHeights.add(style['line-height'], weight);
|
|
81
|
+
if (style['letter-spacing'] && style['letter-spacing'] !== 'normal')
|
|
82
|
+
letterSpacings.add(style['letter-spacing'], weight);
|
|
83
|
+
}
|
|
84
|
+
const bg = style['background-color'];
|
|
85
|
+
if (bg && !transparent(bg))
|
|
86
|
+
background.add(bg, Math.sqrt(width * height));
|
|
87
|
+
if (style['border-top-style'] &&
|
|
88
|
+
style['border-top-style'] !== 'none' &&
|
|
89
|
+
!isZero(style['border-top-width'] ?? '0')) {
|
|
90
|
+
border.add(style['border-top-color']);
|
|
91
|
+
}
|
|
92
|
+
for (const prop of [
|
|
93
|
+
'padding-top',
|
|
94
|
+
'padding-right',
|
|
95
|
+
'padding-bottom',
|
|
96
|
+
'padding-left',
|
|
97
|
+
'margin-top',
|
|
98
|
+
'margin-bottom',
|
|
99
|
+
'gap',
|
|
100
|
+
'row-gap',
|
|
101
|
+
'column-gap',
|
|
102
|
+
]) {
|
|
103
|
+
const value = style[prop];
|
|
104
|
+
if (value && !isZero(value) && value.endsWith('px') && px(value) > 0)
|
|
105
|
+
spacing.add(value);
|
|
106
|
+
}
|
|
107
|
+
const radius = style['border-top-left-radius'];
|
|
108
|
+
if (radius && !isZero(radius))
|
|
109
|
+
radii.add(radius);
|
|
110
|
+
const shadow = style['box-shadow'];
|
|
111
|
+
if (shadow && shadow !== 'none')
|
|
112
|
+
shadows.add(shadow);
|
|
113
|
+
const maxWidth = style['max-width'];
|
|
114
|
+
if (maxWidth && maxWidth !== 'none' && maxWidth.endsWith('px') && px(maxWidth) >= 480)
|
|
115
|
+
containers.add(maxWidth);
|
|
116
|
+
const z = style['z-index'];
|
|
117
|
+
if (z && z !== 'auto' && style.position !== 'static')
|
|
118
|
+
zIndices.add(z);
|
|
119
|
+
const timing = timingParts(style.transition ?? '');
|
|
120
|
+
for (const easing of timing.easings)
|
|
121
|
+
easings.add(easing);
|
|
122
|
+
for (const duration of timing.durations)
|
|
123
|
+
durations.add(duration);
|
|
124
|
+
if (style['animation-timing-function'] &&
|
|
125
|
+
style['animation-name'] &&
|
|
126
|
+
style['animation-name'] !== 'none') {
|
|
127
|
+
easings.add(style['animation-timing-function']);
|
|
128
|
+
durations.add(style['animation-duration']);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const easing of extraEasings)
|
|
133
|
+
easings.add(easing);
|
|
134
|
+
return {
|
|
135
|
+
colors: { text: text.top(16), background: background.top(16), border: border.top(10) },
|
|
136
|
+
fontFamilies: families.top(8),
|
|
137
|
+
fontSizes: sizes.top(16, 1, 'px'),
|
|
138
|
+
fontWeights: weights.top(8, 1, 'px'),
|
|
139
|
+
lineHeights: lineHeights.top(12),
|
|
140
|
+
letterSpacings: letterSpacings.top(8),
|
|
141
|
+
spacing: spacing.top(20, 2, 'px'),
|
|
142
|
+
radii: radii.top(10, 1, 'px'),
|
|
143
|
+
shadows: shadows.top(8),
|
|
144
|
+
containerWidths: containers.top(8, 1, 'px'),
|
|
145
|
+
zIndices: zIndices.top(10, 1, 'px'),
|
|
146
|
+
easings: easings.top(12),
|
|
147
|
+
durations: durations.top(10, 1, 'px'),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const slug = (index, prefix) => `--${prefix}-${String(index + 1)}`;
|
|
151
|
+
/** CSS custom properties for the rebuild's tokens.css. */
|
|
152
|
+
export function tokensCss(tokens) {
|
|
153
|
+
const lines = [
|
|
154
|
+
'/* Generated by multiclone from computed styles. Rename freely. */',
|
|
155
|
+
':root {',
|
|
156
|
+
];
|
|
157
|
+
const group = (title, prefix, entries) => {
|
|
158
|
+
if (!entries.length)
|
|
159
|
+
return;
|
|
160
|
+
lines.push(` /* ${title} */`);
|
|
161
|
+
entries.forEach((entry, index) => {
|
|
162
|
+
lines.push(` ${slug(index, prefix)}: ${entry.value};`);
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
group('Text colors (most used first)', 'color-text', tokens.colors.text);
|
|
166
|
+
group('Background colors', 'color-bg', tokens.colors.background);
|
|
167
|
+
group('Border colors', 'color-border', tokens.colors.border);
|
|
168
|
+
group('Font families', 'font', tokens.fontFamilies.map((entry) => ({ ...entry, value: `'${entry.value}'` })));
|
|
169
|
+
group('Font sizes (small → large)', 'text', tokens.fontSizes);
|
|
170
|
+
group('Font weights', 'weight', tokens.fontWeights);
|
|
171
|
+
group('Line heights', 'leading', tokens.lineHeights);
|
|
172
|
+
group('Letter spacing', 'tracking', tokens.letterSpacings);
|
|
173
|
+
group('Spacing (small → large)', 'space', tokens.spacing);
|
|
174
|
+
group('Radii', 'radius', tokens.radii);
|
|
175
|
+
group('Shadows', 'shadow', tokens.shadows);
|
|
176
|
+
group('Container widths', 'container', tokens.containerWidths);
|
|
177
|
+
group('Z-index', 'z', tokens.zIndices);
|
|
178
|
+
group('Easings', 'ease', tokens.easings);
|
|
179
|
+
group('Durations', 'duration', tokens.durations);
|
|
180
|
+
lines.push('}', '');
|
|
181
|
+
return lines.join('\n');
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/domain/tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/domain/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const DESKTOP = { name: 'desktop', width: 1440, height: 900, mobile: false };
|
|
2
|
+
export const MOBILE = { name: 'mobile', width: 390, height: 844, mobile: true };
|
|
3
|
+
/** Parses `desktop`, `mobile` or `name:WIDTHxHEIGHT` (mobile when narrower than 768px). */
|
|
4
|
+
export function parseViewport(spec) {
|
|
5
|
+
const value = spec.trim();
|
|
6
|
+
if (value === 'desktop')
|
|
7
|
+
return DESKTOP;
|
|
8
|
+
if (value === 'mobile')
|
|
9
|
+
return MOBILE;
|
|
10
|
+
const match = /^(?:([a-z0-9-]+):)?(\d+)x(\d+)$/i.exec(value);
|
|
11
|
+
if (!match?.[2] || !match[3]) {
|
|
12
|
+
throw new Error(`Bad viewport "${spec}". Use desktop, mobile or name:1280x800.`);
|
|
13
|
+
}
|
|
14
|
+
const width = Number(match[2]);
|
|
15
|
+
const height = Number(match[3]);
|
|
16
|
+
return { name: match[1] ?? `${width}x${height}`, width, height, mobile: width < 768 };
|
|
17
|
+
}
|
|
18
|
+
export function parseViewports(spec) {
|
|
19
|
+
if (!spec)
|
|
20
|
+
return [DESKTOP, MOBILE];
|
|
21
|
+
return spec
|
|
22
|
+
.split(',')
|
|
23
|
+
.filter((part) => part.trim() !== 'auto')
|
|
24
|
+
.map(parseViewport);
|
|
25
|
+
}
|
|
26
|
+
/** `auto` in a viewport list asks capture to add one viewport per major CSS breakpoint. */
|
|
27
|
+
export const wantsAutoViewports = (spec) => spec?.split(',').some((part) => part.trim() === 'auto') ?? false;
|
|
28
|
+
/**
|
|
29
|
+
* One viewport just inside each major breakpoint not already covered (within 60px) by `existing`.
|
|
30
|
+
* Widths are taken 1px below the breakpoint so `max-width` rules apply and `min-width` ones don't.
|
|
31
|
+
*/
|
|
32
|
+
export function breakpointViewports(widths, existing) {
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const width of [...widths].sort((a, b) => a - b)) {
|
|
35
|
+
const target = width - 1;
|
|
36
|
+
if (target < 320 || target > 2560)
|
|
37
|
+
continue;
|
|
38
|
+
if ([...existing, ...out].some((viewport) => Math.abs(viewport.width - target) <= 60))
|
|
39
|
+
continue;
|
|
40
|
+
const mobile = target < 768;
|
|
41
|
+
out.push({ name: `bp${String(target)}`, width: target, height: mobile ? 844 : 900, mobile });
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=viewports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewports.js","sourceRoot":"","sources":["../../src/domain/viewports.ts"],"names":[],"mappings":"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"}
|