Episode 0: Turning a “Vibe-Coded” Black Box Into My Own App — A 32-Step Deconstruction Roadmap
I built an advanced web app in a burst of vibe coding—leaning hard on AI (Cursor and the like)—and packed in face recognition, WebGPU, and mobile sensors (heading, tilt, GPS).
Near the finish line, load-related bugs showed up. Then it hit me: I don’t understand what the code is doing, or why the bugs exist. Is this really my app? That disconnect—and a kind of guilt—was strong.
So I’m treating this black-box app as the best textbook I have: break it apart, learn the mechanics from the ground up, and turn it into real skill. This post is the index for that deconstruction journal.
- Live deploy (for verification): Proto Recon (Cloudflare Workers)
- Repository: github.com/katsutoshi0katsutoshi/proto_recon
- Extracted experiments: CodePen / @wlzpaovm-the-bashful
🧭 Deconstruction roadmap (5 phases / 32 steps)
To avoid burning out, the order starts with low-dependency pieces—config and UI polish—and ramps up toward hardware control and ML / performance. Anything that can stand alone gets a minimal CodePen (or similar) as we go. (This plan was also AI-assisted.)
Phase 1 ⭐ — Map & settings (learn by touching)
First: the big picture of the codebase, then how static config and copy steer the whole app.
| # | Title / theme | Main files | What you learn (core tech) | Common errors & traps |
|---|---|---|---|---|
| 01 | Big picture — roles under src/
|
- |
Which file owns what | Memorizing filenames without reading bodies |
| 02 |
devConfig — remote control for behavior |
appConfig.js |
Keys for camera, detection, CRT | One change ripples everywhere |
| 03 | Single source for UI copy: uiLexicon
|
uiLexicon.js, index.html
|
Centralized strings & errors | Finding leftover hard-coded text |
| 04 | CRT tokens into CSS — applyDevConfig
|
applyDevConfig.js, style.css
|
JS config → CSS variables on :root
|
Typo in var name → styles silently fail |
| 05 | HTML skeleton — splash & HUD DOM | index.html |
Layers (video / canvas / HUD) |
z-index vs the hidden attribute |
Phase 2 ⭐⭐ — Look & boot “theater” (no camera permission needed)
UI animation and audio you can verify without device permissions—pure front-end.
| # | Title / theme | Main files | What you learn (core tech) | Common errors & traps |
|---|---|---|---|---|
| 06 | Splash, BIOS, scramble text |
main.js, style.css
|
First-run UI flow & timers | Double-started timers, garbled text |
| 07 | Boot overlay — progress & steps | main.js |
Async status during startup | Failed steps never move to error
|
| 08 | Web Audio — play after click | audioFx.js |
AudioContext & user gesture |
Autoplay policy, silent output |
| 09 | Reticle SVG & fixed layout |
index.html, style.css
|
Center-fixed CSS layout | Why motionStabilityLink was cut |
| 10 | Live HUD frame & CRT noise |
style.css, main.js
|
Scanline overlay on video | Noise canvas render cost |
Phase 3 ⭐⭐⭐ — Media, sensors & tapes (real device required)
Core Web APIs: camera, gyro, GPS.
| # | Title / theme | Main files | What you learn (core tech) | Common errors & traps |
|---|---|---|---|---|
| 11 | Camera — getUserMedia & rear preference |
main.js |
facingMode, stream acquisition |
iOS permission timing, hung connections |
| 12 | How video is shown — object-fit: cover
|
style.css, main.js
|
Hidden → visible preview | Unintended “zoom” on camera feed |
| 13 | Full boot sequence — startCamera
|
main.js |
Tap → camera → model load | Failures when parallel vs sequential order changes |
| 14 | Heading tape — continuous angle & N jump |
compass.js, main.js
|
0°–360° unwrap, SVG control | Clipping at north (N), insufficient padding |
| 15 | Tilt tape — β / γ & motionHud
|
motionHud.js, main.js
|
Device tilt (DeviceOrientation) |
deviceorientationabsolute differences |
| 16 | Altitude tape — GPS altitude callback |
miniMap.js, main.js
|
Geolocation position & altitude |
altitude is null on some devices |
| 17 | Mini map — Leaflet & OSM/CARTO | miniMap.js |
External tiles, markers | Handling denied location |
| 18 | Speed HUD — coords.speed to km/h |
miniMap.js |
Speed from geo updates | Speed shows -- while stationary |
Phase 4 ⭐⭐⭐⭐ — Detection, privacy & ML backend (hardest)
The app’s main bottleneck—and the exciting part: real-time ML in the browser (TensorFlow.js).
| # | Title / theme | Main files | What you learn (core tech) | Common errors & traps |
|---|---|---|---|---|
| 19 | TF.js backend — WebGPU → WebGL → CPU | tfBackend.js |
Graphics API fallback chain | Unsupported devices, first compile, heat |
| 20 | COCO-SSD intro — ensureModel & throttling |
personDetection.js |
Model load, inference throttling | CDN load failure, dynamic import()
|
| 21 | Detection boxes — drawVideoCover & canvas |
personDetection.js |
Canvas aligned to video aspect |
Coordinate drift, device pixel ratio (DPR) |
| 22 | Lock-on — zones, dwell, key stabilization | personDetection.js |
Track ID retention, smoothing | ID swapping, flicker |
| 23 | Distance display — bbox estimate & WebXR | objectRange.js |
Pseudo-range from bounding box | Fallback when WebXR unavailable |
| 24 | Face mosaic — BlazeFace & canvas composite | facePrivacy.js |
requestAnimationFrame + throttled inference |
Camera draw vs inference cycle collision |
| 25 | Mosaic interval & heat — tuning intervalMs
|
facePrivacy.js |
Inference FPS vs device load | Freeze / thermal runaway when FPS too high |
Phase 5 ⭐⭐⭐⭐⭐ — Integration, ops & errors (toward production quality)
Bugs that appear when parts are wired together—including the ones I’m hitting now—and finishing the app as a whole.
| # | Title / theme | Main files | What you learn (core tech) | Common errors & traps |
|---|---|---|---|---|
| 26 | Live health — stall & frozen video detection | liveHealth.js |
Main-thread stall monitoring | False positives under load, retry loops |
| 27 | Startup errors — timeout & catch
|
main.js |
Orphan async work, stream cleanup | Timeouts on huge model loads |
| 28 | Second visit & cache — asset deploy | vite.config.js |
PWA cache, Vite build | failed to fetch dynamically imported module |
| 29 | Revisit & restart — stop & dispose models | main.js |
Leak prevention, releasing instances | Second launch much heavier than first |
| 30 |
motionStabilityLink — why parallax was cut |
motionStabilityLink.js |
Parallax vs readability | Jank when performance drops |
| 31 | Integration pass — main.js orchestration |
main.js (whole file) |
Module lifecycle | “Touch anything, break everything” coupling |
| 32 | Retrospective — bugs fixed & what’s next | App-wide | Load fixes, skills that stuck | Defining “fatal bugs are gone” |
🛠️ How I’ll actually move forward
Taken seriously, 32 steps at one post per day is roughly a month; realistically, one or two posts per week means six months or more. It’s not an obligation—I’ll go at an easy pace, sitting down properly for each piece. I’ll still use AI to polish prose and to help draft posts.
I’ve tasted the fun of AI-assisted idea generation. On purpose, I’m now dismantling this heavy mock—using AI to push ideas to the max, then learning backward until I can rebuild them with my own hands.
Minimal slices go into CodePen as a collection. Months from now, when this index is full of links and I can explain the bugs in my own words, the app should finally be mine in name and in fact.
I’m already close to losing heart while writing this. I assume AI will upgrade fast enough that parts of this article feel dated. Episode 0 is here—will Episode 1 actually show up? I don’t know yet. But that’s the bet.
Top comments (0)