Loading recipe…
Press Run. Three coins land, each drawn by a tiny class you wrote, each showing the value it carries — and the HUD reads those values straight back off the symbols.
What is a symbol?
In pixi-reels a symbol is any subclass of ReelSymbol. The engine creates one instance per visible cell and calls a small set of methods on it as the reel spins and lands. You never construct symbols yourself — you register a class and the engine instantiates it.
Every symbol has a view — a PIXI.Container the engine puts on screen at the right spot. Whatever you addChild to this.view is your symbol.
The methods you must provide
class ValueCoin extends ReelSymbol {
constructor(options) {
super();
this.value = options.value; // the number this coin carries
}
onActivate() { this._draw(); } // this cell just became this symbol
onDeactivate() {} // it's leaving — clean up if needed
async playWin() {} // win flourish (none here)
stopAnimation() {} // snap back to rest
resize(width, height) { // runs on EVERY swap, with the cell's pixels
this._w = width; this._h = height;
this._draw();
}
}
The one that trips beginners up is resize(). It runs on every symbol swap with the cell’s pixel size, so anything position- or size-related goes here, not in the constructor — the constructor runs once, before the symbol knows how big its cell is.
Drawing the coin
_draw() clears the view and adds a gold disc plus the number, centered:
_draw() {
if (this._w === 0) return; // resize() hasn't run yet
this.view.removeChildren();
const r = Math.min(this._w, this._h) / 2 - 4;
this.view.addChild(new PIXI.Graphics()
.circle(this._w / 2, this._h / 2, r).fill(0xf6c945).stroke({ color: 0xb8860b, width: 3 }));
const label = new PIXI.BitmapText({ text: String(this.value), style: { fontFamily: 'GoldDigits', fontSize: r * 1.1 } });
label.anchor.set(0.5); // anchor + center = visually centered
label.position.set(this._w / 2, this._h / 2);
this.view.addChild(label);
}
The number is the game’s gold digit bitmap font (GoldDigits), not a system font — bitmap fonts stay crisp at any cell size and are what slot games ship. Load it once before building (await PIXI.Assets.load('/hw-spine/goldfont.fnt')). anchor.set(0.5) plus positioning at the cell’s center keeps it centered on the disc.
Registering and reading the value
The value is baked into the registration, so each id always carries its number:
.symbols(r => { for (const v of [1,2,5,10,20,50]) r.register(`coin${v}`, ValueCoin, { value: v }); })
Because the value is a property on the instance, you can read it back off any landed cell:
reelSet.reels[col].getSymbolAt(row).value // → 25
Where to go next
This bakes the value into the class — perfect when the values are fixed. A real Hold & Win server sends a different amount per coin, so the next lesson keeps one generic coin and carries the number as data instead.
Related recipes
- Beginner: carry the value as data. one coin, any value, on a Hold & Win board
- Beginner: number on a ready-made coin. use real coin art and just add the number
- CardSymbol (debug). the no-asset placeholder symbol class