Saltar al contenido
← Volver a proyectos

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

Nueva versión disponible.