Configure Visual Pinball and Cade
Configure Visual Pinball and Cade
Cade and VPX split the work: VPX simulates the playfield (physics, the ball, flipper response) and Cade runs the rules (scoring, modes, lights, ball lifecycle). They talk over a gRPC bridge — VPX sends switch events in, Cade sends coil and light commands back, exactly as it would with a physical controller.
On the Cade side you’ll author two files in one directory — a machine definition (.cade) describing the table, and a runtime config (cade.conf) pointing Cade at VPX. On the VPX side, the table script shrinks to almost nothing.
Define the machine
Create a working directory for the table. A machine definition opens with the table’s identity, a game block, and the devices VPX exposes. The bridge matches a VPX object to a Cade device by name — so you name each device exactly what VPX calls it (left_flipper, Bumper1, …) and Cade recognizes it. Here’s a representative slice of vpinball_example_table.cade:
name = "VPinball Example Table"
version = "1.0.0"
game {
name = "VPinball Example Table"
max_players = 4
balls_per_game = 3
}
# Flippers. VPX runs the flipper physics locally for zero latency; Cade enables
# them at ball start, disables them on tilt, and records the hits for scoring.
# grpc_action names the VPX button that drives the flipper.
device "flipper" "standard" "left_flipper" {
id = 1
grpc_action = "left_flipper"
hardware {
coil = "C01"
switch = "S01"
}
settings {
strength = 75
hold_time = "250ms"
}
}
device "flipper" "standard" "right_flipper" {
id = 2
grpc_action = "right_flipper"
hardware {
coil = "C02"
switch = "S02"
}
settings {
strength = 75
hold_time = "250ms"
}
}
# A pop bumper is a switch — the skirt that closes when the ball strikes it.
# The name (Bumper1) matches the VPX object; the table has five, Bumper1–Bumper5.
# VPX fires the bumper coil locally; Cade just scores the hit.
device "switch" "bumper" "Bumper1" {
id = 10
}Score the hits
A device only emits events; scoring is a separate rule. Write one score "event" block per bumper, keyed on that bumper’s own event:
# 100 points for every bumper hit. One rule per bumper — the file repeats this
# for Bumper1 through Bumper5.
score "event" "Bumper1_hit" {
when = device.Bumper1.activated
points = 100
}The blocks above are excerpts. The full file — the two flippers, all five pop bumpers (Bumper1–Bumper5), and a scoring rule for each — is ready to use. Expand it to read the whole thing, or hit Copy to grab it straight to your clipboard:
Save it as vpinball_example_table.cade in your table directory. It’s deliberately small — just bumpers, no audio or other playfield devices — so the first run is easy to follow; you’ll build it out from here. The snippets above are taken straight from it, so the device names already match the VPX objects.
Point Cade at VPX
The machine definition says nothing about how to run the table. That goes in a separate runtime config. Create cade.conf alongside the .cade file:
# Bridge to VPX: Cade hosts a gRPC server; VPX connects to it.
platform "grpc" "vpx_bridge" {
port = 50051
enable_gateway = true
enable_reflection = true
}
# Web server for health checks and the debug dashboard.
web {
enabled = true
port = 8080
}
logging {
level = "info"
format = "text"
}Trim the table script
Bridged to Cade, the VPX table’s VBScript stays deliberately tiny. Flippers, bumpers, slingshots, and scoring are all handled by the bridge and your Cade rules — no Sub …_Hit handlers, no manual balls-in-play counter. Two things the bridge can’t do for you remain in the script: the player’s manual plunger launch, and removing the ball that physically falls into the drain. That’s the only glue you write in vpinball_example_table.vbs:
Option Explicit
Dim EnableRetractPlunger
EnableRetractPlunger = False ' True: retract a button/key plunger at a linear speed — pull
' back, hold at maximum for one second, then return to rest
Sub Table1_KeyDown(ByVal keycode)
If keycode = PlungerKey Then
If EnableRetractPlunger Then
Plunger.PullBackandRetract
Else
Plunger.PullBack
End If
End If
End Sub
Sub Table1_KeyUp(ByVal keycode)
If keycode = PlungerKey Then
Plunger.Fire
End If
End Sub
Sub Drain_Hit()
Drain.DestroyBall
End SubValidate the configuration
From your table directory, check both files before running:
cade validate
.cade file in the current directory. If it reports an unresolved reference, confirm the name in each score rule (Bumper1 … Bumper5) matches a device block — and that those names match the VPX objects exactly.Run it and watch the event tree
Launch the console from the table directory:
cade console
The console opens on the Logs tab and auto-detects the platform "grpc" block in cade.conf, starting the gRPC bridge on port 50051. Press F2 to switch to the Events tab — the live event tree, where every event the table fires appears in real time.
Now bring up the table in VPX: open File ▸ New ▸ Full Example Table and launch it. With the bridge plugin installed it connects to Cade automatically. Then play a game the normal way:
- Press
5to drop a coin and add a credit. - Press
1to start the game.
Each action lands in the event tree as it happens — the game and ball spans appear, then your hits stream in underneath, annotated with the points they scored:
VPinball Example Table · ● RUNNING · v1.0.0
────────────────────────────────────────────────────────────────────────
● Ball in Play player1 400 Ball 1/3
switch.hit ▁▁▂▄█▁▃▁▁▁ 11 flipper.pressed ▁▁▁█▁▁▁▁▁▁ 6
────────────────────────────────────────────────────────────────────────
· [-] Player 1 Ball 1/3 Score: 400 Events: 11
╰── · [-] Ball 1 Score: 400 (8s) Events: 11
├── · +1.204s device.Bumper1.activated [switch] +100
├── · +2.451s switch.hit <left_flipper>
├── · +3.310s device.Bumper3.activated [switch] +100
├── · +4.882s device.Bumper2.activated [switch] +100
╰── · +6.013s device.Bumper1.activated [switch] +1005 then 1, a new game span roots the tree and shows Ball 1/3 for Player 1. As you knock the ball around the pop bumpers in VPX, a device.BumperN.activated … +100 leaf streams in for each hit and the score climbs 100 at a time. That’s the full loop: VPX simulates the playfield, the switch event crosses the bridge, your rule scores it, and Cade streams light and coil commands back.Where to go next
You’ve bridged a simulated table end to end. From here it’s the same shape as any Cade table — more devices, more rules.
- Map the rest of the table — Migrating from Visual Pinball translates each VBScript pattern (targets, drop banks, combos, audio) into HCL.
- Know the driver — the Visual Pinball driver page documents the supported capabilities, the hybrid flipper model, and every
platform "grpc"setting. - Add sound — Audio & Sound covers spatial audio, so you drop the VPX
PlaySoundpan/fade math. - Build out scoring — Recipes has ready-made blocks for multiball, combos, and multipliers.