All skills
heygen-com avatar

/hyperframes-animation

@ff6e210
by HeyGenheygen-com/hyperframes55k stars
4,998

All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.

Use this Skill: https://skilld.dev/gh/heygen-com/hyperframes/hyperframes-animation

This session only. Nothing lands on disk.

ruleschart-scrub-readout.md

≈2.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Chart Scrub Readout

The chart is already ON screen — this rule interrogates it. A vertical tracking line rides the scrub position, a marker dot follows the series, and a live tooltip reads out date: value per position, values flickering past like an odometer. It's the "this data is real — look closer" beat: the scrub proves the chart is an instrument, not a picture.

Boundary with its neighbors: stat-bars-and-fills.md owns the chart's ARRIVAL; counting-dynamic-scale.md owns a single number swelling in place. This rule assumes the graphic already exists and adds a read head moving across it. The three chain naturally: the line draws in (svg-path-draw / stat-bars), this rule scrubs it, and the landing value hands off to a count-up lockup.

How It Works

  1. Data baked at setup — a literal DATA array of { d, v } points (or a pure index formula). The polyline's points attribute is computed ONCE from DATA by pure mapping functions: chart and readout share one source of truth. The argument of the shot is "this data is real" — a random walk regenerated per render breaks both determinism and the rhetorical claim.
  2. One driver tween p: 0 → 1 derives everything in its onUpdate: tracking-line x, marker x/y, tooltip position. Every output is a pure function of p — any seek lands the identical frame. Parallel tweens that merely share timing drift apart under rounding and read as chart chrome, not a read head.
  3. The marker rides the polyline — its y interpolates between the two neighboring baked points, from the same arrays that built the chart; a separately-keyframed marker inevitably floats off the line.
  4. The readout is threshold-stepped — the nearest data index derives from p, and textContent is written ONLY when that index changes (last-index guard). Transforms glide per frame (compositor-cheap); text steps per data point — no per-frame DOM text thrash. The guard is an optimization, not state: any seek recomputes the same index and the same text.

Recipe

<!-- inside a standard scene clip. Size the SVG so viewBox units === CSS pixels:
     one coordinate space serves the polyline, tracking line, marker, AND the HTML tooltip. -->
<div class="chart-wrap">
  <!-- position: relative — the tooltip transforms against this box -->
  <svg class="chart" viewBox="0 0 CHART_W CHART_H" width="CHART_W" height="CHART_H">
    <polyline id="series-a" class="series" fill="none" />
    <line id="track-line" y1="0" y2="CHART_H" stroke-dasharray="6 6" />
    <circle id="marker" r="MARKER_R" />
  </svg>
  <div class="tooltip" id="tooltip">
    <span id="tip-date">{firstDate}</span>
    <span id="tip-value">{firstValue}</span>
  </div>
</div>
.tooltip {
  position: absolute;
  top: 0;
  left: 0;
  min-width: TIP_MIN_WIDTH; /* fixed — the box must not resize as values change length */
}
#tip-value {
  font-variant-numeric: tabular-nums; /* MANDATORY — digits flicker past; widths must not */
}
// Data baked at setup — literal values.
const DATA = [
  { d: "{date1}", v: V1 },
  // ... N points, chronological ...
];

// Pure mapping functions — geometry derives from DATA once.
const PAD = CHART_PAD;
const PLOT_W = CHART_W - PAD * 2;
const PLOT_H = CHART_H - PAD * 2;
const vals = DATA.map((p) => p.v);
const V_MIN = Math.min(...vals);
const V_MAX = Math.max(...vals);
const X = (i) => PAD + (i / (DATA.length - 1)) * PLOT_W;
const Y = (v) => PAD + PLOT_H * (1 - (v - V_MIN) / (V_MAX - V_MIN));

document
  .getElementById("series-a")
  .setAttribute("points", DATA.map((p, i) => `${X(i)},${Y(p.v)}`).join(" "));

const line = document.getElementById("track-line");
const marker = document.getElementById("marker");
const tooltip = document.getElementById("tooltip");
const tipDate = document.getElementById("tip-date");
const tipValue = document.getElementById("tip-value");

// Tooltip pops in as the scrub begins — a small fromTo scale/opacity spring at SCRUB_AT.

// ONE driver — line, marker, and tooltip are all projections of p.
const scrub = { p: 0 };
let lastIdx = -1;
tl.to(
  scrub,
  {
    p: 1,
    duration: SCRUB_DUR,
    ease: SCRUB_EASE,
    onUpdate: () => {
      const f = scrub.p * (DATA.length - 1); // fractional index
      const i = Math.min(DATA.length - 2, Math.floor(f));
      const t = f - i;
      const x = X(i) + (X(i + 1) - X(i)) * t;
      const y = Y(DATA[i].v) + (Y(DATA[i + 1].v) - Y(DATA[i].v)) * t;

      // Transforms glide every frame (cheap, deterministic)
      line.setAttribute("x1", x);
      line.setAttribute("x2", x);
      marker.setAttribute("cx", x);
      marker.setAttribute("cy", y);
      tooltip.style.transform = `translate(${x + TIP_DX}px, ${y - TIP_DY}px)`;

      // Text steps only when the nearest data point changes
      const idx = Math.round(f);
      if (idx !== lastIdx) {
        tipDate.textContent = DATA[idx].d;
        tipValue.textContent = `${DATA[idx].v.toLocaleString()} {unitLabel}`;
        lastIdx = idx;
      }
    },
  },
  SCRUB_AT,
);
// End hold: the driver finishes before the scene does — the landed value reads.

