Files
heygen-com--hyperframes/skills/hyperframes-animation/rules/spring-pop-entrance.md
T
wehub-resource-sync 85453da49f
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docs / Validate docs (push) Has been cancelled
Sync skills to ClawHub / Publish changed skills (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:58:35 +08:00

15 KiB
Raw Blame History

name, description, metadata
name description metadata
spring-pop-entrance The canonical entrance pop — an element (or staggered group) arrives by scaling 0 → 1 on a smooth long-tail settle (power3 default); bouncy overshoot is a rare, explicitly-playful exception. fromTo so it's correct at t=0 under seek.
tags
spring, entrance, pop, scale, power3, settle, stagger, reveal, arrival

Spring-Pop Entrance

Smooth beats bouncy. Per the motion doctrine (references/motion-language.md), this entrance defaults to a smooth long-tail settle — power3.out (or expo.out for a faster arrival) that decelerates cleanly into the resting size with no overshoot. Bouncy back.out overshoot is the #1 instant turn-off in agent-made videos and is almost never executed well; it is demoted here to a rare, explicitly-playful exception (a consumer / fun brand), never the default. When unsure, settle smoothly.

THE entrance primitive: an element (or a staggered group of them) arrives on screen by springing from nothing — scale: 0 → 1, optionally with a small y rise — riding a smooth long-tail ease (power3.out default) so it grows confidently into its resting size and settles without bouncing. This is arrival, not reaction.

Explicitly distinct from press-release-spring.md: that rule is a click/press → release feedback chain (a press phase, then a spring recovery to 1.0). This one has no press phase — there is no prior resting state, the element did not exist on screen, it springs into being. Many blueprints used to borrow press-release-spring to fake an entrance; reach for this instead.

How It Works

A single fromTo carries the whole arrival:

  1. From-state: { scale: 0, opacity: 0 } — the element is collapsed to a point and invisible. Stated explicitly in the from object so a seek to t=0 lands the element in this exact state (never rely on a CSS-hidden start — see Critical Constraints).
  2. To-state (default): { scale: 1, opacity: 1, ease: "power3.out" } — a long-tail decel that grows the element into its resting size and settles smoothly, no overshoot. Use expo.out instead for a punchier, faster-front arrival (still no bounce). This smooth settle is the house style; the bouncy back.out variant is the rare playful exception (see Variations).

For a group, the same fromTo runs per element with a deterministic, index-derived stagger (i * STAGGER), and the total entry window is capped (ITEM_COUNT × STAGGER ≤ ~0.5s) so the group reads as one arriving beat, not a slow arpeggio.

A small y rise (y: 24 → 0) layers a subtle "lifts into place" on top of the pop — optional garnish; the scale grow on a smooth ease is the load-bearing motion. (A rotation settle belongs only to the playful overshoot variant below.)

HTML

<!-- Single hero pop -->
<div
  class="scene"
  data-composition-id="pop-scene"
  data-start="0"
  data-duration="3"
  data-track-index="0"
>
  <div class="pop-hero" id="hero">{heroLabel}</div>
</div>

<!-- Staggered group: nodes / cards / icons / pills / callouts -->
<div
  class="scene"
  data-composition-id="pop-group-scene"
  data-start="0"
  data-duration="3"
  data-track-index="0"
>
  <div class="pop-grid">
    <div class="pop-item">{itemA}</div>
    <div class="pop-item">{itemB}</div>
    <div class="pop-item">{itemC}</div>
    <div class="pop-item">{itemD}</div>
    <div class="pop-item">{itemE}</div>
    <div class="pop-item">{itemF}</div>
  </div>
</div>

CSS

.scene {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: {bgColor};
}
.pop-hero {
  display: grid;
  place-items: center;
  width: {heroSize};
  height: {heroSize};
  background: {heroBg};
  border-radius: HERO_RADIUS;
  font-family: {font};
  font-weight: 900;
  font-size: HERO_FONT_SIZE;
  color: {heroTextColor};
  /* Pop scales around the center — see Critical Constraints */
  transform-origin: 50% 50%;
  will-change: transform;
}
.pop-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: GRID_GAP;
  place-items: center;
}
.pop-item {
  display: grid;
  place-items: center;
  width: {itemSize};
  height: {itemSize};
  background: {itemBg};
  border-radius: ITEM_RADIUS;
  font-family: {font};
  font-weight: 800;
  font-size: ITEM_FONT_SIZE;
  color: {itemTextColor};
  transform-origin: 50% 50%;
  will-change: transform;
}

GSAP Timeline

