One globe, two render engines.
-- A real-time 3D activity globe, built twice over a shared core so the two rendering - strategies can be compared head-to-head. Same scene, same controls, same data — - only the pixels are pushed differently. Each view shows a live FPS meter. -
+ /* ---- side-by-side view ---- */ + body.compare .wrap { + display: none; + } + .stage { + display: none; + flex-direction: column; + height: 100vh; + } + body.compare .stage { + display: flex; + } + .bar { + display: flex; + align-items: center; + gap: 14px; + padding: 10px 16px; + border-bottom: 1px solid var(--line); + background: rgba(5, 6, 12, 0.7); + backdrop-filter: blur(10px); + } + .bar .name { + font-weight: 600; + font-size: 14px; + } + .bar .name b { + color: var(--accent); + } + .bar .spacer { + flex: 1; + } + .frames { + flex: 1; + display: grid; + grid-template-columns: 1fr 1fr; + min-height: 0; + } + .frames .col { + position: relative; + min-width: 0; + border-right: 1px solid var(--line); + } + .frames .col:last-child { + border-right: 0; + } + .frames .col .label { + position: absolute; + top: 10px; + left: 50%; + transform: translateX(-50%); + z-index: 2; + font-family: var(--mono); + font-size: 10.5px; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--accent); + background: rgba(5, 6, 12, 0.6); + border: 1px solid var(--line); + border-radius: 8px; + padding: 5px 12px; + pointer-events: none; + } + .frames iframe { + width: 100%; + height: 100%; + border: 0; + display: block; + background: var(--bg); + } + @media (max-width: 760px) { + .cards { + grid-template-columns: 1fr; + } + .frames { + grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr; + } + .frames .col { + border-right: 0; + border-bottom: 1px solid var(--line); + } + } + + + + +One globe, two render engines.
++ A real-time 3D activity globe, built twice over a shared core so the two rendering + strategies can be compared head-to-head. Same scene, same controls, same data — only the + pixels are pushed differently. Each view shows a live FPS meter. +
-Canvas 2D
-Immediate-mode drawing to a single canvas. The whole frame is cleared and - redrawn each tick — no persistent nodes, no per-frame DOM work. Built for FPS.
- - - -SVG
-Retained-mode: persistent SVG nodes whose attributes are updated each frame. - The original approach — crisp, resolution-independent, identical look.
- - -Canvas 2D
++ Immediate-mode drawing to a single canvas. The whole frame is cleared and redrawn each + tick — no persistent nodes, no per-frame DOM work. Built for FPS. +
+ + + +SVG
++ Retained-mode: persistent SVG nodes whose attributes are updated each frame. The + original approach — crisp, resolution-independent, identical look. +
+ + +
- Needs a static server (the world map is fetched at runtime):
- python3 -m http.server 8000 → http://localhost:8000
- The links above open demo mode (?demo) with live controls + FPS. The bare
- canvas/ or svg/ URL is the clean hero — globe only, no controls.
- Customise HQ / cities / activity types in shared/data.js; scene settings come from the
- platform (?config=<url> or window.__GD_SCENE__), bounded by shared/scene-schema.js.
-
+ Needs a static server (the world map is fetched at runtime):
+ python3 -m http.server 8000 → http://localhost:8000
+ The links above open demo mode (?demo) with live controls + FPS. The
+ bare canvas/ or svg/ URL is the clean hero — globe only, no
+ controls.
+ Customise HQ / cities / activity types in shared/data.js; scene settings come
+ from the platform (?config=<url> or window.__GD_SCENE__),
+ bounded by shared/scene-schema.js.
+