Record any scene, rewind any commit.
GdTimeMachine records your scenes right from the editor — no external capture or window setup. Pick a backend, hit Record, and get a clip named for the scene and time. Built for the “time machine” workflow: rewind your project to any git commit and capture it again to diff how a scene looked across history.
GdTimeMachine is listed on the Godot Asset Library: https://godotengine.org/asset-library/asset/5430
- In Godot: AssetLib → Search "GdTimeMachine" → Download → Install
- Then Project > Project Settings > Plugins → Enable GdTimeMachine
# from your project root
cp -r /path/to/GdTimeMachine/addons/GdTimeMachine addons/Then in Godot:
- Open Project > Project Settings > Plugins
- Enable GdTimeMachine
No extra dependencies for the built-in backends. OBS and ffmpeg are optional (see below).
- Open the GdTimeMachine dock in the bottom panel.
- Pick a backend, format, and FPS (duration
0= record until stopped). - Press Record — press Stop when done. Files are named
<scene>_<timestamp>.<ext>in your output dir.
Shortcuts:
Ctrl+Alt+R/Cmd+Alt+R(macOS) toggles recording from anywhere in the editor.- Command Palette →
GdTimeMachine: Toggle Recording. - Rebind via
Project > Editor Settings > Shortcuts→gd_time_machine/toggle_recording.
The dock status line shows live state while recording (backend, output file, elapsed time) and the final save/convert result.
Tip: Check Remember settings for this scene in the dock to save per-scene overrides.
- Movie Maker (
RESTART_SCENE) — AVI / OGV / PNG. Restarts the scene to record. AVI capped at 4 GB (auto-stops before cap). No external deps. - Screenshot (
IN_PLACE) — PNG / JPG native (+ ffmpeg → MP4 / WebM / AVI / OGV). Records the running scene in real time (~15 fps, no audio). Window must stay visible. No restart, no kill on Stop. - OBS Studio (
IN_PLACE) — MP4 native (Full FPS + audio, auto-launches via WebSocket if not running, no scene restart) + ffmpeg → WebM / AVI / OGV post-convert after stop.
RESTART_SCENE backends must relaunch the scene, so the in-game record button is disabled while a scene runs. IN_PLACE backends capture the running scene directly; if nothing is running, Record launches the scene first.
OBS always appears in the backend list under its plain name — installed-but-idle stays selectable (it auto-launches on Record, with a "will auto-launch" tooltip). If truly unavailable (not installed) the entry is greyed and unselectable with the install reason as tooltip; ffmpeg-dependent formats use the same disabled + tooltip treatment when ffmpeg is missing. Launch progress is narrated in both the dock status line and the terminal [GdTM] log.
Linux and Windows only — on other platforms the backend stays unselectable with the reason shown.
- Install OBS Studio (obsproject.com).
- In OBS: Tools → WebSocket Server Settings → Enable WebSocket Server (default port
4455). Set a password if desired. - In Godot: Project > Editor Settings →
gd_time_machine/obs/*— set matchinghost,port, andpassword. - Optional
obs/*settings:scene(record target, defaultGdTimeMachine),auto_launch(default on),auto_close(stop OBS we launched when Godot closes),auto_setup_scene(default on — build the PipeWire capture scene when the record scene is empty),binary_path(custom OBS binary).
Each Record targets your game window directly — no picker: on Linux the game reports its X11 window id over the debugger channel and OBS captures it via xcomposite_input (OBS is auto-launched under XWayland so the kind registers); on Windows OBS captures [exe]: title via window_capture (best-effort — exact-title matching is OBS-side). Whatever can't be targeted programmatically falls back exactly once to PipeWire screen capture (which needs one human share pick, remembered afterwards); if that fails too, the recording errors instead of going black. Progress is narrated in both the dock status line and the terminal [GdTM] log.
The gear button next to the backend dropdown re-opens the capture status dialog anytime: which scene/source/target the next Record will use, plus a one-shot Set up window capture now action. If PipeWire-fallback recordings show the wrong window: its saved share points at the wrong target — delete that share in OBS (or the whole GdTimeMachine scene and let the next Record rebuild it) and re-pick the game window.
The format dropdown is backend-aware — it shows native formats plus what ffmpeg can convert to.
- Native (no ffmpeg): AVI, OGV, PNG sequence, JPG sequence (availability depends on backend).
- Converted via a transcoder (ffmpeg): MP4 (H.264), WebM (VP9), AVI, OGV from a backend's native artifact — e.g. Movie Maker AVI → MP4, Screenshot PNG/JPG frames → MP4/WebM, OBS MP4 → WebM.
Tier-2 conversion is on by default (transcoders/ffmpeg/auto_convert). It uses the capture's measured average FPS. If no transcoder is available or conversion fails, the native artifact is kept and the status line explains why — never a lost recording. On success, intermediate frames/files are cleaned up per clean_frames.
- AVI: MJPEG, largest files, 4 GB cap.
- OGV: Theora+Vorbis, editor binaries only.
- PNG/JPG: image sequences, lossless/compact masters.
- MP4/WebM: require ffmpeg.
Godot has no built-in MP4 writer — MP4/WebM come from ffmpeg tier-2 conversion of the native artifact.
- Install ffmpeg: Linux
sudo apt install ffmpeg, macOSbrew install ffmpeg, Windowswinget install ffmpeg/choco install ffmpeg. - Verify on PATH:
ffmpeg -versionshould print a version;which ffmpegshows the path. - Tell Godot where it is: if on
PATH, nothing to do; otherwise set Project > Editor Settings →transcoders/ffmpeg/pathto the full path. Test with an MP4/WebM recording — status showsConvertedor a missing-tool notice.
Disable tier-2 via transcoders/ffmpeg/auto_convert = false to keep native formats only.
All defaults live in Project > Editor Settings and can be overridden per scene.
Recorder (gd_time_machine/recorder/*):
output_dir— where recordings are written (defaultres://media/captures)output_format— default format (avi,ogv,png,jpg,mp4,webm)default_backend— backend selected by defaultdefault_fps— target FPS capdefault_duration— seconds (0= until stopped)
Transcoders (transcoders/*):
active— ordered transcoder preference (default["ffmpeg"])transcoders/ffmpeg/*:path— custom ffmpeg binary (empty =PATHlookup)transcoders/ffmpeg/*:auto_convert— auto-convert tier-2 formats after recording (defaulttrue)transcoders/ffmpeg/*:clean_frames— delete frames after successful conversion (defaulttrue)
OBS (gd_time_machine/obs/*):
host,port,password,scene,auto_launch,auto_close,auto_setup_scene,binary_path
Shortcut:
gd_time_machine/toggle_recording—Ctrl+Alt+R/Cmd+Alt+R
Per-scene overrides — addons/GdTimeMachine/config/state/profiles.cfg (gitignored by default):
[default]
output_dir = res://media/captures
output_format = mp4
fps = 60
duration = 30
["res://scenes/menu.tscn"]
fps = 30
output_format = pngEach ["res://..."] overrides [default]. Edit directly or use Remember settings for this scene in the dock. Commit for shared team profiles.
gdtime is the headless companion for the time-machine workflow — same plugin.cfg version as the editor plugin, no extra dependencies.
gdtime validate <manifest.json> [--strict] # check manifest (strict rejects unknown keys)
gdtime run [options] <manifest.json> # worktree → godot → build → record
gdtime doctor [--verbose] [--fix] # git / godot / ffmpeg / OBS / build hook / worktrees
gdtime list-commits <manifest.json> # commit label for each capture
gdtime --help
gdtime --versionManifest (res://addons/GdTimeMachine/cli/schema/batch_manifest.schema.json): project_root, captures[] with commit (hex 4–40 or HEAD), scene (res://…), label ([A-Za-z0-9_-]+, unique), optional duration/fps/godot_version_hint/output_path/build_command and top-level godot_path/build_command/output_dir.
run options: --dry-run (preview), --resume LABEL (skip before label), --keep-worktrees / --keep-failed, --no-git (HEAD-only), --force (overwrite), --build-timeout SECS (default 600), --fail-fast, --strict.
Examples:
gdtime validate test/cli/manifest_history.json
gdtime run --dry-run test/cli/manifest_history.json
gdtime run test/cli/manifest_history.json
gdtime doctor --verboseHistory uses godot --path <worktree> --write-movie (Vulkan, no --headless) with godotenv/GODOT_BIN resolution and rm -rf .godot && godot --editor --headless --quit cache regeneration. Wrapper is addons/GdTimeMachine/cli/gdtime (godot --headless -s addons/GdTimeMachine/cli/main.gd -- … also works).
Exit codes: 0 ok, 1 failure, 2 degraded/partial (doctor warnings or run with --keep-failed).
Apache-2.0 — see LICENSE.txt.