Best Practices and Community Conventions¶
Standards, conventions, and hard-won lessons from VPW table development. This document captures both explicit standards and implicit norms that have emerged across dozens of table builds.
File Naming Conventions¶
Primitive Naming¶
Toolkit-generated primitives follow a structured pattern: bm_ prefix for bakemaps, lm_ prefix for lightmaps, pf_ for playfield elements. Incorrectly named objects are skipped by the export scripts (learned from Diner). The VPX 31-character name limit silently truncates longer names, causing duplicate conflicts and broken lightmap assignments (learned from Haunted House, Iron Man). Keep all component names at most 6 characters.
VBScript does not allow variable or object names that begin with a number. Names like 9_Rails_BM_Room cause runtime errors when the toolkit generates script arrays (learned from Police Force).
Flasher Naming Convention¶
VPW standardized flasher naming: lowercase "f" prefix + "1" prepended to the solenoid callback number. Solenoid callback 9 becomes f109, callback 25 becomes f125. The leading "1" creates a distinct value that cannot be confused with lamp numbers. Anything high-voltage running through solenoid circuits is a flasher; lower-voltage bulbs under inserts are lamps even if they use flash-type bulbs (learned from Police Force, Godzilla).
Insert Naming for Toolkit Tables¶
Insert lights follow the pattern: p32on (lit state), p32off (unlit state), p32bulb (physical bulb light), where the number corresponds to the ROM lamp number. This naming convention allows the toolkit's Blender lightmapper to automatically associate insert meshes with their corresponding ROM-driven lamp states (learned from Earthshaker).
Sound File Naming¶
Skip leading zeros in sound filenames. iaakki spent 30 minutes debugging a sound-stop issue caused by a missing 0 in a script reference. Files sort incorrectly in the VPX sound manager without leading zeros, but the scripting reliability is worth the messy sort order (learned from Fleep Sounds Guide).
Layer Organization Standards¶
Recommended VPX layer organization from Batman DE:
- Layers 1-3: Collidable objects (ramps, flippers, walls, switches, targets, posts, pegs)
- Layers 4-6: Primitives and inserts
- Layers 7-9: Lights
- Layers 10-11: VR objects and playfield-sized flashers
Benefits: makes debugging easier, helps spot duplicate collidable objects, and makes it easier to verify that collidable objects have correct hit thresholds. Keep collidable objects on their own layer so hidden objects on forgotten layers don't create hard-to-debug physics issues (learned from RBION). Create temporary layers during development ("quarantine," "unknown") and clean up before release.
Timer objects must go in the Timers layer, not lightmaps, to survive Blender re-bakes (learned from Countdown).
Versioning and Release Numbering¶
VPW tables follow a sequential version numbering scheme: internal WIP builds (v003-v104), release candidates (RC1-RC9), public release (v1.0), and post-release patches (v1.01-v1.12). The Indiana Jones build went through 100+ WIP versions over 2.5 years.
The VPW Bot checkout system tracks who has the working file, with each check-in including a download link, version number, and change comments. Multiple developers should never work from the same version simultaneously. Even with the bot, versions can diverge if someone works from a cached copy without checking out first (learned from Congo, Black Rose).
Wait at least a week after RC status before publishing -- there is always something found in the extra testing time. Avoid releasing too soon after another premium VPW table release (learned from Cirqus Voltaire).
Performance Optimization¶
Render Probes¶
Setting roughness to 0 on all render probes is the single biggest performance win -- up to 40% FPS improvement on some systems. Roughness requires the GPU to compute blurred reflections, which is extremely expensive. Non-overlapping ramps can share a single refraction probe; overlapping ramps need separate probes. "Too many render probes" hurts performance independently of roughness -- even zero-roughness probes have a base cost per probe (learned from Fish Tales).
The F12 in-game options menu should expose probe settings so users can adjust for their hardware. Fish Tales and Jurassic Park are the two most GPU-demanding toolkit tables due to their probe configurations.
Transparency¶
Transparent elements are consistently the biggest performance impact in VPX. Niwak's top 3 performance recommendations for toolkit tables: (1) limit non-opaque parts, (2) limit bake groups (fewer texture atlas pages means fewer draw calls), (3) limit active lights (learned from Police Force).
Overlapping refractions compound performance issues -- removing refractions from bumper caps had more impact than removing them from ramps (learned from Bad Cats). Each transparent object with refraction requires its own render pass.
Nestmap Sizing¶
Nestmap resolution directly affects both visual quality and file size. The effective playfield width in the nestmap should be at least 2000px -- below that, quality degradation is visible on 4K OLED cabinets. GNR's effective playfield width was only 2050px despite 8K nestmaps (learned from Earthshaker). Texture sizes no longer need to be multiples of 1024 on modern hardware.
Inserts account for approximately 82% of render time and file size impact in toolkit tables. Potential optimization: skip lightmaps for inserts with too little visual influence (learned from Earthshaker, Fish Tales).
VPX Mesh Detail¶
The VPX editor has a mesh detail factor (0-1) that controls how many polygons are displayed in the editor viewport. Setting it lower reduces editor lag without affecting in-game rendering (learned from Fish Tales).
Image Optimization¶
Match image resolution to actual visible area. An inlane texture at 4K resolution can be reduced to 2K since inlanes are approximately 1/8th of the table length -- identical visual quality at 4x smaller file size. Maverick dropped from 190MB to 100MB through image optimization alone.
Convert textures to WEBP format (30-50% smaller than PNG at equivalent quality). Remove alpha channels from opaque textures. Delete unused images from the VPX file. However, note that WEBP forces images to 72 DPI and discards dimension metadata, making it unreliable for precision work like playfield scans (learned from Judge Dredd).
Timer Performance¶
Timer intervals of 1ms are wasteful for most tasks. VPX processes all timers once per frame -- a 1ms timer running when the last frame took 10ms executes 10 times in one frame update. Use interval -1 (per-frame) for visual updates and 10-20ms for physics tracking. GetBalls calls are particularly expensive and should never run at interval 1 (learned from Goldeneye, where changing timers from 1ms to -1 doubled FPS from 80 to 150+).
Testing Standards¶
Competition Play¶
Focused competitive play exposes edge cases that casual testing cannot. The VP Chat competition on Maverick revealed three undiscovered bugs in a released table. Tables should be tested through competition play before declaring release-ready.
Multiple Configurations¶
Test on both desktop and VR -- issues that are invisible in 2D desktop play become immediately obvious in VR. Wire ramp heights, depth bias artifacts, light swimming on transparent objects, and geometry alignment errors are all VR-exposed problems (learned from Goonies, Monster Bash).
Test with both DirectX and OpenGL backends -- insert rendering can differ between them (learned from Iron Maiden). Test with B2S both enabled and disabled -- lamp code that depends on B2S being active will break for non-B2S users (learned from Goldeneye).
Real Machine Reference¶
When providing physics feedback, supply PAPA or competition video timestamps showing expected behavior. Tables are tuned as "new or well-maintained machines" -- they play faster than worn arcade machines. Without video evidence, physics feedback becomes endless back-and-forth tweaking (learned from Monster Bash).
VR Compatibility Requirements¶
VR Room Primitives¶
VRRoom variable must be set to 0 for desktop releases. VR room primitives being loaded cause 20-40 FPS loss even in desktop mode (learned from Batman DE). The VR room should auto-detect VR mode rather than requiring manual script settings.
VR Blocker Walls¶
Copy the cabinet primitive, make it fractionally smaller, flip normals inward. This prevents VR players from seeing through cabinet gaps (plunger lane, coin door edges) to the VR room floor. First implemented on Breakshot, now standard (learned from Countdown).
Transparent Object Handling¶
Transparent objects set to "static" rendering cause lights to "swim" (shift when moving head in VR). Set affected objects to "active" rendering, accepting the performance cost. For playfields, use cutouts instead of transparency when possible (learned from Monster Bash, No Fear).
Normal maps on ON insert primitives break UpdateMaterial in VR -- the material update silently fails. Remove normal maps from any primitive that needs runtime opacity changes in VR (learned from Indiana Jones). Insert normal maps should use tangent space, not object space, as object space breaks in VR's different coordinate system (learned from TFTC).
Post-Processing¶
quality_smaa (post-processing anti-aliasing) should default to off for VR builds. The GPU cost of SMAA in stereo rendering is significant, and VR headsets provide their own sufficient anti-aliasing (learned from Cactus Canyon).
Modding Ethics¶
The Team Tuga Incident¶
The Die Hard Trilogy release established an important community precedent around modding. Team Tuga created a modified PUP pack despite the table being marked "Not Free to Mod" (only two months after release). The key distinction: a traditional PUP-Pack is a standalone addon for ROM-based games and does not modify the table. Die Hard's PUP folder (with videos, sound, coding, fonts) is an integral part of the original table required for it to operate -- modifying it IS modifying the table. "Not Free to Mod" applies to everything that is part of the original table, including PUP media contents (learned from Die Hard Trilogy).
Adopted/Abandoned Tables¶
When adopting an abandoned table: attempt contact with the original author first, assign a new project lead, preserve the original vision ("We should not alter the looks and the idea. Just make it work good and for everyone"), and focus on technical upgrades rather than design changes. Release under VPW with full credit to the original author (learned from MF DOOM).
Reusing Parts and Art¶
Many real pinball parts are shared across manufacturers and eras. Check other VPX tables for better-modeled versions of the same real part before modeling from scratch (learned from Austin Powers). For third-party artwork, always check usage permissions -- some artists actively monitor the community and are sensitive about reuse (learned from Medieval Madness).
For original tables based on existing IP, contact rights holders directly. Non-commercial/free distribution simplifies licensing conversations (learned from Blood Machines).
Anti-Patterns¶
vpmTimer.Add¶
vpmTimer.Add is broken and should never be used (learned from TNA). Use standard VPX timers or custom timer implementations instead. At scale (1000+ calls), the problems compound: typos in queue callback names cause cryptic VBSE_OLE_NO_PROP_OR_METHOD errors at runtime with no line reference. Convert to queue/tick timers for maintainability (learned from MF DOOM).
Lampz at Frame Rate¶
Lampz fading timer running at frame rate (-1 interval) causes different fading speeds at different FPS -- a 165Hz player sees faster fading than a 30fps player. Set the Lampz timer to a fixed interval (e.g., 10ms) independent of frame rate (learned from VPW Example Table).
Oversized Sleeve Primitives¶
RubberBandPost primitives have their zero point at the CENTER of the primitive, not the bottom. At default Z=0, they protrude below the playfield (interfering with subways) and only half-protrude above (causing abnormally high ball bounces). Fix: set Z to 25 so the post sits flush on the playfield surface (learned from Judge Dredd).
Zero Friction on Any Surface¶
Never set friction to 0 on any VPX object. Use 0.1 as the minimum. Zero friction causes unpredictable ball behavior: balls slide without rolling and physics calculations break down (learned from Hook).
Pure Black (#000000) in Materials or Textures¶
VPX has issues with perfect black -- it uses it as a mask in some cases and causes divide-by-zero in lighting calculations. Use minimum RGB 17,17,17 (#111111) for the darkest blacks. Changing drop target material from #000000 to #010101 prevented targets from appearing dead (learned from Radical, Johnny Mnemonic).
debug.print in Production Code¶
debug.print writes to both console and log file. In hot code paths (ball rolling subs), the I/O overhead causes visible frame drops. Remove all debug.print statements before release (learned from Guns N' Roses).
Ball Mass 1.3 for Widebody Tables¶
Ball mass should be 1, not 1.3, even for widebody tables. "Ball mass of 1.3 will throw all of the flipper stuff off." The real ball is the same size and weight on all tables. If mass 1 doesn't feel right, the issue is elsewhere -- flipper angles, ramp friction, or other geometry (learned from Judge Dredd).
Table Validation Checklist¶
Pre-release verification items drawn from across all builds:
- [ ] BallSize = 50 (not legacy 25)
- [ ] Ball mass = 1
- [ ] VRRoom = 0 for desktop releases
- [ ] All debug.print statements removed
- [ ] VSync override = -1 in table User properties
- [ ] Flipper trigger margins at 27 VP units (updated from 23 in 2024 -- see Physics Tuning)
- [ ] Metal wall hit thresholds at 2
- [ ] Pop bumper radius sized to rubber skirt, not plastic cap
- [ ] Playfield physical sounds are mono
- [ ] Cabinet Mode checkbox enabled in VPinMAME settings
- [ ] No pure black (#000000) in materials or textures (use #111111 minimum)
- [ ] No zero-friction surfaces
- [ ] Timer intervals appropriate (no 1ms timers for visual updates)
- [ ] SolCallback subs guard with
If Enabled Then - [ ] tilt functionality implemented (
vpmNudge.TiltSwitchandvpmNudge.Sensitivityset) - [ ] All Fleep collections have "Fire events" checked
- [ ] Depth bias verified on all layered primitives
- [ ] Rubber posts in
dPostscollection, sleeves indSleeves - [ ] cSingleLFlip and cSingleRFlip constants present (even if apparently unused)
- [ ] Playfield dimensions verified against physical measurements
Collaboration Workflow¶
VPW Bot¶
The check-in/check-out system prevents merge disasters. Key rules: only one person checks out at a time, always increment the version number on check-in, note what changed in the check-in message. Script changes can sometimes be merged across versions, but baked assets require the latest checkout (learned from Diner, Congo).
Parallel Work¶
When approaching release with outstanding visual improvements, run a "backup" bake with current assets while a second artist works on enhanced materials. This keeps the release timeline on track regardless of whether the enhanced version is ready (learned from CFTBL).
Blender Render Offload¶
When a builder's PC cannot handle rendering, send the .blend file to someone with a more powerful machine. This allows participation from builders with less capable hardware (learned from Defender).
Newcomer Onboarding¶
New contributors learn most effectively by working alongside experienced developers on specific small tasks. Give them targeted work (animate a kickarm, wire up rubber animations) and point them to reference implementations in other tables. "Like IKEA furniture, once you've built it correctly once, doing it again takes 1/100 of the time" (learned from Countdown).
POV Calibration for Cabinet Users¶
POV settings depend on physical cabinet geometry -- monitor size, tilt angle, player height, and orientation. Key parameters: Inclination (typically 6-20 depending on cabinet), FOV (29-45), Layback (42-70). Once Inclination, FOV, and Layback are dialed in for your physical setup, only X/Y offsets need per-table adjustment (learned from Congo).
The coin-on-glass trick: place a physical coin on the cabinet glass next to a round insert and adjust POV until they match size.
Anti-Ball-Stretch Configuration¶
The "Anti Ball Stretch" checkbox alone is not sufficient -- you must also enter your monitor's aspect ratio (e.g., 16:9) in the associated fields. Without the ratio, the ball still appears egg-shaped on rotated monitors. The ratio may need to be swapped (9:16 vs 16:9) depending on whether the monitor is natively portrait or landscape-rotated (learned from Congo).
Physics Conventions¶
Flipper Strength by Era¶
Flipper strength values correspond to real machine coil types. Standard values from nFozzy:
- System 11 (mid-80s): 2300-2600 (learned from Police Force)
- Early WPC (1991): 2400 (FL-11630 red coil, learned from Bride of Pinbot)
- Mid WPC (1992): 2600 (FL-11629 blue coil, learned from Fish Tales)
- Strong coil tables (Indy, No Fear): 3250-3500 (FL-11629, learned from Indiana Jones)
EOS torque ratio of 0.375 was tuned extensively and should not be changed when adjusting main strength. EOSReturn of 0.4 and EOSTorque of 0.375 together produce more realistic flipper trick behavior than adjusting either alone (learned from Fish Tales).
Sling Threshold Tuning¶
Sling threshold AND hit threshold must match. If they differ, animation and sounds trigger without physics or vice versa. The sweet spot for most tables is 1.5-2.0. Too low (1.0) causes slings to fire on light touches; too high (4.0) misses legitimate hits (learned from Monster Bash).
Bumper Strength¶
Bumpers are generally set too weak. Strength of 13-15 is more realistic than default lower values. Bumper radius should match the rubber skirt/ring, not the plastic cap on top (learned from RBION, Big Bang Bar).
Playfield Friction¶
Default playfield friction of 0.02 is far too low. Calibrated values for realistic ball behavior range from 0.15-0.25 depending on era. Higher friction slows ball travel, making ramp entries and orbit shots require appropriate speed rather than gliding frictionlessly (learned from Iron Man).
Lighting Conventions¶
GI Color Temperature¶
Render all GI lights as pure white in Blender, then apply color modifications in VPX script. This enables unlimited color mod options without re-rendering (learned from Haunted House). GI color temperature options should not mention Kelvin values in user-facing menus.
Flasher Fading¶
The standard VPW flasher fading pattern uses exponential decay: FlashLevel = FlashLevel * 0.93 - 0.01 with cubic function flashx3 = FlashLevel^3. The cubic creates fast initial decay that slows near zero, matching incandescent cooling. Each flasher solenoid gets its own SolCallback sub (learned from Congo). Per-flasher variation in fade speed prevents the "Christmas tree" look where all flashers fire identically (learned from Black Rose).
Lampz FadeSpeed -- LEDs vs Incandescent¶
Different FadeSpeed values simulate physical response characteristics. LEDs: fade up 1/2, fade down 1/8 (near instant with slight persistence). Incandescent: fade up 1/40 (slow warm-up), fade down 1/120 (very slow cool-down). The asymmetric speeds reflect physical reality -- filaments heat faster than they cool (learned from Iron Man).
LUT Best Practices¶
Build table assets with full saturation and use LUTs to reduce it. LUTs can reduce dynamic range but cannot expand it. LUTs apply universally to all elements -- metal, playfield art, and plastics all shift together. For better results, apply color adjustments to playfield and plastics separately from metalwork (learned from RBION, Congo).
When not actively using a LUT, disable it entirely rather than setting a "neutral" LUT. A neutral LUT still processes every pixel through the lookup (learned from Iron Man). For user-facing options, label LUT intensity as "Color Saturation" rather than "LUT."
Insert Bloom Sizing¶
Insert bloom lights should be approximately 1/3 the size that feels natural when first placing them. Oversized blooms create a blown-out appearance, especially on cabinet/VR setups (learned from Dr. Who). For the over-playfield bloom light, use a very dark full-on color (lots of black in the value) to prevent the bloom from looking cloudy (learned from Goldeneye).
Mods Should Default to OFF¶
All mods should be disabled by default. When the snake mod on Metallica was blocking skill shot insert visibility, it highlighted the importance of shipping with a stock configuration. Mods (snake cover, cemetery, mayo lights, GI color options) should be available as F12 menu options but disabled by default so the table matches the real machine's stock appearance (learned from Metallica).
Texture and Color Standards¶
Playfield Image Resolution¶
Power-of-two playfield texture dimensions (2048, 4096, 8192) can render blurry in VPX due to mipmapping. Non-power-of-two sizes (4000, 3950) render sharply. 4000x2000 produced the crispest playfield in testing. Going past 4K does not bring additional sharpness as VPX starts mipmapping. Note: this applies to playfield image textures, not toolkit nestmap atlas sizes which must be 8192 (learned from Bride of Pinbot).
Playfield Scans vs Redraws¶
Redraws (vector art traced from scans) produce perfectly clean art that scales to any resolution. Scans have physical imperfections and resolution limits but provide authenticity. The choice depends on the table's art style and the team's resources (learned from Fish Tales, Bad Cats). For toolkit tables, redraws provide better source material since the toolkit renders at very high resolution where scan artifacts become visible.
Color Grading Workflow¶
Render textures "quite neutral" with no blown-out highlights. Apply contrast and brightness adjustments in VPX using LUTs only. "It's easy to raise contrast but impossible to create information that isn't there" (learned from Jokerz). When debating playfield color saturation, reference real machine photos or in-person experience -- video cameras and compression desaturate colors significantly (learned from Defender).
DOF Safety¶
DOF DOFOn commands left continuously energized can cause real hardware damage (burnt fuse/solenoid) and fire risk. Only solenoid-related DOF outputs should use DOFPulse; DOFOn should be reserved for flippers, button lights, and RGB. Always test DOF thoroughly before release (learned from Game of Thrones).
Diverter solenoids should NOT have DOF contactor effects assigned. On real machines, diverter coils are small and designed to be held on. Assigning contactors to diverters risks burning out physical solenoids in cabinets (learned from F-14). Only momentary solenoids (bumpers, slingshots, kickers) should have contactor mappings.