Raea
Render videos, animations, and games by writing React code with GPU acceleration.
Installation
- Make sure Claude is on your device and in your terminal.
Skills load from
~/.claude/skills/when Claude Code starts up β so you need it on your machine first. If you don't have it yet, install it once with the command below, then runclaudein any terminal to verify.One-time setupnpm i -g @anthropic-ai/claude-codeAlready have it? Skip ahead.
- Paste into Claude Code or into your terminal.
This copies the whole skill folder into
~/.claude/skills/raea-shinyobjectz/β the SKILL.md plus any scripts, reference docs, or templates the skill ships with. Safe default: works for every skill.Faster alternative (instruction-only skills)
Skips the clone and grabs only the SKILL.md file. Don't use this if the skill ships Python scripts, reference markdowns, or asset templates β they won't be downloaded and the skill will fail when it tries to load them.
Quick install (SKILL.md only)Sign up to copy - Restart Claude Code.
Quit and reopen Claude Code (or any other agent that loads from
~/.claude/skills/). New skills are picked up on startup. - Just ask Claude.
Skills auto-activate when your request matches the skill's description β no slash command needed. Trigger phrases live in the skill's own frontmatter; you can read them in the βWhat this skill doesβ section above.
Prefer to read the source first? Open on GitHub.
When Claude uses it
Make video, motion graphics, games and 3D scenes with raea, the Render Anything Engine, by writing React/TypeScript compositions with raea and rendering them on the GPU with the raea CLI (or playing games live). Use when the user wants an agent to produce a rendered video or animation from code, cut footage by its words, add captions or motion graphics, build a small playable game, or render frames headlessly.
What this skill does
raea
raea renders compositions written in TypeScript and React with a GPU engine built on Bevy. A composition is a function of the frame: give it frame N and it draws frame N. The same file renders to video, plays live as a game, or renders single frames to check.
Each step below says where it runs. HEADLESS: the raea CLI alone, in any shell. HOST: needs the raea app
running on this machine (its host answers). PAGE: needs the person's feed open in the app. PERSON: only the
person can do it. Every PAGE step says what a headless agent does instead.
1. Install (once) β HEADLESS
<!-- sources: tools/release.sh apps/site/public/install engine/cli/src/skill.rs -->- macOS (Apple Silicon) or Linux (x86_64):
curl -fsSL https://raea.io/install | sh. Windows 10 or 11, in PowerShell:irm https://raea.io/install.ps1 | iex. Either putsraeaunder~/.raea, puts it on your PATH, and adds this skill and raea-bevy to~/.claude/skills. Run it again to update.raea helplists every verb. - Another agent:
raea skills install --agent claude|codex|kimi|geminiputs the skills where that agent reads them.--pin quieter(any move) adds a/quieterthat loads one move. For Claude it also adds a hook that runsraea check --quickafter a composition is saved and hands you what it finds. - This file's front matter names the raea it shipped with (
version:). Ifraea --versionprints another, readraea skillinstead: it is this skill as your raea ships it. - From a checkout of the repository:
cargo build --release -p raea-cli; the binary istarget/release/raea. - Optional settings live in
~/.raea/env(docs/settings.md). Rendering needs none of them.
Reference
Generated from the code by tools/skills.sh gen, so they're current. Read the one you need instead of guessing a flag:
- reference/cli.md: every
raeaverb, its flags and where it runs (raea helpprints the same). - reference/feed.md: the raea app's tools for an agent it launches, and which need its page.
- reference/files.md: a workspace's and a project's files, what lives in
~/.raea, and each spec's fields (brief.ts, NAME.script.ts, taste.ts, plan.ts, controllers/ID.ts). - reference/sdk.md: what each
raeaimport gives a composition. - reference/app.md: driving the raea app's window over MCP, as a person would (HOST).
2. The workspace and its projects β HEADLESS
<!-- sources: apps/workspace/src -->Work lives in a workspace: a git repo under raea.root (~/Studio unless git config --global raea.root says
otherwise), one per studio or client, holding projects and controllers. In the raea app a project shows as a channel.
raea workspace init NAMEmakes one;raea workspace adopt DIRmakes an existing folder one.raea workspaceshows it (--jsonfor the projects and their paths).raea project new NAMEadds a project: its folder withbrief.ts,media/,out/andbrand/. A project can live inline or as its own repo (raea project split NAME,raea project join NAME); both keep its history.- Work in the project's folder. Footage and other media go in
media/, renders inout/.
3. Read before you make β HEADLESS
<!-- sources: engine/cli/src/guide.rs apps/workspace/src core/brief/src -->raea context .in the project prints everything to read first, in order: the person's taste (~/.raea/taste/taste.ts; a line there beats any guide's default), the workspace's taste, the brief, the look, the workspace's controllers, the craft floor and each of the brief's modes' guides. Read all of it.- Run it once a session. If it refuses, say so in one line ("raea context failed: its message; reading the brief and
controllers directly") and read
brief.ts, any*.script.ts,~/.raea/taste/taste.tsandraea controller lsyourself. ACONTEXT_STALEline meansraea doctorfinds files from another version: runraea doctor --fix. - With no request in hand,
raea nextlists the two or three useful next steps from the brief, the compositions, the renders and their checks. Offer them; never run one unasked. - The controllers (
raea controller ls,raea controller get PATH) are the workspace's settings and workflows: delivery specs, who reviews what, the tools every agent gets. Work to them. Change one only when the person asks:raea controller set PATH VALUE(each change is a commit). - If the brief isn't shaped (no
believe, nomode), shape it before making anything: ask who it's for and the one thing they should believe, or write your best guess and add its field to the brief'sassumedlist. - For a pitch, an explain or a story, plan first: write the deliverable's storyboard as
NAME.script.tsbeside the brief (export default script({...})from "raea/brief": scenes of beats, what's on screen and what each scene must land; its fields are in reference/files.md), name it on the deliverable, and add a task "storyboard approved" taggedgate.raea spec NAME.script.tschecks it. Render nothing until the person approves it (PERSON). - The person's footage and files:
raea library search "WORDS"finds them by meaning across the libraries they've indexed (HEADLESS once indexed; adding a folder waits for the person's yes, PERSON). - Right before any edit to a composition, even a one-line change, read the floor:
raea guide craft. Readraea guide routeronce for the order of work.
4. Make an item β HEADLESS
<!-- sources: sdk/raea/src/index.tsx sdk/raea/src/3d.tsx -->One .tsx file whose root registers compositions (raea init in a footage project writes the files to start from):
import { AbsoluteFill, Composition, Sequence, interpolate, registerRoot, useCurrentFrame } from "raea";
function Card({ text }: { text: string }) {
const f = useCurrentFrame();
const opacity = interpolate(f, [0, 12], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
return <AbsoluteFill style={{ background: "#000", color: "#fff", justifyContent: "center", alignItems: "center", fontSize: 96 }}><span style={{ opacity }}>{text}</span></AbsoluteFill>;
}
registerRoot(() => (
<Composition id="piece" width={1080} height={1920} fps={30} durationInFrames={90} component={() => (
<><Sequence from={0} durationInFrames={45}><Card text="One" /></Sequence><Sequence from={45} durationInFrames={45}><Card text="Two" /></Sequence></>
)} />
));
Rules that keep renders right (raea guide motion has all ten, under "The core rules"; every file needs these):
- Frame-pure. Everything that moves reads
useCurrentFrame();useState,useEffectand timers don't animate a render.Math.random()is seeded per frame, so seed what should hold still from an index. - Clamp every interpolate. Do it unless you mean the line to run on past its ends.
- Cue on words, not on guessed frames.
word("phrase")is the frame where it's said, so cues follow the cut. - Footage:
<Video>and<Audio>. Games:useGameState(initial, step)with a purestep, keys fromuseInput(). - Brand: the kit's
--brand-*variables inbrand/brand.css(raea brand DOMAINreads them from a site), thenimport { css } from "./styles.gen"and Tailwind classes likebg-brand-bg. - 3D: read the raea-bevy skill first; an asset to fix first (scale, pivot, FBX to .glb) goes through Blender
(
raea setup blender, thenraea guide bevy/blender). - Sound:
raea guide soundandraea guide music; to cut to a song, runraea song FILE --plot FILE.song.pngand time cuts from its map, never a constant BPM. npm packages and React apps:raea guide apps. - Generated media:
raea guide genbefore the firstraea gen.
raea check --quick piece.tsx checks three stills' text (clipped, cramped, safe areas) in about a second: run it
after each save when no hook does. Then render, and look before you call it done:
raea render piece.tsx --at 0,45,89 -o frames/ # stills to look at: text fits, nothing overlaps
raea render piece.tsx --alpha -o frames/ # transparent PNGs, for an overlay in another editor
raea render piece.tsx -o out/piece.mp4 --manifest out/render.json
raea check out/piece.mp4 --manifest out/render.json --taste ~/.raea/taste/taste.ts -o out/piece.check.json # P0-P3; exits 1 on a P0 or P1
raea guide rendering covers stills, the check, bitrate and quality; raea guide rubric covers judging the rest.
5. Show it and read the notes β PAGE, PERSON
<!-- sources: sdk/skills/raea/reference/feed.md -->- In the raea app, post the render to the project's feed with
feed_post(a watch, look, listen or play item); the person watches, plays and leaves notes on it there (PERSON).feed_itemsreads the items and their notes. - Headless instead: leave the file in the project's
out/, give the person its path, and take their notes as text. - Every note, from the feed or as text, gets a move before any edit: pick the one it asks for (quieter, bolder,
distill, clarify, retime, recut, regrade, remix, harden, layout, typeset, animate, delight, adapt, optimize, extract,
generate, polish, critique) on the part or moment it names, and run
raea guide MOVEbefore you touch the composition. Answer in their words, and never name the move to them.
6. The next version β HEADLESS, then PAGE
<!-- sources: sdk/skills/raea/reference/feed.md -->- Change the composition under the person's hand edits (the
editsegments and<Nudge>props the app writes; seeraea guide rendering), render again and check again. - Render each version to a new file beside the old (
piece-v2.mp4), never over it: the earlier version stays watchable. In the app, post it withfeed_postnaming the item itreplaces, so the feed keeps both as versions.
7. Deliver β HEADLESS
<!-- sources: runtime/export/src -->- Final exports:
--quality masterfor motion graphics and type; name files with lowercase letters, digits and hyphens only (spring-launch-9x16.mp4). - A render is a standard MP4 but large: H.264 High and AAC on a Mac (VideoToolbox), H.264 Constrained Baseline and
Opus on Windows and Linux (openh264), yuv420p on all. Hand over a share copy too, which any player takes:
ffmpeg -i film.mp4 -c:v libx264 -preset slow -crf 23 -maxrate 2600k -bufsize 5200k -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart film-share.mp4. - Deliver to the controllers' specs (sizes, platforms, loudness) when the workspace sets them.
Apps: web or native β HEADLESS
<!-- sources: docs/targets.feature apps/targets/src sdk/ui/src/app.ts sdk/rune/src -->An app is a React file with a default export: DOM elements, inline style or Tailwind className, on @raea/ui. One
setting picks the host that draws it. Both are desktop windows that draw every pixel themselves (neither uses the
OS's widgets or a browser), with the same kind of text and layout engines. web (the default) is Blitz on Bevy: a
browser engine, so all of CSS (grid included), web npm UI packages and the 3D world. native is Rune, an app UI
framework: springs on every change, GPU effects and kit components, a screen-reader tree (AccessKit), a ~27 MB host
against web's ~175 MB, a subset of CSS (no grid) and no 3D yet. The SDK is the same; only the setting differs. Pick
native for a small, motion-heavy app with no 3D that passes its check; anything else stays on web. A composition or a
game stays a composition; an app is an application's interface.
- Say the target in the app's own file, as a literal (anything else is refused at its line):
export const app = { target: "native", title: "Notes", size: [480, 640], minSize: [360, 480] };. With noappexport, or notargetin it, the target is"web".--target web|nativeon the command line overrides it. - The verbs, the same on both targets:
raea app run app.tsxopens it in a window;raea app check app.tsxruns it headless;raea app bundle app.tsx -o Notes.appmakes a Mac app.raea app bundlesigns ad hoc unless you give--identity "Developer ID Application: ..."(or RAEA_SIGN_IDENTITY) and--notarize PROFILE(a notarytool keychain profile): it always signs with your own identity, never raea's. - Check before you show it. Give the app its input as
export const steps = [{ press: "add" }, { type: "Ada", into: "name" }, { key: "Tab" }, { wheel: "list", dy: 120 }, { frames: 30 }];(elements bydata-testid), or as--script steps.json.raea app check app.tsx --png out/writes a PNG after the mount and after each step (00-mount.png, 01-press-add.png, ...) and tree.json (each element's role, label, text and box). Read the PNGs. Check on both targets when the app should run on both:--target weband--target native. - What the check holds each target to. native fails on any prop Rune doesn't map or call its host doesn't answer, naming each with its element's path (unmapped.json, unanswered.json). Change the prop, or keep the app on web. web passes when it draws, and says what native wouldn't draw and which Rune props it ignores.
- Native draws flex layout (no grid), sizes, padding, margin, gap, absolute insets, scroll, colours and gradients, borders, radius, shadows and rings, outlines, opacity, transforms and transitions, text, images and video, fonts from the app's folder, and Tailwind's classes with hover:, focus:, focus-visible:, active:, disabled:, dark: and sm: to 2xl:. Anything else is reported, never dropped. An empty unmapped.json means the page maps whole.
- What only Rune does is typed props from
@raea/rune:<div {...rune({ motion: "pop", transition: { effect: { push: "top" }, enter: "pop" } })}>, pluslead,instant,blur,backdropBlurandglass, and itsBadge,Spinner,Progress,RollingTextandSwitch. On web, a preset motion becomes a CSS transition and an entrance a keyframe, blur and glass become filters, and the rest is ignored and listed by the check. Without these props an element lands at once, as in a browser. - Part of a web page can be Rune's:
<RuneLayer className="w-80 h-48">...</RuneLayer>from@raea/runedraws its children with Rune, on the GPU, in its box, and the rest of the page stays Blitz's. Give it a size: the layer is its content box. Clicks and wheel reach its elements, and their handlers run as anywhere else. AgetBoundingClientRectinside one is zero, and keys don't reach a field in one yet. In a browser it's a plain div.RAEA_RUNE_LAYERS=0draws it with Blitz. - Host calls (
callandcallSyncfrom@raea/ui/wire), answered on both targets:net.fetch,net.ws.*,net.storage.*,net.clipboard.*,os.open(http, https, mailto),fs.pick,fs.save,fs.read,fs.writeanddialog.message. Headless, a step answers a dialog:{ pick: ["a.txt"] },{ save: "out.txt" },{ dialog: 0 }.world.*(BRP on the 3D world) is web's only: native refuses it with "no world on the native target". - Examples ship with raea and pass the check on both targets:
sdk/rune/examples/signin.tsx(Tailwind only) andsdk/rune/examples/motion.tsx(Rune's props). On a native app,raea app check --video out/app.mp4 [--audio music.wav]films it on the virtual clock at 60 fps, with a cursor gliding to each element it presses. The same app and steps give the same frames.
Go further
- The guides:
raea guidelists them;raea guide NAMEprints one (motionfirst;bevyandbevy/NAMEfor 3D). - The SDK's behaviour:
sdk/raea/spec/motion.feature; what 3D reaches:raea guide coverage.
Related skills
Generative Code Art
anthropics
Create algorithmic art with p5.js using randomness and interactive parameters.
UI/UX Pro Max
anthropics
Build production-grade web components and interfaces with distinctive, polished design.
Artifact Theme Toolkit
anthropics
Apply professional color and font themes to slides, docs, and web pages.
Multi-Component Web Artifacts
anthropics
Build complex React artifacts with Tailwind CSS and shadcn/ui components.