Rocket Board 2048
A 2048 board as a Datastar Rocket component, and a demo that steps through a game
#board-2048
A 2048 board as a Datastar Rocket component. The page keeps the board in a Datastar signal, and the component draws whatever that signal holds. When the signal changes, the tiles slide, merge and appear the way they do in the game.
See it step through a real game at https://rocket-board-2048.ndyg.cross.stream.
<board-2048 signal="board"></board-2048>
#Add it to a page
The component needs the Rocket bundle of Datastar, which is Datastar with Rocket
included. Load it in place of datastar.js, and add an import map that points
the name datastar at it. The component imports Rocket by that name, so the
page and the component share one copy. Two copies of Datastar on one page freeze
it.
<script type="importmap"> { "imports": { "datastar": "/datastar-rocket.js" } } </script> <script type="module" src="/datastar-rocket.js"></script> <script type="module" src="/board-2048.js"></script>
Copy static/board-2048.js and static/datastar-rocket.js from this repo. The
bundle is also on the CDN at
https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js.
Declare the signal as an empty object. A signal that starts as null never
notifies the component.
<body data-signals="{board: {}}"> <board-2048 signal="board"></board-2048> </body>
#Send it a board
Set the signal to a board, from the server as a Datastar signal patch or from page code. A board is a JSON object:
{ "n": 2, "over": false, "tiles": [ {"id": 1, "r": 3, "c": 0, "value": 4, "merged": true}, {"id": 3, "r": 3, "c": 1, "value": 2}, {"id": 4, "r": 0, "c": 2, "value": 2, "spawned": true} ], "ghosts": [ {"id": 2, "r": 3, "c": 0} ] }
| Field | Meaning |
|---|---|
n |
The move number. A board with the same n as the last one is ignored, and a lower n means the game restarted. Optional: without it every board counts as a new move. |
over |
true when the game has ended. Shows "game over", with "you win!" or "you lost". |
tiles |
Every tile on the board. r and c are the row and column, 0 to 3, from the top left. |
tiles[].id |
Stays the same for as long as the tile exists. The component slides a tile from where it was to where it is now. A tile with an id it has never seen appears in place. |
tiles[].merged |
true on a tile a merge just made. It pops after the slide. |
tiles[].spawned |
true on a tile that just appeared. It grows in after the merges. |
ghosts |
Tiles a merge just removed, with the cell each one slid into. A ghost slides there and fades out. |
Fields the component does not know are ignored, so a board can carry more than this.
Every board describes the whole game, so a board sent mid-game draws correctly. If it has a 2048 tile, "you win!" shows for that board and the next two, then hides so the board is not covered. At game over it shows again.
From an http-nu handler, one move looks like this:
{ board: $board } | to datastar-patch-signals | to sse
#Attributes
| Attribute | Meaning |
|---|---|
signal |
The Datastar signal to draw. Default board. A nested path works: signal="games.abc". |
played-at |
An ISO date. Shows "in play", "5m ago", "2h ago" and so on in a corner of the board. |
dim |
Mutes every tile except the biggest, until hovered. For thumbnails. |
#Timing
Set these on the element to change how long each phase takes:
board-2048 { --slide-ms: 180ms; --merge-ms: 140ms; --spawn-ms: 140ms; }
#This repo
| File | What it is |
|---|---|
static/board-2048.js |
The component |
static/datastar-rocket.js |
Datastar 1.0.4 with Rocket, from the CDN |
serve.nu |
The demo site, an http-nu handler |
game.json |
The demo's game, as the id and the 2880 moves it was played with |
tfe/game.nu |
The 2048 rules, from http-nu's 2048 example, which the demo uses to compute the boards |
Run the demo locally:
http-nu --datastar :3002 serve.nu