- JavaScript 83.6%
- CSS 14.1%
- Shell 2.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| conf | ||
| doc | ||
| scripts | ||
| sources/app | ||
| .gitignore | ||
| config_panel.toml | ||
| LICENSE | ||
| manifest.toml | ||
| README.md | ||
| tests.toml | ||
Cartourse for YunoHost
3D race routes from GPX: animated flyovers with a 3D ribbon, broadcast graphics, iframe embeds, EBU OGraf & HyperFrames export. Cartourse was called RaceTracer up to v1.0 (see Moving from RaceTracer below).
Overview
Cartourse turns a GPX file into a 3D race route you can play, embed and broadcast.
- 3D terrain player — MapLibre GL JS (BSD-3) + open Terrain Tiles. Viewers can rotate, tilt and zoom while it plays (drag, wheel, pinch, +/− buttons); the camera keeps following the race, Auto camera (or a double-click) brings the automatic framing back.
- Smooth camera over mountains — the camera pivot follows a smoothed altitude of the route instead of the terrain under the screen centre: no more jumps over ridges and valleys.
- 3D ribbon — a translucent wall standing on the route, revealed with the race (or the classic flat line).
- Leader marker of your choice — pulsing dot, arrow lying on the ground and pointing the way, bike, your own image, or nothing.
- Open imagery by default — Sentinel-2 cloudless 2016 (EOX, CC BY 4.0); IGN orthophotos (France), OpenTopoMap, OSM, custom XYZ; Esri optional.
- Cinematic, deterministic timeline — fly to start → 180° orbit over the start → the trace draws while the camera floats above a smoothed route (70° pitch by default) → smooth outro to a top view. In the final zoom-out the point cards shrink (size adjustable) and can be limited to the start and the finish.
- Points by kilometre (start, city, sprint, mountain HC/1–4, danger, feed, finish) popping up in 3D, flashing when passed, shown on the elevation profile; automatic climb detection.
- Animation themes — Classic (default), Broadcast, Minimal, Neon, plus a theme designer in the editor: colours, shapes, borders, icon, pole, entrance animation (rise, pop, slide, drop, flip, wipe, zoom, fade), pass effect, lower-third — live preview, no CSS needed.
- Logos: one top-left (next to the title), one top-right, plus a row under the elevation profile with as many logos as you like (the first one centred) — per client, overridable per stage.
- Town & village names on the elevation profile, detected automatically from OpenStreetMap (Overpass API) and written vertically, road-book style; hide, rename or turn them into points in the editor.
- Per-client page style: background / text / tab colours and free CSS for the client page and the stage pages (empty = default look).
- Camera keyframes captured with the mouse, blended with smootherstep interpolation.
- Clients → stages: shared branding, one page per stage, one client page with a tab per day.
- Embeds:
/embed/<id>iframes, snippet builder, oEmbed,postMessageAPI. - EBU OGraf export for DaVinci Resolve 21+ (and SPX / CasparCG / Sofie): 3D map graphic + transparent overlay graphic, real-time and non-real-time.
- HyperFrames export:
npx hyperframes render→ MP4.
Shipped version: 1.2.0~ynh1
Install at the root of a domain
The default path is /: https://coursemap.example.org/ serves the public home, /c/<client>, /r/<stage>, /embed/<stage>, and the editor lives at /admin.
sudo yunohost app install ./cartourse_ynh -a "domain=coursemap.example.org&path=/&init_main_permission=visitors&init_admin_permission=admins&embed_origins=*&seed_demo=0&import_racetracer=1"
A domain-root install needs the domain to be free (no other app on it).
Moving from RaceTracer
The app id changed (racetracer → cartourse), so this is a new install rather than an upgrade. Your data is copied automatically:
# 1. safety first
sudo yunohost backup create --apps racetracer
# 2. remove the old app — WITHOUT --purge, so /home/yunohost.app/racetracer stays on disk
sudo yunohost app remove racetracer
# 3. install Cartourse at the root of the same domain; "import_racetracer=1" copies the old data
sudo yunohost app install ./cartourse_ynh --force \
-a "domain=coursemap.example.org&path=/&init_main_permission=visitors&init_admin_permission=admins&embed_origins=*&seed_demo=0&import_racetracer=1"
- Clients, stages, logos and original GPX files are copied (never moved or deleted).
- Old links keep working:
/racetracer/...is redirected (301) to the same page at the new address, so iframes already embedded on other websites keep playing. - The
postMessageAPI accepts and sends bothcartourseand the oldracetracerkey. - Clients created with v1.0 have the Broadcast theme saved explicitly; switch them to Classic in Look → Point animation theme if you want the new default.
Package layout
manifest.toml YunoHost packaging v2 (helpers 2.1)
scripts/ install (+ RaceTracer import), upgrade, remove, backup, restore, change_url, config
conf/nginx.conf public location + SSO-protected /admin (injects a shared secret header)
conf/systemd.service Node.js service, hardened
config_panel.toml allowed iframe origins
sources/app/ the application itself (zero npm dependencies)
server.mjs HTTP server, routing, API, legacy URL redirects
lib/ store (JSON files), domain, pages, places (OSM towns), exporters (OGraf, HyperFrames), zip, demo seed
public/engine/ rt-core (timeline/camera maths), rt-player (MapLibre), rt-ribbon (3D ribbon layer),
rt-themes (theme designer → CSS), rt-ui, rt-overlay, rt-ograf (OGraf bridge),
rt-dem (terrain elevation), rt-player.css (layout + built-in themes)
public/admin/ editor SPA (clients, stages, camera, theme designer)
public/vendor/ MapLibre GL JS 6.13 (BSD-3), GSAP 3.15 (HyperFrames export only)
Run it locally (without YunoHost)
cd sources/app
RT_ADMIN_OPEN=1 node server.mjs # Node.js >= 18, no npm install needed
# → http://127.0.0.1:8095/ public home
# → http://127.0.0.1:8095/admin editor (open, for local testing only!)
npm test # smoke tests (parsing, timeline, exports)
Environment variables: PORT, HOST, DATA_DIR, BASE_PATH (empty = domain root), RT_ADMIN_SECRET, RT_ADMIN_OPEN, RT_EMBED_ORIGINS, RT_SEED_DEMO, RT_LEGACY_PATHS (old URL prefixes to redirect, default /racetracer), RT_OVERPASS_URL (Overpass endpoints for town names, space separated).
Town names need outgoing HTTPS from the server to the public Overpass API (overpass-api.de, with two mirrors as fallback). They are fetched once per stage (at creation, when the track is replaced, or the first time an older stage is viewed) and stored with the stage.
Security model
/adminis a separate YunoHost permission (default groupadmins), enforced by SSOwat.- nginx adds
X-RT-Admin: <random secret>only inside the/adminlocation and strips it everywhere else; the app refuses admin routes without it. The Node process listens on 127.0.0.1 only. - Embed pages send
Content-Security-Policy: frame-ancestors <configured origins>; all other pagesframe-ancestors 'self'. YunoHost'sX-Frame-Optionsis cleared so embeds work. - Uploaded SVGs are served with a restrictive CSP.
Licences
Cartourse code: AGPL-3.0-or-later. Town names: © OpenStreetMap contributors (ODbL). MapLibre GL JS: BSD-3-Clause. GSAP: GreenSock standard licence (free, bundled only in HyperFrames exports because HyperFrames requires it). Imagery/terrain: see attribution in the map (EOX, IGN, OpenTopoMap, OpenStreetMap contributors, Mapzen/AWS Terrain Tiles).