Documentation

Build with TwinPlanet.

Concepts, data formats, the leads API, and how to self-host this website.

Platform concepts

The TwinPlanet pipeline has five stages: Task → Correct → Understand → Reconstruct → Simulate. Each stage emits standard products that reference one georeferenced ground truth, so imagery, vectors, 3D and the digital twin stay consistent.

StageInputOutput
TaskAOI, resolution, cadenceTasked / archive imagery
CorrectRaw imageryPansharpened, super-resolved, ortho-ready pixels
UnderstandCorrected imagerySegmentation, detections, change layers
ReconstructImagery + controlOrtho, DSM/DTM, mesh, CityGML, SD/HD maps
Simulate3D + subsurfaceWeb 3D twin, Unreal/VR scene

Tasking & AOIs

An Area of Interest (AOI) is defined by a polygon or bounding box plus a CRS. You can:

  • New tasking — request a fresh collection (satellite, aerial or drone).
  • Archive tasking — retrieve historical imagery for baselines.
  • Lock an AOI — schedule periodic capture with automatic change notification.
{
  "aoi": { "type": "Polygon", "coordinates": [[[9.99,53.55],[10.05,53.55],[10.05,53.58],[9.99,53.58],[9.99,53.55]]] },
  "crs": "EPSG:4326",
  "mode": "new",            // new | archive | monitor
  "sensors": ["optical","sar"],
  "gsd_cm": 30,
  "cadence_days": 14,        // for monitor mode
  "notify": "alerts@city.example"
}

Data & export formats

Everything TwinPlanet produces exports to open standards:

  • Raster: GeoTIFF, Cloud-Optimized GeoTIFF, JPEG 2000
  • Point cloud: LAS / LAZ
  • Vector: Shapefile, GeoPackage, GeoJSON
  • 3D: OBJ, FBX, glTF/GLB, 3D Tiles, CityGML
  • Mobility: OpenDRIVE
  • Services: WMS / WMTS / WFS, OGC API

Leads / contact API

This website ships with a small PHP endpoint that validates and stores contact requests.

POST /api/contact.phpapplication/json or form-encoded.

curl -X POST https://twinplanet.com/api/contact.php \
  -H "Content-Type: application/json" \
  -d '{
    "csrf": "<token from the page>",
    "name": "Jane Doe",
    "email": "jane@agency.gov",
    "org": "City of Hamburg",
    "need": "Digital twin & simulation",
    "aoi": "Hamburg, DE",
    "msg": "We need a twin of the inner ring."
  }'

Responses:

200 { "ok": true,  "message": "Thanks — your request is in." }
422 { "ok": false, "error": "Please enter a valid work email." }
419 { "ok": false, "error": "Your session expired. Please reload." }

Requests are stored in the leads table and emailed to your team. A CSRF token (rendered into the contact form) and a hidden honeypot field protect the endpoint.

Self-hosting

The site is plain HTML/CSS/JS with a thin PHP backend — no WordPress, no build step. Deploy it on Ubuntu 24.04 with nginx and PHP 8.3 in a few minutes.

Full instructions: docs/INSTALL-Ubuntu-24.04.md (also in the repository). In short:

sudo apt update && sudo apt install -y nginx php8.3-fpm php8.3-mysql mysql-server
sudo mysql < db/schema.sql
sudo cp deploy/nginx.conf /etc/nginx/sites-available/twinplanet
sudo ln -s /etc/nginx/sites-available/twinplanet /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Prefer zero-config? Set DB_DRIVER=sqlite and the form works with no database server.

FAQ

Do I need WordPress?

No. This site is intentionally WordPress-free — pure HTML5, CSS and a small amount of PHP.

Can I host it as a static site?

Yes. Run node tools/export-static.mjs to generate a fully static _static/ build for any CDN. The contact form then needs an external endpoint (e.g. a serverless function).

Which database is required?

MySQL/MariaDB is recommended for production; SQLite works out of the box for local or small deployments.

How do I change content?

Edit the .php files in public/. Shared header/footer live in app/partials/.