Great question — and having just built Crosswise end-to-end in it, I can answer from what I actually leaned on versus what I'd have hand-rolled in a plain web project (like the crosswise.html prototype I made first). Here's the honest breakdown.
What Candela gives you "for free" (that you'd otherwise build)
1. A GPU vector renderer with a fallback backend (Mantle)loadSvg / createTextBundle / mountNode render SVG geometry and text on WebGL, crisp at any scale/DPI, plus a native-SVG fallback backend (the "Native" toggle). In a web project you'd pick canvas/DOM/WebGL and own all the resolution, scaling, and batching yourself. Vector-first is a real fit for clean 2D/UI-heavy games (crosswords, Stroop, matching) — less so if you need heavy sprites/particles/3D.
2. Scene graph + lifecycle scopesNode (transform inheritance, z-order, active flags) and Scope (child scopes that dispose whole subtrees on close) gave me leak-free per-grid teardown with scope.child() + scope.add(() => parent.removeChild(root)). In plain JS you'd write your own retained-mode tree and manual cleanup — a classic source of leaks.
3. The session lifecycle — defineLumosGame + SessionRunner
This is the biggest lift. For free I got: a 60s streaming session (duration feeds the timer and ends the session), awaitTimeout, recordArrival per solve, a scoringStore mirrored to the HUD, and finalize. Streaming vs. trial modes, pause, intro sequencing — all standardized. In a web project this is the game loop, timer, pause, and state machine you'd write from scratch every time.
4. The Lumos shell — all the "game chrome"mountShell supplied the HUD (TIME · SCORE · LEVEL), the 3-2-1 countdown, the pause overlay/menu, and the check/X feedback overlays — themed, animated, and consistent with 50 other games. That's easily days of UI work I didn't do. My prototype re-implemented a fraction of this by hand in CSS.
5. Input abstractionengine.interactables (hit-testing, pointer/tap, cursor), global keyboard via engine.input, and especially createTextField — which gave me physical-keyboard typing and the mobile soft keyboard for free. Hand-rolling a hidden-input soft-keyboard bridge for mobile canvas games is fiddly and I'd have gotten it wrong.
6. Deterministic, replayable sessions
Seeded Rng threads through everything → same seed replays the exact session. That powers both golden-log regression tests and the headless verifier reaching late-game states. In a web project you'd bolt on your own seeding discipline.
7. Responsive/viewport modelcamera.referenceUnit normalizes the short edge to 100 units, viewport.subscribe fires relayout on resize/rotate, pixelToUnitXY converts input coords. Orientation + safe-area handling is a solved problem. Plus prefab when: { aspect } branches for portrait/landscape.
8. Cross-cutting platform infra
Bundled fonts (createTextBundle — the canvas has no system fonts), audio (engine.audio + shared SFX set), WebGL context-loss recovery (auto pause/reinit, Engine.ts:201), visibility/pause handling, per-locale localization, and it targets web and native webviews at 60fps on low-end Android.
9. The domain layer — telemetry, difficulty, persistence
The Lumos payload envelope + stat (LPI), per-trial telemetry, adaptive-difficulty/leveling framework, and saveData/player_state persistence. This is the whole brain-training-platform contract — analytics, scoring science, cross-session level. A new web project has none of it.
10. Asset + animation pipeline
Prefabs (YAML → baked TS), Flash XFL extractors, createShapeTimeline/TransformTimeline, color matrices, 9-slice. For ports especially, this turns "recreate the art" into "extract and mount."
11. Ecosystem leverage
50 reference games, the shared shell, the Science/Art design guides, create-game/evaluate-game//verify skills, and a headless verification harness. Building Crosswise was mostly pattern-matching an existing sibling (word-bubbles, clue-rush) rather than inventing.
Where a plain web project is actually better
I'll be straight about the trade-offs, because they're real:
- Prototyping feel is faster in plain HTML/CSS/JS. My
crosswise.htmlwas runnable and tunable in one file in an hour; the Candela port took far longer and hit engine-specific gotchas (the invisible-glyph color-matrix issue, headless rAF, the crash you're chasing now). For "does this mechanic feel good," a plain web prototype wins. - Candela is domain-shaped, not general-purpose. It's built around cognitive-game sessions (timer, trials, LPI, adaptive difficulty, one accent color, calm chrome). If you wanted a physics platformer, a 3D game, or something outside the brain-training mold, most of that infra is dead weight or fights you.
- Conventions are mandatory.
defineLumosGame, the shell, the payload contract, registration in 4 spots, the pause-slide rules — there's a "right way" you must follow, and deviating causes churn. A web project has no such ceremony. - You inherit its bugs, too. The WebGL/Mantle path has sharp edges (exactly the crash you're seeing) that a DOM/CSS game would never hit.
Bottom line
For this class of game — a timed, scored, adaptive brain-training minigame that has to ship in a 50-game catalog, run in native webviews, and report LPI/telemetry — Candela replaces roughly 70-80% of what you'd hand-build (loop, session, HUD, input, audio, responsive, telemetry, persistence, cross-platform) and enforces consistency across the suite. The right workflow is what we did: prototype the mechanic as a plain web page for feel, then port into Candela to get the session/shell/platform machinery.
If you want, I can turn this into a one-page reference (an artifact) you could share with the team, or map each capability to the exact Crosswise file where I used it.