A focused macOS spike for testing an accessible coaster-builder architecture inspired by OpenRCT2. The app builds one representative Hyper-Twister style coaster, renders it with SDL, and exposes a Swift/AppKit accessibility overlay for keyboard control, VoiceOver navigation, and spoken feedback.
This is not a full OpenRCT2 build and does not bundle RollerCoaster Tycoon assets.
A short web-friendly demo video is included at:
media/hyper-twister-validated-fullscreen-demo-web.mp4
It shows the validated closed-coaster recipe being built and the test train running. The MP4 is compressed for browser playback. Raw screen recordings and build outputs are intentionally not committed.
- C++ owns the coaster builder state, placement rules, completion guidance, metrics, sounds, and SDL rendering.
- SDL is used only as the display and audio driver. Gameplay input events from SDL are disabled.
- Swift/AppKit owns keyboard input and accessibility through an
NSPanel. - Swift sends builder commands directly to C++ through a C bridge.
- C++ sends semantic state back to Swift as JSON.
- Swift updates native accessibility elements so VoiceOver can inspect builder state.
- Command speech uses
AVSpeechSynthesizerfor low-latency spoken feedback. - Optional completion guidance is spoken on demand instead of after every piece.
Keyboard / VoiceOver user
|
v
Swift NSPanel overlay
|
| BuilderSubmitCommand(command)
v
C++ builder core
|
| semantic JSON state
v
Swift accessibility fields + speech
C++ builder core
|
+--> SDL renderer: visual coaster scene
+--> SDL audio: generated game cues
The important architectural choice is that Swift and SDL do not talk to each other. C++ is the hub. Swift controls accessible input/output, while SDL presents pixels and sound.
- OpenRCT2 was used as an architectural and design reference for the coaster type and track-piece vocabulary.
- No OpenRCT2 source files are embedded in this spike.
- No RollerCoaster Tycoon or OpenRCT2 sprite sheets, object files, or sound assets are bundled.
- Visuals are generated directly in C++/SDL: isometric terrain, paths, water, trees, station art, supports, rails, preview track, loops, and train cars.
- Sounds are generated directly in C++/SDL: selection, placement, blocked placement, undo, rotation, toggles, reset, completed circuit, and train clacks.
- Accessibility uses macOS AppKit,
NSAccessibility, andAVSpeechSynthesizer.
- macOS 13 or newer
- Xcode command line tools
- Swift toolchain
- SDL2 installed through Homebrew
brew install sdl2From this repository root:
makeBuild the app bundle:
make appOpen the app:
make open-appRun the non-interactive smoke demo:
make demoExpected smoke-demo signal:
HYPER_TWISTER_SUMMARY ... sdl_input_events=0 ...
sdl_input_events=0 confirms gameplay input is not being handled by SDL.
Validate the known closed-coaster recipe without opening the UI:
make validateEquivalent direct command:
build/hyper-twister-builder --validate-recipe "T SPACE N N SPACE N SPACE N L SPACE P SPACE SPACE P P L SPACE N N N N SPACE N SPACE T"The expected result is:
VALIDATE_RECIPE_RESULT closed=true status="Complete circuit" ...
VALIDATE_RECIPE_PASSED
Validated recipe:
T pause test train
Space place station
N N Space left banked turn
N Space right banked turn
N L Space chain lift hill
P Space right banked turn
Space right banked turn
P P L Space straight track, lift off
N N N N Space steep drop
N Space vertical loop back into station
T start test run
Keyboard commands while the Swift overlay is focused:
N: next pieceP: previous pieceSpaceorReturn: place selected pieceU: undo last pieceR: rotate rightB: cycle bankS: cycle slopeL: toggle chain liftT: toggle test trainM: toggle game soundsX: reset layoutC: speak circuit completion summaryH: speak heading and height mismatchG: speak one suggested next stepShift+G: speak detailed route guidanceV: toggle verbose guidance after every builder commandEsc: quit
For clean video capture:
build/hyper-twister-builder --fullscreenThen run the validated recipe above at human pace.
- Turn on VoiceOver.
- Open the app with
make open-app. - Navigate the Swift overlay fields and controls.
- Confirm VoiceOver reads piece, direction, bank, slope, lift, sound, segment count, cost, ratings, cursor, completion, and last message.
- Place a few pieces and confirm speech feedback is immediate.
- Press
C,H,G, andShift+Gto request optional completion guidance. - Press
Mand confirm game sounds toggle while speech feedback continues. - Switch to another app and confirm the spike does not steal global focus back.
Makefile
README.md
media/hyper-twister-validated-fullscreen-demo-web.mp4
Resources/Info.plist
Sources/BuilderCore.cpp
Sources/BuilderOverlay.swift
Build products are ignored under build/.
This is a spike, not production code. It is intended to demonstrate the accessibility architecture and make the interaction model demoable for discussion.