This catalogs every display screen ("slide" in MPF/mpf-gmc terms) the game will eventually need,
and the architecture they follow. It exists so that when a feature mode gets built, its slide's
shape has already been decided here rather than improvised at build time. It started as a
planning document; the slides it planned now exist (attract, base, one hit overlay per
feature, and multiball_start), so it doubles as the inventory of what's built.
The display runs on mpf-gmc (Godot 4), vendored at machinefolder/addons/mpf-gmc
(1.0.0 since 2026-10-09, stock/unmodified — its CHANGELOG is in the GitHub repo, not the
addon; this section was first derived from 0.1.0.dev2's source, and docs/gmc-bugs.md lists
what behaves differently or surprisingly). There's exactly one mechanism for authoring a slide:
.tscn scene, root node Control, with the mpf_slide.gd scriptMPFSlide, extends MPFSceneBase — addons/mpf-gmc/classes/mpf_slide.gd /mpf_scene_base.gd).GMCMedia.traverse_tree_for()addons/mpf-gmc/scripts/media.gd) recurses every machinefolder/modes/<mode>/slides/ folderfoo.tscn under a mode'sslides/ folder becomes playable as slide foo — no separate registry to update.config/<name>.yaml via slide_player:, keyed by MPF event:slide_player:
mode_base_started: base
MPFDisplay (addons/mpf-gmc/classes/mpf_display.gd) holds a priority-sorted slidemachinefolder/project.godot).Planned change (owner, 2026-10-06, story convergence step 5b): the in-game screen gets a
near-permanent test chamber sign on about half the screen (next shots, running modes, what
the ball is), and feature-hit overlays move to the free half. Concept and mock-ups:
design/research/story-brainstorm/display-concept.md. Built so far for period 1 only (the
sign widget in the inventory below); the feature-hit overlays haven't moved yet.
Two kinds of screen:
Persistent — stays at the bottom of the slide stack for the duration of a game state:
attract while idle, base while a ball is in play (score/ball/credits).
Transient overlay — a short-lived, higher-priority slide pushed on top of whichever
persistent slide is currently showing, for a feature hit or game moment. It expires itself
after a few seconds via slide_player's priority/expire keys, which pops it back off the
stack and reveals the persistent slide underneath again — no manual "restore base" step needed.
slide_player:
orbits_orbit_hit:
orbit_hit:
priority: 200
expire: 2s
Every feature mode now uses exactly these values (priority: 200, expire: 2s) for its hit
overlay. They were picked as placeholders and haven't been tuned against a real playtest on
the cabinet's display yet.
Each feature gets bespoke overlay content rather than one shared parameterized template:
every feature in design/features/*.md already has its own distinct show idea (its ## Presentation)
(flame-wipe, portal-ring flash, spring-launch, etc.), so a shared template would just be building
toward throwing that specificity away later.
Story, period 1 (2026-10-07, placeholder look): modes/story_p1/widgets/chamber_sign.tscn
(the test chamber sign on the right half, over base: the chapter, its chamber number, each test
with a tick, 1B's jackpot multiplier, the cube's status, and the chapter's hazard icons in the
bottom right) and 12 overlays in
modes/story_p1/slides/ (chapter cards 1A-1C, "Now you're thinking with portals", test complete,
the cube chain and C1, the exit, the escape). Generated by tools/display/story_p1_slides.py;
rendered in Godot on the PC (2026-10-07), which checks each state at load time.
Seen live (2026-10-08, CHANGES #72): a virtual mpf run with the Godot display, the switches
pressed over BCP, showed all three periods' signs switching chapters and ticking tests during
play (design/research/live-screen-test/2026-10-08/). Two rules came out of it, for every
widget that stays on screen:
{slide: base} in widget_player). Without a target slideplayer_<var>: {<widget>: {action: update, slide: base}}): GMC's conditionals only re-check on an update action, not when a player variabletests/test_chamber_signs.py checks every sign (periods 1-5, each in its four looks).Story, period 2 (2026-10-08, placeholder look): modes/story_p2/widgets/chamber_sign_p2.tscn
(the same sign, with the decade's year - 1950, 1970, 1980, placeholders - as the chamber number,
and the multiball's lemon count in 2C) and 8 overlays in modes/story_p2/slides/ (chapter cards
2A-2C, Caroline, the elevator, the Combustible Lemons, the lemon jackpot and super jackpot; the
"TEST COMPLETE" overlay is period 1's). Generated by tools/display/story_p2_slides.py; the sign
was seen live on 2026-10-08 (2A, 2B); the overlays aren't rendered in Godot yet.
Story, period 3 (2026-10-08, placeholder look): modes/story_p3/widgets/chamber_sign_p3.tscn
(one layer per stage: 3A's tests, her cores, the finale's waves, the jackpot tour with its count and the 8 tour shots' own icons, each turning blue as its jackpot lands (owner, 2026-10-24),
the climax with the cores burned; the number climbs one per stage, 15/19 to 19/19 at the climax, owner 2026-10-25) and 10 overlays in
modes/story_p3/slides/ (chapter cards 3A and 3B, neurotoxin, her cores, TENACITY, the
stalemate, a core falls, E1, and E8/E2 for the defy path). Generated by tools/display/story_p3_slides.py; the sign was seen
live on 2026-10-08 (3A); its later stages and the overlays aren't rendered in Godot yet.
Story, period 4 (2026-10-09, placeholder look, CHANGES #77): modes/story_p4/widgets/era_sign_p4.tscn,
the sign (no EPILOGUE frame since 2026-10-31: only period 5 is the epilogue, owner 2026-10-18): the big number is the year on Cave's era dial (19-- before the
first click, then 1950 ... 2000, one layer per click, and per jackpot on the ride; 1980 on C5), the 6 dial shots as icons (lit = in use,
made = blue), the time machine's door, the ride's jackpot count and SUPER JACKPOT LIT, C5's STAY WITH CAVE / FIND CAROLINE.
12 overlays in modes/story_p4/slides/ (chapter card 4, the plate, the dial click with the new year,
the door, the ride, a tape, super jackpot lit, the part of the tape you didn't hear, Caroline's last
line - placeholder text until the owner picks it - C5, E3, E4). Generated by
tools/display/story_p4_slides.py; all of them rendered in Godot by the period_4 playtest.
Story, period 5 (2026-10-09, placeholder look, CHANGES #85): modes/story_p5/widgets/wall_sign_p5.tscn,
his wall in red marker: the 8 dots as ticked lines (the two secret dens "???" until found), where his
arrow points or that the passage is open, A Clear Head's scrawls cleaned, the box. 18 overlays in
modes/story_p5/slides/; the 6 dens show Rattmann's murals (Portal 2's ratman_diorama0*) behind his
scrawl (drafts to read, 2026-10-25). Generated by tools/display/story_p5_slides.py; seen in the period_5 playtest.
Small endings (2026-10-09, placeholder look, CHANGES #78): modes/small_ending/slides/end_*.tscn, one
per chapter a game can end in (1A-1C, 2A-2C, 3A, 3B, 4): the period's small-ending line, GAME OVER and
"NEXT: CHAPTER ...". Generated by tools/display/small_ending_slides.py; all 9 rendered in Godot
(design/research/small-endings/2026-10-09/), period 4's also live in the small_ending playtest.
"Your file" (the test-subject file card) waits for the art.
Callouts, backgrounds and small endings (screens round 2, owner 2026-11-01/02, CHANGES #187, #207-#209):
tools/display/callout_widget.py'scallout_slide() draws only the panel on a transparent slide (mpf-gmc keeps the slide stack drawn), so thep4_memory, a widget over the whole screen during the upload tape).tools/display/feature_slides.py, replacing the nine hand-madedesign/art/README.md) but not used for these screens.p<N>_background widget (the picture over the lefttools/display/period_backgrounds.py; images from tools/art/apply_screen_picks.py,images/periods/) to the base slide when it starts; period 1 keeps the GLaDOS art. Periods 2 and 4's signspanel_dirty), the others clean. The Wheatley branch's background is picked andimages/small_endings/end_<N>.jpg, framed insmall_ending_slides.py): GLaDOS, Cave, Cave's ghost, Rattmann (from the Lab Rat comic).The sign's hazard icons show progress (owner, 2026-10-07; like the games' signs): one icon
per test, three looks - not in use yet = very light grey, in use, not done = black with
white, done = a light blue filled background. Most icons are in use for the whole chapter;
a locked one (1A's SPEED, 1B's FIRE, 1C's TURRETS, 2A's BRIDGE, 2B's FIRE, 3A's FAITH PLATE /
FLING / FUNNEL, 3B's waves 2-3 (wave 3 the turret bank since 2026-10-19), the tour's BUTTON) appears when it unlocks instead of showing
grey first, in its own place - an empty gap until then, so the row's order always matches the test
list (owner, 2026-10-10, CHANGES #93). Only a closed exit (1C's EXIT, 2C's ELEVATOR) shows from
the start, as the closed-door X; period 4's dial keeps its own grey-lit-made looks. Driven by the
done variables plus the in-use ones (i_orbit/i_exit/chain3 from story_p1.yaml, etc.). The icons are the games' own chamber-sign icons
(2026-10-09, CHANGES #82: machinefolder/images/signs/, from tools/art/sign_icons.py, the
words mapped in story_p1_slides.ICON_TEXTURES), tinted per look; no sign square is a word any more
(CORE, UP and TAPE got icons in CHANGES #93, JACKPOT shows the tour shots' own icons since 2026-10-24,
CHANGES #137).
C5's squares pair each person with their shot, CAVE SPEED / CAROLINE BRIDGE: the faces are
photos from Portal 2's portrait of Cave with Caroline, grey on the sign
(story_p1_slides.PHOTOS; as is when in use, faded when not, washed blue when done), and the "/"
is the SEPARATOR word (no square). The face you pick shows in colour above its ending (E3 Cave,
E4/E5 Caroline; story_p4_slides.ENDING_FACES). CHANGES #96.
Seen live: design/research/sign-icons/2026-10-09/.
Which icon, and when it changes (owner, 2026-10-10, CHANGES #92; the full list with
previews: design/sign-icons.html): one icon per physical shot, because the icons will also
become the playfield inserts; an icon changes only for a big story moment.
story_p1_slides.ICON_LAYERS).laser_burn (TURRETS: 1C, the finale's wave 3 - the last wave, owner, 2026-10-19); the standupscube_burned (1 when burned) shows the broken cube andcoop_teamdoor_blue / _orange) are recorded for when co-op is builtdesign/rule-sheets.md's co-op section).sign_icons.py crops only the tile's 4-pixel framedesign/art/sign-icons-crop/ has the before/after sheets.Four looks, an operator setting (owner, 2026-10-10, CHANGES #93): sign_style in
config/settings.yaml (the service menu) picks how much the sign says. Every sign widget comes in
four versions, <sign> and <sign>_s1.._s3, generated by the same scripts
(story_p1_slides.STYLES); each story mode shows the picked one when it starts and sends every
update to all four (GMC skips the ones not on screen).
sign_style |
Shows | Icons |
|---|---|---|
| 0 full | number, title, test list, story lines | today's size |
| 1 (default, owner 2026-10-10) | number, title | 1.5x, in the freed space |
| 2 like the games | the number only | 1.5x |
| 3 | number, title, story lines (no test list) | today's size |
The test list is the how-to hints ("LEFT ORBIT: SPEEDY THING GOES IN"); the story lines are the
counters and states ("ESCAPE JACKPOTS x3", "THE COMPANION CUBE IS WITH YOU", "LEMONS: 2").
Big icons go at most 5 to a row, more wrap to an even second row above (1B's 8: 4 + 4). Period 4's
year and dial and period 5's 8 dots and scrawl are those signs' own graphics, in
every look; their hint lines (the door, his arrow, the box) and story lines (jackpots) follow
the style. The "period complete" layer keeps its title in every look. The overlays (chapter cards,
TEST COMPLETE) aren't part of the setting: they're moments, not hints.
The real choices show in every look (owner, 2026-10-10, CHANGES #95): while a choice is open
(ball held, each lit shot a different story), the sign shows one line per option, <CHOICE WORD>: <THE SHOT>, where the test list starts, covering it in the looks that have one. Two lit squares
don't say which shot picks what, and the choice overlay is only up for a few seconds. Built:
C1 BURN IT: THE INCINERATOR / KEEP IT: THE BLUE PORTAL (1B while chain3 is 1), C3 ESCAPE: THE EXIT / DIVE DEEPER: THE BLUE PORTAL (period 3's done layer while p3_c3 is 1; FOLLOW HIS ARROW: <shot> joins with 3+ hints once those exist), C5 STAY WITH CAVE: THE LEFT ORBIT / FIND CAROLINE: THE HARD LIGHT BRIDGE. C0 (PLUG HIM IN / REFUSE) and C1b (CAVE'S ORDERS /
CAROLINE'S ADVICE) get the same lines when they're built. Set in each slide script's CHOICES
(sign(..., choices=)). Not choices, so not here: the comply/defy meter, the CAROLINE letters,
single-shot hints. Planned for the Wheatley branch (owner, 2026-10-24): after "SPACE!" (E7), PotatOS's
face with the meter's word (COMPLIANT / DEFIANT, even showing DEFIANT) before C3's sign, and E1's Portal 2 finish (the
opera, the cube thrown out after you). Planned with D32 (D32, owner 2026-10-24): at Rattmann's arrow moments in 1B, 1C and 3A
the sign shows both faces for 8 s (GLaDOS's white "official" shot and his red arrow, each with its shot); C3
and C5 show the lit side the ledgers lean to (the meter at C3, Cave's record at C5); the last core's BURN side
shows your cube's fate (a scorched cube, "SAME INCINERATOR", or the kept cube on his scrawl, "FOR THE CUBE");
the file at the end becomes two pages (built 2026-10-31, small_ending's file_page_2, with the last core's
cube beside BURN; the paired-shot sign and C3/C5's lit side were built in #138) (GLaDOS's words, then everything the game noticed: cube, singing turret,
moon rock, letters as C_R_L_N_, hints, sabotaged turrets, the path (Wheatley or not), the meter's word, Cave's record).
| Screen | Trigger | File | Notes |
|---|---|---|---|
attract |
attract mode start | modes/attract/slides/attract.tscn (exists) |
Uses images/mainscreen.jpg deliberately (not a placeholder) — the user liked its moody atmosphere and confirmed reuse is fine for this private, non-commercial project despite it reading as Portal-themed fan art. Title label kept in the blue accent color. |
attract_<id> (50 pages since 2026-10-25) |
attract_pages mode, while attract runs |
modes/attract_pages/slides/ (generated) |
The attract page rotation (2026-10-08, CHANGES #74): written in design/attract-pages.yaml (text, picture, voice line per page), built by tools/display/attract_slides.py, which also writes the mode's rotation and sound config. Layouts: scene, poster, quote, stat, files (high scores), gallery (endings found), murals (periods reached), sign (the chamber-sign tour). Pictures: game textures and cited online screenshots, design/art/README.md. Machine-wide data: config/machine-stats.yaml. Edit the YAML, re-run the tool, never edit the slides. |
base |
mode_base_started |
modes/base/slides/base.tscn (exists) |
In-game HUD: score, ball, credits, on the same mainscreen.jpg background as attract. Score label kept in the orange accent color. |
design/features/*.md entry)All transient, pushed over base during play. Since 2026-11-02 they are top-left callouts with an icon,
generated by tools/display/feature_slides.py (see "Callouts, backgrounds and small endings" above); the
"Notes" column is the original show idea per feature (## Presentation), kept for the light shows and a
later animated pass.
| Feature | File (exists) | Notes |
|---|---|---|
orbits |
modes/orbits/slides/orbit_hit.tscn |
Portal-ring "pop" flash on the relevant orbit icon — blue for left, orange for right, per STORY.md's Portal B/A color split. |
slings |
modes/slings/slides/sling_hit.tscn |
Blue springy squash-and-bounce flash on the sling icon (Repulsion Gel motif). |
skillshot |
modes/skillshot/slides/skillshot_hit.tscn |
Lit/rotating top lane pulses to show "this one counts" for the ball in play. |
dropbank |
modes/dropbank/slides/dropbank_hit.tscn |
Fire/incinerator flame-wipe flash on the insinerator shot. |
lanes |
modes/lanes/slides/lanes_hit.tscn |
Turret pop-up-and-topple animation per top-lane hit. |
aerial |
modes/aerial/slides/aerial_hit.tscn |
Springboard/launch flash + brief ballistic-arc trail animation on hit. |
portal |
modes/portal/slides/portal_transfer.tscn |
Portal-ring burn-open/close animation on transfer, then an LED-chase tie-in across the 5-stage exit-open progression. Most involved feature (multi-switch state machine) — build its slide last, per design/README.md's note to prove the pattern out on simpler features first. |
ramps |
modes/ramps/slides/ramps_hit.tscn |
Glowing "bridge extends" animation across the ramp icon while lit (Hard Light Bridge motif). |
See design/GAME_MOMENTS.md for the full design pass on these six. Key finding there: most are
built into MPF already (match, high_score are bundled default modes - just needed adding
to config.yaml's modes: list, now done) rather than needing design from scratch.
| Screen | Likely trigger | Notes |
|---|---|---|
ball_start / match |
ball start | Built-in match mode now active; mpf-gmc ships a default match slide, unused. |
tilt_warning |
tilt warning event | Genuinely hardware-blocked (no tilt switch exists yet), not just undesigned. See design/GAME_MOMENTS.md. |
ball_over |
ball_will_end |
Presentation-only - no device/rules work needed, just a slide once art exists. |
multiball_start / jackpot |
multiball_mb_dropbank_started |
Implemented (2026-08-27): modes/multiball/slides/multiball_start.tscn - user chose a dropbank tie-in (reuses dropbank_hit.tscn's exact background tint/flame shape, 3 white ball circles bursting outward around it) over a feature-independent treatment. Rendered and visually verified in Godot 4.3 (headless, real Vulkan). Sound: machinefolder/sounds/sfx/multiball_ball_lock.wav, from the user's own Portal 2 sound extract - a real door/ball-lock clip already curated by the user into a "multiball" folder. DRAFT pick, user plans to review/adjust manually. |
game_over |
game_ended |
Presentation-only, same as ball_over. |
high_score_entry |
new high score | Built-in high_score mode now active; mpf-gmc ships a default slide, unused. |
A slide is only worth building once its feature mode is actually being implemented — this
document's job is to pre-decide shape, not to schedule the build, matching the project roadmap
(CHANGES.md #3) which sequences display/audio work after flippers, rules architecture, and
feature modes.
Once a feature's slide design here is confirmed against a real build, loop back and update that
feature's design/features/<id>.md ## Presentation slide line from TBD to reference this
catalog, instead of leaving the two out of sync.
attract, a lit terminal frame for base, a distinct line-art icon per feature),.tscn file was## Presentation) in design/features/*.md for theTODO.md.priority: 200/expire: 2s are used by every overlay but untuned — check them in a realdesign/GAME_MOMENTS.md; ball_over,game_over and tilt_warning still have no slide.