feat(lint): font loading + invalid capture path composition rules#989
feat(lint): font loading + invalid capture path composition rules#989ukimsanov wants to merge 1 commit into
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
miguel-heygen
left a comment
There was a problem hiding this comment.
Clean lint rules. google_fonts_import catches both and @import. font_family_without_font_face correctly skips generics, producer-bundled fonts, and font-family inside @font-face blocks. invalid_capture_path scoped correctly — only flags ../capture/ traversal. Tests comprehensive (12 cases).
jrusso1020
left a comment
There was a problem hiding this comment.
Approve at 06e71a39. Magi covered the test count (148 → 151) + producer-bundled-font / generic-family skip lists. Additive:
-
invalid_capture_pathrule scope — counts../capture/matches across HTML + CSS + inline scripts and reports total. Registry source files + installed blocks exempted via existingisRegistrySourceFile/isRegistryInstalledFileguards. Worth confirming: are there legitimate top-level project files (e.g., atools/script) that reference../capture/for off-line preview reasons? If yes, they'd hit this rule. Counter-evidence: this is a lint rule (not a build error), so it surfaces as feedback rather than gating, mitigating false-positive damage. -
google_fonts_importrule fix-hint — points tocapture/assets/fonts/...woff2(root-relative). One thing to verify against hf#988's capture pipeline: doescapture/assets/fonts/actually land at the root-relative path the fix hint claims, OR is it undercapture/extracted/fonts/? Cross-PR consistency between the rule's fix-hint and the capture pipeline's actual output directory will save users an "I followed the hint and it 404'd" moment. -
font_family_without_font_facerule — auto-bundled font set check is solid. The fallback-to-system-ui silent failure was a real eval-blocker; this catches it at lint time. ✓ -
Test coverage — 11 new tests for fonts + 3 for the capture-path rule. Both rules have explicit positive AND negative cases (e.g., auto-bundled families stay clean) — that's the right shape for a lint rule.
Stack base correctly set to feat/capture-pipeline-improvements.
— Rames Jusso
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
Two new composition lint rules catching failure modes that recurred across the 11-round website-to-video eval. Both ship with vitest coverage; total lint suite goes from 148 to 151 tests. **`fonts.ts` (new) — two warnings** - `google_fonts_import`: composition loads fonts from `fonts.googleapis.com` via `<link>` or `@import url(...)`. External font requests fail in sandboxed/offline renders and add latency. Fix hint points to root-relative `capture/assets/fonts/...woff2` with a local `@font-face` declaration. - `font_family_without_font_face`: CSS uses a font-family that isn't declared with `@font-face` and isn't in the auto-bundled font set (Inter, JetBrains Mono, etc.). Text would silently fall back to system-ui — the visual fidelity loss the eval kept hitting. Fix hint points to the captured woff2 files. **`composition.ts` invalid_capture_path (new) — one error** Sub-compositions live in `compositions/` but get served with the project root as their base URL. `<img src="../capture/...">` works on disk but 404s in Studio and renders. Errors with a fix hint saying replace `../capture/` with root-relative `capture/`. Three vitest cases: `<img>` triggers, multi-occurrence url()s are counted, root-relative paths stay clean. Registry source files and installed blocks are exempted. **Wiring** `hyperframeLinter.ts` runs the new fonts rules alongside the existing rule set; the composition rule was added inline so it picks up automatically.
29baca1 to
eeacacc
Compare
Three concrete bugs found while auditing PR #991: 1. html-in-canvas-patterns.md (#1 in catalog, 3D Rotation with Bloom): The code example used `new THREE.EffectComposer(renderer)` UMD-style namespace access while the ESM imports right below pull them in as bare named imports. Three.js r150+ removed the UMD `examples/js/` globals, so as written the example throws `TypeError: THREE.EffectComposer is not a constructor`. Switched to the bare names matching the imports. THREE.Vector2 stays as-is — Vector2 is on the THREE namespace. 2. techniques.md (#5, Lottie Animation): The CDN path `@lottiefiles/dotlottie-web/dist/dotlottie-player.js` returns 404. `@lottiefiles/dotlottie-web` is the JavaScript SDK, not a web component — its `main` is `dist/index.cjs`. The web-component package is `@lottiefiles/dotlottie-wc` and the custom element is `<dotlottie-wc>`, not `<dotlottie-player>`. Updated both. 3. techniques.md (5 occurrences across Lottie / lottie-web / Video / @font-face examples): asset paths used the `../capture/` pattern that PR #989's `invalid_capture_path` lint rule emits an error for. Replaced all with root-relative `capture/...`. PRs #989 and #991 are no longer self-contradictory.
06e71a3 to
e8d2da6
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed after rebase (e8d2da6e).
Same content as before — just rebased onto the updated stack. Five files, all additive: fonts.ts (150 lines), fonts.test.ts (121 lines), composition.ts (invalid_capture_path rule), composition.test.ts (3 test cases), hyperframeLinter.ts (wiring). No content changes from the previously approved version.
Still good. Ship it.

What
Two new composition lint rules catching real failure modes from the website-to-video eval. Total lint suite goes from 148 to 151 tests; all 151 pass.
3 of 5 in the pipeline-quality stack. Stacked on #988.
Why
Both rules were chosen because the failure modes recurred across multiple eval rounds:
<link href="https://fonts.googleapis.com/css2?...">in compositions. Works locally; fails in sandboxed/offline renders, adds latency, and isn't deterministic.@font-face— CSS used a font-family with no declaration and no entry in the auto-bundled set. Text silently fell back to system-ui. Visual fidelity loss across multiple v2 videos (Mercury fonts, GeistMono, "Inter Variable").../capture/paths — Sub-compositions live incompositions/but are served with the project root as their base URL.<img src="../capture/logo.svg">works on disk but 404s in Studio and renders. Four of six framer sub-agents got this wrong; mercury had four of five.How
packages/core/src/lint/rules/fonts.ts(new)google_fonts_import— warning. Detects<link>tofonts.googleapis.comand@import url(...fonts.googleapis.com...). Fix hint points to root-relativecapture/assets/fonts/...woff2with a local@font-facedeclaration.font_family_without_font_face— warning. Checks every used family against@font-facedeclarations + the auto-bundled font set. Fix hint also points to root-relativecapture/assets/fonts/.packages/core/src/lint/rules/composition.tsinvalid_capture_path— error. Counts../capture/matches across the entire file (HTML + CSS + inline scripts) and reports the total. Registry source files and installed blocks are exempted via the existingisRegistrySourceFile/isRegistryInstalledFileguards.Tests
fonts.test.ts(new) — 11 tests covering Google Fonts in<link>and@import, undeclared families, auto-bundled families staying clean.composition.test.ts— three new cases forinvalid_capture_path:<img>triggers, multi-occurrence url()s counted, root-relativecapture/clean.Wiring —
hyperframeLinter.tsruns the new fonts rules alongside the existing rule set.Test plan
../capture/paths produces the expected error.