Disclaimer: This is an independent resource site. Not affiliated with the Voron project or its development team.

Voron Timelapse Guide — Macro Setup, DSLR Control, and Hyperlapse

Klipper Guide Mod

Timelapse videos of your Voron prints are the best way to share your builds, diagnose print issues, and show off that perfect first layer. Klipper's macro system, combined with Moonraker's timelapse support and a DSLR camera, can produce stunning results. This guide covers everything from basic webcam timelapses to remote DSLR triggers, GPU-accelerated video encoding, and Hyperlapse mode for multi-hour prints. Last updated: May 2025.

How Klipper Timelapse Works

The core idea is simple: take a photo after each layer, then stitch those photos into a video. Klipper runs a macro called TIMELAPSE_TAKE_FRAME at the end of each layer, triggered by your PRINT_END or via Moonraker's layer detection. Moonraker manages the photo capture, frame storage, and video rendering.

There are three approaches, from simplest to highest quality:

Prerequisites

Before setting up timelapse, make sure you have:

Basic Webcam Timelapse

Moonraker's timelapse module works out of the box with any webcam that provides a snapshot URL. Enable it in your moonraker.conf:

[timelapse]
# Enable the module
enabled: True
# Snapshot URL from your webcam stream
snapshot_url: http://localhost:8080/?action=snapshot
# Where frames are stored
# Default: ~/timelapse/
output_path: ~/timelapse/
# Frame filename pattern
# Default: timelapse_{print_filename}_{layer_num}.jpg
frame_file_name: timelapse_{print_filename}_{layer_num}.jpg
# FFmpeg variable bitrate quality (crf)
# Lower = better quality, 18-28 is typical
constant_rate_factor: 23
# Output framerate in fps
fps: 30
# Pixel format for FFmpeg
pixel_format: yuv420p
# Time-lapse mode: layer or hyperlapse
time lapse_mode: layer
# Enable GPU acceleration (h264_v4l2m2m for Raspberry Pi)
# Leave empty for software encoding
extra_output_opts: -codec:v h264_v4l2m2m -b:v 20M

The snapshot_url must point to a JPEG snapshot endpoint. For Crowsnest, this is typically http://localhost:8080/?action=snapshot. For MJPG-Streamer, it's the same path.

GPU Acceleration on Raspberry Pi

Encoding 1000+ JPEG frames into a video takes significant CPU time. On a Raspberry Pi 4 or 5, you can use the hardware video encoder to reduce render time from 30 minutes to under 2 minutes.

Install the hardware-accelerated FFmpeg:

# On Raspberry Pi OS or Armbian
sudo apt install ffmpeg libavcodec-extra

# Verify H.264 hardware encoder is available
ffmpeg -codecs 2>/dev/null | grep h264_v4l2m2m

# Should show: h264_v4l2m2m (accelerated encoder)

Then configure Moonraker to use it:

[timelapse]
extra_output_opts: -codec:v h264_v4l2m2m -b:v 20M

For CB1 or other Allwinner-based boards, try h264_omx or h264_mmal instead. For systems with an Intel or AMD GPU, use h264_vaapi or h264_qsv.

Layer Detection — How Moonraker Knows When to Capture

Moonraker detects layer changes by monitoring Z-axis movement. When the toolhead moves up in Z by more than the configured threshold, Moonraker triggers a frame capture. This works automatically without any macro changes.

Configure layer detection in moonraker.conf:

[timelapse]
# Minimum Z movement to trigger a new frame (mm)
# Default: 0.01 — almost any Z move triggers capture
min_layer_height: 0.01
# Maximum time between frames before saving and starting a new segment (seconds)
# Prevents one massive video if print pauses
max_active_delay: 300

If you use variable layer height, set min_layer_height to the smallest layer height your slicer generates (typically 0.08mm for quality profiles). This prevents duplicate frames when Z moves in sub-layer increments for ironing or similar features.

Parking the Toolhead for a Clean Shot

The default behavior captures the frame with the toolhead wherever it happens to be at the end of the layer. For a cleaner timelapse, park the toolhead to a fixed position before each capture. Add this to your PRINT_END or use a dedicated macro:

