Skip to content

feat(registry): add 4 community components - #4906

Merged
miguel-heygen merged 8 commits into
mainfrom
sweep/registry-bundle-2026-10-02
Oct 2, 2026
Merged

miguel-heygen merged 8 commits into
mainfrom
sweep/registry-bundle-2026-10-02

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

What

Four community registry items in one PR. Each author's work lands as their own signed commit (author name, email and date kept), with fix commits on top.

Item Kind Source PR Author
cinemagraph block #4785 @carlosmirandalevy
ai-answer-rank block #4528 @tugrawork-creator
caret-swap component #3898 @AksharP5
pendulum-swing component #3764 @rottenpen

Changes on top of the authors' work

  • Item sources only: hand-added registry/registry.json entries and docs catalog pages are left out (cinemagraph via a fix commit; pendulum-swing's docs page, docs.json, catalog-index.json and registry.json hunks were dropped while replaying its commit onto current main). The catalog publish workflow generates those after merge.
  • caret-swap: the four commits of feat(registry): add caret swap text effect #3898 are landed as their net diff in one commit under the author's name, because the earlier commits added generated files that the later ones removed and they no longer replay onto main. The diff includes the author's catalog payload change: SNIPPET_PREVIEW_RENDERS_STILL becomes PREFER_AUTHORED_DEMO, and caret-swap is added to the set so its preview uses the demo's light canvas.
  • ai-answer-rank is tagged ad-template, and registryBlocks.test.ts requires every ad-template to ship a TEMPLATE.md editing contract. Added one, modelled on ai-chat-reveal and built from the item's declared variables, and listed it in the manifest.
  • pendulum-swing: formatted with oxfmt. The demo caption also moved to the bottom of the frame, because the sign's first 34deg swing covered it (hyperframes check reported content_overlap).

Verification

  • hyperframes lint and hyperframes check (CLI built from current main) on each item, mounted in a scratch project. All four have 0 lint errors.
  • check passes for cinemagraph, ai-answer-rank and caret-swap. ai-answer-rank has 3 contrast warnings, all on rows that are fading out during the re-rank.
  • pendulum-swing check still reports contrast at 1.03:1 while the sign is rotated. This is a false positive: the contrast pass takes the median pixel inside the element's axis-aligned bounding box, which for a rotated sign is mostly page background. The same text passes at rest.
  • Determinism: no unseeded randomness, no wall clock and no requestAnimationFrame. cinemagraph uses a seeded PRNG and paints its canvas from the timeline's onUpdate. The only network asset is the standard GSAP CDN script.
  • bunx oxfmt --check is clean on every item directory, and scripts/check-catalog-source-pr.mjs passes.

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 1216 (base branch 1216), smooth 1045 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (1)

tugrawork-creator and others added 7 commits October 2, 2026 11:48
…o put your brand in it

A 1080x1080, 9s block for answer-engine and AI-visibility marketing. A prompt
types into a chat card, the assistant answers with a ranked list of three picks,
then re-ranks: the promoted brand slides into its slot (brandRank 1-3), the picks
below step down, the third fades out of the list, and the brand row lands with
the one accent highlight and a drawn check. Monochrome placeholder UI; prompt,
lead-in, pick names, brand, rank, accent, ink and ground are variables.
Add a motion-primitive component that hangs content from a fixed pivot and
lets it settle with a damped oscillation, like a hanging sign coming to rest
on its hook.

The swing rides a single unitless custom property (--hf-swing-angle) that the
timeline eases 1 -> 0, so only rotation animates and it stays sub-pixel under
the seek-by-frame capture engine. The demo drives it with a damped-oscillation
ease (a cosine inside an exponential decay, normalised to land exactly upright)
so the sign passes through center several times, each pass smaller, before it
rests.

Four enum variables: pivot (top-center/left/right), amplitude
(gentle/standard/wide), direction (right/left), tone (ink/paper/accent, each a
bg/fg pair to keep AA contrast on any frame). The snippet is recipe-only and
does not own its timeline; its demo carries the same variable declaration.

Ran npx hyperframes lint/validate on both files, regenerated registry.json via
scripts/generate-registry-items.ts and the docs via
scripts/generate-catalog-pages.ts.
@miguel-heygen
miguel-heygen force-pushed the sweep/registry-bundle-2026-10-02 branch from b39c35f to de33b11 Compare October 2, 2026 15:49
@miguel-heygen
miguel-heygen marked this pull request as ready for review October 2, 2026 16:09

@somanshreddy somanshreddy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass at de33b11c. This is a comment, not an approval, and it has no blockers. Two independent passes went into it, mine and Codex's, and I checked every point below at this head. I built the CLI from this head and mounted each item in a scratch project at its install target.

What holds up

  • Lint and check.
    • hyperframes lint: 0 errors on all four items. ai-answer-rank has 2 structure warnings (file size, nested section).
    • hyperframes check: passes for cinemagraph, ai-answer-rank and caret-swap. ai-answer-rank has the 3 contrast warnings the description mentions, on rows that are fading out.
  • Tests and checker.
    • registryBlocks, registryComponents, validation and variableDefaults: 21 passed.
    • The whole src/registry/ directory: 248 passed, 1 skipped.
    • scripts/catalog/ plus generate-catalog-payloads.test.ts: 88 passed.
    • check-catalog-source-pr.mjs passes against origin/main.
  • The pendulum-swing contrast failure is a false positive, as the description says. The check reports fg rgb(250,250,250) on bg rgb(247,247,248) at 0.2 s and 1.0 s, while the sign is rotated. That "background" is the demo page, not the sign's #18181b fill. At 4.5 s, at rest, the same text passes.
  • The rename changes nothing for existing items. buildsFromSnippet is the only consumer, and ascii-render-pass and star-rating-fill are still in the set. The only behaviour change is that caret-swap now previews from its demo.
  • The variable declarations match.
    • Each item's manifest variables is identical to its HTML data-composition-variables: 10, 7 and 4 entries. So is pendulum-swing's inlined copy in demo.html.
    • ai-answer-rank's TEMPLATE.md lists all 10 ids.
    • Removing TEMPLATE.md from the manifest, or deleting the file, fails registryBlocks.test.ts.
  • caret-swap's colour variables work. It reads them as var(--caret_color), while the shared slug helper would write --caret-color. I rendered the demo with data-variable-values set to a green caret and blue text, and both applied. The runtime writes the raw --${id} on each composition root.
  • Provenance holds.
    • All four author commits keep their original author, email and date. GitHub shows them verified, with Miguel as committer.
    • The item sources match the source PRs' heads apart from the fix commits described.
    • The woff2 is Geist 1.800 with a variable weight axis from 100 to 900, so it covers 400–700. Geist-OFL.txt is the complete OFL 1.1.
  • No injection paths. Free text reaches the DOM only through textContent. Enums go through allowlists. ai-answer-rank's colours go through CSS.supports.
  • Render determinism looks fine. There's no Math.random, wall clock or requestAnimationFrame. The fonts are either bundled (Geist) or Inter, which the compiler pins.
    • cinemagraph's loop seam is clean. The frames at 0 s and 9.999 s differ by at most 2/255, against 41/255 at 5 s, and only inside the steam window.
    • ai-answer-rank's worst case still fits in 9 s. With a 90-character prompt and a 48-character lead of 24 one-letter words, the last tween ends at 8.96 s.

Worth fixing

  1. caret-swap doesn't cap to_text (caret-swap.html, the phrases and prefixes loops). Each grapheme adds a prefix, a forced getBoundingClientRect() and three timeline sets, so the cost grows faster than the text.

    • Measured snapshot times: 4 s for the default, 5 s at 2,000 characters, 72 s at 20,000.
    • Text that long is shrunk to fit 90% of the width, so it's unreadable well before it gets slow.
    • ai-answer-rank caps its strings (90/48/32), and the same here (say about 80 graphemes for both phrases) would close this. (Codex found this; I measured it.)
  2. ai-answer-rank's editing contract doesn't protect the accent (TEMPLATE.md, Protected section). The brand monogram (.aar-mono) and the check stroke are drawn in ground on top of accent. The contract only requires ink to stay legible on ground. So a pale brand accent such as yellow #fde047 on the default #fcfcfb ground follows the contract and still blanks out the "YB" tile and the check. One sentence would fix it: keep accent distinguishable from ground. (Codex found this; I confirmed the CSS.)

  3. Nothing tests the PREFER_AUTHORED_DEMO set. I removed "caret-swap" from it, and all 21 registry tests and all 88 catalog-script tests still pass. The set now carries a policy rather than two measured exceptions, so a small test asserting that these three keep demo.html would stop it changing silently. Codex flagged this too.

Lower priority

  • cinemagraph doesn't repaint during motion blur. It paints its canvas only from tl.eventCallback("onUpdate", …), and the motion-blur sampler seeks with suppressEvents: true (frameCapture.ts captureAccumulatedFrame). So with blur on, every sub-frame sample shows the same steam. 43 registry files use this same onUpdate pattern, and soft steam barely shows blur anyway, so this isn't a regression for this PR. Painting from a setter on st.t would fix it if blur matters here. (Codex found this; I confirmed the sampler.)
  • The four source PRs are still open. None of #4785, #4528, #3898 or #3764 is closed by this PR, because it has no Closes lines. Without them, those PRs stay open after this merges and could still be merged on their own.
  • hyperframes check exits 1 on pendulum-swing's shipped demo because of the contrast false positive above. It doesn't block CI today. But anyone running check on the installed component hits it. A checker issue for rotated text would help, or a note in the component.

Nits

  • The pendulum-swing caption shrank. Moving it out of the 1.4× .demo-frame takes it from an effective 15.4 px to 11 px on a 1920-wide frame, which is barely legible in the preview.
  • The "AA contrast on any frame" claim doesn't hold for accent. pendulum-swing's tones comment makes that claim, but accent pairs a fixed #0b0b0c with var(--brand), which fails on a dark brand colour.
  • Two manifests have no author. ai-answer-rank and caret-swap credit theirs, but cinemagraph and pendulum-swing don't, even though the description credits all four.
  • The font's source isn't recorded. Geist-OFL.txt names the upstream repo but not the release or file Geist-Latin.woff2 was cut from (sha256 19f9c925…). The subset has 225 code points, so non-Latin from_text/to_text falls back to system-ui. (Codex raised the provenance half.)

Where I disagreed with Codex: it voted request changes. I rated the motion-blur item lower, because the pattern is shared across the catalog and isn't new here. The other three are fixes for a follow-up commit, not blockers.

CI: green at this head (46 passed, 16 skipped).

— Somu

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving at de33b11c.

What I checked

  • Catalog scripts: SNIPPET_PREVIEW_RENDERS_STILL becomes PREFER_AUTHORED_DEMO, keeps both existing members and adds caret-swap. Nothing still refers to the old name, and buildsFromSnippet keeps the same logic.
  • Untrusted variables reach the DOM through textContent only. I found no innerHTML or insertAdjacentHTML, no eval and no fetch in any of the four items. ai-answer-rank caps every string, checks colours with CSS.supports("color", …) before setProperty, and falls back to slot 0 on a bad brandRank. caret-swap clamps font_size to 36–160 and checks font_weight against an allowlist.
  • Determinism: each item registers a paused timeline. cinemagraph paints from onUpdate with a seeded PRNG. The only network loads are the pinned GSAP 3.14.2 scripts (plus CustomEase in caret-swap).
  • Licensing: caret-swap keeps Remocn's MIT notice and the source commit link. Geist-Latin.woff2 (29.4 KB, a real WOFF2) ships with the Geist OFL 1.1 text, and both are listed in the item's files.
  • Authorship: the four feature commits keep their authors' names and emails, and the fixes on top are separate commits.
  • CI: 46 pass, 0 fail.

Nits, non-blocking

  • caret-swap's to_text / from_text have no length cap. ai-answer-rank's text(value, fallback, max) pattern would work there.
  • monogram() takes name[0], so a brand starting with an emoji or another astral character becomes half a surrogate pair. Array.from(name)[0] fixes it.

I didn't render the items or run hyperframes check myself. For those I'm relying on the description and CI.

— Rames

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 04acbb4 Oct 2, 2026
62 checks passed
@miguel-heygen
miguel-heygen deleted the sweep/registry-bundle-2026-10-02 branch October 2, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants