Projects
A game show that produces itself, and the engine underneath it

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
01

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.

02

Architecture

3 diagrams
01

The client is a television

Client · renders, never decidesServer · the only truthsnapshot with seq down,answer and admin intents upcompact snapshot, under 1 KBGame hookspersistence, economy, moderationBotControllerShowRunnerquiz or timelineQuestionEnginepacks never replicatedScoreServiceaward is the only writeDirectorCameraEngineand lensGraphicsEngineAudioEngineMessagingServiceother servers

Scroll to pan

Snapshots go down, intents come up, and nothing on the client can change a score. The runner, question engine, scoring and bots have no Roblox dependencies, which is what lets the same show run headless under Lune. Other servers get the same snapshot through MessagingService, under a kilobyte.
02

A show is data

unknown mood,Pro cue on LiteQuizrosco and triviaTrivia nightquizEsports casttimelineAwards nighttimelineShow definitionstates, cues, cameras, lighting by nameTheme and scenepalette, light vocabulary, desks, roomValidateNamed error,or a degrade on LiteEnginedirector, rig, graphics, audio, set, crowdA televised showbots fill every empty seat

Scroll to pan

A format is a definition, a theme and a scene — states, cues, cameras and lighting by name, over a palette and a floor plan. Validation names every problem before anything runs, and a Pro-only cue on the Lite build degrades instead of breaking. Four formats ship on the engine with no engine code between them.
03

The boundary that makes it a product

engine · santar/tv-studio-enginesrc · the showcase gamerequires, injectsone source, two buildsComposition rootEngine.server.start with hooksPersistence, economy, shop,cosmetics, moderation, analyticsEngineBoundary and TierClosure specsfail the suite on engine → gameLite · 42 modules · MITdirector, both lifecycles,title card, lower third, scoreboardPro · 81 modulesplus set, rig, crowd, quiz format,host panel, video wallWally packageCreator Store model

Scroll to pan

The game depends on the engine and injects everything the engine needs; the engine never requires the game, and a test fails the suite the day it does. One source builds two models: a free Lite tier under MIT and a Pro tier, for Wally and the Creator Store.
03

Screens

15 captures
TV Studio lobby with a seat board showing one human and three free seats, and a countdown to air
01Lobby — one human in four seats, a countdown to air, bots take the rest
Crane shot over the studio set with the video wall reading TV Studio, hosted by jsantarc
02The open — a crane pulls wide over the set while the video wall credits the host
Word-wheel question with the letter ring, a radial timer, the scoreboard and the answer box
03Word-wheel round — the rosco tracks the letter, the clock runs, the answer box is live
Close-up on the contestant who answered first, with the answer PALOMA revealed and the background thrown out of focus
04The reveal — a hard punch-in on whoever answered first, focus racked onto them
Shot from behind the grandstand over the crowd toward the stage, with a lit applause sign
05Audience POV — shot from behind the stand over the crowd, applause sign lit
The video wall reading Intermission, we will be back, over the contestant desks
06Intermission — the video wall carries the bumper while the rail camera rolls
Winner card for Bot 4 over the stage with confetti falling and the blinders lit
07Grand final — winner card, confetti burst, blinders on the crowd
Credits with the winner on the video wall, the daily quests panel and the scoreboard
08Credits — the wall holds the winner; the day’s quests and the scoreboard sit over it
The studio set with no interface: LED floor, truss, moving heads, grandstands and a studio camera in frame
09Clean feed — the set with no UI: LED floor, truss, moving heads, grandstands, a camera in frame
The host’s switcher panel with a preview and air monitor pair, a cut button and nine camera monitors over a live question
10The switcher — preview and air, nine live monitors, one cut; the host outranks the automatic director
The host control panel with start, skip, difficulty, bot level, seconds per question, questions per round and a custom question box
11Host control room — go to air, skip, difficulty, bot level, pacing, and the host’s own questions
The storefront panel with coin balance, streak, quests, Robux coin packs and cosmetics with equip buttons
12Storefront — coin packs priced in Robux, cosmetics for earned coins, streak and quests up top
The same set in a black and gold theme with five contestant desks and a gold letter ring
13Reskin — the same engine in the gold theme with a five-desk scene; no engine module touched
Wide crane shot with the video wall reading Tonight, Red vs Blue, best of 3
14Esports cast — a timeline format on the same engine: pre-match card, crane open, no quiz anywhere
The video wall reading Winner, Blue, 2–0 under warm celebration lighting
15Esports podium — a held segment the host releases, the theme’s celebrate look and final mood
04

Modules

11 units
01

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
02

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
03

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
04

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
05

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
06

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
07

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
08

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
09

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
10

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
11

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
05

Engineering

What was hard
01

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.

02

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.

03

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.

04

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.

05

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.

06

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.

07

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.

08

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.

06

AI harness

6 pieces

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.

01Context

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
02Skills

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/
03MCP

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
04Skills

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
05Guardrails

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
06Verification

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
07

Stack

12 entries
  • 01Luau
  • 02Roblox
  • 03Rojo
  • 04Wally
  • 05Lune
  • 06Selene
  • 07StyLua
  • 08Lapis
  • 09MessagingService
  • 10TweenService
  • 11Spec Kit
  • 12MCP