packages/template-prompt-to-motion-graphics/src/skills/3d.md
Always wrap 3D content in ThreeCanvas and include proper lighting.
Incorrect (missing ThreeCanvas wrapper):
<mesh rotation={[0, frame * 0.02, 0]}>
<boxGeometry args={[2, 2, 2]} />
<meshStandardMaterial color="#4a9eff" />
</mesh>
Correct (proper ThreeCanvas setup):
import { ThreeCanvas } from "@remotion/three";
<ThreeCanvas>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} />
<mesh rotation={[0, frame * 0.02, 0]}>
<boxGeometry args={[2, 2, 2]} />
<meshStandardMaterial color="#4a9eff" />
</mesh>
</ThreeCanvas>;
Every 3D scene needs ambient + directional light for depth.
Incorrect (no lighting - objects appear flat/black):
<ThreeCanvas>
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial color="red" />
</mesh>
</ThreeCanvas>
Correct (proper lighting):
<ThreeCanvas>
<ambientLight intensity={0.4} />
<directionalLight position={[5, 5, 5]} intensity={0.8} />
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial color="red" />
</mesh>
</ThreeCanvas>
Use frame directly for smooth continuous rotation.
const frame = useCurrentFrame();
const rotationY = frame * 0.02; // Adjust speed with multiplier
<mesh rotation={[0, rotationY, 0]}>
<boxGeometry args={[2, 2, 2]} />
<meshStandardMaterial color="#4a9eff" />
</mesh>;
Use sine wave on Y position for organic floating effect.
const frame = useCurrentFrame();
const floatY = Math.sin(frame * 0.1) * 0.3; // Amplitude 0.3, speed 0.1
<mesh position={[0, floatY, 0]}></mesh>;
Use spring() for bouncy 3D object entrances.
const scaleProgress = spring({
frame,
fps,
config: { damping: 12, stiffness: 100 },
});
<mesh scale={[scaleProgress, scaleProgress, scaleProgress]}>
</mesh>;
Position camera at reasonable distance for scene visibility.
<ThreeCanvas camera={{ position: [0, 0, 5], fov: 75 }}>
</ThreeCanvas>