TinyGames · how it works

Sjoelen 3D

The same board, seen from where you stand. Dutch shuffleboard in perspective: the plank runs away from you up the screen, wide at the bottom and narrowing to the bar and its four gates at the top. Pull DOWN, towards yourself, and the disc slides away from you up the plank, through a gate into a compartment. Thirty discs, three rounds; whatever did not get through a gate comes back to your hand and is slid again. A set of one disc in every compartment scores 20.

Draft. It is built, compiled and tested like every other game, and it is not on the hub: "draft": true in build/games.json keeps it off the cards, out of the sitemap and without a readme page. Take the flag off when it is worth playing.

Both ways up. Upright is how it is meant to be held - the plank is tall and narrow on screen, with the score above it and the hints below. Sideways it is the same picture given the full height, with the readouts in columns beside it: every desktop is a sideways screen, and a portrait-only game there would be a rotate card and nothing else.

sjoelen3d/
  index.html            markup
  style.css             the frame around the canvas
  js/sjoel.js           the board, the discs, the bar and the score - SHARED
                        with Sjoelbak, built from src/sjoelbak/sjoel.ts
  js/perspective.js     the camera: world to screen and back
                        - no pixels, no engine, no DOM
  js/sjoelen3d.js       the playable layer
  test-perspective.js   node test-perspective.js

Built from src/sjoelen3d/; the JavaScript here is generated and never edited.


One rules module, two games

The board, the discs, the bar with its gates, the compartments, the score and the tidy between rounds are Sjoelbak's rules module, unchanged and tested by ../sjoelbak/test-sjoel.js (144 assertions, eighteen mutants). This game adds one thing of its own, the camera, and that is what its suite tests.

The camera

A pinhole camera: the eye a metre and a half above the plank and 2.4 metres behind its near end, looking straight along it, with the picture plane hung a focal length in front. By similar triangles a point d in front of the eye, a to its right and b below its level lands at (a, b) * focal / d. The axis stays horizontal and the picture is cropped rather than the camera tilted, which is what a shift lens does and what keeps the inverse a closed form - the pull and the lane drag use it sixty times a second.

The eye is not where the player's eye is. From the near end the far end would be an eighth the width of the near one and a gate four pixels wide. From where the photograph the look comes from was taken, the far end is half the width of the near end, a gate is the width of a fingertip, and the sightline over the six-unit bar lands half way down the compartments - so the back half of every compartment, and everything tidied into it, is in view.

What the suite checks

$ node test-perspective.js

42 passed, 0 failed

Mutation run

Each mutant is the shipped file with one thing changed: the axes swapped, the camera at ground level, a focal length of zero, the near end drawn at the top, an inverse that forgets the depth, a pull that takes the screen angle as the world angle. All six are caught; a wrapper that changes nothing passes.


Controls

Pull down anywhere, release slide: the disc leaves up the screen along the line from finger to start, as hard as the pull
Drag the waiting disc sideways choose the lane
← → move the lane
↑ ↓ power
Space slide straight up the lane
Escape / P pause
R start again

A pull straight down is a slide straight along the board whatever the lane; a pull that leans goes off at an angle, by exactly the ratio of the eye's height to the disc's depth, so what is drawn is what was drawn. Sound is synthesised and switched off from the config sheet. A saved game is offered on the title card between slides and between rounds, under this game's own key.

Things deliberately left undone