Inspiration
Most tower defense games converge on a single "correct" build the moment a player figures it out — the rest of the run is just executing it. We wanted a game where the swarm punishes that: an enemy that watches which light hurts it most and adapts toward resisting exactly that. That single idea — SPECTRUM, "it learns your light" — became the load-bearing mechanic everything else was built around: route full-spectrum light through mirrors, prisms, and filters at a cyber-thriller optics array, and the enemy's resistance color tells you, honestly, what it's learned to survive.
What it does
SPECTRUM is a single-player tower defense played on a fixed 5x9 portrait grid. One emitter fires white light; the player places MIRROR, PRISM, FILTER, and AMPLIFIER optics to route, split, filter, and amplify it into R/G/B bands before it reaches twelve waves of descending enemies. Each enemy's material color is its resistance vector — no arbitrary tinting — so reading the board tells you exactly what to hit it with. After every wave, an absorption readout shows how the swarm's resistance shifted in response to the damage it actually took, and the player reconfigures the array before the next wave. Push one channel too hard and the swarm overfits: its strongest band goes nearly immune, but the two weakest bands become almost transparent to light, worth 120% bonus damage — so the winning strategy is training the enemy into a trap, not just building the highest-DPS array. Survive twelve waves and a 3800 HP CONVERGENCE boss to win.
How we built it
Stack: classic global Three.js r128, vanilla inline JavaScript, DOM for HUD/labels, and the Web Audio API for fully procedural sound — no external runtime assets, packaged as exactly three files (index.html, vendor/three.min.js, buildlog.md).
We split design from implementation. Design came first: we wrote a full handoff spec, then reviewed it under two adversarial hats — game designer and producer — which surfaced 35 numbered issues, 4 of them blockers. Rather than eyeballing balance, we simulated the adaptation formula, damage budget, and time-to-kill numerically across all 12 waves before writing gameplay code, which is how we caught that the original beam reach let waves 1–2 win for free, and that the original learning constants had a fixed point that killed adaptation permanently after wave 4.
From there we built session by session, each one a playable, testable slice: the portrait shell and raycasting first, then the cached axis-aligned beam graph and optics, then enemies and combat, then the full build/wave/readout lifecycle with adaptive resistance and the boss, then procedural audiovisual polish and clean restart handling, then hardening and packaging, then presentation and onboarding.
Challenges we ran into
- Balance blockers that reading alone couldn't catch. The original spec's numbers looked plausible on paper but produced a fixed point where any band over 21% damage share clamped to permanent zero damage. Only running the gradient step across all 12 waves exposed it.
- Gesture collisions. Tap-to-place, tap-to-cycle, SELL mode, and hold-to-sell all shared one pointer stream and kept triggering each other. We rebuilt input as an explicit small state machine with pointer capture and movement cancellation.
- Overfit ambiguity. Our first "any band ≥ 0.85" rule fired even under balanced play (all three bands could converge near 0.85 by wave 12) and left three-way ties undefined. We redefined it around concentration (
max ≥ 0.72 && spread ≥ 0.35) with stable ordering to resolve ties. - Visual/mechanical honesty. Early on, enemy color and actual resistance could drift apart if we changed only the display value during an overfit event. We fixed it by driving material and emissive color from the same real resistance vector, always.
- Offline integrity. Passing our own "no network calls" bar meant scanning and stripping the vendored Three.js build itself, not just our code, since it shipped with unused external loaders and doc strings.
- Restart correctness. A one-tap restart had to dispose of every dynamic object — geometry, materials, particles, cached paths, combat and economy state — without destroying shared, reusable resources like the audio context.
Accomplishments that we're proud of
Getting the adaptive-resistance mechanic to be numerically sound before it was ever played — verified with exact fixtures (e.g., pure red damage producing a precise 0.3552/0.0752/0.0752 resistance shift) rather than tuned by feel. Shipping a fully self-contained, three-file, offline game with zero external assets, including all audio and particle textures generated procedurally at runtime. Running 1,500 deterministic mixed-optic graphs plus deliberate cycles to prove the beam engine terminates and conserves energy correctly. Verifying a full winning run (boss killed with 60 core integrity and 175 kills) and a losing run, both deterministically. And building an onboarding flow with real accessibility care — focus containment, Escape dismissal, reduced-motion handling — without adding friction to repeat play.
What we learned
Simulating a design's own formulas before writing any gameplay code is cheap and catches failures that would otherwise hide for several waves before becoming obvious in playtesting. An AI coding agent will build enthusiastically whatever you ask for and won't tell you it isn't fun — you have to explicitly instruct it to push back and argue with the design. Touch input needs its release behavior tested as rigorously as its press behavior; correct presses can still hide a double action. And visual polish only helps when it strengthens the game's information hierarchy — brighter or busier isn't automatically clearer, and we had to pull some effects back once they started competing with the resistance-color cues players actually need to read.
What's next for Spectrum
The build is packaging- and balance-verified, but not yet tested on physical mobile hardware for sustained performance and subjective audio feel — that's the immediate next step. Beyond the competition, we'd extend the core idea rather than the scope: more authored scenarios and environmental constraints on the existing grid, new enemy behaviors beyond simple resistance-learning, and longer campaigns that keep visible color as an always-honest signal while making the fight to manipulate what the swarm learns the whole strategic arc.


Log in or sign up for Devpost to join the conversation.