Skip to main content
Warning or error. A top-level timeline element contains another nested structure instead of a sub-composition mount. The timeline draws one row per top-level element, and the root composition is built only from sub-compositions.
Fix: Move the element and its contents into a sub-composition file and mount it with
Warning or error. A timeline element has no
Warning or error. An element looks like a caption row but is not marked as one, so the timeline cannot group it on the caption track.
Fix: Add
Warning or error. Captions are spread across several timeline tracks instead of one caption lane.
Fix: Give every caption element the same
Warning. A clip runs past the root composition’s
Warning or error. A timed clip sits inside another timed element, and its time window never overlaps that
element’s, so it never appears. A nested clip’s
Error.
Error.
Warning. An element binds a variable that is not declared in
Error. A variable’s default is a URL the runtime refuses to load, so bound elements render their authored fallback src while the render still exits 0.
Fix: Use a relative path,
Error. A legacy
Error. The legacy
Error. The same
Error. Asset paths use
Warning. The composition is larger than the 4096px viewport cap that
Warning. The HTML composition file has grown past a size where it stays easy to read, iterate on, and diff.
Fix: Split it into sub-compositions and mount them from the parent with
Warning. Many elements carry heavy overlay CSS (
Warning. A
Warning.
Error.
Warning. The root has no
Error. The root has no
Error. An
Error. CSS
Error. A CSS selector combines two attributes inside one
Error. The root
Warning. A mounted sub-composition is blank for part of its host’s window because its own
Error. A sub-composition’s root element is styled through class selectors, but at render every rule is scoped to
Error.
Warning. An element has timing attributes but no
Warning. One track in this file carries more than 3 timed elements (audio, video, caption cues and sub-composition mounts are not counted), which makes the timeline harder to read, iterate on, and diff.
Fix: Split the elements into sub-compositions and mount them from the parent with
Error. A
Error. A
Warning. A CSS
Warning. A selector sets position properties through
Error / warning. An id starts with a digit, so
Error. An inline
Error. The composition registers no
Error. A script uses a non-deterministic value source (
Error. A selector requires an id to be nested inside another element with the same id. Ids must be unique, so the selector can never match.
Fix: Remove the duplicate ancestor: change
Warning. The root’s
Error. The root composition is missing
Error. The root composition is missing
Error. A selector observes the runtime-owned hidden style (used to hide native video during frame copying) and forces
Warning. Scoped CSS targets a composition id for which no matching wrapper exists in this HTML.
Fix: Keep the matching composition wrapper, or align the CSS scope to an existing wrapper.
Warning. A timeline-visible element has no
Error. A timeline is registered under a key for which no element carries the matching
Error. A
Error. A tag is missing its closing
Error. CSS or JS block-comment syntax (
Warning. Audio-reactive captions use a single tween per group based on peak values, which sets one static value and is not perceptible as audio reactivity.
Fix: Sample the audio data at 100-200ms intervals across each group’s lifetime and create a tween per sample point.
Error. GSAP sets visibility-affecting properties (
Warning. A timeline callback reaches DOM measurement (
Error. An element authored hidden uses
Error. An element has a CSS
Error. An element has CSS
Error. A full-frame overlay starts visible before its first GSAP opacity tween, so it covers earlier render frames — often as a blank or white video.
Fix: Author the overlay hidden in CSS, or add an immediate
Error / warning. A function-valued tween var reads transform-sensitive geometry, measures layout at tween init, or accesses its first parameter (which is a number, not the element). Error for transform-sensitive reads and bad member access, warning otherwise.
Fix: Compute the value once at build time and pass a constant; for per-element logic use the second parameter:
Warning. A GSAP tween targets several elements with shared keyframes, so editing one element’s keyframes in Studio changes all of them.
Fix: Replace the group selector with individual
Error / warning. A GSAP tween or timeline uses
Error. A GSAP tween animates layout properties (
Error. A relative tween value (
Warning. A repeat count computed with
Warning. A repeat calculation can evaluate to
Error.
Warning. Several
Error. A GSAP timeline is created but never registered on
Error.
Error. Code captures the return of
Warning. The initial hidden state is set with
Warning. GSAP animates a
Error. A tween uses a plugin-specific property such as
Error. The composition uses GSAP but no GSAP script is loaded, so the animation will not run.
Fix: Add the GSAP
Warning. Two GSAP tweens overlap on the same target for the same properties, so the later one overwrites the earlier mid-flight.
Fix: Shorten the earlier tween, move the later one, or add
Error. GSAP writes
Error / warning.
Warning. A voiceover carve names its member clips directly instead of carving an
Warning. An
Error. An audio group exists that no clip joins, so its fader, effects and automation are silently dropped.
Fix: Add
Warning. An
Warning. An element has both a volume automation lane and a GSAP tween on
Warning. An element has
Error. Inline base64 audio or video is present. Base64 media bloats file size and breaks rendering.
Fix: Use a relative path or HTTPS URL for the
Error.
Error.
Error.
Warning. Several matching media entries share the same source, start and duration, so the compiler can discover the same media twice.
Fix: Remove the duplicated media nodes so discovery sees one.
Error. A media
Error. An inline script controls managed media imperatively (
Error. The element has
Error. A media element has
Error. A timed media element has no
Error. A timed media element has no
Warning. The element has
Warning. An inline script mutates the
Error. A media URL’s kind does not match its element — for example a still image on
Warning. The element relies on
Warning. A nested media element’s
Error. The element uses a placeholder media URL that will 404 at render time.
Fix: Replace it with a real, reachable media URL.
Error. A self-closing media tag (
Warning. A speed-ramp lane sits on a non-media element; only
Error. An
Error. A timed
Error. A
Error. A
Error. A caption selector uses
Error. Caption exit animations (
Warning.
Error. A caption container has
Warning. A caption selector has
Warning.
Error. A captions composition loads its transcript with
Error. A
Warning. A system font family is used without a matching
Warning. A texture material class is used without the base
Error. A texture material class is not defined by any local CSS, so the text renders untextured.
Fix: Paste the Texture Mask Text component’s
Warning. A drop shadow is applied directly to textured text, which shadows the mask rather than the glyphs.
Fix: Wrap the textured text and apply
Warning.
Error. A slideshow island contains invalid JSON or a structure that does not match the manifest schema.
Fix: Make the
Error. The slideshow manifest references a
Error. The composition uses Lottie but no Lottie script is loaded, so the animation will not render.
Fix: Add the
Error. The composition uses Three.js but no Three.js script is loaded, so the 3D scene will not render.
Fix: Add the Three.js
Warning. A clip carries
Warning. Clips sharing a
Error. Several root-level HTML files carry
Error. The default
Error. A
Error. An element references local files that do not exist in the project, so the renderer silently skips them and the video ships with missing visuals.
Fix: Add the file to the project directory, or update the
Warning. The project contains audio files but no
Error. An
Warning. Two audible elements overlap on the same track index, so their audio doubles up.
Fix: Use non-overlapping time windows or different track indices.
Error. A CSS
Error. A remote media URL did not answer a
Info. A video file uses the HEVC/H.265 codec. Renders are unaffected (FFmpeg pre-decodes), and preview automatically falls back to a cached H.264 proxy when the browser cannot decode HEVC.
Fix: Nothing required. If preview playback still fails, run
Warning. A video’s
Composition reference
Lint rules
Every lint finding code with its severity, what it catches, and how to fix it.
hyperframes lint, hyperframes check and the @hyperframes/lint package report findings with a stable code. This page lists every code with its severity, what it catches, and how to fix it. The codes come straight from the rule set in packages/lint/src/rules/ plus the project-level probes that run as part of a project lint.
Severities:
- Error — the composition is broken or the render will fail or visibly diverge. Fails
hyperframes checkby default. - Warning — a quality, determinism or maintainability hazard. Does not fail
hyperframes checkunless you pass--strict; inrender, warnings abort only under--strict-all. - Info — a heads-up that needs no action. Shown by
hyperframes lint --verbose.
Looking for a code from a render or check log? Codes appear in the output of
npx hyperframes lint [dir] — add --json to script over them. check additionally runs runtime, layout and motion audits beyond these lint rules; see Troubleshooting.Structure and timeline
Source:packages/lint/src/rules/structure.ts.
The five codes marked Warning or error are warnings when the CLI lints a project, and errors when Studio
lints the file it is editing.
nested_structure_needs_subcomposition
Warning or error. A top-level timeline element contains another nested structure instead of a sub-composition mount. The timeline draws one row per top-level element, and the root composition is built only from sub-compositions.
Fix: Move the element and its contents into a sub-composition file and mount it with data-composition-src.
timeline_element_missing_timing
Warning or error. A timeline element has no data-duration, so the timeline cannot draw where it ends.
Fix: Add data-duration (in seconds) to the element.
caption_track_kind_missing
Warning or error. An element looks like a caption row but is not marked as one, so the timeline cannot group it on the caption track.
Fix: Add data-track-kind="captions" to the element.
multiple_caption_tracks
Warning or error. Captions are spread across several timeline tracks instead of one caption lane.
Fix: Give every caption element the same data-track-index.
clip_ends_past_root_duration
Warning. A clip runs past the root composition’s data-duration, so it is cut off in previews, posters and renders.
Fix: Extend the root data-duration, or make the clip end at or before it.
nested_clip_never_visible
Warning or error. A timed clip sits inside another timed element, and its time window never overlaps that
element’s, so it never appears. A nested clip’s data-start counts from the composition’s start, not from the
element around it. Runs in sub-composition files too.
Fix: Give the clip a data-start inside its parent’s window, in composition time, or move it out of the
parent.
Composition contract
Source:packages/lint/src/rules/composition.ts.
invalid_composition_variables_declaration
Error. data-composition-variables is not valid JSON or not an array of variable declarations.
Fix: Provide a JSON array such as data-composition-variables='[{"id":"title","type":"string","label":"Title","default":"Hello"}]' — single-quote the attribute, double-quote the JSON.
invalid_variable_values_json
Error. data-variable-values is not valid JSON.
Fix: Single-quote the attribute and double-quote the JSON keys and values, e.g. data-variable-values='{"title":"Hello"}'.
unknown_variable_binding
Warning. An element binds a variable that is not declared in data-composition-variables, so the binding silently keeps the authored fallback.
Fix: Declare the variable on the composition root (<html>, or the data-composition-id root of a template or fragment composition).
unloadable_media_variable_default
Error. A variable’s default is a URL the runtime refuses to load, so bound elements render their authored fallback src while the render still exits 0.
Fix: Use a relative path, http(s), blob:, or a data:image/* URI. Copy the file into the project and reference it relatively.
deprecated_data_end
Error. A legacy data-end is used without data-duration, or a stale data-end disagrees with the data-duration next to it.
Fix: Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.
deprecated_data_layer
Error. The legacy data-layer attribute is used.
Fix: Replace it with data-track-index, the canonical name Studio and the linter read.
duplicate_composition_id
Error. The same data-composition-id appears on several elements in one file — often a <meta> tag carrying the same id as the root <div>.
Fix: Keep data-composition-id on exactly one element: the composition root. Remove it from metadata or duplicate hosts.
invalid_parent_traversal_in_asset_path
Error. Asset paths use ../ to traverse above the project root; render and preview clamp or misresolve them.
Fix: Point the path at a file inside the project — from compositions/scene.html, both ../assets/x.png and assets/x.png reach the project’s assets folder.
composition_exceeds_inspection_viewport_cap
Warning. The composition is larger than the 4096px viewport cap that check, validate, snapshot, compare and layout audits clamp to. render is unaffected, but a clean inspection result no longer covers the whole canvas.
Fix: Keep the authored size if the output needs it, and verify the region past the cap from a render rather than from inspection commands.
composition_file_too_large
Warning. The HTML composition file has grown past a size where it stays easy to read, iterate on, and diff.
Fix: Split it into sub-compositions and mount them from the parent with data-composition-src.
composition_heavy_overlay_count_high
Warning. Many elements carry heavy overlay CSS (filter: blur, radial-gradient, clip-path), which can cap capture performance — including hidden ones.
Fix: Split the composition and concat the pieces so each capture sees a small subset of heavy overlays; remove overlays that are not visible anyway.
missing_data_no_timeline
Warning. A data-composition-id element (or the root) has neither a matching window.__timelines registration nor data-no-timeline, so the producer polls up to 45 seconds before timing out.
Fix: Register the timeline, mount the composition with data-composition-src, or add data-no-timeline for genuinely static sections.
negative_z_index
Warning. z-index below 0 paints the element behind its nearest stacking context’s content; with no stacking-context ancestor that is the composition root, so an opaque background there hides the element entirely.
Fix: Give the element’s parent a stacking context (isolation: isolate is the cheapest; transform, filter, opacity below 1, contain: paint, will-change also work).
requestanimationframe_in_composition
Error. requestAnimationFrame runs on wall-clock time, not the GSAP timeline, so it desyncs from frame capture and can flicker or drop frames in renders.
Fix: Use GSAP tweens or timeline onUpdate callbacks for animation logic instead.
root_composition_duration_derived
Warning. The root has no data-duration and no GSAP timeline, so its length is inferred from its clips.
Fix: Add data-duration="<seconds>" to the root element to set the length yourself.
root_composition_missing_duration_source
Error. The root has no data-duration, no GSAP timeline, and no CSS, WAAPI, Lottie or Three.js animation to infer a duration from, so the render engine cannot determine how long to capture and fails.
Fix: Add data-duration="<seconds>" to the root, or add a paused GSAP timeline registered on window.__timelines.
root_composition_missing_html_wrapper
Error. An index.html carrying data-composition-id is a bare fragment without <!DOCTYPE html>, <html> or <body>, so browsers quirks-mode it and the preview server mis-serves it.
Fix: Wrap the composition in <!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>...</body></html>.
root_zoom_rescales_a_fixed_canvas
Error. CSS zoom on the canvas rescales the painted composition inside a capture frame that does not rescale with it — the frame is sized from the root’s data-width and data-height in layout pixels.
Fix: Author at the real size: set data-width and data-height (and the root’s width and height) and drop the canvas-level zoom. To scale the output without changing layout, pass --output-resolution to render. zoom on descendants is fine.
split_data_attribute_selector
Error. A CSS selector combines two attributes inside one [...] block, which browsers reject — GSAP timelines or querySelector calls fail before they register.
Fix: Use separate attribute selectors: [data-composition-id="x"][data-track-index="1"].
standalone_composition_wrapped_in_template
Error. The root index.html is wrapped in a <template> tag, so the runtime cannot play it — only sub-compositions loaded via data-composition-src use <template> wrappers.
Fix: Remove the <template> wrapper and serve the composition as a real document.
subcomposition_blanks_before_host
Warning. A mounted sub-composition is blank for part of its host’s window because its own data-duration is shorter than the slot it fills.
Fix: Set the sub-composition’s data-duration to fill the host window, or cover the gap with another clip.
subcomposition_root_styled_by_class
Error. A sub-composition’s root element is styled through class selectors, but at render every rule is scoped to [data-composition-id=...], so the class-keyed styles stop applying.
Fix: Give the root id="root" and style it with #root plus plain descendant selectors.
template_literal_selector
Error. querySelector is called with a template-literal variable, which the bundler’s CSS parser crashes on.
Fix: Use hardcoded string selectors instead of interpolated ones.
timed_element_missing_clip_class
Warning. An element has timing attributes but no class="clip". The runtime still times it, but Studio and the clip-ownership rules use .clip to recognise it, so it is harder to edit and to lint.
Fix: Add class="clip" to the element.
timeline_track_too_dense
Warning. One track in this file carries more than 3 timed elements (audio, video, caption cues and sub-composition mounts are not counted), which makes the timeline harder to read, iterate on, and diff.
Fix: Split the elements into sub-compositions and mount them from the parent with data-composition-src.
Document, CSS and scripts
Source:packages/lint/src/rules/core.ts.
host_missing_composition_id
Error. A data-composition-src host element has no data-composition-id of its own.
Fix: Set data-composition-id on every data-composition-src host element.
css_parse_error
Error. A <style> block fails to parse as CSS.
Fix: Fix the reported CSS syntax error.
css_transition_used
Warning. A CSS transition declaration runs on the browser clock and cannot be seeked deterministically across render workers. transition: none and all-zero durations are allowed.
Fix: Keep the class or attribute swap for state, but put the visual change on the paused GSAP timeline.
id_override_reduced_specificity
Warning. A selector sets position properties through [id=...] or :where(#id), which has class-level or zero specificity, so a compound class rule on the same element can silently win.
Fix: Use the plain #id selector; id specificity beats any selector built only from classes.
id_requires_css_escape
Error / warning. An id starts with a digit, so #id selectors throw a SyntaxError in querySelector and GSAP, and CSS drops the rule. Error when such a selector is actually used in the composition, warning otherwise.
Fix: Rename the id to start with a letter (recommended), or build selectors with CSS.escape(id) at runtime.
invalid_inline_script_syntax
Error. An inline <script> is closed with malformed syntax.
Fix: Close inline scripts with a valid </script> tag.
missing_timeline_registry
Error. The composition registers no window.__timelines registry at all.
Fix: Register each composition timeline on window.__timelines[compositionId].
non_deterministic_code
Error. A script uses a non-deterministic value source (Math.random, Date.now, gsap.utils.random, "random(...)"), so renders can differ between frames or runs.
Fix: Precompute the value once at build time and pass a constant, or seed and freeze it.
repeated_id_descendant_selector
Error. A selector requires an id to be nested inside another element with the same id. Ids must be unique, so the selector can never match.
Fix: Remove the duplicate ancestor: change #x #x to #x.
root_dimensions_mismatch
Warning. The root’s data-width/data-height were edited directly, but the scaffold’s html, body CSS and <meta viewport> still hold the old resolution, and a stale overflow: hidden body visually clips the correctly-sized root.
Fix: Update the body CSS and viewport to match, or scaffold with hyperframes init --resolution portrait.
root_missing_composition_id
Error. The root composition is missing data-composition-id.
Fix: Add a stable data-composition-id to the entry composition wrapper.
root_missing_dimensions
Error. The root composition is missing data-width or data-height.
Fix: Set numeric data-width and data-height on the entry composition root.
runtime_hidden_style_opacity
Error. A selector observes the runtime-owned hidden style (used to hide native video during frame copying) and forces opacity to zero, which breaks the video replacement pipeline.
Fix: Restrict the guard to sub-composition hosts (for example [data-composition-src][style*="visibility: hidden"]) and do not derive element or media opacity from the runtime’s hidden style.
scoped_css_missing_wrapper
Warning. Scoped CSS targets a composition id for which no matching wrapper exists in this HTML.
Fix: Keep the matching composition wrapper, or align the CSS scope to an existing wrapper.
studio_missing_editable_id
Warning. A timeline-visible element has no id, so Studio cannot target it stably for timeline and canvas edits.
Fix: Add a stable, human-readable id such as id="hero-title" to elements that agents or Studio should edit.
timeline_id_mismatch
Error. A timeline is registered under a key for which no element carries the matching data-composition-id, so the runtime cannot auto-nest it.
Fix: Make window.__timelines["<key>"] match the element’s data-composition-id, or vice versa.
unbalanced_style_tags
Error. A <style> block is never closed (following markup is parsed as CSS and disappears), or an extra </style> closes the stylesheet early and dumps CSS into the body as visible text.
Fix: Keep <style> and </style> paired.
unclosed_tag_swallowed_element
Error. A tag is missing its closing > before the next <, so the following element is swallowed as bogus attribute text and never becomes a real node.
Fix: Close the previous tag’s > before opening the next element.
visible_markup_comment
Error. CSS or JS block-comment syntax (/* ... */) appears in visible HTML markup, where only <!-- ... --> is a comment — so it renders as on-screen text.
Fix: Remove the text or convert it to a real HTML comment; keep CSS comments inside <style> and JS comments inside <script>.
GSAP animation
Source:packages/lint/src/rules/gsap.ts.
audio_reactive_single_tween_per_group
Warning. Audio-reactive captions use a single tween per group based on peak values, which sets one static value and is not perceptible as audio reactivity.
Fix: Sample the audio data at 100-200ms intervals across each group’s lifetime and create a tween per sample point.
gsap_animates_clip_element
Error. GSAP sets visibility-affecting properties (opacity, visibility, autoAlpha) directly on a clip element whose visibility the framework owns.
Fix: Remove the visibility or autoAlpha tween, or move the content into a child <div> and target that instead.
gsap_callback_dom_measurement
Warning. A timeline callback reaches DOM measurement (getBoundingClientRect, getTotalLength, getComputedStyle, …). Callbacks re-fire on every seek, and a cold render worker runs them against a different layout than the sequential pass.
Fix: Do all measurement and DOM setup synchronously at build time, before registering the timeline, or derive geometry from fixed composition coordinates.
gsap_cold_seek_hidden_fromto_missing_reveal
Error. An element authored hidden uses gsap.fromTo() whose destination vars omit opacity/autoAlpha, so cold render workers restore the hidden state and the element can stay invisible.
Fix: Add opacity: 1 (or autoAlpha: 1) to the destination vars so every seek path establishes the visible end state.
gsap_css_transform_conflict
Error. An element has a CSS transform (for example translateX(-50%) centering) and a GSAP tween animates transform properties — GSAP overwrites the full CSS transform.
Fix: Remove the transform from CSS and express it in GSAP properties instead; tl.fromTo with explicit start values is exempt.
gsap_from_opacity_noop
Error. An element has CSS opacity: 0 and a gsap.from() that also sets opacity to 0, so it animates from 0 to 0 and never appears.
Fix: Remove opacity: 0 from the CSS or inline style and let the gsap.from() own the initial hidden state.
gsap_fullscreen_overlay_starts_visible
Error. A full-frame overlay starts visible before its first GSAP opacity tween, so it covers earlier render frames — often as a blank or white video.
Fix: Author the overlay hidden in CSS, or add an immediate gsap.set(..., { opacity: 0 }) before the reveal tween.
gsap_function_value_hazard
Error / warning. A function-valued tween var reads transform-sensitive geometry, measures layout at tween init, or accesses its first parameter (which is a number, not the element). Error for transform-sensitive reads and bad member access, warning otherwise.
Fix: Compute the value once at build time and pass a constant; for per-element logic use the second parameter: (index, target) => ....
gsap_group_selector_keyframes
Warning. A GSAP tween targets several elements with shared keyframes, so editing one element’s keyframes in Studio changes all of them.
Fix: Replace the group selector with individual tl.to() calls per element.
gsap_infinite_repeat
Error / warning. A GSAP tween or timeline uses repeat: -1. Warning when the composition declares a finite data-duration (seeking and export are clipped to it), error when nothing bounds the timeline.
Fix: Declare a finite data-duration, or replace repeat: -1 with a finite count such as repeat: Math.max(0, Math.floor(totalDuration / cycleDuration) - 1).
gsap_non_transform_motion
Error. A GSAP tween animates layout properties (left, top, width, …), text-reflow properties (fontSize, letterSpacing, …) or sets roundProps, all of which snap to integer device pixels and stutter under frame capture.
Fix: Animate transforms instead: positional properties become x/y/scale; reflow properties need per-character splits or a static final value; remove roundProps.
gsap_relative_value_second_writer
Error. A relative tween value (+=...) starts while another writer is still active on the same property, so different seek paths init the relative tween from different bases and the frame snaps.
Fix: Use absolute values or a fromTo() with explicit endpoints for that property. A relative value with a single writer is safe.
gsap_repeat_ceil_overshoot
Warning. A repeat count computed with Math.ceil can overshoot the composition duration, extending the animation past it.
Fix: Use Math.floor in the repeat calculation: repeat: Math.max(0, Math.floor(totalDuration / cycleDuration) - 1).
gsap_repeat_floor_unclamped
Warning. A repeat calculation can evaluate to -1 when the composition is shorter than one cycle, which GSAP interprets as an infinite repeat.
Fix: Clamp the count at zero: repeat: Math.max(0, Math.floor(totalDuration / cycleDuration) - 1).
gsap_repeat_refresh_relative_value
Error. repeatRefresh: true combined with a relative value accumulates per iteration; a cold render worker seeking into iteration N never performed the earlier accumulation, so its result differs.
Fix: Remove repeatRefresh: true, or replace the relative value with absolute endpoints (a fromTo()).
gsap_repeated_fromto_without_baseline
Warning. Several tl.fromTo() calls target the same element with no stable baseline, so the last-authored “from” values become the resting state for any seek before the first tween runs.
Fix: Add immediateRender: false to every fromTo except the earliest-positioned one.
gsap_timeline_not_registered
Error. A GSAP timeline is created but never registered on window.__timelines, so the runtime never discovers it and the animation does not play in preview or render.
Fix: Add window.__timelines = window.__timelines || {}; and assign the timeline under the composition’s data-composition-id.
gsap_timeline_registered_before_async_build
Error. window.__timelines is assigned before the timeline is built inside document.fonts.ready, so an empty timeline registers first and can nest empty in sub-compositions.
Fix: Move the window.__timelines[id] = tl assignment to the end of the async build callback, after the tweens are added.
gsap_timeline_return_used_as_tween
Error. Code captures the return of tl.to()/tl.from()/tl.set() expecting the tween, but those methods return the timeline itself — so a later kill() or overwrite hits the whole timeline.
Fix: Put the group of tweens in a nested timeline (gsap.timeline() added with tl.add(nested, 0)) and kill that instead.
gsap_timeline_set_initial_hide
Warning. The initial hidden state is set with tl.set(..., 0) inside the paused timeline; a zero-duration set at position 0 does not render while the playhead sits exactly at 0, so frame 0 shows the un-hidden state.
Fix: Use gsap.set(...) outside the timeline, or author the hidden state directly in CSS or attributes.
gsap_undefined_css_variable
Warning. GSAP animates a var(--...) CSS variable that no static CSS or composition-variable declaration defines, so the computed color may become invalid or transparent.
Fix: Define the variable in CSS, declare it in data-composition-variables, or add a var(--x, #fff) fallback.
missing_gsap_plugin
Error. A tween uses a plugin-specific property such as motionPath, but the plugin is not loaded and registered, so core GSAP ignores the property.
Fix: Load the plugin before the animation script and register it with gsap.registerPlugin(...), or express the motion with core x/y tweens.
missing_gsap_script
Error. The composition uses GSAP but no GSAP script is loaded, so the animation will not run.
Fix: Add the GSAP <script> tag before the animation script.
overlapping_gsap_tweens
Warning. Two GSAP tweens overlap on the same target for the same properties, so the later one overwrites the earlier mid-flight.
Fix: Shorten the earlier tween, move the later one, or add overwrite: "auto".
svg_drawon_css_dasharray_conflict
Error. GSAP writes strokeDasharray on an element whose CSS declares a multi-component stroke-dasharray; GSAP merges dash lists per component, so the CSS gap survives and the draw-on breaks.
Fix: Remove the CSS stroke-dasharray (decorative dashes belong on a separate element), or set the full two-component value in GSAP.
svg_measure_before_path_d
Error / warning. getTotalLength() is called on a path with no static d attribute, so it returns 0 and the dash animation dies. Error when no d assignment exists anywhere, warning when d is only assigned inside a function body.
Fix: Assign the path’s d synchronously at build time (top level, before measuring), or author a static d attribute in the HTML.
Media elements
Source:packages/lint/src/rules/media.ts.
audio_carve_ungrouped_sources
Warning. A voiceover carve names its member clips directly instead of carving an <hf-audio-group>, so the list silently rots when clips change.
Fix: Group the voice clips and carve against the group.
audio_group_carve_attr
Warning. An <hf-audio-group> carries data-fx-carve (or a carve-derived chain), but a carve belongs on the bed clip, not the bus.
Fix: Remove data-fx-carve from the group and carve the bed clip instead.
audio_group_no_members
Error. An audio group exists that no clip joins, so its fader, effects and automation are silently dropped.
Fix: Add data-audio-group="<id>" to the clips the bus is for, or delete the bus.
audio_group_timing_attrs
Warning. An <hf-audio-group> carries timing attributes (data-start, data-duration, data-track-index). A group has no clip window of its own; its members carry the timing.
Fix: Remove the timing attributes from the group and set them on the member clips.
audio_volume_double_automation
Warning. An element has both a volume automation lane and a GSAP tween on volume; the lane wins and the tween is ignored in preview and render.
Fix: Keep one: delete the lane to tween, or drop the tween and shape the level in the lane.
audio_volume_tween_overrides_gain
Warning. An element has data-volume gain and a GSAP tween on volume; tween values are absolute and replace the gain rather than scale it.
Fix: Write tween targets as absolute gains that already include the gain, or reset data-volume to 1 and let the tween carry the level.
base64_media_prohibited
Error. Inline base64 audio or video is present. Base64 media bloats file size and breaks rendering.
Fix: Use a relative path or HTTPS URL for the src — never embed media as base64.
color_grading_invalid_json
Error. data-color-grading on a <video> or <img> starts with { or [ but is not valid JSON, so the grade does not render.
Fix: Use valid JSON, for example data-color-grading='{"preset":"skin-soft","intensity":0.6,"adjust":{"highlights":-0.08}}' — single-quote the attribute, double-quote the JSON.
color_grading_invalid_structure
Error. data-color-grading parses as JSON but breaks the grading contract — an unsupported key, a value of the wrong type, or a number out of range. The runtime silently ignores unknown keys, so a control can look applied in the HTML yet never render. One finding is reported per problem, naming the offending path.
Fix: Correct or remove the value the finding names, following the Color grading reference.
color_grading_non_media
Error. data-color-grading is set on an element other than <video>, <img> or <canvas>, such as a
wrapper or an element with a CSS background. The shader runtime only grades real <video>, <img> and
<canvas> elements, so the attribute has no effect.
Fix: Move the attribute to the <video>, <img> or <canvas> element itself.
duplicate_media_discovery_risk
Warning. Several matching media entries share the same source, start and duration, so the compiler can discover the same media twice.
Fix: Remove the duplicated media nodes so discovery sees one.
duplicate_media_id
Error. A media id is defined on multiple elements, so preview and the producer can build different media graphs.
Fix: Give each media element a unique id.
imperative_media_control
Error. An inline script controls managed media imperatively (play, pause, currentTime, …). HyperFrames must own playback to keep preview, timeline and renders deterministic.
Fix: Express timing with data-start/data-duration and media offsets such as data-media-start instead.
media_crossorigin_breaks_preview
Error. The element has crossorigin, which forces a CORS-checked fetch; if the host omits CORS headers, the load fails silently in Studio preview (blank media) while renders still work.
Fix: Remove crossorigin unless you read the media back through canvas, WebGL or WebAudio from a host known to send CORS headers.
media_missing_data_start
Error. A media element has src but no data-start, so HyperFrames cannot own its playback and preview and render can diverge.
Fix: Add data-start="0" (or the intended start) and data-duration if the clip should stop before the source ends.
media_missing_id
Error. A timed media element has no id, so the renderer cannot discover it — the audio goes silent or the video freezes.
Fix: Add a unique id attribute to the element.
media_missing_src
Error. A timed media element has no src (on the element or a <source> child), so the renderer cannot load it.
Fix: Add src to the element, or a <source src="..."> child.
media_preload_none
Warning. The element has preload="none", which prevents the renderer from loading the media (the compiler strips it for renders, but preview can misbehave).
Fix: Remove preload="none" or change it to preload="auto".
media_runtime_src_mutation
Warning. An inline script mutates the src of existing managed media, which races media discovery and extraction.
Fix: Author the final static src, or bind data-var-src to a declared variable so the source is applied before discovery.
media_src_kind_mismatch
Error. A media URL’s kind does not match its element — for example a still image on <video> or a video URL on <img>, so the element renders nothing.
Fix: Match the element to the media: <img> for stills, <video> for video URLs, <audio> for sound.
media_variable_src_no_fallback
Warning. The element relies on data-var-src with no fallback src, so renders without that variable value cannot load the media, and audio extraction reads the authored src.
Fix: Add a fallback src the composition can render with when the variable is not provided.
nested_media_start_basis_ambiguous
Warning. A nested media element’s data-start is ambiguous: composition-local or a legacy root-global timestamp, and the two read as different frames.
Fix: Keep data-start composition-local, or mark the legacy basis with data-hf-media-start-basis="global"; otherwise convert to local time.
placeholder_media_url
Error. The element uses a placeholder media URL that will 404 at render time.
Fix: Replace it with a real, reachable media URL.
self_closing_media_tag
Error. A self-closing media tag (<video ... />) is invalid HTML: the browser leaves the tag open and swallows all subsequent elements as invisible fallback content, making the composition invisible.
Fix: Write explicit closing tags: <video ...></video>. Media elements must never be self-closed.
speed_ramp_on_non_media
Warning. A speed-ramp lane sits on a non-media element; only <video> and <audio> clips can be retimed, so the lane does nothing.
Fix: Move the rate lane onto the video or audio clip, or retime an animation with a GSAP timeline.
video_audio_double_source
Error. An <audio> element and a <video> element point at the same source at the same time; the unmuted video already carries the sound, so playback echoes.
Fix: Let the video carry its own sound (recommended), or mute the video and keep the separate <audio> when picture and sound must be cut independently.
video_missing_muted
Error. A timed <video> declares neither muted nor data-has-audio="true", so the linter cannot tell silent footage from sound-carrying footage.
Fix: Add data-has-audio="true" when the file has sound, or muted when it is silent.
video_muted_with_declared_audio
Error. A <video> declares data-has-audio="true" but also carries muted, so Studio preview silences the audio the declaration promises.
Fix: Remove muted if the video should be audible, or drop data-has-audio and use data-volume="0" for silent visual video.
video_nested_in_timed_element
Error. A <video> with data-start is nested inside another timed element; the frame extractor resolves the video’s start without the wrapper’s offset while visibility uses the wrapper’s window, so the clip shows wrong frames and disappears partway.
Fix: Time the wrapper or the video, never both: remove data-start from the wrapper, or move the <video> up to be a direct child of the stage.
Captions
Source:packages/lint/src/rules/captions.ts.
caption_container_relative_position
Error. A caption selector uses position: relative, which causes overflow and breaks caption stacking.
Fix: Use position: absolute for all caption elements.
caption_exit_missing_hard_kill
Error. Caption exit animations (tl.to with opacity: 0) have no hard tl.set kill, so conflicting karaoke tweens can leave captions stuck on screen.
Fix: Add tl.set(groupEl, { opacity: 0, visibility: "hidden" }, group.end) after every exit tween as a deterministic kill.
caption_fittext_scale_mismatch
Warning. fitTextFontSize uses a maxWidth that leaves no headroom for emphasis words scaled above 1x, so the effective width can overflow the composition.
Fix: Reduce maxWidth to leave headroom for the scale factor.
caption_overflow_clips_scaled_words
Error. A caption container has overflow: hidden while GSAP scales caption words above 1x, so scaled emphasis words and their glow are clipped.
Fix: Use overflow: visible on caption containers and prevent overflow with fitTextFontSize and a reduced maxWidth instead.
caption_text_overflow_risk
Warning. A caption selector has white-space: nowrap but no max-width, so long phrases clip off-screen.
Fix: Add max-width: 1600px (landscape) or 900px (portrait), keeping overflow visible.
caption_textshadow_on_group_container
Warning. textShadow is tweened on a caption group container; with semi-transparent children the glow renders as a visible rectangle behind the whole group.
Fix: Apply textShadow to individual active word elements and use scale on the group for pulsing.
caption_transcript_not_inline
Error. A captions composition loads its transcript with fetch(), but the Studio caption editor needs an inline var TRANSCRIPT = [...] array to detect and edit captions.
Fix: Embed the transcript inline as var TRANSCRIPT = [...] with JSON-quoted keys.
Fonts
Source:packages/lint/src/rules/fonts.ts.
font_family_without_font_face
Error. A @font-face-undeclared font family is used, so the renderer cannot supply it and text falls back to a default face.
Fix: Declare each family with @font-face pointing at the captured .woff2 files, or bundle the font under capture/assets/fonts/.
system_font_will_alias
Warning. A system font family is used without a matching @font-face; in distributed rendering system-font capture is disabled, so the font is substituted at render time and text can reflow. Only reported when the linter runs with the distributed: true option (linting for distributed or Lambda renders); a local render captures the system font as designed, so it is not flagged there.
Fix: Bundle the font with @font-face and a project-local file instead of relying on OS fonts.
Textures
Source:packages/lint/src/rules/textures.ts.
texture_class_missing_base
Warning. A texture material class is used without the base hf-texture-text class, so the texture pipeline does not engage.
Fix: Add the base class alongside the material class, e.g. class="hf-texture-text hf-texture-lava".
texture_class_unknown
Error. A texture material class is not defined by any local CSS, so the text renders untextured.
Fix: Paste the Texture Mask Text component’s <style> block into the composition, or fix the class typo.
texture_drop_shadow_on_text
Warning. A drop shadow is applied directly to textured text, which shadows the mask rather than the glyphs.
Fix: Wrap the textured text and apply filter: drop-shadow(...) to the wrapper, not the hf-texture-text element.
texture_text_missing_mask
Warning. hf-texture-text is used without a texture material class or a custom mask-image, so there is nothing to reveal.
Fix: Add a material class such as hf-texture-lava, or set mask-image and -webkit-mask-image on the element.
Slideshows
Source:packages/lint/src/rules/slideshow.ts.
slideshow_invalid
Error. A slideshow island contains invalid JSON or a structure that does not match the manifest schema.
Fix: Make the <script type="application/hyperframes-slideshow+json"> block valid JSON matching the SlideshowManifest schema.
slideshow_unresolved_ref
Error. The slideshow manifest references a sceneId with no matching scene element, or a scene with no explicit window.
Fix: Make every sceneId match a scene element’s data-composition-id, or provide explicit startTime/endTime.
Adapters: Lottie and Three.js
Source:packages/lint/src/rules/adapters.ts.
missing_lottie_script
Error. The composition uses Lottie but no Lottie script is loaded, so the animation will not render.
Fix: Add the lottie-web <script> tag before the Lottie code.
missing_three_script
Error. The composition uses Three.js but no Three.js script is loaded, so the 3D scene will not render.
Fix: Add the Three.js <script> tag before the Three.js code.
Linked clips
Source:packages/lint/src/rules/linkedClips.ts.
linked_clip_orphan
Warning. A clip carries data-link whose partner clip no longer exists, so it edits as a group of one.
Fix: Remove the data-link attribute, or restore the partner clip.
linked_clips_out_of_sync
Warning. Clips sharing a data-link differ in their timing attributes, but linked clips are edited as one.
Fix: Give every member the same data-start, data-duration, data-media-start and data-playback-rate, or remove data-link from all of them to unlink.
Project-level checks
Source: the project lint pass inpackages/lint/src/project.ts, packages/lint/src/hyperframeLinter.ts and packages/lint/src/hevcPreviewLint.ts.
multiple_root_compositions
Error. Several root-level HTML files carry data-composition-id, so the runtime may discover multiple entry points and duplicate audio playback.
Fix: Keep exactly one root index.html with data-composition-id; remove or rename the extra files.
blank_root_with_standalone_composition
Error. The default index.html has no renderable content while another file holds a standalone timed composition, so default commands open an empty video.
Fix: Move the composition into index.html, or mount it with data-composition-src; if the separate file is intentional, render it explicitly.
missing_or_empty_sub_composition
Error. A data-composition-src points at a folder, an empty file, or a missing file, so the mount is unusable and the render pre-flight rejects it.
Fix: Point data-composition-src at the HTML file (such as <folder>/index.html) and make sure it renders content.
missing_local_asset
Error. An element references local files that do not exist in the project, so the renderer silently skips them and the video ships with missing visuals.
Fix: Add the file to the project directory, or update the src to an existing file. A common cause is renamed captured assets.
audio_file_without_element
Warning. The project contains audio files but no <audio> element in any composition, so the rendered video will be silent.
Fix: Add an <audio> element referencing the file.
audio_src_not_found
Error. An <audio> element references files that are not in the project, so the rendered video will be silent.
Fix: Add the missing file(s) to the project directory, or update the src to point at existing files.
duplicate_audio_track
Warning. Two audible elements overlap on the same track index, so their audio doubles up.
Fix: Use non-overlapping time windows or different track indices.
texture_mask_asset_not_found
Error. A CSS mask-image references files that are not in the project, so the texture mask fails to load.
Fix: Add the missing mask file(s) to the project, or update the mask-image URL.
inaccessible_media_url
Error. A remote media URL did not answer a HEAD request with a 2xx status (or the request failed or timed out), so the media cannot load. Reported only by the async lintMediaUrls() export of @hyperframes/lint; hyperframes lint and hyperframes check do not run it.
Fix: Replace it with a valid, reachable media URL.
hevc_preview_codec
Info. A video file uses the HEVC/H.265 codec. Renders are unaffected (FFmpeg pre-decodes), and preview automatically falls back to a cached H.264 proxy when the browser cannot decode HEVC.
Fix: Nothing required. If preview playback still fails, run hyperframes doctor and check that media auto-proxying is enabled.
video_media_start_at_or_past_eof
Warning. A video’s data-media-start sits at or past the source’s playable duration, so the video holds its final frame for the whole slot.
Fix: Trim data-media-start below the source duration if the final-frame hold is unintended.