Skip to content


20,000 times out of my league

svelte, grid, 20481 min read

This project took way longer than I intended...

Today we'll explore building 2048 with svelte and CSS grid layout. This post is short, so jump down to the resources to get started on your own!

Svelte is a front end framework promising less boilerplate code. Less is more, so less try it out.

1npx degit sveltejs/template 2048
2cd 2048
4yarn dev

Once up and running, let's navigate to localhost:5000. Once there, let's add a 4x4 grid. When working with CSS grid, we set the container to display:grid, as well as other grid properties. Finally, let's set the properties of the cell (height, width, and how we will display the content). See the minimal example below:

1.grid {
2 display: grid;
3 grid-gap: 10px;
4 grid-template-columns: 1fr 1fr 1fr 1fr;
5 grid-auto-rows: 1fr;
8.cell {
9 width: 48px;
10 height: 48px;
11 display: flex;
12 justify-content: center;
13 align-items: center;

Once the layout is setup, we write some code to handle the key/touch events since we want to support both mobile and desktop. We use the swiped-events repo to detect mobile swipes. Neat...

1const mobileKeyMap = {
2 'swiped-up': 'ArrowUp',
3 'swiped-down': 'ArrowDown',
4 'swiped-left': 'ArrowLeft',
5 'swiped-right': 'ArrowRight',
7const mobileKeys = Object.keys(mobileKeyMap);
9const setupMobile = () => {
10 mobileKeys.forEach(eventName => {
11 document.addEventListener(eventName, (event) => {
12 event.key = mobileKeyMap[event.type];
13 handleInput(event);
14 });
15 })
18const handleInput = (event) => {
19 switch (event.key) {
20 case 'ArrowUp':
21 case 'ArrowDown':
22 case 'ArrowLeft':
23 case 'ArrowRight':
24 game.handleInput(event.key);
25 game.grid = game.grid;
26 return;
27 default:
28 return;
29 }

And with a lot of help from Rosetta Code, we create a separate game.js class to handle the game logic. Finally, we create a separate svelte component to make it rain when the player wins:

Game Won!


Quaerite Et Invenietis