<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
  window.__timelines = window.__timelines || {};
  const tl = gsap.timeline({ paused: true });

  // --- Single hero pop (default: smooth long-tail settle, no overshoot) ---
  // fromTo states the collapsed start explicitly so the hero is correct at t=0
  // under seek. power3.out grows scale into 1.0 and decelerates smoothly.
  tl.fromTo(
    "#hero",
    { scale: 0, opacity: 0 },
    {
      scale: 1,
      opacity: 1,
      duration: POP_DUR,
      ease: "power3.out", // smooth beats bouncy; expo.out for a punchier front
    },
    ENTRY_AT,
  );

  // --- Staggered group pop ---
  // Deterministic, index-derived stagger (no Math.random). The cap keeps the
  // whole group inside one arriving beat: ITEM_COUNT * STAGGER <= ~0.5s.
  const items = gsap.utils.toArray(".pop-item");
  items.forEach((el, i) => {
    tl.fromTo(
      el,
      { scale: 0, opacity: 0, y: Y_RISE },
      {
        scale: 1,
        opacity: 1,
        y: 0,
        duration: POP_DUR,
        ease: "power3.out",
      },
      GROUP_ENTRY_AT + i * STAGGER,
    );
  });

  window.__timelines["pop-scene"] = tl;
</script>

Variations

Calm settle (refined / enterprise / "premium calm") — default

power3.out, no rotation, drop the y rise or keep it tiny (~12px). Reads as a confident, weighted settle — right for a hero wordmark or a single product shot landing. The safe default for premium / enterprise brands.

Firm settle (default product reveal) — default

The everyday entrance. power3.out (or expo.out for a punchier front), optional Y_RISE ~24px. Clear, deliberate arrival that decelerates clean — the safe default for cards, icons, and callouts. No overshoot.

Bouncy pop (RARE — explicitly-playful only)

The exception, not the default. Only for a deliberately playful register (a consumer / fun brand, a toy-like icon set) where a bounce is clearly the intent — never for product / enterprise / serious launch tone. Bouncy is the #1 turn-off and the agent rarely lands it, so reach for this knowingly and sparingly. Swap power3.out for back.out(OVERSHOOT) and (optionally) add a rotation settle so each element looks hand-placed:

// Playful exception only — default to power3.out (see above).
tl.fromTo(
  el,
  { scale: 0, opacity: 0, rotation: ROT_FROM },
  { scale: 1, opacity: 1, rotation: 0, duration: POP_DUR, ease: `back.out(${OVERSHOOT})` },
  GROUP_ENTRY_AT + i * STAGGER,
);

Keep OVERSHOOT modest even here (≤ ~2) — past that it reads as a cartoon wobble, not an arrival. Better still: the baked spring at dampingFraction: 0.60.7 (../adapters/gsap-easing-and-stagger.md → Spring Eases) gives ~510% overshoot with a second-order settle that reads physical where back.out reads cartoon.

Origin-anchored pop (callout springs from a pointer / source)

When a callout should appear to grow out of a specific point (e.g. a station marker or pointer tip), set transform-origin to that point instead of center, so the scale: 0 → 1 reads as "emerging from the source" rather than "inflating in place."

.callout {
  transform-origin: 0% 100%; /* bottom-left = pointer tip; match to the anchor */
}

Pop into a held slot — then hold (jitter at most)

When a popped element then holds an ongoing slot (a constellation node, a persistent badge), do not bake an idle loop into this entrance — it must stay finite. Land the pop and let it hold still; if the held frame genuinely needs life, hand off to sine-wave-loop.md for subtle jitter (low amplitude) on a separate, later tween — not a breathing loop. Prefer revealing the next element on its VO cue over keeping this one animating.

