Input tutorial

We'll read all 12 buttons every frame and draw a colored cell per button. Held buttons light up; released ones dim out.

1. Open the starter cart

The starter reads all 12 buttons once per frame and draws a 12×12-pixel cell for each — bright (palette index 11) when held, dim (index 5) when released. The cells are arranged in a 2-row × 8-column grid at the top-left of the screen.

variable bid
: cell ( id -- )
  dup bid !
  dup 8 / 16 * 2 +              ( id y )
  swap 8 mod 16 * 2 +           ( y x )
  swap                          ( x y )
  12 12                         ( x y w h )
  bid @ btn if 11 else 5 then   ( x y w h c )
  rect ;                        ( x y w h c -- )
: update
  0 cls
  12 0 do i cell loop ;

2. The 12 button ids

IdButton
0Up
1Down
2Left
3Right
4A
5B
6X
7Y
8L
9R
10Start
11Select

3. btn vs btnp

btn returns -1 when the button is held this frame. btnp returns -1 only on the rising edge — the first frame the button transitions from up to down. Use btnp for one-shot actions (jump, fire, menu select); use btn for continuous motion.

4. Keyboard + gamepad bindings

The browser maps both keyboard and any connected USB / Bluetooth gamepad (Web Gamepad API standard mapping) to the 12 logical button ids. Both sources are OR'd into the same btn surface — you don't need to know which the player used.

IdLogicalKeyboardGamepad (standard mapping)
0Up↑ / WD-pad up
1Down↓ / SD-pad down
2Left← / AD-pad left
3Right→ / DD-pad right
4AZA / × (face-button 0)
5BXB / ○ (face-button 1)
6XCX / □ (face-button 2)
7YVY / △ (face-button 3)
8LQLB / L1 (left shoulder)
9RERB / R1 (right shoulder)
10StartEnterStart / Menu / Options
11SelectSpaceBack / View / Share

Analog triggers (gamepad indices 6 / 7 = LT / RT), stick clicks (10 / 11), and the guide button (16) are intentionally unmapped in v1 — the platform's 12-button surface doesn't have slots for them. Exotic / generic-mapping gamepads also fall through; only Web-standard-mapping pads (Xbox-class, most modern controllers) work.