Communitygithub.com

3D Animator

Direct a short 3D film in code, with a camera, light, motion and sound, using Remotion and three.js.

What is 3D Animator?

Treats a 3D clip like a directed shot instead of a spinning object in a grey void. It sets the camera, the light, the motion and the sound, and writes the frames in Remotion and three.js. Use it for a product or object animation, a cinematic 3D clip, a vertical short, or an existing scene that looks flat.

Works with✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Haseeburrahmann/3d-animator-skill/tree/HEAD

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does 3D Animator do?

A plain prompt gets you an object spinning in the middle of a grey void: a static camera, flat light, linear motion and no sound. An animator thinks about four things before writing any code: camera, light, motion and sound. This skill makes you think like that, then write every frame in code.

The rules come from a WhatsNext AI (@whats.nextai) production pipeline, tuned against measured top-performing reels:

  • under 10% static frames;
  • about 0.7 hard cuts per 10 s;
  • music about 9 dB under the voice.

0. Before any code: direct it

Write a shot list first. Every beat gets one line:

beat | seconds | subject | CAMERA move | LIGHT change | MOTION event | SOUND cue

Rules for the shot list:

  • Frame 1 shows the subject. Don't fade in from black, don't show a logo, don't open on an empty stage.
  • Change something visible by about 1.5 s: a camera move, a reveal or a light change.
  • Each beat changes one thing: the scale (wide ↔ macro), the angle, the light, or the state of the object. Never all at once.
  • Restage the same object rather than cutting to unrelated scenes. The ending shot should rhyme with the opening shot.
  • No subject? Pick one with a hidden inside, so the camera has somewhere to go: a watch, a phone, an engine, a city block, a cable. Plan a cutaway or reveal.

1. Camera (references/camera.md)

  • The camera never rests. Add a slow orbit and bob made of two incommensurate sines on top of every shot, so no frame is static. Starting values: about 0.17 rad × sin(0.8t) + 0.09 rad × sin(1.9t + 0.7).
  • Move between key cameras with ease-in-out (cubic). Never use linear moves, and never snap.
  • Dolly, don't zoom. Move the camera position and keep the field of view between 30° and 40° for objects. Wide-angle FOV distorts products.
  • Push in on reveals. Pull back to give context. One move per beat.
  • Few hard cuts: about 0.7 per 10 s. Motion comes from the camera, not from cutting.
  • Vertical 9:16 framing:
    • Keep the subject in the middle 60% of the frame height.
    • The top 15% is for a title.
    • The bottom 25% is for captions and app UI.
    • Leave the right 150 px clear on Instagram and TikTok.
  • Depth: put something in the foreground, the subject in the middle and a soft background behind. Add floating dust motes or particles near the look-at point so even a slow move reads as motion.

2. Light (references/light.md)

  • Dark background, one accent colour, one subject. For example, a navy #0B0F18 scene with an orange #FF914D accent for "information".
  • Light setup:
    • A hemisphere fill: sky #A9BDE0, ground #0B0F18, intensity about 0.8.
    • A cool key directional light from above-left: intensity about 1.5, casting shadows.
    • A warm point light on one side and a cool point light on the other, so edges separate from the background.
  • Reflections: use an environment map (RoomEnvironment through PMREMGenerator) at an intensity of 0.2–0.6. Without it, metal and glass look like plastic.
  • Bloom only on purpose:
    • Use UnrealBloomPass with threshold 0.9 or more, strength about 0.4 and radius about 0.4.
    • Things that should glow use emissive, and nothing else glows.
    • The overexposure trap: pure white materials plus bloom wash the frame out. Use light grey (#C9CFD9) for "white" plastics.
  • Use fog (<fog args={[bg, near, far]}/>) so distance falls off into the background colour.
  • Light changes are story beats: a part lights up as it's named, the room dims for a reveal, a flash lands on the payoff.

3. Motion (references/motion.md)

  • Every animation is a pure function of the frame: t = frame / fps.
    • Never use Date.now() or Math.random(). Use random(seed) from remotion.
    • Never animate with useFrame.
  • Pops use springs (damping 12–14, stiffness about 170). Moves use ease-in-out cubic. Use linear only for constant things like conveyor belts and particle drift.
  • Stagger related elements by 3–5 frames. Never move ten things on the same frame.
  • Add secondary motion: a slow turntable spin on the hero object (±0.4 rad), drifting motes, a breathing scale (±1%).
  • Holds are a choice. A freeze of up to 2 s is fine when it's a deliberate dramatic beat. Otherwise something always moves.
  • Labels: short uppercase status labels pop in on the beat they name. Mark recreations "3D RECREATION".

4. Sound (references/sound.md)

  • One SFX per event:
    • a whoosh on a big camera move;
    • a hit on a reveal;
    • a riser (about 2 s) into a reveal;
    • a click or pop on labels.
    • Synthesise them (scripts/sfx_synth.py) or use CC0 packs.
  • The music bed sits 6–11 dB under the voice, about 9 dB as a target. Sidechain-duck it under the narration.
  • Silence is an effect. Drop the music out for one beat before the key line, then slam back in on a hit.
  • Master to −14 LUFS integrated, with true peak at or below −1.5 dBTP. Pad the voice key to the full length so the music tail isn't cut.

5. Code rules (Remotion + three.js)

  • Canvas: wrap 3D in <ThreeCanvas width={width} height={height}> from @remotion/three, and always include lights.
  • Sequences: any <Sequence> inside the canvas needs layout="none".
  • Post-processing: an EffectComposer can take over rendering with a priority-1 useFrame(() => composer.render(), 1). That's the one allowed use, because Remotion advances the scene once per frame so output stays deterministic. See templates/Fx3D.tsx.
  • State: drive the scene from a single state function worldAt(t) that returns camera, stage and flags. Keep the components dumb.
  • Rendering: render with --gl=angle on macOS when WebGL output is black or unstable. Use H.264, yuv420p, 1080×1920, 30 fps.

Ready-made pieces (copy, don't import):

  • templates/Fx3D.tsx: Env reflections and Bloom.
  • templates/camera.ts: easeCam, orbit, ramp, pop.
  • templates/Motes.tsx: deterministic dust particles.

6. Verify like an editor

  1. Render 4–6 stills: the hook, every reveal, and the last frame. Look for overexposure, the subject cut off by captions or the title, empty frames and unreadable text.
  2. Render the video, then run scripts/check_motion.sh out.mp4. Target: under 10% static frames, motion (YDIF) at about 2 or more, and about 0.7 hard cuts per 10 s. If it's static, increase the orbit or bob, add motes, or add a push-in. Don't add cuts.
  3. If there's audio, check loudness (−14 LUFS) and that the music sits about 9 dB under the voice.
  4. Re-render only what failed.

Done means: a shot list exists, every beat has a camera move, a light role, a motion event and a sound cue, the checks pass, and you looked at the stills.

Related Skills