You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(lint): stop erroring on the documented canonical clip block (#3374)
Linting the primitive-clip example from packages/core/docs/core.md produced
two errors against the docs' own linter:
error timed_element_missing_clip_class el-3 <img data-start ...>
error self_closing_media_tag el-4 <audio ... />
Both are now fixed, in opposite directions — one was the rule's fault, one was
the docs'.
`timed_element_missing_clip_class` claimed the element "will be visible for the
entire composition instead of only during its scheduled time range". That is
not what happens. `syncTimedElementVisibility` walks
`querySelectorAll("[data-start]")` and toggles `style.visibility` off the
ATTRIBUTE, with no reference to the class; the runtime's own init test pins it
with a bare `<div data-start data-duration>` carrying no `class="clip"`. Every
other consumer of the string "clip" — Studio's label derivation, the runtime's
timeline labels, core's selector helper — treats it as a name to skip, never as
a behaviour key. So the class is an authoring convention the tooling reads, not
the mechanism that hides the element.
The rule is therefore a warning rather than an error, and its message now says
what is actually true. `img` joins `audio` and `video` in skipTags: the three
media primitives sit on adjacent lines of the same documented clip block, all
three authored without `class="clip"`, and flagging only the `<img>` is what
made the documented pattern fail.
`self_closing_media_tag` was right and the docs were wrong: `/` is ignored on a
non-void element, so `<audio ... />` leaves the element open and everything
after it nests inside. Changed to `<audio ...></audio>`. The `<img ... />` on
the line above is a genuine void element and stays as it is.
The same false mechanism claim had been copied into the talking-head-recut
skill, in both the annotated example and the rules list, where agents read it
as fact. Corrected there too.
No effect on the 643 shipped registry files (this rule fires on none of them);
the change is to the documented pattern and to agent-authored compositions.
Regression test lints the canonical block verbatim and asserts it produces no
errors or warnings, so docs and linter cannot drift apart again silently.
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has timing attributes but no class="clip". The element will be visible for the entire composition instead of only during its scheduled time range.`,
542
+
// Not an error: the runtime drives timed visibility off the `data-start`
543
+
// ATTRIBUTE, not this class — `syncTimedElementVisibility` walks
544
+
// `querySelectorAll("[data-start]")` and toggles `style.visibility`
545
+
// regardless of class (pinned by the runtime's own init test, which
546
+
// uses a bare `<div data-start data-duration>` with no `class="clip"`).
547
+
// The class is an authoring convention the tooling reads, so a missing
548
+
// one is worth flagging but does not break the render.
549
+
severity: "warning",
550
+
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has timing attributes but no class="clip". The runtime still hides it outside its time range, but Studio and the GSAP clip-ownership rules use .clip to recognise a clip, so leaving it off makes the element harder to edit and to lint.`,
539
551
elementId,
540
552
fixHint:
541
-
'Add class="clip" to the element. The HyperFrames runtime uses .clip to control visibility based on data-start/data-duration.',
553
+
'Add class="clip" to the element so Studio and the linter can recognise it as a clip.',
<!-- - "clip" → the marker Studio and the linter use to recognise a -->
954
+
<!-- clip. Visibility itself comes from data-start / -->
955
+
<!-- data-duration, which the runtime honours with or -->
956
+
<!-- without this class -->
957
+
<!-- (lint: timed_element_missing_clip_class, a warning). -->
957
958
<!-- Example: card-01 with zone="fullscreen" → card-host covers (0,0,1920,1080) -->
958
959
<div
959
960
class="card-host clip"
@@ -1158,7 +1159,7 @@ decides where the actual visible card sits.
1158
1159
- Animate wrappers such as `#video-wrap`, not the video element dimensions directly.
1159
1160
- Avoid animating the same property on the same element from multiple timelines at the same time.
1160
1161
- Use `data-track-index`, not `data-layer`; use `data-duration`, not `data-end`.
1161
-
- Every timed element (`card-host`, sub-composition, etc.) MUST include `class="clip"` alongside its own classes — e.g. `class="card-host clip"`. The HyperFrames runtime uses `.clip` to gate visibility to the `data-start … data-start+data-duration`window. Without it the element is visible for the whole video (lint: `timed_element_missing_clip_class`).
1162
+
- Every timed element (`card-host`, sub-composition, etc.) should include `class="clip"` alongside its own classes — e.g. `class="card-host clip"`. Visibility itself is driven by `data-start` / `data-duration`: the runtime gates every `[data-start]` element to its window whether or not this class is present. `.clip` is the marker Studio and the GSAP clip-ownership rules read to recognise a clip, so leaving it off makes the element harder to edit and to lint (lint: `timed_element_missing_clip_class`, a warning).
1162
1163
- For body / global `font-family`, list **concrete font names** (`'Inter', 'Caveat', …`) — not a CSS variable like `var(--font-family)`. The HyperFrames font resolver doesn't expand CSS vars during static analysis (lint: `font_family_without_font_face`). Cards may still use `var(--font-family)` internally since their `@font-face` declarations are loaded.
0 commit comments