DEV Community

Donovan Lafferty
Donovan Lafferty

Posted on

Building a 1980s Mainframe Slot Machine in Vanilla JS: RNG Math, Web Audio, and CLI Integration

Hello, my name is Donovan Lafferty. For my latest project showcase, I wanted to build something that blended the rigid constraints of vintage computing aesthetics with modern browser-native engineering.

The result is a fully functional, text-based dot-matrix slot machine emulator designed to mimic the look, feel, and sound of an early 1980s microcomputer text terminal. Built entirely from scratch using vanilla JavaScript (ES6+), HTML5, and Tailwind CSS, the project operates completely without external game engines, libraries, or dependencies.

In this build log, I’ll break down the core software architecture, the casino math engine driving the volatility, and how I approached procedural retro sound synthesis.

πŸ‘‰ Watch the full gameplay demonstration on YouTube: https://youtu.be/OWGsAOXGGtE
πŸ‘‰ Play the live build right in your browser: https://silver-nadia-34.tiiny.site

1. The Visual Architecture: High-Contrast Monospace Styling

To establish a pure retro engineering aesthetic, I bypassed classic analog textures or simulated CRT scanline filters. Instead, the layout prioritizes razor-sharp, high-DPI custom monospace typography (utilizing the Fira Mono typeface) optimized for flat, pixel-sharp monochrome displays.

The terminal chassis selection lets the user swap between classic hardware profiles on the fly:

  • *P1 Phosphor Green *(Classic terminal VFD style)
  • VT100 Amber Plasma (DEC plasma emulation)
  • Teletype Paper White (Early paper terminal output)
  • Lab VFD Cobalt (Compact laboratory vacuum fluorescent style)

To make winning combinations visually striking within a flat text space, the engine maps the winning payline vector coordinates and injects a synchronized, inverted-color blink cycle (.win-blink) directly into the VT100 grid cells.

2. The Casino Math Engine: Volatility Tuning & Hit Frequency

Designing a slot machine that feels authentic requires moving beyond uniform randomness. If every symbol has an equal chance of appearing on every reel, the game fails to replicate a genuine casino experience.

Virtual Reel Strips & Symbol Weighting
The mathematics engine utilizes a high-density, weighted simulation array. Each virtual reel strip is an array of custom symbol objects defined with varying frequencies (weights). Lower-tier symbols appear frequently to keep line hits steady, while top-tier symbols are intentionally scarce:

  • [7] LUCKY SEVEN (Jackpot Multiplier: 120x) β€” Weight: 2
  • [@] MONITOR (Multiplier: 45x) β€” Weight: 3
  • [$] CORE (Multiplier: 20x) β€” Weight: 4
  • [♣] CLOVER (Multiplier: 10x) β€” Weight: 4
  • [β–²] SHIELD (Multiplier: 5x) β€” Weight: 5
  • [β‰ˆ] COMMS (Multiplier: 2x) β€” Weight: 6
  • [?] PORT (Scatter/Wild Utility) β€” Weight: 1

Math Balancing
In standard play, each strip contains 25 symbols with exactly 1 Scatter Port. The probability ($p$) of a scatter landing anywhere in the 3 visible rows of a single column is exactly $\frac{3}{25} = 12.0\%$.

By mapping this across a 5-reel matrix using a binomial distribution, the bonus trigger probability calculates to roughly 1.43%, meaning a player will experience the main bonus sequence approximately once every 70 spins. This creates an incredibly engaging standard-play loop.

3. Advanced Gameplay Logic: Dual-Utility Scatter Wilds

One of the most complex algorithmic tasks in this project was engineering a payline scoring engine capable of processing symbols left-to-right while factoring in Dual-Utility Scatter Wilds.

When the [?] Port symbol lands on the grid, the payline evaluator runs a two-tier check:

  1. Global Scatter Array Scan: It tracks the total quantity of [?] symbols across all 5 columns to check for bonus game triggers.
  2. Wild Substitution Algorithm: On active paylines, it treats the [?] symbol as a wildcard. The evaluator dynamically searches the array for the first non-wild symbol on the path to establish the winning target type, smoothly computing payouts even if a line is a mixture of standard symbols and scatters.

Additionally, I hardcoded a 2-of-a-Kind Momentum Mechanic specifically for the highest-paying symbol. Landing just two consecutive [7] symbols (or a [7] and a Wild [?]) on an active payline returns an exciting 15x line bet payback, ensuring close calls still reward the player.

  1. The "Core Intrusion" Bonus Loop & Screen-Collapse Transition

Landing 3, 4, or 5 Scatters activates the Core Intrusion Free Spins Mode, granting 8, 12, or 20 Free Spins respectively.

To heighten the cinematic experience, the game pauses user inputs and triggers an automated terminal cutscene. The screen undergoes a dramatic "CRT power shutdown" style horizontal collapse animation before reopening into a warning-red emergency interface.

// A look at the automated cutscene staging
function executeTransitionCutscene(onMidpoint, onComplete) {
  const shutter = document.getElementById('crt-shutter');
  shutter.classList.add('crt-turn-off'); // Collapses screen horizontally

  setTimeout(() => {
    if (onMidpoint) onMidpoint();
    shutter.classList.remove('crt-turn-off');
    shutter.classList.add('crt-turn-on'); // Re-opens screen to new theme

    setTimeout(() => {
      shutter.classList.remove('crt-turn-on');
      if (onComplete) onComplete();
    }, 700);
  }, 750);
}
Enter fullscreen mode Exit fullscreen mode

During this free spins loop, the mathematics change entirely to maximize volatility:

  • Lower-paying symbols (SHIELD and COMMS) are completely purged from the reels.
  • The jackpot LUCKY SEVEN symbol doubles its frequency weight.
  • The reel strips shrink to just 16 symbols, driving the retrigger probability up to 4.87% (about 1 in 20.5 spins). If 3, 4, or 5 scatters land during the bonus, they cleanly stack +5, +10, or +15 extra spins onto the player's remaining total without freezing the automatic game progression.

5. Procedural Audio Synthesis via Web Audio API

To keep the game truly lightweight and completely self-contained in a single file, I refused to load external .mp3 or .wav sound samples. Instead, the entire soundscape is synthetically generated on the fly using the browser's native Web Audio API.

By building custom oscillator chains and exponential gain envelope decays, the game mimics vintage hardware components:

  • Mechanical Keystrokes: High-frequency, ultra-short sine wave burst ($950\text{Hz} - 1200\text{Hz}$ over $0.012$ seconds).
  • Teletype Relays & Reel Locks: Short, crisp sawtooth waves mimicking physical stepper motors clicking into place.
  • Jackpot Chimes: A cascading, musical arpeggio array of pure sine frequencies scaling up to $1046\text{Hz}$.
  • Emergency Siren Warbles: Alternating, low-frequency sawtooth wave sweeps that pitch up and down to build tension during the Core Intrusion transition.
  1. Interactive Command Line Interface (CLI)

The control panel bridge connects the physical button layout directly to an interactive input terminal channel. When a user changes their active lines or stakes via the deck interface, an automated autotyping function types out the raw system instructions (e.g., THEME COBALT, BET +5, LINES 5) character-by-character inside the input field alongside real mechanical typing sound effects before executing the change. Users can also select the input bar and type these diagnostic terminal commands manually.

Thanks for checking out my work! If you have any questions about the pseudo-RNG logic, the Web Audio architecture, or vintage interface replication in vanilla JS, let's chat in the comments section below.

Developed by Donovan Lafferty.

By building custom oscillator chains and exponential gain envelope decays, the game mimics vintage hardware components:

Top comments (0)