3D video by code · no AI video

Create animated video with code

A bedroom and a house built piece by piece, with real light computed on the graphics card and narration in a local voice.

Banner: 3D reel made with code, bedroom built piece by piece
In short

reel3d is a project that makes short 3D videos (9:16 format, for phones) by writing the scene in code, without using an artificial intelligence video generator. Each piece of furniture is a part with real-world dimensions that animates into place; the light is computed by path tracing (a simulation of how light hits and bounces off surfaces) on the graphics card. It is for anyone who wants to show spaces, products or ideas with full control of camera and timing. To run it, you need Node.js, a graphics card and patience: each frame takes a few seconds.

What it is

A scene you write, not one you roll the dice on

Instead of asking an AI for a video and hoping for the best, you describe the space in TypeScript. Everything is repeatable: same code, same video.

Banner with the parts of the project: scene in code, path tracing, CC0 furniture, local narration

🧱 Real-scale scene

Walls, bed, wardrobes and counters are boxes with dimensions in meters; ready-made models (sofa, plants, lamp) come from Poly Haven, free to use (CC0).

💡 Photorealistic light

three-gpu-pathtracer accumulates 64 samples per frame with 4 light bounces, and a denoise filter cleans up the grain at the end.

🎙️ Synchronized narration

The voice is generated locally (chatterbox, through inemavox); the timing of each sentence drives the camera shots and the captions.

How it works

From script to MP4

Remotion opens the scene in a headless browser, three.js builds the 3D, and the path tracer computes the light frame by frame.

Script (.txt)→ Narration per sentence→ tempos.json→ Scene + camera (src/)→ Path tracing on the GPU→ Denoise filter→ MP4 with voice

src/engine.tsx

The shared engine: PBR materials, boxes, model loading, camera shots, per-frame path tracing and word-by-word captions.

src/Quarto60.tsx · src/Casa90.tsx

Each video is a composition: it builds the scene and says when each piece comes in and where the camera goes.

produz.sh

Full render, denoise filter, narration merge and a light copy (up to 44 MB) to send on Telegram.

Prerequisites

What you need

Tested on an NVIDIA GB10 (DGX Spark) with Linux ARM64. Any GPU with Vulkan should work; only the time changes.

Node.js 20+

For Remotion and three.js.

node -v

GPU with Vulkan

The render uses --gl=angle (real GPU). --gl=swangle falls back to the CPU and is very slow.

vulkaninfo --summary

ffmpeg

Denoise filter, voice merge and final compression.

ffmpeg -version
User guide · step by step

Render the bedroom and the house

The commands below are the same ones used to generate the two videos on this page.

1

Download the project and the dependencies

The textures and models (217 MB, CC0) are not in the repository: the script downloads everything from the Poly Haven CDN into public/ph.

git clone https://github.com/inematds/reel3d-teste
cd reel3d-teste && npm install
node baixa-assets.mjs public/ph   # 132 files
2

Check a frame before the video

A single frame with few samples shows whether the scene, light and camera are right. With debug, the time of each stage is written on the image.

npx remotion still src/index.ts Quarto60 out/teste.jpg --frame=300 --gl=angle --props='{"spp":16,"debug":true}'
bash stills.sh Quarto60 16   # one frame per shot + contact sheet
3

Record the narration (optional)

One line of narr/quarto.txt per sentence. gera.sh uses inemavox's local TTS; swap in your own reference voice. monta_audio.py joins the sentences and writes the timings to narr/tempos.json; after transcribing each WAV with Whisper (word by word), the second stage writes the caption words.

bash narr/gera.sh
python3 narr/monta_audio.py             # sentences → quarto.wav, casa.wav
python3 narr/monta_audio.py --palavras  # caption words
4

Render the full video

A single tab (one GPU), a 24 GB memory cap and a 6 h limit. It ends with the denoise filter and the narration in the MP4.

bash produz.sh Quarto60 "quarto 60 s"
bash produz.sh Casa90 "casa 90 s"
grep -a "Rendered" out/render.log | tail -1   # progress

The last step of produz.sh sends the video to a local Telegram bot; without it, the final MP4 stays in out/<nome>-v1-final.mp4.

5

Tune the quality

More samples = less grain and more time. Measured on the GB10 at 1080×1920:

SettingTime per frameUse
spp 64 · bounces 4~5 sfinal video (with denoise filter)
spp 256 · bounces 6~27 scover frame, grain-free
Videos

What has come out of here

Both videos were rendered in full on this machine, with no AI-generated frames.

8 m² bedroom · 64 s. Floor-to-ceiling wardrobe, a long desk at the window, a raised bed with drawers that double as steps. Render: 3 h 44.
Single-story house · 87 s. From the facade inward: open-plan living room, in-line kitchen and, at the end, the same bedroom. Render: 5 h 26.
Next

Where it goes

What has been done and what comes next.

Done
Bedroom 10 s, Bedroom 60 s and House 90 sShared engine, word-by-word captions, narration with a local voice and full render on the GPU.
Next
The same scene in BlenderRedo the bedroom and the house with headless Blender (Cycles), to compare quality, render time and build cost.