Splatalign
ICP alignment for 3D Gaussian Splatting temporal captures
Install / Use
/learn @terminusfilms/SplatalignREADME
SplatAlign
ICP alignment for 3D Gaussian Splatting temporal captures.
Download Mac App | Download Windows App | Python install
Align two 3DGS scans of the same location taken at different times. Get a 4x4 transform matrix to use in your own code, or export an aligned PLY with the transform baked in.

Output
- 4x4 Transform Matrix — Column-major (WebGL/Three.js/PlayCanvas) and row-major (numpy) formats
- Aligned PLY (optional) — Transform baked into vertex data for viewers that can't apply runtime transforms
Features
- Multi-scale ICP — 4-stage alignment (5m → 1m → 0.3m → 0.1m) handles large initial offsets
- ~5cm accuracy — Median alignment error suitable for seamless time-toggle switching
- Ground filtering — Excludes seasonal vegetation (trees, grass) for stable structural alignment
- GUI + CLI — PyQt6 interface or command-line automation
Why Baked PLY?
Some 3DGS viewers (like Virtual Tour Pro) can't apply runtime transforms. The optional baked PLY export solves this — positions and rotations are transformed, all other properties preserved. Load the aligned PLY alongside your primary scan in any viewer.
Installation
Requirements: Python 3.8+
git clone https://github.com/terminusfilms/splatalign.git
cd splatalign
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Usage
GUI Mode
python splat_align.py
- Select Primary PLY (reference scan — usually your first capture)
- Select Secondary PLY (scan to align — your later capture)
- Check "Export aligned PLY" to bake the transform
- Click Run Alignment
- Use the aligned PLY directly, or copy the transform matrix
CLI Mode
# Transform matrix only
python splat_align.py --cli primary.ply secondary.ply
# With baked PLY output
python splat_align.py --cli primary.ply secondary.ply --bake
# Custom output directory
python splat_align.py --cli primary.ply secondary.ply --bake /path/to/output
Output
Aligned PLY File
secondary_aligned.ply — Ready to load alongside your primary in any viewer. Positions and quaternion rotations are transformed; colors, scales, and spherical harmonics preserved.
Transform JSON
{
"quality": {
"mean_cm": 5.23,
"median_cm": 4.89,
"p90_cm": 8.12,
"inlier_pct": 94.2
},
"matrix_column_major_flat": [0.93, 0.36, -0.02, 0.0, ...],
"matrix_row_major": [[...], [...], [...], [...]]
}
Using Transforms in Code
PlayCanvas / Three.js (column-major):
// PlayCanvas config.js
transforms: {
oct2025: null, // Primary, no transform
dec2025: [0.93, 0.36, -0.02, 0.0, ...] // Paste matrix_column_major_flat
}
// Three.js
const matrix = new THREE.Matrix4();
matrix.fromArray(result.matrix_column_major_flat);
mesh.applyMatrix4(matrix);
Python/numpy (row-major):
import numpy as np
T = np.array(result['matrix_row_major'])
aligned_points = (T[:3,:3] @ points.T).T + T[:3,3]
How It Works
- Load PLY — Extract XYZ positions from 3DGS vertex data
- Sample & Filter — Random sample + bottom 40% Z (ground/structure only)
- Multi-scale ICP — Iterative Closest Point at decreasing distance thresholds
- Quality metrics — Mean, median, 90th/95th percentile errors
- Export — Transform matrix JSON + optionally baked PLY
Ground Filtering
Seasonal changes (foliage, grass) create noise for alignment. By filtering to the bottom 40% of Z values, SplatAlign focuses on stable structural elements — paths, buildings, rocks — that don't change between captures.
Building Standalone App
For distribution without Python:
pip install pyinstaller
pyinstaller --onefile --windowed --name SplatAlign splat_align.py
Creates dist/SplatAlign.app (macOS) or dist/SplatAlign.exe (Windows).
Use Cases
- Time-toggle viewers — Switch between temporal states at the same camera position
- Seasonal documentation — Gardens, landscapes, construction progress
- Before/after — Renovations, events, environmental change
- Multi-capture fusion — Combine overlapping scans from different sessions
Next Steps: Build a Viewer
Once you have your aligned splats, use the Splat Time Toggle Template to build an interactive web viewer:
- Clone the template
- Add your LOD-converted splats
- Paste your
matrix_column_major_flatintoconfig.js npm run dev
The template includes WASD navigation, mobile support, time toggle UI, and optional collision.
Memory Considerations
Displaying multiple aligned splats simultaneously (for toggling or comparison) requires loading all splats into GPU memory. For large captures:
- LOD streaming (recommended) — Convert splats to hierarchical LOD format using @playcanvas/splat-transform. Only visible detail levels load, enabling multi-gigabyte scenes on standard hardware.
- Compressed splats — Formats like SOG (Sorted Gaussians) can reduce file sizes significantly, making multiple smaller splats feasible without LOD. Best for compact scenes under ~10M gaussians each.
Credits
Developed by Steve Bransford.
Part of the Atlanta Space Machine project — aerial-to-ground 3DGS exploration of Atlanta landmarks.
Alignment pipeline proven on PortalCam (XGRIDS) captures of Mason Mill ruins, achieving ~5cm median accuracy across seasonal changes.
License
MIT License — see LICENSE
Related Skills
node-connect
351.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
110.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
351.8kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
351.8kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
