mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix/de-verify-wait-luts
104
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0e32ee9b56 |
ci: keep the bun cache warm and skip binary downloads in preflight (#6648)
* ci: keep the bun cache warm and skip binary downloads in preflight * test(ci): pin the single cache writer and preflight's skipped downloads * test(ci): keep the cache-writer scan out of the test body |
||
|
|
d94132e609 |
ci: a release PR runs a fast release check instead of the heavy suites (#6524)
* ci: a release PR runs a fast release check, not the heavy suites * ci: keep the release check's header within the comment limit * ci: shorten the release check's usage line * ci: trim the release check's comments * ci: the release check's classifier hands the manifest test to a helper |
||
|
|
1819276fc3 |
test: real-Chrome and CI smoke pages inline GSAP so they wait on no CDN (#6406)
* test(studio): real-Chrome tests inline GSAP so their page waits on no request * test(ci): smoke projects inline GSAP so required checks wait on no CDN |
||
|
|
603f4214ff |
fix: Remotion ports keep box sizes, the manifest hook runs after format, a drag test stops flaking (#6392)
* feat(skills): a Remotion port carries Remotion's box-sizing rule so bordered boxes keep their size * chore(skills): regenerate the skills manifest after the format pass * fix(hooks): the skills manifest is hashed after the formatter has run * test(studio): a drag is measured against the box the preview shows * test(studio): another element is read bare until it is selected |
||
|
|
35a28e913a |
ci: re-run changed test files to catch flaky tests before merge (#6339)
* ci: re-run changed test files to catch flaky tests before merge * ci: give the flake gate the full test workspace setup * ci: share the test workspace setup between the Test lanes and the flake gate * ci: split the flake gate main for the fallow complexity gate and format * ci: run node:test files with node, skip uncollected files, bound the gate's run time |
||
|
|
38afc0b013 | fix(deps): update esbuild for the security advisory (#6277) | ||
|
|
9ac16b4aa1 |
fix: install git hooks in linked worktrees (#4387) (#4722)
The prepare guard used `test -d .git`, which is false in a linked worktree where .git is a file, so lefthook install was silently skipped. Use `test -e .git` so clones and linked worktrees both install hooks while non-git directories remain a no-op. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2faf660ac1 |
fix(ci): packed consumer installs keep same-day dependency bumps on every Bun release (#6059)
* fix(ci): packed consumer installs keep same-day dependency bumps on every Bun release Bun 1.4.4 swapped the quoted package and range in its minimum-release-age error, so the retry excluded the range instead of the package and the install failed again. The package is now the token that bun's "<name>@<range> failed to resolve" line pairs with the other one, and an unrecognised message fails visibly instead of excluding the wrong name. CI installs the newest Bun when nothing pins it, which let the 1.4.4 release turn every PR's support tests red mid-day. engines.bun in the root package.json pins it for every setup-bun step that does not set a version (packageManager would make corepack's pnpm refuse the repo). * fix(ci): keep the release-age parser's doc comment to one line |
||
|
|
f5873b8089 |
ci(skills): hide retired skills on ClawHub once the sync has run (#5656)
* ci(skills): hide retired skills on ClawHub once the sync has run clawhub sync stops publishing a retired skill but leaves its last version listed. A new step inspects each RETIRED_SKILLS name under heygen-com and runs `clawhub hide --yes` with its retirement notice for the ones still listed. A hidden skill reads as not found, so later runs hide nothing; a dry run only names the skills still listed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci(skills): import the retirement manifest at the top of the unlist script Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
688229314f |
feat(skills)!: publish seven knowledge skills aligned with Studio and retire the workflow skills (#5651)
* refactor(skills): fold six domain skills into hyperframes and media-use guides
hyperframes-core, -animation, -keyframes, -creative and -studio move to
skills/hyperframes/{core,animation,keyframes,creative,studio}/, and
hyperframes-audio moves to skills/media-use/mix/. Each moved SKILL.md becomes
a frontmatter-free GUIDE.md so installers that scan recursively for SKILL.md
no longer see them as skills; the published list goes from 21 to 15.
Relative links, code paths and skill-name mentions are rewritten to the new
locations, the catalog surfaces, marketplace core-skills list, fallback core
set, module-copy targets and skills-manifest.json follow, and
`hyperframes skills update` now removes the retired skills (RETIRED_SKILLS)
when they are still installed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills): slim the core entries and give media-use a HeyGen and a free path
The four entries every run opens are rewritten to what an agent cannot infer:
hyperframes 21.8 KB to 7.7 KB, hyperframes-cli 24.8 KB to 6.9 KB,
hyperframes-registry 9.9 KB to 4.3 KB, media-use 9.7 KB to 4.9 KB. Detail moved
whole into references (routing close calls and creator edits, CLI pin upgrades,
catalog search tiers, CLI conventions and feedback reports).
- hyperframes: state table, routing, the render contract, a terminal work loop
(check, snapshot, preview before render), the desktop-app hand-off, and a
table of the folded guides.
- media-use: one table of HeyGen versus free local tools per need; HeyGen
sign-in, credits and the CLI's video-agent, avatar, clone, lipsync, translate
and clipping commands; every free path works with no account.
- scripts/check-core-skills.mjs holds entries and descriptions to budget and
checks every taught `npx hyperframes` command and path; runs in lint.
- Core entries are exempt from the formatter: its table padding cost ~1.5 KB
per entry on every run.
- Content tests follow the text to its new home.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): plugin runs skip skills update; media-use explains HeyGen sign-in and TTS setup
The smoke eval showed a presenter request never reaching media-use and the
free voiceover failing on a missing kokoro-onnx; plugin runs also ran the
skills update the plugin rules forbid.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(skills): drop a committed Python bytecode file and ignore bytecode
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills): align the entry with the Studio skills and keep the workflows' measured facts
The entry drops routing and the intent interview and carries the contract, the
editable-project rules and the work loop. Studio's format, runtimes, motion,
look and captions references come over for terminal use, frame presets move to
assets/, media-use gains Studio's mixing and local-command references, and
film.md and overlays.md keep what the workflow skills measured.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills)!: retire the workflow skills and folded guides; publish seven knowledge skills
The skill pack now publishes exactly seven skills - hyperframes,
hyperframes-cli, hyperframes-registry, media-use, figma, slideshow and
remotion-to-hyperframes - carrying knowledge, not process. The eight
workflow skills, the folded domain guides and the routing/interview
references are deleted; their measured facts already live in the
hyperframes references (format, runtimes, motion, look, captions, film,
overlays) and media-use's mixing reference.
- bake-basemap.mjs and locate.mjs move to skills/hyperframes/scripts/
(bake-basemap gains --help); extract-audio-data.py moves to
media-use/audio/scripts/ for the caption motion reference.
- skills update: the eight workflows join RETIRED_SKILLS so existing
installs prune them (by lock attribution only, since their names are
generic); naming a retired skill reports where its knowledge went and
succeeds instead of failing as unknown.
- Capture prompts point at the hyperframes skill's references/film.md;
the live-map warning names the new bake-basemap path.
- Content tests that pinned knowledge are retargeted to the kept
references; tests of deleted workflows, scripts and process go.
- Catalog surfaces, templates and docs describe the seven skills.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): resolve the local.md captions link and allow capture's output files in citations
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): regenerate the skills manifest from tracked files only
The committed media-use hash included an ignored __pycache__ bytecode file present
in the local checkout, so CI's clean checkout hashed differently.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(docs): restore generated catalog pages and docs navigation to main
Catalog PRs commit item sources only; CI regenerates the pages from the edited
registry sources. docs/docs.json is catalog navigation, so its Workflows group
rename is left for a non-catalog PR.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* build(cli): raise the CLI size budget for the skill references it bundles
The CLI bundles skills/hyperframes, which now carries the folded domain guides and
frame presets (155 KB to 1.08 MB in git). Budgets are the CI-measured size plus 5%:
packed 7526634, unpacked 22593213.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test: keep repo-sweep guards meaningful after the workflow skills left
The last shell ffprobe caller and most root index.html examples lived in retired
skills. The shell detector is now pinned on a literal command line, and the
structure-rule sweep needs more than 5 roots (11 remain) rather than 30.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills): slim figma, slideshow and remotion to the Studio shape; restore the storyboard board
slideshow 33.5 KB to 4.9, figma 18.2 to 6.2, remotion-to-hyperframes 11.0 to
4.9, each keeping the facts only it holds (the figma motion helpers, verify gate,
storyboard decoding and usage beacons; present and hand-off; the Remotion lint,
SSIM check and API map). The board page format from the storyboard recipe comes
back as hyperframes/references/storyboard.md: the desktop app's Storyboard tab
reads boards/storyboard.html by its frame, title and time classes. The entry and
the init template now say to snapshot the moments an edit changed before
replying, which the terminal eval found skipped in 22 of 38 runs.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): manifest without local bytecode; Studio's edit prompt names kept files
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): render when the person asks for the file or for no stops, not only after approval
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): keep the voiceover carve in media-use; presets stage their own fonts
Review follow-ups on #5651:
- carve.mjs and its tests move to skills/media-use/audio/scripts; the audio
docs, mixing.md and two Studio comments point there.
- code-editorial's FRAME.md says to copy its bundled WOFF2s and add the
@font-face blocks, instead of promising the retired build-frame.mjs.
- media-use states the host rule before the HeyGen sign-in steps.
- storyboard-format marks transition_in as a note the agent builds itself.
- Two stale citations (creator-editing-recipes.md, sub-compositions.md).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(skills): regenerate the manifest without local bytecode
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): the CLI render step follows step 4's rule, not approval alone
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(ci): run the core-skills check from lint again after the main merge
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills): films that tell a story start from three storylines; maps use real imagery
Opus 5.5 arm D read motion.md and applied it, but its launch film was a
feature list (pain, three feature cards, proof, logo): film.md left story
to the model. And the map case never opened film.md, so it drew Natural
Earth outlines instead of baking satellite tiles.
- references/story.md: the generic half of Studio's moment-film story and
craft (one thing, three storylines with world and device, the hook,
beats, worlds, copy, brand, tells of a generated film). The person picks
a storyline, or the agent takes its recommendation when asked for the
file or for no stops.
- The entry's work loop names the storyline step for films over ~15 s; the
references table routes stories to story.md and maps to film.md.
- film.md points at story.md and gives maps and real places a section.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): story.md follows the entry: no voiceover unless asked
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): bake-basemap starts from a globe and stops waiting out its idle timeout
The Opus 5.5 map run spent 13 of its 38 minutes on parallel bakes that
stalled and 15 more recording 300 frames, after rewriting the script because
it could only start on a flat map.
- PROJECTION=globe with a seeded starfield and atmosphere, and FROM/PAN to
turn the globe to CENTER before the dive.
- Each frame polls for loaded tiles instead of waiting for an "idle" event
that had often already fired: 30 frames went from 198-219 s to 10-13 s
locally with byte-identical frames.
- Progress prints seconds a frame and minutes left; film.md shows the globe
call and says to run one bake at a time.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): render in the foreground; wait on a detached render's log, never pgrep -f
Both Opus 5.5 explainer runs started a detached render, then waited with
`until ! pgrep -f "hyperframes render"`, which matches its own loop: each
render took 88-117 s and the wait sat for the tool's full 10 minutes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills): route each kind of film; storylines carry look and sound; add review and sound
The entry routes by request (launch, explainer, music, data, vertical, 3D,
character) to a self-contained file under references/types/, and a film
over ~15 s now gets music and sounds on its visible actions unless the
person asked for silence. Each storyline names its look and its sound, so
picking one picks both; STORYBOARD.md frames carry `reads` and `sound`.
review.md is the whole-film pass: the check warnings, the review sheets,
seven questions to look for, P0/P1/P2 notes and REVIEW.md. motion.md gains
eases by role, six title entrances, a reading-time rule and nine measured
transitions; look.md a design plan before the first scene, with presets
kept for decks and named picks. story.md adds the second default that
generated design falls into, with what to do instead.
The blank template and format.md no longer teach the fade-and-slide-up
entrance on a dark canvas.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(cli): check warns on unread lines, dead stretches, small type, empty frame 0 and silence
A coding agent cannot watch its film, so check now measures what a viewer
notices over time. A new `craft` section holds warnings only (exit 0
unless --strict), sampled on the dense 8 fps grid the overlap pass
already seeks, skipped for --range checks:
- line_unread: a reading-size line (>= 30 px tall at 1080) on screen
under 0.4 s for 1-2 words, else under 3/4 of 0.5 s + 0.3 s a word;
the film's last line needs 2 s. Short lines are re-measured between
samples to ~0.01 s before judging. Captions-track and
data-layout-ignore text are exempt.
- dead_stretch: more than 3 s where the keepsMoving liveness signature
does not change, outside the final 3 s and any data-hold element;
quiet when sweep_static fires or a whole-composition keepsMoving
assertion owns the limit.
- text_below_floor: text under 2.6% of the short side (28 px on 1080)
held 0.5 s, one finding per file listing every element.
- first_frame_empty: frame 0 paints only the background.
- film_silent: over 15 s with no unmuted audio or audible video.
Each message names the fix and the skill reference to read. keepsMoving
now also leaves the film's last 3 s (a still end card) out of its
static runs, so the two agree.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(cli): snapshot --review captures a beat sheet, seam strips and a phone sheet
snapshot --review picks the frames that show a film over time instead of
evenly spaced ones, in the same single browser session:
- review-beats.jpg: one settled frame per scene at its start + 0.3 s,
plus one per timed data-beat="name" element, labelled time and id.
Scenes are the composition's top-level timed clips and sub-composition
hosts, read like `timeline` reads rows (captions and audio excluded)
and timed by the runtime's start resolver over the live page.
- review-seam-NN.jpg: frames at -0.2, -0.1, 0, +0.1, +0.2 s around
every cut (each scene start, and any scene end no scene starts at).
- review-phone.jpg: the beat frames at 360 px wide.
--composition scopes the review to one sub-composition; with fewer than
two scenes the beats spread evenly and a note says so. snapshot also
gains --json: one envelope with every frame's path and time and, under
--review, the scenes, beats and seams behind the sheets; progress moves
to stderr.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cli): craft warnings stay out of --strict; a hold gets a real next action, not a caret
Craft findings (unread lines, dead stretches, small type, an empty first
frame, silence) are judgment calls a film may break on purpose, so
--strict keeps gating defects only. The check reference no longer
suggests a blinking caret to keep a still frame moving.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cli): review spreads beats when every scene starts together; map credits skip the type floor
A map film whose basemap and overlay both start at 0 s got one beat
frame; the even spread now keys on distinct scene starts. film.md tells
agents to mark the imagery credit data-layout-ignore and back it, since
the new type floor flagged it on the first real run.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cli): review frames each scene at its middle too, not only 0.3 s in
On the first real explainer, 0.3 s into a scene showed a bare colour
field before its title entered. Each scene longer than about a second
and a half now adds a frame at its middle, so the sheet shows what the
scene builds.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(skills): a film is built from a numeric SPEC.md, with defaults banned by name and a look test
Studied in full: flxrnc's Motion Lab (vague vs directed prompt), 0xMovez's
course, EianLu's riso skill, agentchengfeng's style samples and the two
Opus 5.5 guides. Their common point: adjectives are where the default look
lives, so the agent now writes SPEC.md before any scene (GOAL, OUTPUT,
TIME, LOOK, MOTION, SHOTS, BANNED, QA), with a number for every adjective.
spec.md bans the defaults by name, unless the brand or reference uses
them (a dark void with small things floating, glow and particles, the
cream-serif-mono-label look, fade-and-slide-up, corner brackets), and
grows that list after the first render. Each storyline gets a 3 s test of
its hero shot before the pick; a look is written as the rules of one
medium. Composition numbers: the hero fills 40% of the frame, one hero
move per shot, the shot's information in within 2.5 s then a held poster.
motion.md adds springs by damping ratio, shorter exits, overlap, stagger
and the beat grid; review.md reviews as a harsh director and grows BANNED;
vertical.md takes the riso skill's measured safe band; explainer.md the
shapes of information.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): story before look; every object reads as itself; posters only for info cards
The first spec-driven C02 swapped the dark default for a flat Swiss
poster, and the story went with it: two black bars nobody read as mirrors,
slogans instead of cause and effect, a storyline picked for its picture.
The spec now serves the story: a storyline is picked for the story a
stranger would follow, the look test asks first whether a stranger
understands what they see, and SPEC.md gains an OBJECTS line giving each
thing the material and details that make it read without a label. The
2.5 s held-poster rule is limited to information cards; in a story film
every shot causes the next. Explainers start from a person or situation
the viewer knows. Review names every object as a stranger would and
treats one that needs explaining as a P0.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): storylines are three films in words, each with a device and a form
The three storylines are pitched as text and the person picks from them;
nothing is built for a storyline before the pick, so the 3 s hero-shot
look test is gone. Ideas pair a device with a form, five or more first,
keeping the three that differ most, and the one stop states the rest in
an assumption line that names every paid item beside its free option.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* ci: list main's new embedded-captions hf-cli test among the retired workflow files
The merge with main removed it with the rest of the retired skill, and the
deletion guard rejects any removal it has not been told about.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(core): keep the audio preset comment within core's size budget
The comment's new citation to media-use's mixing reference made the published
package 14 bytes larger than its budget, which sits at main's exact size.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cli): craft keeps its own 8 fps grid; comments back within the checks
Review on #5651 found that the merge moved craft onto the overlap pass's
times, which main caps at 180, so a brief line in a long film fell between
samples and line_unread missed it. Craft now builds its own grid at 8 fps up to
600 samples, as before the merge, and a 60 s film with a line shown for 0.2 s
pins it.
The Comments check passes again: REVIEW.md and STORYLINES.md join the files a
skill writes into a project, the comment lines this branch added come back
under each file's share at the merge-base, and the audio preset comment drops
a word the check reads as history.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
||
|
|
b16d5a7063 |
fix(catalog): token-themed component previews no longer render black (#5995)
* fix(catalog): token-themed component previews no longer render black Seven components read theme tokens with no fallback, so with no theme pack they painted dark text on a black canvas, both when installed and in their live Catalog preview. They now carry exact-value fallbacks from their own demos, as the theme contract requires, and a test fails any registry item that reads a contract token bare. The Catalog's snippet preview wrapper also copies the tokens each demo sets on its mount, and paints the demo's background, so the preview wears the demo's theme. * fix(catalog): trim the preview theme helper comment * test(catalog): strip HTML comments with the parser in the theme fallback gate |
||
|
|
23e7a384b6 |
feat(registry): add echo-smear component (#5980)
* feat(registry): echo-smear engine and math tests Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * feat(registry): echo-smear demo Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * feat(registry): register echo-smear Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear copies inherit visibility and record fast Final review fixes. Copies were forced visible and escaped a hidden scene. A selector matching earlier copies re-targeted them, and copies kept data-start and data-duration. A later attach re-drew every earlier copy at each recording sample. Tests now run the engine through a fake gsap and timeline, and catch five seam mutations. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear skips targets that are not out of flow Found testing on real blocks: transitions-push and blue-sweater animate static elements. Their copies stacked in normal flow and pushed the scene 64800px down, rendering black. The snippet now warns and skips a target that is not absolute or fixed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear group keeps the target's z-index The wrapper group formed a new stacking context at z-index auto, so a target that sat above a sibling dropped below it (the cursor went under the card). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear copies live in a sibling group, like motion-blur The target is no longer wrapped, so it keeps its parent, blend mode and pointer events. Static targets smear in place; the group mirrors the target's visibility and z-index. Copies carry resolved styles, media inside is inert, and an element is attached once. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear records resolved transforms and leaves callbacks alone Poses come from the resolved transform and opacity, so xPercent and any other transform survive. Travel is measured on the element's own box, so ancestor-only motion draws no copies. The recording sweep is quiet unless callbacks: true, survives a missing root, and releases its flag. Copies share one style rule per target and are built to the peak count. The demo is pinned to the snippet by a test. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear copies follow the box, root and look of their target Copies hidden at a box change never caught up, so a static target drew at the corner. A shadow-root target threw on every seek; its rules now live in its own root. Copies show the recorded filter, clip-path and individual transform properties. No ResizeObserver, so a frame no longer depends on the first frame a worker drew. Parent perspective, border-box sizing, media children and SVG children are handled. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * test(registry): echo-smear leaves real GSAP callbacks unfired at attach Covers the blocker from review: a call or onComplete on the timeline fired during attach. Runs against real GSAP 3.15 with a removal callback; it fails if the sweep seeks with events on. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear frames do not depend on the seek path Group visibility and the copies' box are recorded in the sweep, not read live in the update. A backward seek renders the update before the target, so the live read was stale. Individual translate, rotate and scale are folded into the measured transform. An element named twice in one call is attached once. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(registry): echo-smear resolves a percentage translate against the box A computed translate of 150% was read as 150px, so count and copy placement were wrong. Percentages are now a share of the element's own width and height; a scale percentage is a factor. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
|
|
434ad8c41c |
perf(cli): a repeat check starts with the CLI and Chrome already up (#5943)
* fix(cli): the browser the CLI launches exits with it, even on kill -9 * fix(build): the root build runs on Windows * perf(cli): a repeat check runs in a process that already has the CLI and Chrome up * fix(cli): a warm check delivers all its output before it exits * fix(cli): the warm check only talks to a server that proves it is the user's The warm socket now lives in a private, owner-verified directory (XDG_RUNTIME_DIR, ~/.cache or LOCALAPPDATA) next to a 0600 token. Client and server prove the token to each other over fresh nonces before any request is sent, the request carries an HMAC of the environment instead of the environment itself, and frames are capped. * fix(cli): a warm check prints its stdout even after something went to stderr The client stopped writing frames once any frame had been written, so a check that printed a notice to stderr first lost its JSON report. * test(cli): list the warm-check client fixture as a fallow entry instead of an inline ignore * fix(cli): a check started while a warm one is busy runs cold at once on Windows The warm server stopped listening when it accepted a client. On Windows the pipe name stays alive through the served connection, so a second client's connect saw a busy pipe and waited 30 s for a free instance before running cold. It now keeps listening while serving (accept already declines anyone else) and stops when the served check finishes. * test(cli): the orphan test reads the check's own Chrome and watchdog instead of racing a poll On Windows each process listing is a PowerShell call of about a second, so a check that finishes quickly could start and close Chrome between two polls, and the test failed its own 'Chrome was seen' precondition. A fixture now records the Chrome tree and the watchdog from inside the check when its first page opens. |
||
|
|
5583ae4293 |
perf(cli): commands run without esbuild, puppeteer-core or sharp until they need them (#5930)
* perf(cli): commands run without esbuild, puppeteer-core or sharp until they need them A host that bundles the CLI can now leave these packages out: each command loads them only where it uses them, and sharp installs once on first use when it is missing. The build check fails on any static import of them again. * fix(cli): use a host's sharp from NODE_PATH and let hosts turn first-use installs off * fix(cli): capture fails when sharp is missing, and one install serves every caller A missing sharp now stops the asset download up front instead of counting every image as unavailable. Concurrent first uses share one install, a failed install is not retried in the same run, and preview thumbnails report why. Hosts can turn off installs for a list of packages, e.g. HYPERFRAMES_NO_OPTIONAL_INSTALL=sharp. * fix(cli): snapshot --describe still works without sharp, resizing only when it is installed * style(cli): format the sharp loader and its tests * build(cli): sharp is an optional dependency, so a host can ship the CLI without it * build(studio-server): keep sharp out of the bundle now that it is optional |
||
|
|
aa63a8c70d |
chore: stop the fallow audit hook from piling up base snapshots (#5882)
* chore: stop the fallow audit hook from piling up base snapshots Upgrade fallow to 3.34, which reuses one base snapshot per checkout, and prune snapshots unused for a day with its own audit-cache command. The hand-written prune script and its test go away. Also drops the unused concurrently devDependency and moves yaml, imported by a root script, to dependencies, the two findings 3.x reports on main. * chore: allow deleting the replaced fallow prune script |
||
|
|
a403ea1e8b | ci(studio): re-run an edit accuracy shard on a fresh runner when its runner is too slow (#5659) | ||
|
|
f55b366175 |
fix(build): ship NodeNext-resolvable declarations from every package (#5532)
* fix(build): ship NodeNext-resolvable declarations from every package tsc copies relative specifiers verbatim, so packages whose sources use bundler-style extensionless imports (core, inspector) published .d.ts files that a module/moduleResolution nodenext consumer cannot resolve. Core already rewrote its emitted JavaScript for this, but not its declarations. Move that rewrite to scripts/rewrite-relative-import-extensions.mjs, make it cover .d.ts too (adding .js or /index.js, and failing the build when a declaration import has no declaration), and run it after every tsc emit: core, engine, sdk, producer, aws-lambda, gcp-cloud-run and inspector. verify:packed-manifests now typechecks the clean packed consumer with skipLibCheck false and type-only imports of every typed subpath, so an unresolvable import inside a published declaration fails the gate and is attributed to its package. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ci): allow the moved core rewrite-esm-extensions script deletion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci: rebuild the edit-accuracy bench when the import-extension rewriter changes The package builds now run scripts/rewrite-relative-import-extensions.mjs, so main's edit_accuracy paths filter has to include it (check-edit-accuracy-filter test). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
9a2c1c6e80 |
ci(studio): run the edit accuracy slice on PRs and the full grid in the merge queue (#5566)
* ci(studio): run the edit accuracy slice on PRs and the full grid in the merge queue The edit accuracy gate used about 83% of CI job-minutes, ran on changes that cannot reach the bench (encoder, render and CLI command code), and never ran in the merge queue, so main could drift and fail every later PR. - Path filter: its own paths-filter step with some-with-excludes, limited to what the bench runs: Studio, studio-server, core, parsers, player, sdk, lint, the CLI preview server path, and the engine and producer modules in the import closure of browserManager, frameCapture and both fileServers. Test files, fixtures and docs no longer trigger it. The bench's webmcp-host.mjs, which it imports but the old filter missed, now does. - merge_group: the filter's base is the event's base_sha there. In the queue the full grid always runs (20 shards) whenever the filter matches. The queue is the last point before main, and nothing else measures the full grid now that PRs run a slice. Skipping it would let zoom 50/200 and rotated regressions land on main, where they fail every later PR against the banked baseline. That drift caused about a fifth of past gate failures. - PRs: the existing `pr` grid becomes zoom 100 with no rotation in both nestings (435 of 2061 cases), in 5 shards. Of the 11 PRs whose real regressions the full gate caught, this slice held a regressed case for 10. - Gate: newly passing cases missing from baseline.json are listed in the comment and as a notice, not failed (45% of past gate failures). A partial grid compares only the cases it ran. `--shards` fails the gate when a shard reported no results, and only a full grid writes a bankable baseline.json. - The required check "Studio: edit accuracy gate" keeps its name. It is skipped when the filter does not match, as before. - check-test-reachability models negated globs as exclusions under some-with-excludes and still fails closed elsewhere. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci(studio): run the edit accuracy gate when its install inputs change The path filter missed the root package.json, the dependency install script and the ffmpeg setup action, which Build and every shard run. A change to any of them could alter the bench while the gate skipped. Add them, and a test that every local input of the jobs that build and run the bench is in the filter. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci(edit-accuracy): cover transitive bench inputs in the path filter The filter test now walks the files the bench actually runs: the bench entry files, their relative and @hyperframes/* imports, the CLI commands the bench invokes, and the build scripts, configs and files those builds read for every package the bench reaches. Globs are matched with picomatch, the matcher dorny/paths-filter uses. The walk found 183 inputs the filter missed, including the producer's frameCapture.ts, build-hf-early-stub.ts and stubs/hf-early-stub.ts, the engine services behind engine/src/index.ts, and the CLI browser command. The filter now covers them. picomatch is not in the no-install Test reachability job, so the filter test moves to test:scripts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
f31b3c982b |
build(inspector): publish @hyperframes/inspector to npm (#5530)
* build(inspector): publish @hyperframes/inspector to npm * fix(inspector): drop prepack so pnpm pack --json stays parseable * fix(inspector): add .js to published declaration imports for NodeNext * fix(inspector): declare @hyperframes/parsers, which the published types import * chore(fallow): ignore @hyperframes/parsers, which inspector's published types import |
||
|
|
071ce8044f |
feat(registry): add filmed-screen component (#5487)
* feat(registry): add filmed-screen component Films a live-DOM scene like a camera pointed at a monitor: a tilted screen plane in perspective, depth of field that follows a named element, chromatic fringing, LED sub-pixels, per-shot palettes and cut tears. The focused element stays sharp. Ported from ff-tracking's lens.sksl, with each colour channel weighted by its own sample in the bokeh average. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(registry): land the filmed-screen catalog poster on the title The catalog poster is captured at min(3 s, 0.6 × duration), which was the demo's first cut, so it showed a tear over a blurred title. The first cut moves to 3.8 s and the first shot racks back to the title before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(registry): filmed-screen glides between shots and racks focus Shots now glide into each other by default: camera, palette and colour mode ease over `glide` seconds, and `transition: "cut"` keeps the hard cut with its tear. Focus racks instead of snapping: the focus box is a Hann-weighted average of where it was over the last `rack` seconds, so a new target eases in on an S-curve and every seek order still renders the same frame. The demo now films three scenes in the style of other compositions, a code editor, an analytics card and a chat thread, one shot and grade each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(registry): filmed-screen shares the composite slot and films each instance Review on #5487: - The composite hooks no longer cycle with data-vfx-chain. Both re-arm every seek, and core's resolver reads its prior when called, so a stale wrapper of ours is re-entered through it. Each wrapper now keeps its own prior and returns at once when re-entered, so the chain stays a constant depth. The slot is only claimed once a lens is mounted. - A second instance films its own canvas. mount() takes the snippet's caller-scoped query result and picks the first canvas not already filmed; the library's own document belongs to whichever copy loaded first. - No WebGL2 now steps aside like no HTML-in-Canvas. mount() returns { destroy() }, a lens whose canvas leaves the page is dropped, and a lens whose composition is not on screen skips its capture instead of logging. - Docs: fadeOut and zIndex, the rack comment, and the description and tags now describe glides instead of cuts. filmed-screen.test.mjs runs both arm orders against core's arming pattern, two mounts over two canvases, and that the demo pastes the snippet's library. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(registry): filmed-screen test passes oxlint The vfx stand-in returned `true || prior`, which oxlint rejects as a constant-truthiness expression. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(registry): match script tags case-insensitively in the filmed-screen test CodeQL reads the extraction regexps as HTML filters (js/bad-tag-filter). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(registry): filmed-screen waits for the scene's first paint instead of erroring In Studio's preview the first draw can run before Chrome has painted the layoutsubtree scene once (the paint wait gives up after 250 ms on a busy machine). drawElementImage then throws "No cached paint record", which was logged with console.error and surfaced as a preview console error. That error is now a wait: the lens requests a paint and draws again when it lands. Other capture failures still log. Render output is unchanged: the demo renders byte-identical to before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9825614d91 |
fix(studio): Studio's own text reads without em or en dashes (#5414)
* fix(studio): text in Studio reads without em or en dashes * fix(studio): the dash check also catches HTML entities, and peak reads Unavailable * test(studio): the dash check test covers every entity form * fix(studio): messages Studio shows from lint, sdk, core and the renderer drop dashes too * fix(producer): the gate check stops early on the engine's new fallback wording |
||
|
|
0ca99b30da |
fix(ci): skills sync publishes hyperframes-creative past its hidden 1.0.13 and checks it went live (#5081)
* fix(ci): skills sync publishes past a version the registry holds unpublished * fix(ci): skills sync fails unless a republished skill is the registry's latest * fix(ci): skills sync republishes one patch past a hidden version and checks it as owner * test(ci): skills sync fails the job on an error and stops after a clean sync Two mutants survived review: dropping the line that sets the exit code (the job would print its ::error:: lines and still pass) and dropping the clean-sync return. One test runs the script with a failing fake clawhub on PATH and expects exit 1; another pins that a clean sync makes no further call. * test(ci): the exit-code test can only reach its fake clawhub The child's PATH was the fake's folder plus the inherited PATH, so on a machine where the fake cannot execute, a real logged-in clawhub further down would run sync for real. PATH is now the fake's folder alone. * fix(ci): skills sync skips only hyperframes-creative's hidden 1.0.13 Republishing one patch past any taken version would publish past every future hidden version with no one looking. Only the acknowledged case (hyperframes-creative, 1.0.13 taken) is published at 1.0.14; any other taken version fails the sync as before. * test(ci): the skip allowlist matches the skill, not just the version A taken 1.0.13 on any other skill must fail the sync too; without this case, accepting 1.0.13 for every skill passed all tests. * refactor(ci): skills sync picks the republish version in its own helper The allowlist check took republishTaken to cyclomatic 5, which the Fallow audit scores at its 30.0 CRAP threshold; deciding the version in versionPastSkippable keeps each function under it. Behaviour unchanged. |
||
|
|
f835f83164 |
fix(catalog): 3D previews load their scripts under the docs host's script policy (#5090)
* fix(catalog): 3D previews load their scripts under the docs host's script policy * fix(catalog): preserve script text through HTML parsing * docs(catalog): describe the shared script bundle |
||
|
|
d2398d686a |
feat(registry): eight ad templates show their video preview in the catalog (#4979)
* feat(registry): eight ad templates show their video preview in the catalog * refactor(scripts): the preview backfill reuses the shared entrypoint guard |
||
|
|
d218cec091 |
ci(studio): gates read the base the run measured, and drag frames on a quiet runner (#4872)
* ci(studio): measure drag smoothness on a quiet runner, with a blank-page control * ci(studio): gates read the base the run measured, not the base branch tip * style(ci): format the base-file test |
||
|
|
0a5e3c7fc4 |
feat(plugins): ship portable agent bundles and installation guides (#4608)
* feat(plugins): ship portable agent bundles and installation guides * fix(plugins): align new manifests with current release * test(plugins): split caption fixture setup and cleanup * test(plugins): pass render fixture path as an argument |
||
|
|
2b1bb8b731 |
test(cli): CLI tests run with a home folder of their own, never the user's (#4587)
* test(cli): CLI tests run with a home folder of their own, never the user's * style(cli): format the test home check * test(cli): the skills test lane also runs with a home folder of its own * style(cli): format the test home check * ci: the test reachability map follows the skills lane's new command |
||
|
|
c238abfe6f |
fix(media-use): tests never write into the person's media library (#4459)
* fix(media-use): tests never write into the person's media library * fix(media-use): guard the media home only in this repo's test runs * test(media-use): probe the media home from a plain child process * fix(media-use): keep miss logging best-effort when home is unresolvable * test(media-use): miss logging survives an unresolvable media home * docs(media-use): describe the media library without naming an app * chore(media-use): refresh the skills manifest hash |
||
|
|
81d8a03d2e | fix(repo): keep one fallow audit base cache per checkout instead of one per main commit (#4525) | ||
|
|
fbaa9f9205 |
ci: stop running CodeQL on merge queue groups, where its upload races the merge (#4492)
* ci: stop running CodeQL on merge queue groups, where its upload races the merge The code scanning rule does not apply to merge queue groups, and the queue deletes a group ref when it merges, so the upload failed on about half the groups. Pull requests and pushes to main keep scanning. * ci: catch merge_group in any trigger form and say the upload race is intermittent |
||
|
|
0e34d69641 | ci: comment checks grade branches cut before their scripts existed (#4466) | ||
|
|
3520c8225c | ci: a package file's comment share may not rise (#4445) | ||
|
|
3194c2ae87 | ci: grade the comments each PR touches (#4444) | ||
|
|
096a586b41 |
ci: editing a PR's text no longer cancels its running checks (#4420)
* ci: editing a PR's text no longer cancels its running checks
CI, regression and Windows render re-run on pull_request edited (for base changes) with cancel-in-progress, so a body or title edit cancelled the running checks and the fail-closed Test aggregator went red on the cancelled run. Only a push or a base change cancels now; a text edit queues behind the running run.
* test(ci): read the workflows folder by path, not as a module URL
Fallow treated new URL('../.github/workflows/', import.meta.url) as an unresolvable import. Use import.meta.dirname and join, as scripts/check-skill-mirror.mjs does.
|
||
|
|
d49e7b95e0 |
feat(media-use): resolve brand logos from theSVG (#4291)
* feat(media-use): resolve brand logos from theSVG Replace the svgl and simple-icons tiers of the `logo` cascade with a single theSVG (thesvg.org) tier. theSVG ships 7,400+ official brand SVGs with color, mono, light/dark and wordmark variants. The tier fetches one manifest pinned to a glincker/thesvg commit on jsDelivr, memoizes it per process, and matches entities locally by normalized slug, title, or alias. That drops the hand-kept svgl alias and simple-icons slug maps. GitHub org avatar and favicon stay as the fallbacks for brands theSVG lacks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(media-use): sanitize fetched SVGs and gate theSVG by license freezeUrl/freezeLocalFile wrote every fetched SVG to disk unsanitized; the theSVG tier is now the sole SVG-returning logo provider, so an inline script tag or on-event handler would land verbatim in a user project. Route .svg destinations through the existing Figma sanitizer (new @hyperframes/core/sanitize-svg subpath, synced via package-subpaths). thesvgMatch never checked theSVG's own license field: entries theSVG itself marks unresolved (Proprietary, Unknown, Custom, TODO, or an explicit no-redistribution-license string) could still resolve and freeze into a project. Gate matches to the ten SPDX ids theSVG's submission form accepts; a rejected entry falls through to a lower ranked theSVG match, then to the github/favicon tiers. Also caps the theSVG manifest fetch at 20MB, streamed, matching freeze.mjs's existing cap discipline. It had a timeout but no bound. * chore(skills): regenerate skills-manifest for media-use/motion-graphics The original submission edited skills/media-use and skills/motion-graphics docs without regenerating skills-manifest.json; its own CI never ran (fork approval gate), so the drift went unnoticed until this pass's first CI run caught it. * fix(media-use): drop the sanitizer's workspace import, add parity test freeze.mjs importing @hyperframes/core/sanitize-svg broke the test-skills CI lane: packages/cli/src/media-use tests run with node builtins only, zero install, by design (media-use is vendored standalone into other projects, e.g. packages/desktop). Port the sanitizer into media-use/lib/svg-sanitize.mjs instead, and drop the now-unused core export. Parity between the port and packages/core/src/figma/sanitizeSvg.ts is enforced by a new test (scripts/check-svg-sanitize-parity.test.mjs, run in the test:scripts lane, which does have an install) over a hostile-SVG corpus, so the two cannot drift silently. * fix(media-use): close three sanitizer bypasses, add fetch timeout Independent review of the maintainer pass found the SVG sanitizer (packages/core/src/figma/sanitizeSvg.ts, reused by media-use's own port) was itself bypassable: an unquoted href/xlink:href survived, inline style="..." attributes were never checked, and a href bound through a renamed XML namespace prefix (xmlns:x=".../1999/xlink", x:href=...) slipped past the literal "xlink:href" match. Rewrote sanitizeSvg as a tag/attribute tokenizer instead of a set of literal-spelling regexes: parse each tag's attributes in any quoting form, resolve the local name after stripping any namespace prefix, then drop by local name (any on* handler, any *href whose value is not a #fragment or data:image/ embed, any style attribute containing url(, @import, expression( or javascript:). Ported the fix into media-use's svg-sanitize.mjs identically. Legitimate url(#id) references on non-style attributes (clip-path, fill) are untouched. Also adds a 10s AbortSignal.timeout to freezeUrl's fetch, matching every other fetchMedia call in this package - it had a size cap but no deadline. New cases for all three bypasses in both sanitizeSvg.test.ts and the parity corpus, each reproducibly failing against the prior head. * fix(media-use): replace regex SVG sanitizer with a DOM allowlist Two rounds of regex/tokenizer patches to sanitizeSvg found new bypasses in the same shape each time (unquoted href, style= url(), aliased xlink prefix; then presentation-attribute url(), unquoted '=' handling, SMIL animate/set href rewrite, self-closing-slash tag corruption, data:image/ navigation via <a>). Denylisting attribute names against a hand-rolled tokenizer was the wrong approach regardless of how careful the regex. Rewrote sanitizeSvg (packages/core/src/figma/sanitizeSvg.ts) as a real DOM walk (linkedom, already a dependency of core and cli) with an allowlist: known-safe elements and attributes only, everything else dropped by construction rather than pattern-matched as dangerous. href/xlink:href (any namespace prefix) kept only for a same-document fragment, or data:image/ off non-<a> elements. Any attribute value or <style> text containing url() kept only when every url() argument is a fragment; @import/expression(/javascript: dropped from style content. Serializing from a real DOM means output is always well-formed, so the self-closing-slash corruption class of bug is gone by construction. media-use's own copy (packages/cli/src/media-use/lib/svg-sanitize.mjs) can't import linkedom directly: its CI test lane runs bare `node --test` with no install step, so even an external dependency fails to resolve, not just a workspace import. It's now a generated file instead of a hand-copy: scripts/generate-media-use-svg-sanitize.mjs bundles the core source (esbuild, minified, zero remaining imports) and scripts/check-media-use-svg-sanitize-generated.test.mjs fails the build on drift. Verified the generated file runs with plain node in an empty directory with no node_modules on the path. Every payload from both independent-review reports is now a table-driven test in sanitizeSvg.test.ts (46 cases) and the same corpus in check-svg-sanitize-parity.test.mjs (39 cases) asserts core and the generated media-use copy agree and each independently rejects every non-local url(), javascript:, data: href on <a>, and on* handler. Mutation-proved against the real pre-fix blob, not a synthetic case. Sampled 56 real theSVG icons across all 7 collections to check the allowlist doesn't over-strip legitimate content: found and fixed three missing attributes (fx/fy, enable-background, a blanket data-* allowance) and one real behavioral bug - <style> elements were being dropped outright, silently unstyling any Illustrator-exported logo that colors paths via CSS classes. Fixed by keeping <style> on the allowlist and content-checking its text the same way as an inline style= attribute, with a regression test using that exact shape. Full suite after the fix: sanitizeSvg.test.ts 46/46, parity+drift tests 39/39, media-use suite 298/298, tsc/oxlint/oxfmt clean. * fix(lint): ignore generated svg-sanitize.mjs bundle in oxlint Minified esbuild output (packages/cli/src/media-use/lib/svg-sanitize.mjs, generated by scripts/generate-media-use-svg-sanitize.mjs) trips oxlint's correctness rules 504 times and fails `bun run lint`. Same shape as the existing registry/blocks/**/*.iife.js exclusions: a generated, minified, non-hand-edited bundle, not hand-written source. * fix(format): ignore generated svg-sanitize.mjs bundle in oxfmt Same generated esbuild bundle that needed an oxlint exclusion in the previous commit also fails (minified, no formatting to check against), cascading Preflight into Player perf, regression, Windows render verification, and preview-regression on CI. Same established pattern as the existing registry/blocks/**/*.iife.js and skills/**/*.min.js entries in .prettierignore. * refactor(media-use): reduce complexity flagged by fallow audit isSafeAttribute (10 cyclomatic) and the parity test's aggregate-marker check (11 cyclomatic, 26 cognitive, CRAP 132) both exceeded fallow's per-function thresholds after the rebase pulled in a stricter baseline. Extracted isXmlnsAttribute/isKnownAttribute as named predicates and survivingUnsafeMarkers as a named per-output helper; no behavior change, same guard order, same failure strings. Regenerated svg-sanitize.mjs. * refactor(media-use): make the parity test's marker check table-driven Fallow gives .mjs scripts no coverage credit, so its CRAP gate needs each function at cyclomatic 4 or less. The extracted survivingUnsafeMarkers still scored 9 (CRAP 90). The four regex markers are now a table, and the data:image-on-<a> and non-local url() checks are small named helpers. Same checks, same order, same failure strings. * fix(media-use): close CSS-escape and image-set bypasses in sanitizeSvg The url()/@import checks scanned raw text for the literal "url(" and "@import". A browser decodes CSS escapes first, so fill="\75 rl(...)", url\28...\29 and @\69mport all loaded an external resource, and image-set("https://...") loads one with no url() at all. Reproduced in headless Chrome: 8 of 8 payloads fired a request through the old code. CSS can only load a resource through a function or @import, so CSS text now passes only if it has no @import, every function is on a compute-only allowlist (color, transform, filter and math functions), and every url() is a same-document fragment, all checked on escape-decoded, lowercased text. Same fix reaches media-use through the regenerated bundle. Checked against all 13,384 files of the pinned theSVG corpus: 13,383 sanitize byte-identically; one drops an unreferenced id="XRP-(XRP)". The parity oracle now fails on any surviving attacker host, so it no longer shares the sanitizer's parsing blind spot. * refactor(media-use): share one capped body reader for freeze and manifest fetchJson copied freezeUrl's declared-length check and streaming size cap line for line. Both now call readCappedBody in media-fetch.mjs, which both already import; it has its own tests, since freeze's cap had none. The freeze cap errors now read "freeze failed for <url>: ..." (no caller or test matches the old wording). Also fixes freeze.mjs's comment, which still called the sanitizer a lexical pass. * style(media-use): format the parity test corpus * fix(media-use): make the sanitizer's CSS scans linear on hostile input The url() check used /url\(\s*(['"]?)([^)]*)\1\s*\)/ and the function check /([-\w]*)\(/: on attacker padding these backtracked cubically and quadratically (an unclosed url( plus 4,000 spaces took 20s; an 80,000 character word took 7.7s), and freeze runs the sanitizer synchronously on bodies up to 256MB. Both are now single-pass indexOf scans (a million characters in under 15ms), with the same verdict on ordinary input. A url() value holding "(" is rejected, so a nested url( can't hide inside one. A size test holds both payloads under 2s. * test(media-use): size payloads that fail the old scans fast instead of hanging * fix(media-use): stop the freeze timeout from aborting long downloads The 10 s AbortSignal.timeout on freezeUrl also aborted the response body, so any stock video, generated video or LUT that took longer than 10 s to download failed. The timer now covers only the wait for response headers and is cleared once they arrive; the 256 MB cap still bounds the body. * refactor(media-use): trim logo-provider comments to the repo limit The tier list and the thesvgMatch doc block ran past the four-line comment cap that the merge check enforces. Same facts, shorter blocks. * refactor(media-use): name the header wait and restore the variants note Renames the freeze timeout controller to headerWait so it no longer reads as HTTP headers, puts the theSVG variants fact dropped by the comment trim next to the line that picks the default mark, and keeps thesvgMatch on the file's JSDoc style. --------- Co-authored-by: Imad Phelps <imad.phelps@heygen.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com> |
||
|
|
ca4af78184 | ci: dispatch required checks for catalog publication (#4345) | ||
|
|
b1cf88aeba |
ci: generate catalog artifacts through a standing publish PR (#4337)
* ci: generate catalog artifacts through a standing publish PR * fix(catalog): reconcile obsolete publication snapshots * refactor(catalog): report failures after staging cleanup * refactor(catalog): separate generation and publication decisions * fix(catalog): unpublish deleted items with their sources * docs(catalog): keep scaffolding guidance concise |
||
|
|
2c71a3a112 |
fix(catalog): registry set-delta check accepts intentional additions (#4287)
check-registry-set-delta.mjs only recognized removals: an added name in
registry.json had no matching allowance, so any pure-addition PR failed
with "unexpected in registry.json: <name>" even though the item's own
registry-item.json was added in the same diff. Mirror the deletion rule
for additions: a name is expected when its own registry-item.json was
added or deleted in the same diff, same condition either side already
required.
CI's audit tool flagged the CLI entry itself (high-crap-score rule,
scripts/check-registry-set-delta.mjs:30 main, CRAP 42.0 threshold 30.0,
cyclomatic 6): main() shelled to git and parsed JSON inline. The git/fs
boundary is now injected as runRegistrySetDeltaCheck(base, { run,
readRegistryJson }), covered directly by a test with a fake run/read, so
main() is a thin print-and-exit wrapper.
|
||
|
|
05d09a7452 |
chore(registry): remove low-use catalog items and variant tails (#4274)
* chore(registry): remove low-use catalog items and variant tails * fix(registry): remove stale references to deleted catalog items * style: format catalog fixture * fix(ci): use surviving catalog preview canary * chore(ci): allow intentional catalog deletions * fix(ci): scope fallow audit for catalog fixtures * chore(catalog): regenerate local search vectors * chore(catalog): update vector revision * fix(catalog): validate registry set delta |
||
|
|
cff467a352 |
ci: select the remaining orphan tests in their owning runners (#4260)
* ci: select the remaining orphan tests in their owning runners * ci: provide FFmpeg for the catalog preview witness * ci: pass the installed Chrome path to catalog rendering * test: align creator capability checks with speed ramp support #4153 added supported speed ramps as rate lanes in data-automation. The previously unselected capability tests still required preprocessing. Require the documented rate-lane representation and its precedence over the constant playback rate, matching the runtime resolver. |
||
|
|
86e27b00f6 |
ci(studio): ratchet colour contrast of timeline tokens (#4257)
* ci(studio): ratchet colour contrast of timeline tokens * refactor(studio): clarify contrast ratchet branches and state citations * fix(studio): resolve contrast baseline from the repository root * test: parse contrast channel tokens without color wrappers * ci: keep contrast gate artifacts outside runtime sources * test: honor strict indexed access in contrast scripts * test: require removal of zero contrast baseline entries |
||
|
|
3091dcb787 |
feat(cli): route media search through media-use (#4230)
* feat(cli): move media-use engine into the CLI * fix(cli): replace media-use compatibility asset * fix(cli): replace moved media-use tree * fix(cli): copy moved media-use files cleanly * fix(cli): copy media-use engine files individually * fix(cli): keep audio helper compatibility import * fix(cli): clear copied skill destinations * test(cli): preserve moved media-use test paths * fix(cli): preserve media-use script compatibility imports * fix(cli): preserve media-use telemetry shim * fix(cli): resolve packaged media-use LUT assets * fix(cli): resolve packaged bundled SFX assets * chore(skills): regenerate media-use manifest * fix(cli): preserve media-use parity coverage * fix(cli): cover relocated media-use tests * chore(skills): regenerate media-use manifest * fix(cli): format bundled media provider * fix(ci): run relocated media-use tests with node * fix(ci): preserve fallow script exemptions * fix(ci): scope media-use fallow exemption * refactor(cli): trim media-use essay comments * feat(cli): index media-use assets for catalog search * feat(catalog): commit media-use search vectors * chore(catalog): track media vector metadata * fix(catalog): validate media vector row order * fix(catalog): validate media artifact freshness * fix(catalog): cover media metadata and credits * fix(cli): reject malformed media rows * fix(catalog): compare complete media rows * feat(cli): route media search through media-use * refactor(cli): trim relocated media-use comments * fix(cli): make media search runtime-safe * fix(cli): preserve sfx fallback diagnostics * fix(cli): probe sfx fallback provider explicitly * chore(skills): regenerate manifest * refactor(cli): keep typed media ranker source * fix(cli): align media search checks with local-first flow * fix(cli): scope vector audit exceptions * fix(cli): ship resolver registry beside skill * fix(cli): keep media-use skill scripts standalone * test(cli): cover local vector validation * test(cli): correct media vector fixtures * fix(cli): prefer exact media keys * fix(cli): stem exact media keys * test(cli): skip media lint for snippets without media * fix(cli): align skills test discovery Keep the CI skills job's bash discovery as the single source of truth so its empty-list guard covers the exact files Node executes. Make hasMediaVectors private because it has no external callers and needs no Fallow suppression. * fix(cli): close media-use review gaps Prioritize literal ids before stemmed ids and cover the collision alongside the plural regression. Add command seam tests for engine discovery, actionable failure, and argv passthrough. Add a deterministic parity check for standalone media-use copies, with documented allowlists for the standalone media-fetch shim and self-contained npx resolver. Keep the bash-discovered skills test list as the CI source of truth. * fix(cli): lower parity check complexity Split missing-copy and unallowlisted-drift checks so the parity guard keeps its behavior without a threshold CRAP score. * fix(cli): close media-use review seams Run the parity test in the skills job so skills-only edits exercise the same check. Export the verb mapping and inject command dispatch for direct coverage. Keep missing-copy diagnostics separate from drift reads. |
||
|
|
f24ff83834 |
feat(catalog): add the seven 3D-motion pieces as installable registry blocks (#4056)
* feat(catalog): add the seven 3D-motion pieces as installable registry blocks Each piece ships as a registry block with a CDN poster and preview, a live catalog detail page and its source. Scripts travel inside the catalog payload (shared vendor libraries fetched once, item scripts inline, the one HDR as a data URI) because the docs host only serves fonts, images and JSON. NO_ESSAY_COMMENTS_OK: the long comment blocks are in vendored libraries and the ported frost source under registry/blocks, not hand-written here. HF_MAX_NONLFS_KB=6000: four hosted texture PNGs under docs/public/catalog/items are runtime assets the docs host must serve as files. fallow skipped locally: it audits against origin/main and this branch is stacked on an older main. * chore(catalog): regenerate gallery data and nav after rebasing onto main * fix(catalog): read the install manifest through the bounded project reader * fix(catalog): a script the inliner missed fails the payload instead of shipping a dead URL * refactor(catalog): the leftover-script check reuses the reference finder * fix(catalog): frost and glass textures load from the CDN and the iteration presets are gone * chore(catalog): regenerate the frost and glass payloads and nav * fix(catalog): frost and glass textures are hosted through the registry url field, not hardcoded * chore(catalog): regenerate the frost and glass payloads against the hosted texture URLs * fix(catalog): the hosted-reference rewrite refuses a bare name it cannot safely replace * ci(catalog): verify changed catalog payloads in headless Chrome and check the docs catalog * feat(catalog): every item page follows the shared layout with a Tune panel and tabs * fix(catalog): let the texture-mask item host its masks so its tile plays live * chore(catalog): regenerate item pages, gallery data and the texture-mask payload * chore(catalog): regenerate item pages after merging main * fix(catalog): declared-only variables get the Tune panel, Code and Docs tabs capped * feat(catalog): give the blend-difference caption a demo scene so its tile plays live * chore(catalog): live payload for the blend-difference caption * perf(catalog): heavy 3d pieces compile and draw before ready, not on the first visible frame * feat(catalog): the avatar promo card hosts its videos, audio and fonts on the CDN * feat(catalog): the avatar promo card tile plays live from its CDN-hosted media * chore(catalog): the avatar promo card plays live, no allowlist left * chore(catalog): shorten two comment blocks * chore(catalog): trim first-party comment blocks to the comment-check limits * chore(catalog): shorten two frost source comments * fix(catalog): the Docs tab renders as prose again, and the detail page honours reduced motion Frame-mode pages carry no prose wrapper, and the detail component sat inside not-prose, so the Docs slot's headings, paragraphs, links and lists had no styling at all. The slots now carry their own prose classes and the chrome around them keeps not-prose. The recorded clip also gets the reduced-motion guard the docs-snippet check requires, and the generator reads stability from the source metadata type so the scripts typecheck passes. * fix(catalog): docs-tab paragraphs render as blocks Mintlify emits paragraphs as inline spans, so two paragraphs in the Docs slot ran together. * fix(ci): drop the duplicate docs_catalog job output git's line-based auto-merge silently duplicated the outputs key when main and this branch each added it on non-adjacent lines during the rebase; oxfmt's yaml parser rejects the repeated map key. * fix(catalog): close four CodeQL alerts in the frost source * chore(catalog): allowlist the avatar-promo-card CDN asset deletions, format sync-docs-catalog check-no-main-deletions.mjs was rejecting 11 local mp4/font files this branch already deleted in favor of CDN hosting; scripts/sync-docs-catalog.mjs had one line over the 100-col print width from an earlier edit in this branch. * fix(catalog): detail tabs use docs prose spacing, Install first; previews skip no-WebGPU runners * fix(catalog): the docs tab scrolls with the page instead of a capped inner box * refactor(catalog): split the payload asset and verify scripts into single-purpose helpers * refactor(catalog): split the preview generator into single-purpose helpers * ci(catalog): fail when the committed catalog differs from generator output The docs host serves the committed catalog and nothing regenerates it, so a stale copy shipped silently. The catalog payloads job now generates into a temp dir and compares it with the committed tree. * chore(catalog): regenerate docs/public/catalog with the refactored scripts One full regeneration from an empty output tree with the current scripts. The tree grows from 58.4 MB to 65.1 MB. Two hosted assets are about 2 MB each (an avatar png and a wav); the same bytes are already committed under assets/, so HF_MAX_NONLFS_KB is raised for this commit only. * fix(catalog): run the catalog script tests under the runner they are written for The rebase put three node:test files in the vitest half of test:scripts, where they report "No test suite found". They now sit in the node --test list. * fix(catalog): a WebGPU item without an adapter shows its recorded clip and says why * ci(catalog): the drift check runs from a committed fetch mirror with no network Generation now serves every font and CDN script fetch from scripts/catalog-fetch-mirror and fails when a fetch is not in it, even if the caller swallowed the error. CATALOG_FETCH_MIRROR=record refreshes the mirror from the live network. The docs_catalog filter also watches packages/core, packages/producer and the mirror, and the 13 re-hashed font files are listed in ALLOWED_DELETIONS. * chore(catalog): clean up the temp font cache and sort the mirror index without a locale * fix(catalog): hide Tune when the clip stands in, time out the adapter request, share one check * fix(catalog): the adapter probe survives a sync throw and a hang; test the clip guard * fix(catalog): keep the adapter probe inside the component, Mintlify evaluates only exports * fix(catalog): run the detail and page generator tests in CI; no Tune flash while probing WebGPU * docs(catalog): credit vendored libraries and make each SKILL.md list what the block installs CREDITS.md names every vendored dependency with its upstream and licence, and flags the two leaf textures whose origin is still to be confirmed. Each SKILL.md Files table now comes from the block manifest and its install and render paths point at compositions/<name>/. A test checks that every path a SKILL.md names is a manifest file that exists. * fix(catalog): a declared WebGPU item passes verify by its manifest tag, not by console wording verify-catalog-payloads forgave a missing adapter only by matching the markup and the message, which library-reported errors and widgets never satisfy. The webgpu tag in the item manifest is now the owner: a tagged item ignores its page and console errors, an untagged one gets no forgiveness, and a marker payload with no html is listed instead of crashing the run. * docs(catalog): correct the credits per block and guard the mount and render paths CREDITS.md states the three.js version and vendored-or-CDN status per block, adds d3-delaunay, Clipper on the CDN and the Google Fonts loads, and lists every texture with no known origin. The SKILL.md test now also checks the mount and render paths against the manifest composition. * test(catalog): read each block manifest once in the SKILL.md file test The two checks shared a copied manifest read, which fallow flagged as a clone with a high score. * fix(catalog): commit the hosted item files a gitignore rule kept out, and check git not the disk The compositions/ and *-ad/ ignore rules matched folder names under docs/public/catalog/items, so 33 hosted fonts, textures and marks were generated but never committed and would 404 on the docs host. The rules now have a negation for that tree and the files are added. The drift check read the checkout, where git-ignored files still exist, so it passed locally and failed only in CI. It now unpacks HEAD with git archive and compares that. * fix(catalog): a tile keeps its poster until the composition has painted * fix(catalog): a tagged WebGPU item forgives only the adapter-absent error, and test the wiring The manifest webgpu tag now decides whether an item may lack an adapter, and the error wording decides which lines are that absence. Any other page or console error on the item, and every failed request, still fails. The per-item decision is one exported function the tests drive, marker payloads are parsed by a tested helper, and the SKILL.md variable counts are checked against their tables (cuboid-carousel said forty-nine for forty). * fix(catalog): the pinned group's posters load eagerly at high priority * fix(catalog): type the tile reveal test so the scripts typecheck passes * fix(catalog): stop the adapter signature matching an unrelated failed adapter request failed to request .*adapter also matched errors about other adapters. It now matches only a request for the WebGPU adapter, so a tagged item cannot hide an unrelated failure behind it. * test(catalog): a tagged item still fails on an error about some other adapter * feat(catalog): the install command sits above the preview, as on the live catalog * fix(catalog): find the install slot through Mintlify's child wrapper * fix(docs): catalog copy buttons keep their size when the label swaps to Copied * refactor(docs): name the shown copy label once in the catalog copy button * fix(docs): primary catalog button keeps a readable label on hover and after copy * fix(docs): inset the catalog tab strip and tab content to match the boxed panels |
||
|
|
a94466256e | ci: require before and after captures on studio and player PRs (#4131) | ||
|
|
2db126d4c8 |
docs(skills): one owner doc for everyday edits and a hyperframes-studio skill (#4125)
* docs(skills): one owner doc for everyday edits and a hyperframes-studio skill Agents got contradictory advice on volume fades and were blocked from splits and copies by the Ask-agent guardrails. - creator-editing-recipes.md is the single owner: adds align-to-event, copy-a-group and swap-media recipes and the one volume rule (use the lane) - variables-and-media, data-attributes (skill and CLI copy), the gsap adapter and tracks-and-clips now defer to it - Ask-agent guardrails allow the neighbour edits a split, retime, copy or swap requires and point at the owner doc - new hyperframes-studio skill: sub-compositions for every scene, one caption track, one element kind per track, safe zones - drift test lints every html example in the owner doc with the real linter and fails on any doc teaching a volume tween * refactor(skills): drop unused tween allowlist from recipes drift test * docs(skills): name the track kind attribute in the studio skill * docs(skills): stop claiming lint rules that do not exist yet and fix track numbering Review fixes: - studio skill: drop the severity claim and the preview-overlay claim, group tracks by data-track-kind instead of numeric ranges that clashed with the recipes - recipes: audio data-start is root time only in the root composition; scene-local inside a sub-composition file - guardrails: timeline edits are exempt from the element-only and timing lines; the pointer names the skill reference, not a repo path - montage doc defers to the volume lane; skill count is 21 everywhere - drift test also scans the montage doc * fix(skills): the ducking generator emits a volume lane and captions defer to the studio safe zones - audio-duck.mjs prints a data-automation lane (clip-local times from the target data-start) instead of a timeline volume tween; --json adds the lane - operations.md shows the generated lane; the drift test scans it - embedded-captions safe-zone lines point at the studio skill, which owns the values * chore(skills): regenerate the skills manifest after rebase * docs(skills): remotion translation docs point volume ramps at the automation lane * docs(skills): studio safe zones use the action-safe 90 and title-safe 80 boxes * docs(skills): caption docs defer to the studio safe boxes * chore(skills): regenerate the skills manifest after rebase * fix(skills): studio skill names the safe margins; guardrail test matches the timeline-edit wording |
||
|
|
9bb4f5cd57 |
feat(catalog): browse the catalog as a live grid, not a static index (#4051)
* feat(catalog): browse the catalog as a live grid, not a static index
The Catalog overview page now mounts a browse grid (posters, tags,
per-category rows, expandable sections) generated over the existing
~380 registry items, instead of one static hero video plus two links.
docs/snippets/catalog-gallery.jsx and docs/catalog-gallery.css are
ported from a reference implementation of this same UX; the CSS keeps
its original comments as-is (NO_ESSAY_COMMENTS_OK: vendored file).
scripts/sync-docs-catalog.mjs and build-docs-gallery-nav.mjs are new,
generating the gallery's data and the Catalog tab's nav directly from
this repo's registry/*/registry-item.json and docs.json, so no sparse
clone or snapshot of another project is needed. scripts/check-docs-catalog.mjs
proves every catalog page from before this change still exists, on
disk and in the sidebar, with an identical page list.
No catalog page or snippet is removed; the previous overview content
(catalog-overview-player.jsx) is unused on this page but stays in the
repo.
* refactor(catalog): share the docs-catalog helpers across the sync scripts
Three independent adversarial reviews (reuse, quality, efficiency) all
converged on the same shape: sync-docs-catalog.mjs, build-docs-gallery-nav.mjs
and check-docs-catalog.mjs each hand-wrote the same docs-root resolution,
the same catalog-gallery-data.mdx parse, and the same Catalog-tab lookup.
Extracted into scripts/docs-catalog-shared.mjs.
sync-docs-catalog.mjs also ran build-docs-gallery-nav.mjs as a dynamic
import purely for its side effect, forcing a same-process re-read and
re-parse of the data file it had just written. build-docs-gallery-nav.mjs
now exports buildNav(docs), called directly with the path already
resolved; its CLI entry is guarded for standalone use.
slug() dropped the /^-+|-+$/ trim in favor of the character-scan trim
packages/core/src/tokenSlug.ts already uses for the same reason (CodeQL
flags that regex as polynomial ReDoS, js/polynomial-redos); not imported
directly since tokenSlug.ts is compiled TS with a different domain
(CSS variable naming) and no existing scripts/*.mjs imports packages/core
source at plain node runtime.
Fixed one bug found while re-verifying after the refactor: the recursive
nav walk wasn't idempotent against its own generated output — re-running
sync-docs-catalog.mjs a second time saw the "Catalog" wrapper buildNav()
adds and misattributed every flat, single-section group under it, 9
groups collapsing to 7. walk() now treats "Catalog" as transparent, the
same way it already treated "Overview". Verified: three consecutive runs
from a fresh origin/main checkout now produce identical 9 groups / 400
items each time, and check-docs-catalog.mjs still passes.
* chore(catalog): scrub an internal decision code from a code comment
* fix(catalog): stop losing a section's label when its nav is flattened
An independent adversarial review found real data loss: build-docs-gallery-nav.mjs
collapsed a group with exactly one section into a flat page list (a clean sidebar
for the common case), but sync-docs-catalog.mjs's walk() derives an item's section
from nav depth, so a second sync run over that flattened nav could no longer
recover the section name and silently fell back to the group's own label. Data &
charts / Data was the one real casualty in this catalog; Carousels and Blocks
happened to already have a section named the same as their group, so the loss
was invisible there.
Fix: only flatten when the section label equals the group label, so nothing
non-recoverable is thrown away. Verified with a deliberate mutation (reverted the
condition, reproduced the exact bug from a clean origin/main checkout, confirmed
the new check-docs-catalog.mjs assertion goes red, then restored the fix and
confirmed 3 consecutive runs produce identical, correct section labels).
check-docs-catalog.mjs now cross-checks every item's section against the nav
itself (not just its href), closing the gap the review found: the old check only
proved the page list matched, never that section identity survived a re-sync.
Also deletes docs/snippets/catalog-overview-player.jsx: unreferenced anywhere in
the repo now that catalog/index.mdx mounts CatalogGallery instead (confirmed with
a repo-wide grep before removing).
* chore(catalog): allowlist the deliberate catalog-overview-player.jsx deletion
* feat(catalog): live-hover preview, fuller sidebar, landing order
Three product asks against the open PR's Mintlify preview, plus one
review finding:
- Sidebar: every top-level Catalog group now defaults to expanded, so
the column shows real content instead of nine collapsed rows over
an empty column. Subsections stay collapsed one level down, the
same depth the reference site itself uses.
- Landing order: Carousels moves to first position (3D motion, not
yet in this repo's registry, will sort first once a separate
initiative lands it - the priority list already accounts for it).
Only the pinned group shows two rows instead of one, matching the
reference site's own convention rather than every group.
- Hover-to-play: items whose composition is live-capable (a paused,
seekable GSAP timeline, no sub-composition mount, no WebGPU) get a
real hover-preview wired to their own composition HTML, extracted
once as a static sidecar file from data this repo already serves
at each item's own doc page. Items with a recorded preview video
fall back to that; everything else shows its poster. Verified no
WebGL/three.js item is ever marked live (238 live, 30 video, 132
poster-only of 400).
- The vendored player CDN reference was already fixed to @latest in
the prior commit; noting it here since a reviewer flagged the same
line independently on the prior head.
docs/public/catalog/gallery-live/**/*.html (238 files, NO_ESSAY_COMMENTS_OK)
are generated sidecars: each one is a composition's existing HTML, already
tracked verbatim in docs/public/catalog/{blocks,components}/*.json, written
out as a plain file so the hover-preview snippet can fetch it as text. Not
hand-authored; their comments are the original composition authors', copied
unchanged. Regenerated by scripts/sync-docs-catalog.mjs on every run.
* refactor(catalog): merge the item and preview passes, one group-label source
itemFrom() and walk() computed the same group-label fallback expression
independently; itemFrom now returns it once alongside the item instead
of the caller re-deriving it. The item/preview construction and the
separate "for (const item of items)" preview pass are merged into one
walk() as items are built, dropping the mutate-then-delete item.live
scratch field. Byte-identical generated output, confirmed by diff.
* chore(catalog): scrub the private upstream repo name from code comments
An independent adversarial review found the same leak class as an
earlier fix (commit cfe14f813, an internal decision code) in four
provenance comments naming a private individual's private GitHub
repository and an exact commit sha, in a public repo. Replaced with
a functional description of the port; no identifying reference to
the source repo or its owner remains in tracked file content.
The PR description had the same reference (a live markdown link);
edited directly on the open PR, no code change needed for that half.
* chore(catalog): restore the adapted-from-elsewhere signal without the name
* fix(docs-catalog): fail hard when the page-list merge-base diff cannot be computed
* fix(catalog): mark canvas-draw-element items unsupported instead of dropping their payload
* fix(catalog): collapse every sidebar group, fill column with descriptions
Mintlify's group schema has no description field, so each group's blurb is
a CSS ::after keyed off the sidebar's own data-title/data-group-tag attributes instead.
NO_ESSAY_COMMENTS_OK: false positive.
The real /* */ block is 3 lines. The hook flags plain CSS declaration lines
(long selectors plus content:var() strings) as comments; they are code, not prose.
* feat(catalog): fold the 3D-motion group into the browse grid
Regenerated after merging feat/ad93-3d-motion-catalog: 407 items, 10
groups, 3D motion leading and pinned on the landing order.
* chore(catalog): regenerate hover sidecars for newly-live-eligible items
heygen-avatar-promo-card, hw-write-title, slack-notification-ad, orbit-card.
NO_ESSAY_COMMENTS_OK: generated composition HTML, not hand-authored.
* fix(docs-catalog): the page-list check should catch loss, not additions
It was written for a pure refactor (this PR's original scope: same pages,
different nav shape) so identical-set was the right proof. Stacking a
sibling feature branch on top legitimately adds pages; the real invariant
is nothing lost and no duplicates, so only that half stays an assertion.
* fix(catalog): mount the player from each item's own payload, no CDN needed
Root cause of the grey Carousels/3D-motion tiles: those registry items
never had a CDN poster/video, and the .html hover sidecar 404s on the
deployed docs host (Mintlify drops .html/.js/.css from docs/public with
no error). Cards now fetch the same repo-served .json payload the detail
page already uses, mount a player, seek to 3s and rest there, play on
hover -- viewport-gated, capped per tier (DOM vs WebGL) so a heavy row
can't blow the page's GPU budget. Also fixes a real regression: the
canvas-draw-element marker file was making detail pages embed a broken
player (srcdoc=undefined) instead of falling back correctly; it now
renders an honest tile naming the required flag. Deletes the now-dead
.html sidecar mechanism and its vendored gating helper.
* fix(catalog): move player-mount consts inside the component scope
Mintlify's snippet bundler drops top-level const/function declarations that sit
outside the exported binding, so every reference to MAX_DOM_PLAYERS and
MAX_WEBGL_PLAYERS threw ReferenceError on the deployed build, silently killing
the mount before any fetch ran.
Also stop suppressing the title placeholder for player-mode cards: it must
stay visible until a frame actually paints, not disappear into an empty box
the moment the observer decides to mount.
* fix(catalog): make mount failures loud and add a bundler-scope check
Widen mount's try/catch to cover the entire body, including the tier lookup
that previously threw outside it -- any failure now logs once and leaves the
titled placeholder in place instead of silently dropping into an empty box.
Add a check-docs-catalog.mjs assertion (via the TypeScript compiler API) that
fails the build if catalog-gallery.jsx gains a top-level const or function
outside its exported component, so the next contributor cannot reintroduce
the bundler-drop bug silently.
* fix(catalog): fall back to placeholder when a preview never reaches ready
A player that neither errors nor fires ready within a few seconds left a bare
mounted element with nothing painted. Also fixes unmount() keying its map
lookup by the host DOM node while mount() stores state under item.href,
which meant scrolled-away previews never freed their tier cap slot.
* docs(catalog): trim an essay-length comment in docs-catalog-shared.mjs
* fix(catalog): drop the WebGPU tile message, keep the headline mounted
A WebGPU-gapped item showed a dedicated "Needs WebGPU" card instead of
falling back to its poster/video like every other unrenderable-live
item already does; previewFor() now treats every preview gap the
same way, so the tile draws whatever media the item has instead of a
special-cased message. Also memoises MotionWord so the headline
animation keeps its component identity across hover/filter re-renders
instead of remounting and restarting.
* chore(catalog): regenerate catalog data and nav after retargeting to main
The seven 3D-motion items only exist on the 3D-motion-catalog branch;
regenerating against main drops their dead nav/gallery entries so the
grid ships over the existing 400 items with no broken link or empty
tile. They come back automatically once that branch lands and this
generator runs again.
* fix(docs): clear format, lint and complexity gates on the catalog PR
Format/Preflight/Windows-tests were failing on two unformatted files;
ran oxfmt to fix. Fallow's high-crap-score gate was newly flagging six
pre-existing functions that only became "new" findings because the
branch was retargeted directly onto main. Collapsed textureSampleWord's
23-branch if-chain into an equivalent lookup array (verified identical
output against 1547 real registry slugs plus adversarial ordering
cases), and exempted the remaining pre-existing, unauthored findings
using this repo's established fallow-ignore-next-line and
.fallowrc.jsonc health.ignore conventions.
* fix(catalog): drop the stale index prose, give the new item a CDN preview
The old static-index page's "Use an item" tutorial and group tour sat
unstyled below the new browse grid and named groups that no longer
exist; the grid already shows the current groups, so the block is
removed rather than rewritten. Kept the required Related topics
section.
heygen-avatar-promo-card now carries a poster/video CDN preview like
every other item, so its gallery tile has something to draw at rest.
* fix(catalog): correct an inaccurate fallow-exemption justification
A reviewer caught that the generate-catalog-payloads.ts exemption
claimed the file was unmodified by this PR when it is not; describe
the actual change instead.
* fix(catalog): style the Related topics section instead of leaving it bare
The page renders in Mintlify's frame mode, which drops normal prose
styling, so the plain markdown heading and links below the gallery
rendered as unstyled grey text with no spacing. Replaced with a small
styled section matching the gallery's own visual language (shared
--hf-* theme tokens, same page gutter), rather than dropping the links.
* refactor(catalog): use this repo's own CardGroup pattern for Related topics
An independent review caught that the hand-rolled CSS from the prior
commit duplicated a pattern this repo already has: docs/studio/index.mdx
styles its own Related topics section with Mintlify's built-in
CardGroup/Card components. Switched to that instead and dropped the
custom CSS. Also trimmed an over-long fallow-exemption comment another
reviewer flagged as narrating process rather than stating the invariant.
* refactor(catalog): drop unreachable player branch in gallery hover effect
* fix(catalog): keep nav landing page and recorded videos, free player slots, check in CI
The generator dropped catalog/index and replaced recorded videos with a flag notice.
A card scrolled away before ready released its player slot twice.
check-docs-catalog now runs in CI.
* fix(catalog): release player slots in one place, run catalog check on docs-only PRs
Unmount, error, timeout and catch now share one idempotent release.
The Lint job also runs when only docs or registry files change.
* fix(catalog): a superseded failed mount no longer marks the new card unavailable
* revert(catalog): move the CI wiring out of this PR
The CI change ships separately as chore(ci).
* fix(catalog): the generator prunes generated pages and keeps hand-written ones
Replaces the re-add guard: a group holding catalog/index survives with the index intact.
|
||
|
|
eae4892ae8 |
chore(deps): update dependency vitest to v4 [security] (#3789)
* chore(deps): update dependency vitest to v4 [security] * fix(test): preserve test behavior on Vitest 4 --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: James <james.russo@heygen.com> |
||
|
|
cd1a996ba4 |
fix(catalog): confine hosted preview asset downloads (#3843)
* fix(catalog): confine hosted preview asset downloads * test(catalog): pin credential and port refusal with finite streams |
||
|
|
962c95406d |
fix(registry): verify staged asset content before publishing manifests (#3832)
* fix(registry): verify staged asset content before publishing manifests * test(registry): run asset staging regression in script CI * refactor(registry): separate verified manifest publication |
||
|
|
db51d5479d |
fix(ci): generated files never read half-written, lint scaling test runner-proof, probe cache test off disk (#3834)
* fix(build): stop generated files from being read half-written during the build Two unrelated pull requests kept failing CI for reasons that had nothing to do with their changes. Typecheck failed with "TS1002: Unterminated string literal" pointing at a generated file. The root build compiles several packages at the same time, and more than one of them regenerates files under a package's src/generated while a sibling's tsc is already reading them. A plain write empties the file and then refills it, so for a few milliseconds what is on disk is the first half of the new file. Whichever build read it in that gap saw a truncated file and stopped. It never happened locally because locally nothing else is reading. Every generator now writes the new version under a temporary name and then renames it over the target, which the filesystem does in one step. A reader either gets the whole previous version or the whole new one; there is no moment where it can see half of either. Content that has not changed is not rewritten at all, so repeat builds no longer touch these files. Four generators were affected and all four now go through one shared helper, which is where the rule lives from now on. The build also rebuilt the core package a second time, in parallel with the packages that read it. That second rebuild was already redundant, and removing it takes the writers out of the window entirely. Renaming is what makes the file safe; dropping the duplicate build makes the build shorter as well. Separately, a linter performance test failed on four of the last ten failed runs on main. It timed a scan with a stopwatch and demanded the result come in under two seconds; one run took 3.7s. That is a statement about how busy the shared runner was, not about the code, because a stopwatch also counts the time the machine spent running someone else's job. The test now counts only the processor time this process actually used, and checks that the cost grows in step with the input rather than against a fixed number of milliseconds. Measured on a machine under load, the stopwatch ratio for the same input reached 45x while the processor-time ratio stayed at 20x. Both fixes come with a check that fails if the fix is removed. * fix(build): keep the shared write helper inside the core package The helper the generators call had been placed in the repo-root scripts folder. Every container image that builds a package copies the packages folders whole but cherry-picks root scripts one file at a time, so the image builds failed on a missing module. The repo already shows both halves of that convention: the one root script a package build imports has a matching copy line in the image, and cross-package imports into the core package need none. The helper now lives with the core package's other build scripts, and the one generator outside that package reaches it the way the engine package already reaches core. * test(engine): keep the probe cache bound test off the filesystem The eviction test wrote, stat'ed and deleted 129 temp files to exercise an in-memory LRU rule. Its runtime tracked filesystem contention rather than the code under test, and on a busy Windows runner the file churn alone pushed a ~300ms test past the 5s timeout, failing unrelated pull requests. Cache identity comes from stat, so the test now synthesises stat results and never touches disk. While here, the test also asserts the LRU touch: re-probing an entry before the bound is hit must keep it resident and evict the next-oldest one instead. The previous shape never hit the cache during the fill, so that branch was untested. * test(lint): keep the scaling check inside the scanner's linear range The CPU-ratio version sampled 320k characters, where the output string's own growth dominates and the whole test cost seconds of CPU; on a shared runner that tripped the default test timeout, the failure this change exists to remove. Sample 10k and 80k characters instead, where 8x input measures ~8x and a quadratic scan still measures 60x or more, and give the test an explicit timeout so a slow runner reports the ratio. * test(core): snapshot file identity through a descriptor The before/after inode and mtime checks read the file through a path stat and then exercised the writer on the same path, which reads as a check-then-use race to static analysis. Snapshot through an open descriptor instead; the assertions are unchanged. |