Variations

  • Peak stop — the scrub is the wind-up, the landing is the stat: SCRUB_EASE: "power3.out" decelerates onto the final/peak point, then pop the emphasis at landing (fromTo marker scale: 1 → PEAK_POP_SCALE at SCRUB_AT + SCRUB_DUR). Pair with a pill tooltip that springs to its final label (spring-pop-entrance.md) — the classic "line breaks above the band" climax.
  • Second-series activation on cross — series B sits dimmed; at SCRUB_AT + SCRUB_DUR * CROSS_P tween its stroke to the lit color (0.25s, power2.out), and in the driver's onUpdate read from B's array once scrub.p ≥ CROSS_P (still index-guarded). The color flip lands ON the cross — same-frame causality.
  • Two-chart glide — two scrub beats: sweep chart A, glide the cursor/tooltip group across the gutter (a plain x tween, no readout — dead travel, not data), then chart B activates with its own driver. One driver per chart.
  • Cursor-led scrub — an oversized cursor is the visible actor: another projection of the SAME driver (positioned from x in the same onUpdate, tip at the tracking line's head) — never a second tween that merely matches timing. Cursor look and click grammar from cursor-click-ripple.md.
  • Playhead form — no cursor; the tracking line IS the actor (timeline scrubbers, audio waves, session replays). ease: "none" — mechanical playback, not a hand.

Values

token range / default notes
N (data points) 10–40 <10 reads as a slideshow; >40 blurs into texture. The flicker is the point — only first and final values must be legible
SCRUB_DUR 1.5–3s shorter = confident sweep; longer = inspection. Leave ≥0.8s of scene after the driver ends so the landed value holds
SCRUB_EASE power1.inOut default "none" playhead form; power3.out peak stop. Never back.out — a read head that overshoots and re-reads looks broken
CROSS_P 0.55–0.75 earlier and A never establishes; later and B's readout has no time to live
TIP_DX / TIP_DY 16–48px, up-and-right flip the sign near the chart's right edge so the tooltip never exits the frame
MARKER_R / stroke width r 6–12 / 4–8px the marker must dominate the line it rides
TIP_MIN_WIDTH ≥ longest date: value state without it the box breathes as digits change

Critical Constraints

  • DATA is literal at setup; polyline points derive from it via pure functions — chart and readout share one source of truth.
  • Seed at setup — call the scrub applier once with p = 0 right after building (à la 3d-camera-flight's applyCamera()), or a seek to t=0 before the driver runs shows the tracking line/marker at their HTML-default positions.
  • Single driver — one p tween; all scrub outputs (line, marker, tooltip, any cursor) computed in its onUpdate, each a pure function of p.
  • Readout writes guarded by index change — onUpdate stays O(1): a few attribute sets, one transform, text only on step.
  • SVG viewBox units = CSS pixels (viewBox="0 0 W H" with matching width/height) — one coordinate space must serve the SVG internals and the HTML tooltip's transform.
  • tabular-nums + fixed min-width on the tooltip value.
  • The chart pre-exists — draw-in belongs to svg-path-draw / stat-bars-and-fills; sequence it BEFORE the scrub, don't blend them.
  • Land the read — hold the final value ≥0.8s (or hand off to a count-up lockup).

See also

svg-path-draw (the series draws in first) · stat-bars-and-fills (surrounding dashboard chrome) · spring-pop-entrance (peak dot + pill pop at the landing) · counting-dynamic-scale (closing stat lockup) · cursor-click-ripple / context-sensitive-cursor (the cursor-led form's actor) · control-target-sync (the sibling WRITE direction — there a control edits a target; here a scrub reads a dataset).

Source: SKILL.md on GitHub

No alerts3d3 checks · Risk SAFE
  • Gen Agent Trust Hub3d

    The skill is a comprehensive knowledge base and utility set for HyperFrames animations. It includes an auditing tool that dynamically installs vendor-specific dependencies from the NPM registry to analyze project timelines. The behavior is documented, tested, and follows established development patterns for CLI utilities.

  • Socket3d

    No alerts

  • Snyk3d

    Risk: LOW · No issues

Signed by skilld at ff6e210. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 16 hours ago.

Activeupdated 4 days ago

README badge

README badge for heygen-com/hyperframes/hyperframes-animation