[OK] DELEGATING TO STACK OVERFLOW...
[OK] REMOVING TODO COMMENTS (WITHOUT FIXING THEM)...
[OK] BYPASSING CODE REVIEW RULES...
[OK] READY TO DISSAPOINT...

V-FEED [06]_

[ FAIL CASE #01 ] 60 FPS WebGL CRT simulator & AI body-tracking spaceship vs. 6 physical TVs and $4 RCA adapters.

<-- INDEX /FAIL-CASESOVER-ENGINEERED / HARDWARE REALITY CHECK
// SECTION 00 :: CASE DOSSIER & METADATA SPEC SHEETCASE_ID: FAIL-01 // REV_2026.10
PROJECTV-FEED [06]
CLASSIFICATIONFAIL CASE #01 — Interactive Transmedia CRT Installation
TL;DR METRIC2,839 LOC Calibration GUI vs. 1 Loose Composite Cable
STACK
  • [TypeScript]
  • [Three.js / WebGL]
  • [Custom GLSL]
  • [@mediapipe/tasks-vision]
  • [Web Audio API]
  • [Express]
  • [yt-dlp]
  • [6x CRT Matrix]
OFFICIAL AUTOPSY VERDICT ::

"Wrote closed-form inverse bilinear quad-warping shaders and a 2,839-line calibration deck to fix problems that belonged to physics."

// SECTION 01 :: EXPECTATION VS. EXHIBITION TELEMETRY

THE PITCH VS. THE REALITY_

[ THE ART SCHOOL PITCH // WHAT I THOUGHT I WAS BUILDING ]SPEC_THEORY

An interactive transmedia art installation projecting vertical YouTube Shorts across a vertical totem of 6 vintage Cathode Ray Tube (CRT) televisions arranged in a 2×3 matrix—conceived as a cybernetic tribute to video artist Joshua Ellingson.

"Six cathode ray tubes, a YouTube feed, and a motion sensor: the user is the only missing wire in the system."

Spectators act as a "Human Antenna"—their physical distance (3m to 1m), movement velocity, and body postures tuning or corrupting the analog broadcast in real time like human dipole antennas.

[ EXHIBITION FLOOR REALITY // WHAT ACTUALLY HAPPENED ]FIELD_INCIDENT

Me crouched in the dark hitting Ctrl+Shift+C to tweak poseGuideOffsetX: 0.29 and rgbSplit: 1.269 because the camera couldn't tell a gallery visitor from a shadow, while yt-dlp downloaded 313 videos of boats sinking.

Instead of a seamless human-machine symbiosis, I built a 60 FPS WebGL spaceship to fight $4 plastic HDMI-to-RCA composite adapters, ambient gallery floodlights glaring off curved leaded glass, a webcam held to a steel shelf with a binder clip, and strangers who understandably refused to hold a "Rabbit Ears" pose in public for 1.8 seconds.

// SECTION 03 :: HOW I BUILT A SPACESHIP FOR A TOASTER PROBLEM

ANATOMY OF THE OVER-ENGINEERING (THE 4 PILLARS OF DOOM)_

[01]

SIMULATING CRTS IN SOFTWARE... FOR REAL ANALOG CRTS

CompositeShader.ts (346 LOC) + CRTShader.ts + NoiseShader.ts + AudioEngine.ts

The installation was designed for six physical 14"–20" CRT televisions—literal vacuum tubes with real curved leaded glass, real shadow-mask phosphor triads, real plastic bezels, and real 15.734 kHz flyback transformers.

Instead of just sending video to the TVs, I wrote a 346-line single-pass GLSL fragment shader (CompositeShader.ts) that mathematically simulates barrel glass curvature (uCurvature, uTubeCurve), RGB shadow-mask phosphor triads and horizontal scanlines (CRTShader.ts), a 3D beveled dark plastic monitor chassis with specular highlights (uBezelChassis), chromatic aberration (uRgbSplit), V-Hold vertical frame roll (uVHold), horizontal sync jitter (uHJitter), and Gaussian RF snow (NoiseShader.ts).

On top of that, I built a Web Audio API synthesizer (AudioEngine.ts) with pink/white noise buffers and a sine oscillator locked to 15,734 Hz to emulate the NTSC CRT flyback transformer whine—for a room meant to have six real flyback transformers already screaming at 15,734 Hz. And when physical hardware and projection realities hit, the software ended up having to pretend to be the hardware it was supposed to feed.

// FILE: src/shaders/CompositeShader.ts (Closed-Form Inverse Bilinear Quad-Warping)GLSL FRAGMENT SHADER :: 38 UNIFORMS
float cross2d(vec2 a, vec2 b) {
  return a.x * b.y - a.y * b.x;
}

// Closed-form inverse bilinear interpolation for 24-point keystone pinning
vec2 invBilinear(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) {
  vec2 e = p1 - p0;
  vec2 f = p3 - p0;
  vec2 g = p0 - p1 + p2 - p3;
  vec2 h = p - p0;

  float k2 = cross2d(g, f);
  float k1 = cross2d(e, f) + cross2d(h, g);
  float k0 = cross2d(h, e);

  if (abs(k2) < 0.0001) {
    float u = (h.x * k1 + f.x * k0) / (e.x * k1 - g.x * k0 + 0.00001);
    float v = -k0 / (k1 + 0.00001);
    return vec2(u, v);
  }

  float w = k1 * k1 - 4.0 * k0 * k2;
  if (w < 0.0) return vec2(-1.0);
  w = sqrt(w);

  float v1 = (-k1 - w) / (2.0 * k2);
  float u1 = (h.x - f.x * v1) / (e.x + g.x * v1 + 0.00001);
  return vec2(u1, v1);
}
[02]

SOLVING CARPENTRY WITH LIL-GUI: THE 2,839-LINE CALIBRATION CONSOLE

CalibrationConsole.ts (2,839 LOC) + SyncChannel.ts + config/calibration.json (351 LOC)

Mounting and aligning 6 displays in a real physical space is messy. Instead of solving alignment with a wrench, a shim, or a spirit level, I tried to solve carpentry in WebGL.

I built CalibrationConsole.ts—a 2,839-line lil-gui mission control deck synced across browser windows via BroadcastChannel (SyncChannel.ts) and backed by a 351-line JSON config (config/calibration.json). It featured 24-point 4-corner perspective keystone pinning (uCorners[24]) solved per-pixel in GLSL, per-screen discrete 90° rotations, fine continuous angle rotation (-180° to +180°), X/Y sub-pixel offsets, individual horizontal/vertical flips for all 6 screens, per-screen signal lock and noise gain overrides, plus custom SMPTE color bars, crosshatch patterns, and focus reticles.

// FILE: config/calibration.json (Actual Committed Production Battle Scars)IEEE-754 DESPERATION & TYPO IMMORTALITY
{
  "shader": {
    "curvature": 2.6,
    "rgbSplit": 1.269,
    "vHold": 0,
    "bezelChassis": true
  },
  "tracking": {
    "zapHoldDurationMs": 400,
    "poseGuideOffsetX": 0.29
  },
  "frames": [
    {
      "id": 0,
      "label": "CRT [01}",
      "offsetX": -0.00600000000000001,
      "offsetY": 0.014,
      "fineAngle": -1.4,
      "rotation": 0,
      "flipX": false,
      "flipY": false
    }
  ]
}
[03]

THE OVER-THINKER'S COMPUTER VISION PIPELINE: HUMAN WALKIE-TALKIES

FeatureExtractor.ts + BroadcastQuerySynthesizer.ts (@mediapipe/tasks-vision @ 60 FPS)

Using @mediapipe/tasks-vision (running PoseLandmarker with 33 3D body joints + HandLandmarker with 21 hand joints in Wasm/GPU at 60 FPS), I refused to simply map proximity to static noise. Instead, I engineered a full semantic classifier that:

1. Optical Inverse-Square Rangefinder: Estimates physical distance in meters using the Euclidean span between shoulder landmarks 11 and 12 (which immediately hallucinated whenever a child walked into the frame).

2. Harmonic Wrist Zero-Crossing Dance Detector: Analyzes a 1,800 ms rolling window of vertical wrist velocity zero-crossings (1.2 Hz–2.5 Hz) to classify whether the spectator is dancing rhythmically (RHYTHMIC) versus flailing erratically (HIGH_MOTION).

3. Torso HSV Clothing Color Sampler: Samples a 48×48 offscreen canvas across the user's torso, converts RGB to HSV, and classifies their outfit (WARM_RED, COOL_BLUE, DARK_NEUTRAL, NEUTRAL) to tint the YouTube search query mood.

4. Six Antenna Postures & The 1.8s Panic Patch: Mapped 6 specific body postures 1:1 to the 6 CRT screens—originally requiring visitors to hold a pose for 1.8 seconds (1,800 ms), which had to be panic-tuned down to zapHoldDurationMs: 400 because no human being in an art gallery will hold a T-pose for 1.8 seconds in front of strangers without feeling ridiculous.

CRT [01} :: POSE_ANTENNA"Rabbit Ears"
CRT [02] :: POSE_DIAL_TUNER"Yagi Point"
CRT [03] :: POSE_SURPRISE"TV Shock"
CRT [04] :: POSE_WINGSUIT"Horizontal Dipole"
CRT [05] :: POSE_LOOP_HALO"UHF Loop"
CRT [06] :: POSE_SIGNAL_LOCK"Human Capacitor"
[04]

THE 4.5-HOUR SOAK TEST, YOUTUBE QUOTA BURN & EXHIBITION PHYSICS

QuotaGuard.ts + LRU Disk Cache + reports/perf-report-latest.md

Every synthesized body query hit the YouTube Data API v3 (search.list) at 100 quota units per call, spawning yt-dlp and ffmpeg on an Express backend to transcode vertical MP4s on the fly.

During a 4.5-hour soak test (reports/perf-report-latest.md), the installation downloaded 313 bizarre vintage Shorts—ranging from 1950s TV test patterns and Max Headroom to SpongeBob lost episodes and pontoon boats hitting rocks—burning 4,140 quota units at 919.9 units/hr. That meant the 10,000-unit daily Google Cloud quota would die 5.3 hours into an 8-hour gallery day, forcing me to emergency-engineer a QuotaGuard.ts circuit breaker and an LRU disk cache pruner.

Meanwhile, in the physical venue: camera angles, portrait webcam rotation matrices (0°/90°/180°/270°), ambient glare on glass, cable spaghetti, and real human behavior proved that no amount of TypeScript architecture diagrams (I wrote 8 full architecture manuals—12 markdown files total—for a 1-person project) survives first contact with an exhibition space.

// SECTION 04 :: THE OVER-ENGINEERING RECEIPT

"BY THE NUMBERS" RECEIPT TABLE_

METRIC / SUBSYSTEMRECORDED VALUEFIELD AUDIT NOTES
Calibration Console (CalibrationConsole.ts)2,839 linesMore code to calibrate the screens than to render them
Architecture Documentation Suite12 markdown filesWritten for a team of 1 (me), including 8 full architecture manuals
GLSL Uniforms in CompositeShader.ts38 uniformsIncluding uCorners[24] for 24-point quad warping
NTSC Flyback Sine Oscillator15,734 HzSynthesizing a sound that CRT hardware makes for free
Initial Pose Hold Debounce1,800 msPanic-reduced to 400 ms (zapHoldDurationMs) in production
YouTube API Quota Runway5.3 hoursFor an 8-hour exhibition day (919.9 units/hr burn rate)
Floating-Point Calibration Scars-0.00600000000000001Actual frames.offsetX committed to config/calibration.json
// SECTION 05 :: AUTOPSY SUMMARY & LESSONS LEARNED

WHY IT'S IN /FAIL-CASES_

[01] ATOMS ARE UNDEFEATED

Software is frictionless; atoms are undefeated. No shader uniform can fix a loose RCA composite plug or a $4 plastic signal converter overheating behind a steel shelf.

[02] PUT DOWN THE KEYBOARD, PICK UP A SCREWDRIVER

If you find yourself writing a 2D cross-product quadratic solver in a fragment shader because a display is crooked, put down the keyboard and pick up a screwdriver.

[03] HUMANS ARE NOT DETERMINISTIC STATE MACHINES

Twelve architecture markdown files and a 4.5-hour soak test won't save you when your entire interactive loop depends on strangers doing "Rabbit Ears" poses for 1.8 seconds in front of a binder-clipped webcam.