launchframe 0.1.5 → 0.1.6
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 +61 -34
- package/package.json +1 -1
- package/packages/extract/dom-crawler.ts +521 -0
- package/packages/extract/emit.ts +2 -2
- package/packages/extract/extract.ts +66 -16
- package/packages/extract/mirror-emit.ts +522 -0
- package/packages/extract/types.ts +118 -0
|
@@ -170,6 +170,120 @@ export interface DesignSystem {
|
|
|
170
170
|
notes: string[];
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/* -------------------------------------------------------------------------- */
|
|
174
|
+
/* Layout mirror (per-site) */
|
|
175
|
+
/* -------------------------------------------------------------------------- */
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Structural roles a top-level section can play. Inferred heuristically from
|
|
179
|
+
* geometry, content kinds, and document position — not from the source's
|
|
180
|
+
* class names.
|
|
181
|
+
*/
|
|
182
|
+
export type SectionRole =
|
|
183
|
+
| "nav"
|
|
184
|
+
| "hero"
|
|
185
|
+
| "feature-grid"
|
|
186
|
+
| "feature-deep-dive"
|
|
187
|
+
| "proof-logos"
|
|
188
|
+
| "proof-quotes"
|
|
189
|
+
| "pricing"
|
|
190
|
+
| "conversion"
|
|
191
|
+
| "footer"
|
|
192
|
+
| "other";
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Coarse composition shape used by the emitter to pick a wrapper layout.
|
|
196
|
+
*/
|
|
197
|
+
export type Composition =
|
|
198
|
+
| "single-column"
|
|
199
|
+
| "split-2"
|
|
200
|
+
| "grid-2"
|
|
201
|
+
| "grid-3"
|
|
202
|
+
| "grid-4"
|
|
203
|
+
| "list"
|
|
204
|
+
| "logo-row"
|
|
205
|
+
| "unknown";
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The kinds of content a section can hold. The emitter renders an
|
|
209
|
+
* appropriately-styled placeholder (`<TextSlot>` / `<MediaSlot>`) per slot
|
|
210
|
+
* so the user fills in their own copy and assets.
|
|
211
|
+
*/
|
|
212
|
+
export type SlotKind =
|
|
213
|
+
| "heading-1"
|
|
214
|
+
| "heading-2"
|
|
215
|
+
| "heading-3"
|
|
216
|
+
| "eyebrow"
|
|
217
|
+
| "body"
|
|
218
|
+
| "bullet"
|
|
219
|
+
| "button-primary"
|
|
220
|
+
| "button-secondary"
|
|
221
|
+
| "image"
|
|
222
|
+
| "logo-mono"
|
|
223
|
+
| "icon"
|
|
224
|
+
| "code"
|
|
225
|
+
| "badge"
|
|
226
|
+
| "input"
|
|
227
|
+
| "video";
|
|
228
|
+
|
|
229
|
+
export interface SlotCount {
|
|
230
|
+
kind: SlotKind;
|
|
231
|
+
count: number;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* A single top-level section in document order. Geometry is normalized to
|
|
236
|
+
* [0, 1] over the rendered page so the emitter can compare relative weight.
|
|
237
|
+
*/
|
|
238
|
+
export interface SectionLayout {
|
|
239
|
+
/** Stable id assigned in document order: s1, s2, ... */
|
|
240
|
+
id: string;
|
|
241
|
+
role: SectionRole;
|
|
242
|
+
composition: Composition;
|
|
243
|
+
density: "thin" | "balanced" | "dense";
|
|
244
|
+
/** Bounding box [x, y, w, h] normalized to [0, 1] over the rendered page. */
|
|
245
|
+
bbox: [number, number, number, number];
|
|
246
|
+
/** Aggregated content-kind counts inside the section. */
|
|
247
|
+
slots: SlotCount[];
|
|
248
|
+
/** Per-section style hints; the emitter applies these as inline overrides. */
|
|
249
|
+
styles: {
|
|
250
|
+
backgroundHex: string | null;
|
|
251
|
+
foregroundHex: string | null;
|
|
252
|
+
paddingTopPx: number | null;
|
|
253
|
+
paddingBottomPx: number | null;
|
|
254
|
+
};
|
|
255
|
+
/** Free-form notes the emitter surfaces in `MIRROR_NOTES.md`. */
|
|
256
|
+
notes: string[];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Page-level computed-style tokens. These complement the synthesized
|
|
261
|
+
* `DesignSystem` so a mirror page can apply a site-specific theme without
|
|
262
|
+
* the system having to reseed the cross-corpus palette.
|
|
263
|
+
*/
|
|
264
|
+
export interface SiteTokens {
|
|
265
|
+
bodyFontFamily: string;
|
|
266
|
+
headingFontFamily: string;
|
|
267
|
+
backgroundHex: string;
|
|
268
|
+
foregroundHex: string;
|
|
269
|
+
primaryHex: string;
|
|
270
|
+
mutedHex: string;
|
|
271
|
+
borderHex: string;
|
|
272
|
+
radiusPx: number;
|
|
273
|
+
containerPx: number | null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export interface SiteLayout {
|
|
277
|
+
url: string;
|
|
278
|
+
host: string;
|
|
279
|
+
capturedAt: string;
|
|
280
|
+
viewport: { width: number; height: number };
|
|
281
|
+
/** Full rendered page height in CSS pixels. */
|
|
282
|
+
pageHeightPx: number;
|
|
283
|
+
sections: SectionLayout[];
|
|
284
|
+
tokens: SiteTokens;
|
|
285
|
+
}
|
|
286
|
+
|
|
173
287
|
/* -------------------------------------------------------------------------- */
|
|
174
288
|
/* Run summary */
|
|
175
289
|
/* -------------------------------------------------------------------------- */
|
|
@@ -180,6 +294,10 @@ export interface SiteCapture {
|
|
|
180
294
|
capturedAt: string;
|
|
181
295
|
screenshotPath: string;
|
|
182
296
|
rawTokensPath: string;
|
|
297
|
+
/** Path to the per-site `SiteLayout` JSON, if the mirror crawl succeeded. */
|
|
298
|
+
layoutPath?: string;
|
|
299
|
+
/** Path to the per-site mirror page directory, if emission succeeded. */
|
|
300
|
+
mirrorDir?: string;
|
|
183
301
|
status: "ok" | "skipped" | "failed";
|
|
184
302
|
reason?: string;
|
|
185
303
|
}
|