How to Choose Values

  • EASE — the settle curve (the load-bearing decision)

    • Default: power3.out — a smooth long-tail settle, no overshoot; the house style for product / enterprise / serious tone. Use expo.out for a punchier, faster-front arrival (still smooth).
    • Exact-physics option: springEase({ response: 0.4 }) (critically damped, ζ=1) from ../adapters/gsap-easing-and-stagger.md → Spring Eases — the curve power3.out approximates, with a harder front and a longer settle tail; take duration from the helper. Use when the settle IS the shot (a wordmark landing, a final lockup).
    • Playful exception only: back.out(OVERSHOOT) — see the Bouncy pop variation; reach for it only when a bounce is clearly the brand intent.
  • OVERSHOOTback.out(OVERSHOOT) overshoot strength — only used in the rare bouncy variant; the smooth default has no overshoot dial

    • Range (playful only): ~1.3 (barely) → ~2.0 (clearly bouncy)
    • Constraints: keep ≤ ~2 — past that the overshoot exceeds the element's bounds and reads as a cartoon wobble, not an arrival. If you're not in the explicitly-playful case, don't use this — use power3.out.
  • POP_DUR — duration of each element's scale: 0 → 1 tween

    • Range: 0.4 0.7 s
    • Effects: shorter = tight snap; longer = a looser, more floating pop
    • Constraints: the main subject must be visible by t ≤ 0.5s — keep ENTRY_AT + POP_DUR's readable midpoint early; don't let the hero finish arriving after the half-second mark
  • STAGGER — gap between successive items' start times (group only)

    • Range: 0.04 0.08 s
    • Effects: < 0.04 reads as a simultaneous chord; > 0.08 feels lazy / arpeggiated
    • Constraints: ITEM_COUNT × STAGGER ≤ ~0.5s (the cap) — beyond that the group stops reading as one beat. Cap the per-item stagger for large groups: STAGGER = min(0.06, 0.5 / ITEM_COUNT)
  • ITEM_COUNT — number of elements in a group pop

    • Range: 3 9
    • Effects: 3 = sparse; 9 = full grid. More than ~9 forces STAGGER so small the stagger vanishes — switch to a wipe/sweep reveal instead
  • Y_RISE — optional upward offset the element lifts from (y: Y_RISE → 0)

    • Range: 0 (pure pop) 32 px
    • Effects: adds a subtle "lifts into place"; keep small so the scale pop stays dominant
    • Constraints: 0 for the calm-settle variant; never large enough to read as a slide-up (that's a different primitive)
  • ROT_FROM — optional starting rotation, playful (bouncy) variant only (rotation: ROT_FROM → 0)

    • Range: 10° +10°
    • Effects: a small tilt that resolves makes the element look hand-placed
    • Constraints: derive sign/size deterministically from index if you want alternating tilt (e.g. i % 2 ? 6 : -6) — never Math.random
  • ENTRY_AT / GROUP_ENTRY_AT — timeline offset before the (group's) pop begins

    • Range: 0 0.4 s
    • Effects: > 0 gives a beat of quiet before the arrival; keep small so the subject still lands by t ≤ 0.5s

Geometry & tokens

  • {heroSize} / {itemSize} — footprints. A hero entrance should occupy a clearly readable share of the frame; group items size down so the grid fits with GRID_GAP breathing room.
  • HERO_RADIUS / ITEM_RADIUSheight × 0.15 (sharp) → height / 2 (pill).
  • {heroBg} / {itemBg} / {*TextColor} — surface + label tokens; inherit from the composition palette.

Key Principles

  • Smooth beats bouncy — default to power3.out (or expo.out): a long-tail settle into scale: 1, no overshoot. Bouncy back.out is the rare, explicitly-playful exception (the #1 turn-off, and the agent rarely lands it). When unsure, settle smoothly.
  • fromTo, always — the collapsed { scale: 0, opacity: 0 } start is stated in the from object so a seek to t=0 lands it exactly there. An entrance built on a CSS-hidden start (e.g. opacity:0 in CSS + a .to()) flickers under HF seek — the element renders visible before the tween claims it.
  • Easing carries the motion, not keyframes — let the ease produce the settle for free. Don't hand-key a scale: 1.1 mid-state; that double-bounces and fights the curve. (And in the playful variant, the overshoot is a byproduct of back.out, not a hand-keyed bounce.)
  • The grow is the motionscale is load-bearing; the y rise (and, in the playful variant, the rotation settle) is garnish layered on top. If you drop everything but the scale grow, it should still read as a clean entrance.
  • Cap the stagger window — a group must arrive inside ~0.5s total or it stops reading as one beat and starts reading as a slow list reveal. Derive the stagger from ITEM_COUNT so it self-caps.
  • Deterministic per index — all stagger and any rotation/tilt variation comes from the loop index, never Math.random — the renderer must produce the identical frame on every seek.
  • Visible early — the main subject must be on screen by t ≤ 0.5s. A hero that finishes arriving at t=1s wastes the opening beat.
  • Don't bake an idle loop here — this entrance is finite. If the element then holds a slot, hand off to sine-wave-loop on a later tween; an infinite repeat/yoyo here breaks seek.

Critical Constraints

  • Timeline must be paused: gsap.timeline({ paused: true })
  • Registry key = data-composition-id
  • Entrances use fromTo — explicit { scale: 0, opacity: 0 } from-state; never rely on a CSS-hidden starting state
  • No CSS transition on popped elements — those interpolate independently of HF seek and cause flicker
  • No repeat / yoyo / infinite tweens — this is a finite arrival; idle motion is a separate sine-wave-loop tween
  • No Math.random / Date.now — stagger and tilt are index-derived and deterministic
  • GSAP transform aliases only: x, y, scale, rotation. Never tween width / height / left / top
  • transform-origin: 50% 50% for an in-place pop (default); set it to the source point only for the origin-anchored variation
  • Default ease power3.out (smooth, no overshoot); back.out(OVERSHOOT) only in the explicitly-playful variant, and there keep OVERSHOOT ≤ ~2 — beyond that it reads as a cartoon wobble, not an arrival
  • ITEM_COUNT × STAGGER ≤ ~0.5s — the group must land inside one beat
  • will-change: transform on popped elements, especially groups — many simultaneous spring tweens benefit from compositor hints

Combinations

  • sine-wave-loop.md — at most subtle jitter on a held node/badge AFTER its pop lands (don't bake any loop into the entrance; and prefer a VO-timed reveal over ambient motion — see that rule's caution)
  • center-outward-expansion.md — elements pop in as they radiate from center to their slots
  • press-release-spring.md — the reaction counterpart: once popped in, a button can take a press→release; this rule supplies the arrival, that one the click feedback

Pairs with HF skills

  • /hyperframes-animationpower3.out settle (smooth default), fromTo entrances, deterministic stagger
  • /hyperframes-core — composition wiring
  • /hyperframes-clihyperframes lint