Skip to content

Commit 4e87f28

Browse files
ukimsanovclaude
andcommitted
fix: address PR heygen-com#339 review — 7 issues
1. Catalog failure safety: warn when catalog is empty or throws, so capture doesn't silently produce zero images 2. Dead path: extract-audio-data.py → skills/gsap/scripts/ (was skills/hyperframes/scripts/) 3. --json fonts compat: emit both `fonts` (string[]) and `fontsDetailed` (FontToken[]) to avoid breaking external consumers 4. Restore .cursorrules writing alongside AGENTS.md + CLAUDE.md 5. .gitignore: remove over-broad `projects/` and `videos/` entries, keep scoped `cursor-tests/` and `launch-video*/` 6. agentPromptGenerator: mark unused params as reserved with comments, remove _animations from buildPrompt 7. Cookie filter: threshold 20 → 8 chars to preserve footer copy like "© 2026 Stripe" (16 chars) and "Privacy & Terms" (15 chars) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 517e327 commit 4e87f28

7 files changed

Lines changed: 21 additions & 22 deletions

File tree

.gitignore

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,8 @@ captures/
7979
*-tour/
8080
*-brand/
8181

82-
# Local regression-test scratch directories (website-to-hyperframes runs).
83-
# These hold per-site captures, SCRIPT/STORYBOARD/DESIGN.md, compositions,
84-
# narration audio, rendered MP4s — all reproducible, never commit.
82+
# Local regression-test and video project scratch directories.
83+
# These hold per-site captures, compositions, narration audio, rendered MP4s.
8584
cursor-tests/
8685
basecamp-video/
87-
projects/
88-
videos/
86+
launch-video*/

packages/cli/src/capture/agentPromptGenerator.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,22 @@ export function generateAgentPrompt(
2020
outputDir: string,
2121
url: string,
2222
tokens: DesignTokens,
23-
animations: AnimationCatalog | undefined,
23+
_animations: AnimationCatalog | undefined, // reserved for future animation summary
2424
hasScreenshot: boolean,
2525
hasLottie?: boolean,
2626
hasShaders?: boolean,
27-
_catalogedAssets?: CatalogedAsset[],
27+
_catalogedAssets?: CatalogedAsset[], // reserved for future asset inventory
2828
detectedLibraries?: string[],
2929
): void {
30-
const prompt = buildPrompt(
31-
url,
32-
tokens,
33-
animations,
34-
hasScreenshot,
35-
hasLottie,
36-
hasShaders,
37-
detectedLibraries,
38-
);
30+
const prompt = buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries);
3931
writeFileSync(join(outputDir, "AGENTS.md"), prompt, "utf-8");
4032
writeFileSync(join(outputDir, "CLAUDE.md"), prompt, "utf-8");
33+
writeFileSync(join(outputDir, ".cursorrules"), prompt, "utf-8");
4134
}
4235

4336
function buildPrompt(
4437
url: string,
4538
tokens: DesignTokens,
46-
_animations: AnimationCatalog | undefined,
4739
hasScreenshot: boolean,
4840
hasLottie?: boolean,
4941
hasShaders?: boolean,

packages/cli/src/capture/assetDownloader.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export async function downloadAssets(
5757
}
5858

5959
// 3. Images — use the catalog as the single source of truth (highest resolution, deduplicated)
60+
// If the catalog is empty, asset download produces zero images — this is surfaced as a warning
61+
// so the capture doesn't silently produce a half-empty dataset.
6062
const imageUrls: { url: string; isPoster: boolean }[] = [];
6163

6264
if (catalogedAssets && catalogedAssets.length > 0) {

packages/cli/src/capture/contentExtractor.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@ export async function extractVisibleText(page: Page): Promise<string> {
134134
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;
135135
var tag = el.tagName.toLowerCase();
136136
if (tag === 'script' || tag === 'style' || tag === 'noscript') continue;
137-
// Skip short text inside nav/footer (catches nav links, cookie consent)
137+
// Skip very short text inside nav/footer (catches single-word nav links)
138+
// Threshold is 8 chars to preserve footer copy like "© 2026 Stripe" (16 chars)
138139
var inNavOrFooter = el.closest('nav, footer, [role="navigation"]');
139-
if (inNavOrFooter && text.length < 20) continue;
140+
if (inNavOrFooter && text.length < 8) continue;
140141
// Skip common cookie/consent patterns
141142
if (cookieRe.test(text)) continue;
142143
texts.push('[' + tag + '] ' + text);

packages/cli/src/capture/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,13 @@ export async function captureWebsite(
339339
const { catalogAssets } = await import("./assetCataloger.js");
340340
catalogedAssets = await catalogAssets(page1);
341341
progress("design", `${catalogedAssets.length} assets cataloged`);
342+
if (catalogedAssets.length === 0) {
343+
warnings.push(
344+
"Asset catalog is empty — no images will be downloaded. The page may use non-standard image loading.",
345+
);
346+
}
342347
} catch (err) {
343-
warnings.push(`Asset cataloging failed: ${err}`);
348+
warnings.push(`Asset cataloging failed (no images will be downloaded): ${err}`);
344349
}
345350

346351
// ── MUTATION phase: extractHtml modifies the live DOM (converts images to data URLs) ──

packages/cli/src/commands/capture.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ export default defineCommand({
115115
screenshots: result.screenshots.length,
116116
assets: result.assets.length,
117117
detectedSections: result.tokens.sections.length,
118-
fonts: result.tokens.fonts,
118+
fonts: result.tokens.fonts.map((f) => f.family),
119+
fontsDetailed: result.tokens.fonts,
119120
animations: result.animationCatalog?.summary,
120121
warnings: result.warnings,
121122
},

skills/website-to-hyperframes/references/techniques.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ for (var f = 0; f < AUDIO_DATA.totalFrames; f++) {
367367
Per-frame sampling is required — a single tween will not react. Use the extract script:
368368

369369
```bash
370-
python3 skills/hyperframes/scripts/extract-audio-data.py narration.wav --fps 30 --bands 16 -o audio-data.json
370+
python3 skills/gsap/scripts/extract-audio-data.py narration.wav --fps 30 --bands 16 -o audio-data.json
371371
```
372372

373373
Keep text/logo intensity subtle (≤5% scale, ≤30% glow) — audio-reactive motion on tiny elements reads as jitter. Bigger backgrounds can push to 10–30%.

0 commit comments

Comments
 (0)