[gcode_macro TIMELAPSE_PARK]
gcode:
    # Save current position
    SAVE_GCODE_STATE NAME=timelapse_state
    # Park toolhead out of frame
    # Adjust X/Y to your camera's field of view
    G90                              ; Absolute positioning
    G1 X250 Y250 F12000              ; Park position
    G1 Z{toolhead.z_position + 5}   ; Lift 5mm above current
    # Take the frame
    TIMELAPSE_TAKE_FRAME
    # Restore position
    RESTORE_GCODE_STATE NAME=timelapse_state

Call this macro from your slicer's layer change G-code. In SuperSlicer or OrcaSlicer, add to "After layer change G-code":

TIMELAPSE_PARK

Or integrate it directly into your PRINT_START macro by adding TIMELAPSE_TAKE_FRAME after each layer completes:

[gcode_macro PRINT_START]
gcode:
    {% set BED_TEMP = params.BED|default(100) %}
    {% set EXTRUDER_TEMP = params.EXTRUDER|default(250) %}
    
    # ... heating, homing, probing ...
    
    # Start timelapse
    SET_GCODE_VARIABLE MACRO=timelapse VARIABLE=recording VALUE=True
    
[gcode_macro _TIMELAPSE_LAYER_CHANGE]
gcode:
    {% if printer['gcode_macro timelapse'].recording %}
        TIMELAPSE_TAKE_FRAME
    {% endif %}

DSLR Camera Timelapse

For professional-quality timelapses, use a DSLR or mirrorless camera with a wired GPIO trigger. A Raspberry Pi GPIO pin connected to the camera's shutter release cable lets Klipper capture full-resolution photos.

Hardware Setup

You need a camera with a wired remote shutter port (2.5mm or 3.5mm jack). Build a trigger cable:

For Sony cameras with Multi-Terminal (USB Micro-B), use the sony-pmca-ptp protocol via USB instead of GPIO.

dslr_connecter Integration

The dslr_connecter project turns a DSLR into a network camera. Install it alongside Moonraker:

# Install dslr_connecter
cd ~
git clone https://github.com/jongough/dslr_connecter.git
cd dslr_connecter
python3 -m venv --system-site-packages .
source bin/activate
pip install -r requirements.txt

# Test connection
python3 dslr_connecter.py -p

Once running, dslr_connecter provides an HTTP endpoint at http://localhost:8081. Point Moonraker's timelapse at it:

[timelapse]
snapshot_url: http://localhost:8081/capture
# DSLR captures are much higher resolution
# Downscale to 1920x1080 for reasonable file sizes
extra_output_opts: -codec:v h264_v4l2m2m -b:v 20M -vf scale=1920:1080

GPIO Shutter Macro

If you prefer direct GPIO control (no dslr_connecter), use a Python script called from your macro:

#!/usr/bin/env python3
# ~/scripts/shutter.py
import RPi.GPIO as GPIO
import time
import subprocess
from datetime import datetime

PIN = 17  # GPIO17
OUTPUT_DIR = "/home/pi/timelapse"

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT)

# Pulse the shutter pin
GPIO.output(PIN, GPIO.HIGH)
time.sleep(0.1)  # 100ms pulse
GPIO.output(PIN, GPIO.LOW)

# Optionally trigger gphoto2 for tethered capture
# subprocess.run(["gphoto2", "--capture-image-and-download", "--filename", 
#     f"{OUTPUT_DIR}/{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"])

GPIO.cleanup()

Then create a Klipper macro to call it:

[gcode_macro TIMELAPSE_TAKE_FRAME]
gcode:
    RUN_SHELL_COMMAND CMD=shutter
    
[shell_command shutter]
command: python3 ~/scripts/shutter.py
timeout: 10.0

Hyperlapse Mode for Long Prints

For prints that run 12+ hours with thousands of layers, a frame-per-layer timelapse produces a video that's minutes long but takes hours to encode. Hyperlapse captures one frame every N layers instead of every layer.

Enable Hyperlapse in Moonraker:

[timelapse]
# hyperlapse mode
time lapse_mode: hyperlapse
# Capture 1 frame every 5 layers
hyperlapse_frequency: 5

