Add HyperFrames skills (from heygen-com/hyperframes, Apache-2.0)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXVsD1DgdzZLiPuwtKzMSY
This commit is contained in:
Claude committed 2026-10-21 23:18:32 +00:00
1 parent 3e3f41ee5f
commit daac216bb9
300 files changed
+49175

No files matched your search

@@ -0,0 +1,50 @@
import React, { useState, useEffect, useLayoutEffect } from "react";
import { useCurrentFrame, AbsoluteFill, delayRender, continueRender } from "remotion";
import { Button } from "@mui/material";
// Custom hook in `export const useFoo = ...` form — earlier custom-hook
// regex anchored to `^\s*(?:function|const|let)` and missed the `export`
// prefix. This covers the regression.
export const useFadeMixed = (n: number) => {
const f = useCurrentFrame();
return f / n;
};
export const BadComposition: React.FC = () => {
const frame = useCurrentFrame();
const [data, setData] = useState<string | null>(null);
const [handle] = useState(() => delayRender());
// Multi-line useEffect body with commas inside (fillRect args) — regression
// coverage for r2hf/use-effect-deps. An earlier regex `[^,]+` would stop at
// the first comma inside the body and miss the deps array entirely.
useEffect(() => {
fetch("/api/data")
.then((r) => r.json())
.then((d) => {
const ctx = document.createElement("canvas").getContext("2d");
ctx?.fillRect(0, 0, 100, 100);
setData(d.text);
continueRender(handle);
});
}, [handle]);
// Expression-bodied useEffect — the form `useEffect(() => fetch(...), [deps])`
// has no closing `}`, which an earlier regex anchored on. This and the
// useLayoutEffect below cover the false-negative cases Miguel surfaced.
useEffect(() => fetch("/api/heartbeat"), [frame]);
useLayoutEffect(() => (document.title = `frame ${frame}`), [frame]);
return (
<AbsoluteFill>
<Button>{data ?? "loading"}</Button>
<span>{frame}</span>
</AbsoluteFill>
);
};
export const calculateMetadata = async () => {
const res = await fetch("/api/duration");
const { duration } = await res.json();
return { durationInFrames: duration };
};
@@ -0,0 +1,46 @@
import React, { useEffect } from "react";
import {
useCurrentFrame,
useVideoConfig,
AbsoluteFill,
interpolate,
spring,
Sequence,
staticFile,
Audio,
Img,
} from "remotion";
// Mount-only useEffect with empty deps + a later expression containing a
// non-empty array — regression coverage for the over-match Miguel reported:
// the earlier regex spanned past `[]` and matched `[frame]` from `pick(...)`,
// falsely flagging this clean fixture as having a blocker.
function pick<T>(_key: string, items: T[]): T {
return items[0];
}
const TitleCard: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
useEffect(() => {
console.log("mounted");
}, []);
const _picked = pick("x", [frame]);
const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
const scale = spring({ frame, fps, config: { damping: 12 } });
return (
<AbsoluteFill style={{ justifyContent: "center", alignItems: "center" }}>
<div style={{ fontSize: 72, opacity, transform: `scale(${scale})` }}>Hello</div>
<Img src={staticFile("logo.png")} />
</AbsoluteFill>
);
};
export const MyComposition: React.FC = () => (
<AbsoluteFill>
<Sequence from={0} durationInFrames={90}>
<TitleCard />
</Sequence>
<Audio src={staticFile("music.mp3")} volume={0.5} />
</AbsoluteFill>
);