launchframe 0.1.13 → 0.2.1

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 (72) hide show
  1. package/README.md +143 -175
  2. package/bin/launchframe.mjs +234 -30
  3. package/package.json +52 -65
  4. package/template/.aider.conf.yml +3 -0
  5. package/template/.amazonq/cli-agents/clone-website.json +9 -0
  6. package/template/.amazonq/rules/project.md +156 -0
  7. package/template/.augment/commands/clone-website.md +516 -0
  8. package/template/.claude/skills/clone-website/SKILL.md +515 -0
  9. package/template/.clinerules +156 -0
  10. package/template/.codex/skills/clone-website/SKILL.md +515 -0
  11. package/template/.continue/commands/clone-website.md +517 -0
  12. package/template/.continue/rules/project.md +160 -0
  13. package/template/.cursor/commands/clone-website.md +512 -0
  14. package/template/.cursor/rules/project.mdc +7 -0
  15. package/template/.dockerignore +60 -0
  16. package/template/.gemini/commands/clone-website.toml +518 -0
  17. package/template/.gitattributes +9 -0
  18. package/template/.github/ISSUE_TEMPLATE/bug_report.yml +86 -0
  19. package/template/.github/ISSUE_TEMPLATE/config.yml +5 -0
  20. package/template/.github/ISSUE_TEMPLATE/feature_request.yml +50 -0
  21. package/template/.github/PULL_REQUEST_TEMPLATE.md +19 -0
  22. package/template/.github/copilot-instructions.md +156 -0
  23. package/template/.github/copilot-setup-steps.yml +3 -0
  24. package/template/.github/skills/clone-website/SKILL.md +515 -0
  25. package/template/.github/workflows/ci.yml +36 -0
  26. package/template/.nvmrc +1 -0
  27. package/template/.opencode/commands/clone-website.md +515 -0
  28. package/template/.windsurf/workflows/clone-website.md +512 -0
  29. package/template/.windsurfrules +2 -0
  30. package/template/AGENTS.md +74 -0
  31. package/template/CHANGELOG.md +80 -0
  32. package/template/CLAUDE.md +1 -0
  33. package/template/Dockerfile +114 -0
  34. package/template/Dockerfile.dev +15 -0
  35. package/template/GEMINI.md +1 -0
  36. package/template/README.md +129 -0
  37. package/template/components.json +25 -0
  38. package/template/docker-compose.yml +53 -0
  39. package/template/docs/design-references/.gitkeep +0 -0
  40. package/template/docs/design-references/comparison.png +0 -0
  41. package/template/docs/research/INSPECTION_GUIDE.md +80 -0
  42. package/template/eslint.config.mjs +18 -0
  43. package/template/next.config.ts +8 -0
  44. package/template/package.json +59 -0
  45. package/template/postcss.config.mjs +7 -0
  46. package/template/public/images/.gitkeep +0 -0
  47. package/template/public/seo/.gitkeep +0 -0
  48. package/template/public/videos/.gitkeep +0 -0
  49. package/template/scripts/.gitkeep +0 -0
  50. package/template/scripts/sync-agent-rules.sh +88 -0
  51. package/template/scripts/sync-skills.mjs +111 -0
  52. package/template/src/app/favicon.ico +0 -0
  53. package/template/src/app/globals.css +130 -0
  54. package/template/src/app/layout.tsx +33 -0
  55. package/template/src/app/page.tsx +9 -0
  56. package/template/src/components/ui/button.tsx +60 -0
  57. package/template/src/hooks/.gitkeep +0 -0
  58. package/template/src/lib/utils.ts +6 -0
  59. package/template/src/types/.gitkeep +0 -0
  60. package/template/tsconfig.json +34 -0
  61. package/packages/extract/automated-clone-pass.ts +0 -353
  62. package/packages/extract/browser-extract.ts +0 -237
  63. package/packages/extract/cloner-research-emit.ts +0 -270
  64. package/packages/extract/dom-crawler.ts +0 -521
  65. package/packages/extract/emit.ts +0 -553
  66. package/packages/extract/extract.ts +0 -547
  67. package/packages/extract/host-slug.ts +0 -5
  68. package/packages/extract/mirror-emit.ts +0 -620
  69. package/packages/extract/package.json +0 -13
  70. package/packages/extract/reference-dump.ts +0 -431
  71. package/packages/extract/synthesize.ts +0 -551
  72. package/packages/extract/types.ts +0 -316