Alternatively, use conditional macro logic to skip frames:

[gcode_macro _TIMELAPSE_LAYER_CHANGE]
gcode:
    {% set timelapse = printer['gcode_macro timelapse'] %}
    {% set current_layer = printer.toolhead.layer_number|default(0) %}
    {% if current_layer % 5 == 0 %}
        TIMELAPSE_TAKE_FRAME
    {% endif %}

A 2000-layer print at 30fps with 1 frame per layer = 67 seconds of video. With hyperlapse at every 5th layer = 13 seconds. Both are watchable, but the hyperlapse encodes in a fraction of the time.

Manual Rendering with FFmpeg

Moonraker renders the video automatically after the print finishes. But if you want more control — different codec, custom framerate, or re-rendering with new settings — use FFmpeg directly:

# Render all JPG frames in a directory into a video
cd ~/timelapse/my_print
ffmpeg -framerate 30 -pattern_type glob -i "*.jpg"   -codec:v h264_v4l2m2m -b:v 20M   -pix_fmt yuv420p   timelapse.mp4

# Add a title overlay
ffmpeg -framerate 30 -pattern_type glob -i "*.jpg"   -vf "drawtext=text='Voron V2.4 - 4h Print':x=w-tw-20:y=h-th-20:fontsize=24:fontcolor=white:box=1:boxcolor=black@0.5"   -codec:v h264_v4l2m2m -b:v 20M   timelapse_with_title.mp4

# Speed up 2x (for long timelapses)
ffmpeg -framerate 30 -pattern_type glob -i "*.jpg"   -filter:v "setpts=0.5*PTS"   -codec:v h264_v4l2m2m -b:v 20M   timelapse_speedup.mp4

Storage Management

Raw frames consume significant disk space. A 1000-frame timelapse at 1920x1080 JPEG (quality 90) uses about 500MB-1GB. Estimate your needs:

# Check timelapse disk usage
du -sh ~/timelapse/

# Set up automatic cleanup — keep last 3 renders
cat >> ~/scripts/cleanup_timelapse.sh << 'EOF'
#!/bin/bash
cd ~/timelapse
ls -t *.mp4 | tail -n +4 | xargs -r rm
# Remove raw frames older than 7 days
find . -name "*.jpg" -mtime +7 -delete
EOF
chmod +x ~/scripts/cleanup_timelapse.sh

# Add to crontab
(crontab -l 2>/dev/null; echo "0 3 * * * ~/scripts/cleanup_timelapse.sh") | crontab -

Troubleshooting

Example: Complete Timelapse Config

# In moonraker.conf
[timelapse]
enabled: True
snapshot_url: http://localhost:8080/?action=snapshot
output_path: ~/timelapse/
frame_file_name: timelapse_{print_filename}_{layer_num}.jpg
constant_rate_factor: 23
fps: 30
pixel_format: yuv420p
time lapse_mode: layer
min_layer_height: 0.01
extra_output_opts: -codec:v h264_v4l2m2m -b:v 20M

# In printer.cfg
[gcode_macro TIMELAPSE_PARK]
gcode:
    SAVE_GCODE_STATE NAME=timelapse_state
    G90
    G1 X250 Y250 F12000
    G1 Z{printer.toolhead.z_position + 20}
    G4 P200
    TIMELAPSE_TAKE_FRAME
    RESTORE_GCODE_STATE NAME=timelapse_state

With this setup, every print that goes through your slicer with the TIMELAPSE_PARK layer change G-code will produce a smooth, professional timelapse automatically. Whether you're using a $30 webcam or a $2000 DSLR, the workflow is the same — and the results are always worth sharing.

Need Camera Mounts?

We stock Voron-compatible camera mounts, GPIO trigger cables, and DSLR brackets — all tested on Voron V2.4, Trident, and Switchwire. Save 30-50% compared to Western vendors.

Shop Timelapse Gear →
🚨

Voron LDO 商标 · 域名 打包出售

Trademark & domains sold as one package

Voron LDO 商标 (中国区 · China)
voron.cn
voronldo.com
ldovoron.com

有意者请联系 · Contact us:

📧 346290742@qq.com
📞 +86 13522926174