TV Studio
A Roblox quiz show where the cameras, graphics, lighting, audio and crowd are run by code rather than people — then the production engine pulled out as a two-tier kit other creators drop into their own experiences. Server-authoritative, headless-tested, public.
- Role
- Solo — engine, game, content, production design, go-to-market
- Period
- 2026
- Type
- Lab
- Status
- live
- 15.1k
- Lines of Luau
- 153
- Headless specs
- 4
- Formats, zero engine edits
- 2,610
- Original questions
Overview
Most Roblox games look like Roblox. This one looks like television. A host and three contestants play a word-wheel round and a trivia round on a studio set, and everything a broadcast crew would do — the crane open, the camera cuts, the lower thirds, the lighting cues, the applause, the crowd reacting to a reveal — happens automatically, driven by the state of the show. Nobody operates anything. A solo player still gets a full show, because bots take the host’s chair and every empty desk, answer with a tunable accuracy, and lose convincingly.
Underneath it is an engineering project. The server owns the show as a state machine and is the only thing that can change a score; the client is a television — it renders replicated snapshots and sends intents. The show runner, the question engine, scoring, the bots and the network codec have no Roblox dependencies at all, so the whole show runs headless under Lune with an injectable clock: 153 specs drive it from lobby to credits in about a second, long before a playtest.
Then the interesting decision. The quiz is the least valuable thing in the repository; an automatic production engine is rare. So the engine became the product. A show is data — states, cues, cameras, a lighting map — the look is a theme, the floor plan is a scene, and the same 81 modules run a quiz, a trivia night, an esports cast and an awards ceremony with no engine code between them. One source builds a free Lite tier under MIT and a Pro tier, as a Wally package and a Creator Store model, with a five-minute quickstart, a field reference and a reskin guide.
The game is the showcase for the kit rather than the business. A 199 Robux pass nets about fifty cents after the platform’s cut and the exchange rate; a kit sells to developers in dollars at one hundred percent net, so forty kit sales are worth roughly the same as 160,000 monthly players. From a written constitution to a public experience with a packaged engine took six days and 140 commits, working spec-first with an AI harness committed beside the code.
Architecture
The client is a television
Scroll to pan
A show is data
Scroll to pan
The boundary that makes it a product
Scroll to pan
Screens