@@ -1,270 +0,0 @@
1
- /**
2
- * Emits research artifacts under each extract run, aligned in layout and intent
3
- * with the AI Website Cloner template (topology, behaviors bible, per-section
4
- * specs). Values are derived from Launchframe's automated crawl where available;
5
- * interactive sweeps still require manual Browser MCP work for full fidelity.
6
- */
7
-
8
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
- import { dirname, join } from "node:path";
10
-
11
- import type { ExtractionRun, SectionLayout, SiteLayout } from "./types.js";
12
- import { hostSlug } from "./host-slug.js";
13
-
14
- export function emitClonerResearch(
15
- run: ExtractionRun,
16
- layoutsByHost: Map<string, SiteLayout>,
17
- ): string[] {
18
- const written: string[] = [];
19
- const root = join(run.outputDir, "docs", "research");
20
- mkdirSync(root, { recursive: true });
21
-
22
- written.push(
23
- writeFile(
24
- join(root, "README.md"),
25
- emitResearchReadme(run, layoutsByHost.size > 0),
26
- ),
27
- );
28
-
29
- for (const cap of run.captures) {
30
- if (cap.status !== "ok") continue;
31
- const layout = layoutsByHost.get(cap.host);
32
- const hostDir = join(root, hostSlug(cap.host));
33
- mkdirSync(join(hostDir, "components"), { recursive: true });
34
-
35
- written.push(
36
- writeFile(join(hostDir, "PAGE_TOPOLOGY.md"), emitTopology(cap.url, cap.host, layout)),
37
- );
38
- written.push(
39
- writeFile(
40
- join(hostDir, "BEHAVIORS.md"),
41
- emitBehaviors(cap.url, cap.host, run, layout),
42
- ),
43
- );
44
-
45
- if (layout) {
46
- for (const section of layout.sections) {
47
- const name = `${section.id}-${section.role}`.replace(/[^a-z0-9-]+/gi, "-");
48
- written.push(
49
- writeFile(
50
- join(hostDir, "components", `${name}.spec.md`),
51
- emitSectionSpec(cap.host, layout, section),
52
- ),
53
- );
54
- }
55
- }
56
- }
57
-
58
- return written;
59
- }
60
-
61
- function writeFile(path: string, body: string): string {
62
- mkdirSync(dirname(path), { recursive: true });
63
- writeFileSync(path, body, "utf8");
64
- return path;
65
- }
66
-
67
- function automatedJsonAppend(outputDir: string, host: string): string {
68
- const slug = hostSlug(host);
69
- const base = join(outputDir, "docs", "design-references", slug);
70
- const probe = join(base, "header-scroll-probe.json");
71
- const hints = join(base, "interaction-hints.json");
72
- const chunks: string[] = [];
73
- if (existsSync(probe)) {
74
- chunks.push("\n### Embedded: header-scroll-probe.json\n\n```json\n");
75
- chunks.push(readFileSync(probe, "utf8").trimEnd());
76
- chunks.push("\n```\n");
77
- }
78
- if (existsSync(hints)) {
79
- chunks.push("\n### Embedded: interaction-hints.json\n\n```json\n");
80
- chunks.push(readFileSync(hints, "utf8").trimEnd());
81
- chunks.push("\n```\n");
82
- }
83
- const manifest = join(outputDir, "downloaded_assets", slug, "manifest.json");
84
- if (existsSync(manifest)) {
85
- chunks.push(
86
- `\n### Asset downloads\n\nLocal manifest: \`downloaded_assets/${slug}/manifest.json\`\n`,
87
- );
88
- }
89
- return chunks.join("");
90
- }
91
-
92
- function emitResearchReadme(run: ExtractionRun, hasLayouts: boolean): string {
93
- const idea =
94
- run.saasIdea?.trim() ||
95
- "_No SaaS idea passed. Re-run with:_ `npx launchframe <url> \"your idea\"` _or_ `--idea \"...\"`.";
96
-
97
- const layoutNote = hasLayouts
98
- ? ""
99
- : "\n**Note:** No `SiteLayout` was available for any host (DOM crawl may have failed). Topology files are stubbed; rely on `reference/<host>/` + tokens.\n";
100
-
101
- return `# Research artifacts
102
-
103
- This folder mirrors the **artifact roles** of [ai-website-cloner-template](https://github.com/JCodesMore/ai-website-cloner-template) (\`PAGE_TOPOLOGY.md\`, \`BEHAVIORS.md\`, \`components/*.spec.md\`) so coding agents can follow the same **recon → specs → build** cadence.
104
-
105
- **Run:** \`${run.runId}\`
106
- **Output:** \`${run.outputDir.replace(/\\/g, "/")}\`
107
-
108
- ## Operator SaaS idea
109
-
110
- ${idea}
111
-
112
- ## Per-host paths
113
-
114
- For each captured host: \`<host>/PAGE_TOPOLOGY.md\`, \`<host>/BEHAVIORS.md\`, \`<host>/components/*.spec.md\`
115
-
116
- Screenshots for visual QA live in \`../design-references/<host-slug>/\` (multi-viewport + scroll sweep). Downloaded binaries (when enabled): \`../downloaded_assets/<host-slug>/manifest.json\`.
117
- ${layoutNote}`;
118
- }
119
-
120
- function emitTopology(url: string, host: string, layout: SiteLayout | undefined): string {
121
- const lines: string[] = [
122
- `# Page topology`,
123
- ``,
124
- `- **URL:** ${url}`,
125
- `- **Host:** ${host}`,
126
- `- **Generated by:** Launchframe automated crawl (primary viewport + optional responsive passes under \`docs/design-references/\`)`,
127
- ``,
128
- `## Section order (top → bottom)`,
129
- ``,
130
- ];
131
-
132
- if (!layout?.sections.length) {
133
- lines.push(
134
- `_No section model — see \`reference/${host}/structure-outline.txt\` and \`dom-structure.json\`._`,
135
- );
136
- return lines.join("\n");
137
- }
138
-
139
- for (const s of layout.sections) {
140
- const [x, y, w, h] = s.bbox;
141
- lines.push(
142
- `### ${s.id} — ${s.role}`,
143
- `- **Composition:** ${s.composition}`,
144
- `- **Density:** ${s.density}`,
145
- `- **BBox (normalized):** x=${x.toFixed(3)}, y=${y.toFixed(3)}, w=${w.toFixed(3)}, h=${h.toFixed(3)}`,
146
- `- **Slots:** ${s.slots.map((sl) => `${sl.kind}×${sl.count}`).join(", ") || "_none_"}`,
147
- `- **Notes:** ${s.notes.join("; ") || "—"}`,
148
- ``,
149
- );
150
- }
151
-
152
- lines.push(
153
- `## Fixed / sticky overlays`,
154
- ``,
155
- `_Not inferred automatically. Inspect \`reference/${host}/page.html\` or re-scan with Browser MCP per [clone-website skill](https://github.com/JCodesMore/ai-website-cloner-template/blob/master/.claude/skills/clone-website/SKILL.md)._`,
156
- ``,
157
- );
158
-
159
- return lines.join("\n");
160
- }
161
-
162
- function emitBehaviors(
163
- url: string,
164
- host: string,
165
- run: ExtractionRun,
166
- layout: SiteLayout | undefined,
167
- ): string {
168
- const vpLine = layout?.viewport
169
- ? `${layout.viewport.width}×${layout.viewport.height}px`
170
- : "See crawl viewport in run.json / raw/*.layout.json";
171
-
172
- return `# Behaviors bible
173
-
174
- - **URL:** ${url}
175
- - **Capture viewport:** ${vpLine}
176
-
177
- ## What Launchframe captured automatically
178
-
179
- - Single desktop pass in headless Chromium with **reduced motion** forced for deterministic screenshots.
180
- - **Automated multi-viewport + scroll sweep** PNGs under \`docs/design-references/${hostSlug(host)}/\` (desktop/tablet/mobile + scroll frames).
181
- - **Header scroll probe** (\`header-scroll-probe.json\`) and **interaction hints** (\`interaction-hints.json\`) — check for scroll-driven chrome, Lenis-like wrappers, scroll-snap.
182
- - Computed-style tokens and a typed **section scaffold** when DOM crawl succeeds (\`raw/${host}.layout.json\`, \`mirror/${host}/page.tsx\`).
183
- ${automatedJsonAppend(run.outputDir, host)}
184
-
185
- ## What still needs a manual interaction sweep
186
-
187
- Use Browser MCP (or the upstream **clone-website** workflow) to fill gaps — match their checklist:
188
-
189
- 1. **Scroll sweep** — header shrink, scroll-driven tabs, scroll-snap, sticky sidebars, Lenis / Locomotive markers.
190
- 2. **Click sweep** — modals, dropdowns, tab panels; extract **every** tab state.
191
- 3. **Hover sweep** — transitions (duration + easing), not just before/after colors.
192
- 4. **Responsive sweep** — 1440 / 768 / 390 viewports with breakpoint notes.
193
-
194
- Document findings below as you discover them.
195
-
196
- ## Recorded behaviors (manual)
197
-
198
- | Area | Interaction model | Trigger | State A | State B | Transition |
199
- |------|---------------------|---------|---------|---------|------------|
200
- | _(empty)_ | | | | | |
201
-
202
- ---
203
-
204
- ## Operator SaaS idea
205
-
206
- ${run.saasIdea?.trim() || "_Pass `--idea` or a second positional string when invoking launchframe._"}
207
-
208
- When rebuilding UI, preserve **interaction models** from this table (once filled); rewrite **copy** to match the SaaS idea without impersonating the reference brand.
209
- `;
210
- }
211
-
212
- function emitSectionSpec(host: string, layout: SiteLayout, s: SectionLayout): string {
213
- const mirrorHint = `mirror/${host}/page.tsx — section marker starts with \`${s.id}:\` inside data-mirror-section`;
214
- const slotsMd = s.slots.map((sl) => `- **${sl.kind}** × ${sl.count}`).join("\n");
215
-
216
- return `# Section specification — ${s.id}
217
-
218
- ## Overview
219
-
220
- - **Source URL:** ${layout.url}
221
- - **Mirror:** \`${mirrorHint}\`
222
- - **Interaction model:** _unknown — infer via scroll-first sweep per clone-website skill; default treated as **static** for this automated extract._
223
-
224
- ## Section summary
225
-
226
- - **Role:** ${s.role}
227
- - **Composition:** ${s.composition}
228
- - **Density:** ${s.density}
229
-
230
- ## Layout hints (from crawl)
231
-
232
- ### Container style hints
233
-
234
- - **Background:** ${s.styles.backgroundHex ?? "—"}
235
- - **Foreground:** ${s.styles.foregroundHex ?? "—"}
236
- - **Padding block:** top ${s.styles.paddingTopPx ?? "—"}px / bottom ${s.styles.paddingBottomPx ?? "—"}px
237
-
238
- ### Site tokens (page-level)
239
-
240
- - **Body font:** ${layout.tokens.bodyFontFamily}
241
- - **Heading font:** ${layout.tokens.headingFontFamily}
242
- - **Background / foreground:** ${layout.tokens.backgroundHex} / ${layout.tokens.foregroundHex}
243
- - **Primary:** ${layout.tokens.primaryHex}
244
- - **Radius:** ${layout.tokens.radiusPx}px
245
-
246
- ## Slots (mirror placeholders)
247
-
248
- ${slotsMd || "_None_"}
249
-
250
- Fill each \`<TextSlot>\` / \`<MediaSlot>\` using **verbatim** strings from \`reference/${host}/visible-text.txt\` only when you own rights or are authorized; otherwise substitute original copy aligned with the operator SaaS idea.
251
-
252
- ## States & behaviors
253
-
254
- _N/A for automated single-state crawl — add rows after MCP extraction._
255
-
256
- ## Assets
257
-
258
- - Crawl index: \`reference/${host}/media.json\` (respect licensing).
259
- - When downloads ran (no \`--no-download\`): \`downloaded_assets/${hostSlug(host)}/manifest.json\` maps remote URLs to \`files/*\`.
260
-
261
- ## Responsive behavior
262
-
263
- Automated PNGs live under \`docs/design-references/${hostSlug(host)}/\` (tablet 768×900, mobile 390×844, scroll sweep). Refine breakpoints using those artifacts alongside the mirror scaffold.
264
-
265
- ## Text content
266
-
267
- See \`reference/${host}/visible-text.json\` / \`.txt\`. Map strings into slots by section order and landmark roles.
268
-
269
- `;
270
- }