# 22 pinball achievements as data, with five rule kinds

> Graveyard Pinball's achievements are a JSON file and a tiny rules engine: count, distinct, stat, event and custom rules with ball, game and lifetime scopes.

Canonical page: https://andersonmancini.dev/blog/graveyard-pinball-achievements-as-data

Published: 2026-09-07 · 2 min read · Tags: game-dev, pinball, data-driven, javascript, design

[Graveyard Pinball](https://andersonmancini.dev/blog/graveyard-pinball.md) has 22 achievements, and none of them is a line of game code. They are entries in a JSON file read by a small rules engine, and the same engine runs in Node tests.

## Five kinds of rule

- **`count`**: N hits of something, such as 50 cauldron hits in a game.
- **`distinct`**: N different things from a glob or an explicit set, such as three different lanes lit.
- **`stat`**: a number crosses a line, such as a score of 100,000.
- **`event`**: something happens, optionally with a payload filter, such as a drain where the ball lived under 10 seconds.
- **`custom`**: the few that do not fit, such as a Konami code on the attract screen, a game started after midnight, or every other achievement unlocked.

## Three scopes

A rule counts per **ball**, per **game** or for the **lifetime**, which is persisted. The same kind of rule means different things in different scopes: "Early Grave" is lifetime, "Say Its Name" is per game, and "Nine Lives" is a three-minute ball.

## Four tiers

Common, rare, legendary and secret. The tier decides the palette and how loud the reaction is: common plays only on the display, rare swells the display and chases the lamps, and legendary takes the top of the screen and slows physics to 40%.

## Reactions are data too

Each achievement can carry a `react` block with the lamps to chase or flash and the actors to animate, using the same names as the table manifest. The engine hands it to a hook, and the 3D side decides what to do with it.

## Why the camera is not hijacked

The lens is 70 degrees and every play view looks down at the table, so the backbox is out of frame in all of them. Flying the camera away mid-ball would also lose the ball. So a "cinematic" is the display swelling toward the middle of the screen plus slow motion.

The display itself is in [the DMD post](https://andersonmancini.dev/blog/graveyard-pinball-dmd-in-4kb.md). The project is on its [project page](https://andersonmancini.dev/projects/graveyard-pinball.md).

## Related projects

- [Graveyard Pinball](https://andersonmancini.dev/projects/graveyard-pinball.md) — Free Halloween game