Modules
Show runner
A server-side state machine with two lifecycles — the fixed quiz arc and a generic timeline of named segments — driving cues, bots, seating and scoring from a data definition. Deterministic: the same definition and the same ticks produce the same snapshots.
- Invalid transitions are rejected, never coerced
- Host overrides apply per room, never by mutating the shared definition
- Lobby policy: a fill wait, bots after a timeout, fast re-entry once a room has seen a show
- Every game concern arrives through an injected hook
Camera director
A Scriptable camera re-asserted every frame, so a respawn can never steal the shot, cutting across a twelve-mark bank — nine fixed broadcast angles plus a rail, a jib arc and a top shot — with a lens that follows the shot.
- A crane open that pulls wide while it rises
- Rail track, jib orbit, push-in and breathe moves
- Depth of field racks onto the contestant’s face on a reveal and keeps tightening
- Operator hand: Perlin noise on the framing, scaled by how tight the shot is
- Phone framing steps back only as far as the studio walls allow
A studio set built from code
No external assets. The room, the deck, the LED wall, the truss, the quiz desks with edge-lit acrylic wings, the flown PA, the grandstands and the crowd are generated on the server from the theme — 2,046 parts, 40 lights, 38 light shafts.
- Every colour in the set is theme data, so a reskin never touches a builder
- Fresnels clamped to a ceiling grid, guaranteed to hang below the pipe that holds them
- Light shafts as six additive beams whose widths diverge toward the floor
- The crowd bobs in slices, so the per-frame cost does not grow with the seating
Lighting as a vocabulary
A three-point rig, an audience blinder bar and moving heads choreographed off the replicated show state. The theme defines named looks and moods, a format maps its states onto those names, and a definition may override any of them.
- Looks: fan out, sweep, focus, cross, celebrate, wave, skyward
- Moods: colour, energy, speed, level, chase and a flourish cadence
- Blinders strike on every reveal and on the finale
- Shadows only on the keys, because they cost
Broadcast graphics
Title cards, lower thirds, wipes, a radial timer, the rosco wheel, the scoreboard, desk plates, a video wall with live cards and the winner ceremony with confetti — all from the theme’s palette, fonts and motion presets, so a reskin reaches every widget.
- One layout module owns every screen rule: phone, short landscape, on-screen keyboard
- Widgets fade as one object, and nothing hides until the tween has really ended
- Injected overlays share the contract the built-in widgets use
Question engine
Serves 2,010 rosco and 600 trivia questions in neutral Spanish and validates answers fairly: diacritics folded, one typo tolerated, the wheel letter derived from the answer’s first character so “ñandú” lands on Ñ.
- One question per letter drawn at random from that letter’s pool, so every rosco is different
- Never repeated within a show, avoided across consecutive shows and across a player’s history
- Difficulty ramps from the easy end of the pack to the hard end within a round
- Packs live server-side; the client never holds an answer key
Bots and the cold start
The game never needs more than one human. Bots take the host role and every empty desk and answer with a profile the host picks — clumsy, normal or expert — and their hesitation is part of the design.
- 35, 60 or 85 percent accuracy, one to seven seconds to answer
- Negative user ids by convention, so nothing downstream mistakes them for people
- A pure module, deterministic under an injected random source
Networking under a kilobyte
Cross-server spectating rides MessagingService, whose payload cap is one kilobyte: a compact codec with single-letter keys, a monotonic sequence number, and a receiver that drops anything stale or duplicated.
- Only discrete transitions are broadcast; spectators interpolate locally
- Publish and subscribe touch the service only when called, so the module tests headless
- High-frequency intra-server data goes over UnreliableRemoteEvent
Persistence, economy and retention
Session-locked profiles through Lapis, a skill-earned coin economy with no gambling primitive, daily streaks and quests, a 28-day Series Pass with twelve tiers, a Robux storefront with receipts deduplicated by purchase id, and nine procedural cosmetic slots on the player’s desk, plate, scoreboard row and avatar.
- Receipts are confirmed only after the profile has saved
- A repeated cosmetic pays out coins instead of duplicating
- Every user-authored string passes TextService before it is shown or stored
The host’s control room
The Producer Pass makes its owner the host of a private server: go to air, skip, set difficulty and pacing, pick the bot level, and write questions for their own audience. Every button is an intent the server re-authorises and re-validates.
- Room settings clamped so a host cannot make a room unplayable
- Custom questions stored already filtered; the engine refuses to serve unfiltered text
- The experience owner always hosts, detected by creator id rather than a hardcoded user
- A switcher: preview and air monitors per camera mark and a cut the server holds on air before the automatic director takes back over
The engine as a kit
Two entry points — a server start and a client start — take a definition, a scene, a theme, question sets, an audio manifest, overlays and hooks. A tier manifest lists what Lite ships, and one command builds both models with the version stamped in.
- Lite: the director, both lifecycles, title card, lower third, scoreboard, countdown, wipes
- Pro: the set, the rig, the crowd, the creative moves, the quiz format, the host panel, the video wall
- A Pro cue on a Lite install degrades with a named message; it never breaks the show
- Quickstart, field reference and reskin guide, written for a creator who has never seen it
Engineering
The client is a television
Every cheat in a quiz game is a client that writes state. Here it cannot: a score changes only through one validated award function, show transitions are a whitelist on the server, and the question packs live under ServerScriptService because replicating them to ReplicatedStorage would hand every client the answer key — which an earlier layout had quietly done.
A show that runs without Studio
Studio-only testing does not scale and cannot run in CI, so the show engine, the timeline, the question engine, scoring, the bots and the codec were written with zero Roblox requires. A fake harness ticks the state machine with a huge delta so each tick is exactly one transition, and 153 specs run under Lune in about a second. Three of them are static guards that read the source: every require target exists on disk, no engine module reaches the game, and the Lite allowlist is closed under its own requires.
Broadcasting a show in under a kilobyte
MessagingService caps a payload at 1 KB and its quotas are tight, so cross-server spectating cannot stream anything. Snapshots are compacted to single-letter keys and size-estimated in the engine before publishing, they carry a monotonic sequence number, and the receiver is a pure function that accepts only newer ones — dropped, duplicated and reordered messages all resolve to the same view.
Fair answers in Spanish
A rosco lives on typed answers, and “camión” and “camion” have to be the same word. Normalisation folds diacritics in both cases — string.lower only folds ASCII, so an accented capital would have survived it — then a bounded Levenshtein distance allows one typo. The packs deliberately carry no alternative answers: the source’s alternatives turned out to be same-letter distractors that would have marked wrong answers right.
The content cliff
The first show template consumed 26 questions from a pack of exactly 26: one unique playthrough, then one hundred percent repeats. The fix reshaped the content model rather than adding rows — per-letter pools of up to 80 questions drawn at random, so each show is a different rosco; a memory of recent ids across shows on a server; the ids a player has already met persisted on their profile; and a difficulty ramp that finally used a field 2,610 questions already carried.
A set that is only code
Not a single mesh or texture is loaded to build the studio, which is what makes it reskinnable and sellable. It also means geometry has to be right by construction: a fresnel aimed steeply down extends its body backwards, which at that angle is upwards, and the first pass left nine fixtures poking through the ceiling grid. Two more passes — hang it from the yoke, then account for the body’s radius rather than its axis — got it to zero, measured in the running set rather than by eye.
Extracting the engine without breaking the game
The dependency direction was already right; eight concrete couplings were not. Everything the engine needed from the game — persistence, economy, moderation, analytics, custom questions, seat dressing — became an injected hook, overlays and remotes became registrations, and scene constants became a descriptor. The boundary is enforced by a test rather than a convention, and the showcase kept every feature: the same suite passes, and the two demo formats ran end to end with no engine change between them.
Suspect the probe before the game
A verification probe compared a desk’s size to a Lua literal and reported zero of fourteen desks while the crowd count said 154. Roblox stores vectors as float32 and Lua literals are float64, so 3.2 never equals 3.2. When one metric contradicts another, suspect the probe: the rule now lives in the project memory, and every comparison builds the value the same way the set did.
AI harness
TV Studio was built spec-first, with the governance and the tooling committed next to the code: a constitution that prevails over convenience, a specify, plan, tasks and implement workflow as slash commands, Roblox Studio driven through MCP for playtests, and guard tests that encode the architecture so an agent cannot drift it. Six days from the constitution’s ratification to a public experience with a packaged engine.
A constitution the code answers to
Nine principles, two of them non-negotiable: server-authoritative truth, content safety, disciplined networking, session-locked persistence, filesystem-first, headless testability, fun with one host and three contestants, small typed files, modularity for extraction. Each states its rationale, the document is versioned, CLAUDE.md is required to stay consistent with it, and the plan and spec templates carry its Definition of Done.
- .specify/memory/constitution.md
- CLAUDE.md
Spec-driven development as slash commands
Each feature is a spec with prioritised user stories and measurable success criteria, a plan with a research file that records the rejected alternatives, contracts per subsystem, a data model, checklists and a dependency-ordered task list. The engine extraction was specified, planned and tasked before a single file moved.
- .claude/skills/speckit-*/
- specs/001-quiz-show-mvp/
- specs/002-engine-kit/
Studio as a tool the agent drives
The Roblox Studio MCP server imports built models into the edit DataModel, starts playtests and evaluates Luau inside the live server and client VMs. Runtime verification is a number rather than an impression: 2,046 parts, 38 beams, 40 lights with 7 casting shadows, zero fixtures through the grid, depth of field measured per shot.
- .mcp.json
A capture tool, for when the harness broke
The MCP’s screenshot came back solid magenta during any playtest. Rather than verify by eye, I wrote and published a skill that captures the Studio window through the macOS window server by window id — unaffected by which Space the window sits on, and needing only Screen Recording permission. Open source, installable as a plugin.
- roblox-studio-capture/skills/roblox-studio-capture/SKILL.md
- roblox-studio-capture/bin/roblox_studio_capture.swift
Architecture enforced by tests
Static specs read every source file: no engine module may name a module that exists only in the game, no absolute path may reach the game tree, every Lite module’s requires must resolve inside the Lite list, and every WaitForChild target must exist on disk. Lint, format and the suite are the Definition of Done for every task, and the build script refuses a Lite model whose closure is broken.
- tests/EngineBoundary.spec.luau
- tests/TierClosure.spec.luau
- tests/RequirePaths.spec.luau
- scripts/build-engine.luau
A handover that tells the truth
Every session ends with what changed, what was verified live and how, what could not be verified and why — simulated input does not activate GUI buttons, the harness cannot observe the first lobby — and what needs the owner’s decision. The commercial plan sits beside it with dates and kill criteria, and a plain-language version explains how the platform pays before a single number is argued.
- docs/handover.md
- docs/monetization-strategy.md
- docs/business-model.md
Stack
- 01Luau
- 02Roblox
- 03Rojo
- 04Wally
- 05Lune
- 06Selene
- 07StyLua
- 08Lapis
- 09MessagingService
- 10TweenService
- 11Spec Kit
- 12MCP