mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
docs(registry,skills): surface code-highlight 0-based indexing and opacity-reveal sweep guidance (#2418)
* docs(registry,skills): surface code-highlight 0-based indexing and opacity-reveal sweep guidance From the 2026-07-14 CLI feedback digest (skills-owner action): a user building code teaching videos hit two authoring gaps. 1. code-highlight's `line` is intentionally zero-based (`line: 1` = second displayed line) but the warning lived only in pr-to-video's code-vocabulary reference — nowhere an author actually touches the value. Call it out at the block-use sites: the `__BLOCK` declaration itself, the registry-item description, and the motion-graphics catalog map. 2. Opacity-only code-typing tripped `sweep_static` for that user, who worked around it with a slow host y-drift. The sweep fingerprint does include per-element opacity, so document the actual trap (a reveal that settles before the sampled window, then holds a static frame) and the idiomatic fixes (spread the reveal / keep a blinking caret alive) in the check reference — and pin the fingerprint's opacity sensitivity with a regression test covering both the visibility-floor crossing and a mid-fade value change. * docs(catalog): regenerate code-highlight page from updated registry-item description Only the code-highlight page is committed: a full generate-catalog-pages run also surfaces ~34 blocks missing from the git-tracked catalog index (pre-existing drift on main), which belongs in its own chore PR.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: "Code Highlight Sweep"
|
||||
description: "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line."
|
||||
description: "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line. `line` is 0-based: `line: 1` targets the second displayed line (unlike code-scroll, whose target is 1-based)."
|
||||
---
|
||||
|
||||
# Code Highlight Sweep
|
||||
|
||||
A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line.
|
||||
A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line. `line` is 0-based: `line: 1` targets the second displayed line (unlike code-scroll, whose target is 1-based).
|
||||
|
||||
`code` `code-animation` `highlight` `developer`
|
||||
|
||||
|
||||
@@ -63,6 +63,49 @@ describe("layout-audit.browser", () => {
|
||||
expect(after).not.toBe(before);
|
||||
});
|
||||
|
||||
// Opacity-reveal fixture (CLI feedback digest 2026-07-14): code-typing style
|
||||
// scenes reveal pre-laid-out characters via opacity only — no geometry ever
|
||||
// moves. The sweep fingerprint must treat that as motion, both while a glyph
|
||||
// fades (opacity value changes) and when it crosses the 0.2 visibility floor
|
||||
// (element enters the signature); otherwise `check` misfires `sweep_static`
|
||||
// and authors reach for geometry hacks (a slow host y-drift) to pass.
|
||||
it("changes the sweep fingerprint when text reveals via opacity alone", () => {
|
||||
document.body.innerHTML = `
|
||||
<div id="root" data-composition-id="main" data-width="640" data-height="360">
|
||||
<div id="code"><span id="char">c</span></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
let charOpacity = "0";
|
||||
installGeometry(
|
||||
{
|
||||
root: rect({ left: 0, top: 0, width: 640, height: 360 }),
|
||||
code: rect({ left: 40, top: 40, width: 560, height: 48 }),
|
||||
char: rect({ left: 40, top: 40, width: 18, height: 48 }),
|
||||
},
|
||||
{
|
||||
char: {
|
||||
get opacity() {
|
||||
return charOpacity;
|
||||
},
|
||||
} as Partial<CSSStyleDeclaration>,
|
||||
},
|
||||
);
|
||||
|
||||
installAuditScript();
|
||||
const collect = (window as unknown as { __hyperframesLayoutGeometry: () => string })
|
||||
.__hyperframesLayoutGeometry;
|
||||
|
||||
const hidden = collect(); // below the 0.2 visibility floor — not in the signature
|
||||
charOpacity = "0.5";
|
||||
const fading = collect(); // mid-fade — present, opacity part of the signature
|
||||
charOpacity = "1";
|
||||
const revealed = collect(); // settled
|
||||
|
||||
expect(fading).not.toBe(hidden);
|
||||
expect(revealed).not.toBe(fading);
|
||||
});
|
||||
|
||||
it("uses authored canvas dimensions when the root bounding rect is degenerate", () => {
|
||||
document.body.innerHTML = `
|
||||
<div id="root" data-composition-id="main" data-width="640" data-height="360">
|
||||
|
||||
@@ -536,6 +536,9 @@
|
||||
id: "code-highlight",
|
||||
effect: "highlight",
|
||||
seq: "feature",
|
||||
// `line` is ZERO-BASED: line: 1 highlights the SECOND displayed line
|
||||
// (gutter 2). Note code-scroll's target is 1-based — don't carry a
|
||||
// value between the two blocks without re-checking it.
|
||||
line: 1,
|
||||
duration: 5,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "code-highlight",
|
||||
"type": "hyperframes:block",
|
||||
"title": "Code Highlight Sweep",
|
||||
"description": "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line.",
|
||||
"description": "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line. `line` is 0-based: `line: 1` targets the second displayed line (unlike code-scroll, whose target is 1-based).",
|
||||
"dimensions": {
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"files": 102
|
||||
},
|
||||
"hyperframes-cli": {
|
||||
"hash": "bc0feefa2255c5e1",
|
||||
"hash": "1065ea34fecfda50",
|
||||
"files": 11
|
||||
},
|
||||
"hyperframes-core": {
|
||||
@@ -50,7 +50,7 @@
|
||||
"files": 133
|
||||
},
|
||||
"motion-graphics": {
|
||||
"hash": "1aee662a16dedc08",
|
||||
"hash": "cc93e3d220a0ebf5",
|
||||
"files": 23
|
||||
},
|
||||
"music-to-video": {
|
||||
|
||||
@@ -56,7 +56,7 @@ One command, one Chrome boot. `check` runs the linter first and skips the browse
|
||||
|
||||
Every finding carries a selector, the element's `data-*` identity, the composition source file, a bbox, and the sample time: jump straight from the JSON to the HTML you must edit and re-run.
|
||||
|
||||
**Severity is persistence-aware.** A dynamic issue observed at a single grid sample (an entrance/exit transient) demotes to info and never gates. Issues held across samples gate the exit code, a held `content_overlap` is an error, and a held, partially-visible `canvas_overflow` breaching ≥5% of the canvas promotes to warning. Coordinate-frame findings (`escaped_container`, `panel_out_of_canvas`, `connector_detached`) flag geometry computed in one frame but rendered in another — an element far outside its offset parent, a painted panel stuck across the canvas edge, a connector line detached from every node. If a 3s+ composition shows zero geometry change across every sample, `check` fails with `sweep_static`: a frozen timeline makes every green verdict unreliable, so it refuses to pass.
|
||||
**Severity is persistence-aware.** A dynamic issue observed at a single grid sample (an entrance/exit transient) demotes to info and never gates. Issues held across samples gate the exit code, a held `content_overlap` is an error, and a held, partially-visible `canvas_overflow` breaching ≥5% of the canvas promotes to warning. Coordinate-frame findings (`escaped_container`, `panel_out_of_canvas`, `connector_detached`) flag geometry computed in one frame but rendered in another — an element far outside its offset parent, a painted panel stuck across the canvas edge, a connector line detached from every node. If a 3s+ composition shows zero geometry change across every sample, `check` fails with `sweep_static`: a frozen timeline makes every green verdict unreliable, so it refuses to pass. The fingerprint includes per-element opacity, so opacity-only reveals (code typing, staggered fades) count as motion — but only while they're still in flight at the sampled times. The classic trap is a reveal that completes early and then holds a static frame for the rest of the duration: every sample lands on the settled state and the run fails. Spread the reveal across the timeline or keep one continuously animated element alive (a blinking caret is idiomatic for code typing) — don't bolt on a slow position drift just to appease the check.
|
||||
|
||||
**Escape hatches** (mark intent in the HTML, then re-run):
|
||||
|
||||
|
||||
@@ -10,19 +10,19 @@ After classifying intent → category, the **Director names the block(s) + what
|
||||
|
||||
## Category → block(s)
|
||||
|
||||
| Category | Borrow from catalog | Customize | Gaps → hand-author |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
||||
| **kinetic-typo** | one of **18 `caption-*`** (kinetic-slam, editorial-emphasis, clip-wipe, gradient-fill, neon-glow, glitch-rgb, matrix-decode, particle-burst, weight-shift, pill-karaoke, highlight, blend-difference…) | words; `emphasis_words` → `word--emphasis`; palette; font; timing | a motif none of the 18 cover |
|
||||
| **charts** | `data-chart` (bar+line, staggered, value labels) | edit the data array + headline/subtitle; `--bg`/`--text` | pie/donut, bar-chart-race, ring/% |
|
||||
| **stat** | `apple-money-count` (finance: $ counter + burst + SFX) **or** our generic `stat-motion` (any %/number + ring) | target, prefix/suffix, label, palette | — |
|
||||
| maps/geo | **vector lane**: `us-map` (+bubble/hex/flow), `world-map`, `spain-map` + **hand-author** `geo-highlight`/`geo-flow`/`flag-borders`/`pin-rollout` (NOT in registry — build per `categories/maps/module.md`). **basemap lane** (real satellite/dark / zoom-to-place): bake via `categories/maps/bake-basemap.mjs` → `<video>` + geo-aligned SVG overlay (border draw-on + colour-block fills) | regions/data, palette, callouts/connectors, basemap style | (basemap lane now covers real imagery + zoom-to-address — was the gap) |
|
||||
| diagram | `flowchart` (SVG connectors + nodes) | nodes, edges, labels | — |
|
||||
| **code / code-reveal** | one of the **9 Code Animations** blocks: `code-typing` (live typing), `code-diff` (a change), `code-morph` (a refactor), `code-highlight` (spotlight a line), `code-scroll` (walk a file), `code-snippet-flight` (assemble); GPU hero reveals `code-3d-extrude` / `code-shader-dissolve` / `code-particle-assemble` for a title-card moment; for a static themed code/terminal window use a `code-snippet-*` block | the baked code string / diff / theme | a code motion none cover |
|
||||
| **brand reveal** | `logo-outro` (piece assembly + glow + tagline + URL pill) | logo asset, tagline, URL, palette | — |
|
||||
| transitions | 15+ shader transitions (domain-warp, whip-pan, sdf-iris, glitch…) | direction, timing | — |
|
||||
| social overlay | ig / tiktok / yt / x / reddit / spotify / macos cards | handle, metrics, avatar | — |
|
||||
| polish | grain-overlay, vignette, shimmer-sweep, texture-mask-text | intensity | — |
|
||||
| **asset-fusion (RWA)** | **annotation kit from `north-korea-locked-down`** — scribble-circle draw-on, pop-up pill + pointer, red-wash, scanline, corners, camera push; + `us-map-bubble` callouts/connectors | asset, annotation position (`element_positions`), label, palette **eyedropper'd from the asset** | **NET-NEW (not in catalog): the affordance binding — asset geometry _becomes_ the chart axis (straw → gauge)** |
|
||||
| Category | Borrow from catalog | Customize | Gaps → hand-author |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
||||
| **kinetic-typo** | one of **18 `caption-*`** (kinetic-slam, editorial-emphasis, clip-wipe, gradient-fill, neon-glow, glitch-rgb, matrix-decode, particle-burst, weight-shift, pill-karaoke, highlight, blend-difference…) | words; `emphasis_words` → `word--emphasis`; palette; font; timing | a motif none of the 18 cover |
|
||||
| **charts** | `data-chart` (bar+line, staggered, value labels) | edit the data array + headline/subtitle; `--bg`/`--text` | pie/donut, bar-chart-race, ring/% |
|
||||
| **stat** | `apple-money-count` (finance: $ counter + burst + SFX) **or** our generic `stat-motion` (any %/number + ring) | target, prefix/suffix, label, palette | — |
|
||||
| maps/geo | **vector lane**: `us-map` (+bubble/hex/flow), `world-map`, `spain-map` + **hand-author** `geo-highlight`/`geo-flow`/`flag-borders`/`pin-rollout` (NOT in registry — build per `categories/maps/module.md`). **basemap lane** (real satellite/dark / zoom-to-place): bake via `categories/maps/bake-basemap.mjs` → `<video>` + geo-aligned SVG overlay (border draw-on + colour-block fills) | regions/data, palette, callouts/connectors, basemap style | (basemap lane now covers real imagery + zoom-to-address — was the gap) |
|
||||
| diagram | `flowchart` (SVG connectors + nodes) | nodes, edges, labels | — |
|
||||
| **code / code-reveal** | one of the **9 Code Animations** blocks: `code-typing` (live typing), `code-diff` (a change), `code-morph` (a refactor), `code-highlight` (spotlight a line; `line` is 0-based), `code-scroll` (walk a file), `code-snippet-flight` (assemble); GPU hero reveals `code-3d-extrude` / `code-shader-dissolve` / `code-particle-assemble` for a title-card moment; for a static themed code/terminal window use a `code-snippet-*` block | the baked code string / diff / theme | a code motion none cover |
|
||||
| **brand reveal** | `logo-outro` (piece assembly + glow + tagline + URL pill) | logo asset, tagline, URL, palette | — |
|
||||
| transitions | 15+ shader transitions (domain-warp, whip-pan, sdf-iris, glitch…) | direction, timing | — |
|
||||
| social overlay | ig / tiktok / yt / x / reddit / spotify / macos cards | handle, metrics, avatar | — |
|
||||
| polish | grain-overlay, vignette, shimmer-sweep, texture-mask-text | intensity | — |
|
||||
| **asset-fusion (RWA)** | **annotation kit from `north-korea-locked-down`** — scribble-circle draw-on, pop-up pill + pointer, red-wash, scanline, corners, camera push; + `us-map-bubble` callouts/connectors | asset, annotation position (`element_positions`), label, palette **eyedropper'd from the asset** | **NET-NEW (not in catalog): the affordance binding — asset geometry _becomes_ the chart axis (straw → gauge)** |
|
||||
|
||||
## Reuse mechanics
|
||||
|
||||
|
||||
Reference in New Issue
Block a user