All skills
heygen-com avatar

/remotion-to-hyperframes

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

Port an existing Remotion (React) composition's source to HyperFrames HTML. Use ONLY on an explicit ask to port/convert/migrate/translate a Remotion source — one-way, Remotion-only. A passing Remotion mention, reference-only code, or "make something like my Remotion video" is a fresh build (/general-video). Unclear → /hyperframes.

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

This session only. Nothing lands on disk.

referencestiming.md

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

Timing translation: interpolate, spring, easing

The single highest-leverage reference. Easings and timings are what readers notice; getting them wrong costs more SSIM than any other translation choice. Empirically validated against tiers T1–T3.

Conversion: frames → seconds

HF's timeline is in seconds. Remotion is frame-based. Always:

time_seconds = frame / fps

So at fps=30:

  • frame 15 → 0.5 s
  • frame 30 → 1.0 s
  • frame 90 → 3.0 s

Do this conversion once when translating, not at runtime.

interpolate — linear

const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: "clamp" });

Translates to:

gsap.to(target, { opacity: 1, duration: 1.0, ease: "none" }, 0);
// fromTo if the property starts at 0 and CSS doesn't already set it
gsap.fromTo(target, { opacity: 0 }, { opacity: 1, duration: 1.0, ease: "none" }, 0);

ease: "none" matches Remotion's default linear interpolation. CSS sets the from value if your initial state is in CSS; otherwise use fromTo.

extrapolateLeft/extrapolateRight defaults to "extend" in Remotion but "clamp" is what the agent will see most often. GSAP doesn't extend — values hold at the start and end of the tween. So for clamp, GSAP matches; for extend, you'd need to extend the input range manually before emitting.

interpolate — multi-segment

const opacity = interpolate(frame, [0, 15, 75, 90], [0, 1, 1, 0]);

Three keyframed tweens at offsets [0]/fps, [1]/fps, [2]/fps:

const tl = gsap.timeline({ paused: true });
tl.to(target, { opacity: 1, duration: 0.5, ease: "none" }, 0);
tl.to(target, { opacity: 1, duration: 2.0, ease: "none" }, 0.5);
tl.to(target, { opacity: 0, duration: 0.5, ease: "none" }, 2.5);

Validated in T1 — mean SSIM 0.974 against Remotion baseline.

spring → GSAP back.out

Remotion's spring() is the most lossy translation. The mapping is approximate but close enough that real-world compositions hold ≥ 0.92 SSIM (T2: 0.985, T3: 0.953).

Remotion spring config GSAP equivalent Validated in
{damping: 12, stiffness: 100, mass: 1} (snappy) back.out(1.4) over ~0.7 s T2, T3 (TitleScene)
{damping: 14, stiffness: 90, mass: 1} (calmer) back.out(1.2) over ~0.7 s T3 (StatCard)
{damping: 8, stiffness: 200} (very bouncy) back.out(2.0) or elastic.out(1, 0.5) over ~0.6 s not validated; budget ~0.05 SSIM
{overshootClamping: true} power3.out over ~0.6 s (no overshoot) not validated

Rule of thumb: back.out(N) overshoot ratio ≈ (stiffness / damping^2) * 1.4. For damping:12, stiffness:100 that gives 1.4 * 100/144 = 0.97, which is close to the validated 1.4 (the formula is rough; tune by visual). Default duration is ~0.7 s for the typical config.

When the spring's delay/from/to are non-default, scale the duration proportionally.

interpolate with custom easing

import { Easing } from "remotion";
interpolate(frame, [0, 30], [0, 1], { easing: Easing.out(Easing.cubic) });
Remotion GSAP
Easing.in(Easing.linear) ease: "none"
Easing.out(Easing.cubic) ease: "power3.out"
Easing.inOut(Easing.cubic) ease: "power3.inOut"
Easing.out(Easing.poly(N)) ease: "power<N>.out" (N=2 quad, 3 cubic, 4 quart, 5 quint)
Easing.bezier(a,b,c,d) CustomEase.create("c", "M0,0 C${a},${b} ${c},${d} 1,1") (requires CustomEase plugin)
Easing.elastic(bounciness) ease: "elastic.out(${bounciness}, 0.3)"
Easing.bounce ease: "bounce.out"
Easing.back(overshoot) ease: "back.out(${overshoot * 1.7})" (Remotion's overshoot scale differs)

interpolate driving non-numeric properties

const color = interpolateColors(frame, [0, 30], ["#ff0000", "#0000ff"]);

GSAP does color tweens natively:

gsap.to(target, { color: "#0000ff", duration: 1.0, ease: "none" }, 0);

Same for backgroundColor, borderColor. The from value is read from CSS or the inline style.

Custom count-up / number tweens

When Remotion uses a frame-driven number ramp (Math.round(value * eased)):

const t = interpolate(frame, [0, 45], [0, 1]);
const eased = 1 - (1 - t) ** 3; // cubic ease-out
const value = Math.round(target * eased);
return <div>{value.toLocaleString()}</div>;

GSAP equivalent — tween a counter object, write textContent on update:

const counter = { v: 0 };
tl.to(
  counter,
  {
    v: target,
    duration: 1.5,
    ease: "power3.out",
    onUpdate: () => {
      el.textContent = Math.round(counter.v).toLocaleString();
    },
  },
  0,
);

power3.out matches 1 - (1-t)^3 exactly. Validated in T3 (mean SSIM 0.953). Per-frame digit mismatches occur on sub-frame timing offsets but final values converge — no SSIM impact above the noise floor.

Stagger via per-instance prop

When custom subcomponents take a delayInFrames prop:

<StatCard delayInFrames={i * 12} value={...} />

Translate to GSAP timeline offsets:

cards.forEach((card, i) => {
  const start = base + i * (12 / fps); // i * 0.4s at fps=30
  tl.to(card, { ... }, start);
});

Validated in T3 — three StatCards staggered at 0.0/0.4/0.8 s.

Source: SKILL.md on GitHub

1 warning3d3 checks · Risk SAFE
  • Gen Agent Trust Hub3d

    The skill is a specialized tool for migrating Remotion video compositions to HyperFrames HTML. It includes a security-conscious linter that identifies and blocks non-deterministic or side-effect-heavy React patterns (like useState or side-effects in useEffect) from being translated. It uses standard industry tools (ffmpeg, npm) and official vendor resources from trusted and well-known services.

  • Socket3d

    No alerts

  • Snyk3d

    Risk: MEDIUM · 1 issue

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 17 hours ago.

Activeupdated 4 days ago

README badge

README badge for heygen-com/hyperframes/remotion-to-hyperframes