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.

rulesviewport-change.md

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

Viewport Change (Virtual Camera)

Simulates camera effects (zoom / pan / focus-lock on a moving element) by transforming a wrapper around ALL scene content. The "world" moves opposite to the perceived camera. Distinct from multi-phase-camera (2-3 discrete phases + drift) — viewport-change is a single continuous zoom/pan, often used for focus-lock following a moving element.

How It Works

Camera intent → world transform. Camera pans right → world translateX(-distance); camera zooms in → world scale(>1); camera follows element X → world translateX(viewportCenter - elementWorldX) per-frame. Get the sign right or everything moves the wrong way. The single .world wrapper holds the camera transform; elements inside are positioned in world space, unchanged.

Single-element composite transform (this rule's form). Both scale and translate live on ONE wrapper as translate(x, y) scale(S). CSS applies scale FIRST, then translate (right-to-left matrix composition), so a point at world offset (ox, oy) lands on screen at (S × ox + x, S × oy + y). To map the target to viewport center, solve S × offset + T = 0:

T = -offset × S

This is different from coordinate-target-zoom, which uses two nested wrappers (outer scales, inner translates) and derives T = -offset (independent of S). Mixing up the two forms drifts the target off-center as scale changes. Use this single-wrapper form when you want one source of truth for camera state (cam.scale, cam.x, cam.y) written via onUpdate; use nested wrappers when scale and translate can tween independently with shared ease.

Recipe

<div class="world" id="world">
  <div class="content">
    <div class="hero">{Brand}</div>
    <div class="tagline">{tagline}</div>
    <div class="cta" id="cta">{ctaUrl}</div>
  </div>
</div>
.scene {
  overflow: hidden; /* REQUIRED — any non-1.0 scale reveals edges or pushes content off-frame */
  background: {bgGradient}; /* on .scene, NOT .world — a world-borne background warps with the camera */
}
.world {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  transform-origin: 50% 50%; /* centered scaling is what the math assumes */
  will-change: transform;
}
const world = document.getElementById("world");

// Camera state — single source of truth. The world transform is composed from
// this object in ONE place so the transform string order is stable.
const cam = { scale: 1, x: 0, y: 0 };
function applyCamera() {
  world.style.transform = `translate(${cam.x}px, ${cam.y}px) scale(${cam.scale})`;
}
applyCamera(); // seed frame 0

// Zoom in on the CTA: single-element composite transform → T = -offset × S.
// TARGET_OFFSET_Y is the target's measured offset from viewport center at
// neutral camera (sign matters — positive = below center).
const counterY = -TARGET_OFFSET_Y * TARGET_SCALE;

tl.to(
  cam,
  {
    scale: TARGET_SCALE,
    y: counterY,
    duration: ZOOM_DUR,
    ease: "power3.inOut",
    onUpdate: applyCamera,
  },
  ZOOM_START,
);

Scale Value Guide

Effect Scale Feel
Subtle 1.02 - 1.05 Barely perceptible — "professional"
Medium 1.05 - 1.15 "Ta-da" emphasis
Noticeable 1.15 - 1.30 Focus on region
Dramatic 1.5 - 2.5 Element fills screen
Full-screen 3.0+ Element covers viewport

Perception: < 5% scale change is imperceptible; 10-15% is comfortable emphasis; > 30% is cinematic/dramatic. For a natural product feel, prefer 1.05-1.15× over 2-3s; save big > 1.3× zooms for dramatic narrative moments.

Extreme range — 4–12× outward (workspace reveal)

The same single-cam math runs far past the table: a zoom-out workspace reveal opens punched-in at 4–12× on one detail (a single cell, message, or button) and pulls out to the full workspace in one continuous move. The mechanics don't change — one cam object, T = -offset × S, one applyCamera() writer — only the authoring direction does:

  • Build the workspace at its final (1×) layout and OPEN scaled-in (cam.scale = 8, counter-translate aiming the opening detail; state it in a fromTo / seed via applyCamera() so a seek to t=0 lands punched-in). The wide landing frame is then everything at native design size — text crisp, raster assets at source resolution.
  • Never the inverse — authoring the close-up at 1× and scaling the world down to 0.08–0.25 for the wide frame drops every label below legible pixel size and softens raster media; the reveal lands on mush.
  • Measure the opening target — at S = 8, a 1 px error in the baked offset is 8 px on screen at the opening pose. Take the offset from the target's real laid-out center (getBoundingClientRect after fonts.ready, once at setup — the measuring doctrine in coordinate-target-zoom.md), never from a layout formula.
  • The opening detail must survive ×S — it renders at S × its design size on the first frames (vector/DOM text is safe; raster needs sourceResolution ≥ rendered × S).

Variations

  • Focus-lock (camera follows a moving cursor/character) — keep the element at a fixed screen X by computing the world offset per-frame inside the driver's onUpdate:
const focusEl = document.querySelector(".moving-cursor");
const targetScreenX = VIEWPORT_WIDTH * FOCUS_SCREEN_X_FRAC; // 0.4–0.7; 0.5 = dead center
const focusUpdate = { p: 0 };
tl.to(
  focusUpdate,
  {
    p: 1,
    duration: FOLLOW_DUR, // matches how long the focused element is in motion
    ease: "power2.inOut",
    onUpdate: () => {
      const rect = focusEl.getBoundingClientRect();
      cam.x = targetScreenX - (rect.left + rect.width / 2);
      applyCamera();
    },
  },
  FOLLOW_START,
);
  • Composite scale (multi-phase) — two proxy tweens multiplied through one writer: cam.scale = scaleUp.v * scaleDown.v; applyCamera(). Combine a slow push-in (~1.15) with a brief release (~0.9) for a breath/punch shape.
  • Camera mode transition (centered → follow) — crossfade two camera modes via a 0→1 weight tween; intermediate frames interpolate between the modes' offsets.

Values

token range notes
TARGET_OFFSET_Y measured, not a free parameter target's offset from viewport center at neutral camera; measure via getBoundingClientRect
TARGET_SCALE 1.3× modest → 1.6–2.0× typical → 3×+ raster media needs sourceResolution ≥ rendered × TARGET_SCALE
ZOOM_START content landed + ~0.5s scan time let the viewer read before the camera moves
ZOOM_DUR 1.0–2.0s under 0.8s teleports, over 2.5s drags
DWELL ≥ 1.0s after the zoom settles the viewer must be able to read the focal point (climax dwell)
VIEWPORT_WIDTH = the root's data-width real value, not abstract

Critical Constraints

  • One .world wrapper carries the whole camera — every scene element lives inside it; a second transformed wrapper is a second camera.
  • Single source of truth via the cam object + applyCamera() — when scale and translate both change, write them in ONE place; never split them across tweens that touch world.style.transform directly (the transform string composition order becomes unpredictable).
  • Single-wrapper counter-translate is T = -offset × S — don't import the nested-wrapper T = -offset formula.
  • overflow: hidden on .scene; transform-origin: 50% 50% on .world; background on .scene, never on .world.

See also

coordinate-target-zoom.md (nested-wrapper alternative, T = -offset) · multi-phase-camera.md (viewport-change inside one phase) · sine-wave-loop.md (idle micro-drift after the viewport settles).

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