JS13kGames 2021: LOSSST - A Snake in Space

August-September 2021




A special year

Welcome!

2021 is a special year: it's the 10th edition of JS13kGames, and it will be the 10th game that I'll develop in solo!
(I started in 2014, but I made 2 games in 2016 and 3 games in 2018)

This making-of will cover the completion of a simple idea I've had in 2017, implemented in many forms,
and how I plan to make it grow outside of this competition!

You can play the game on js13kGames.com

The source code is available on Github

This making-of is the long version of this Twitter thread



Results

My game worked pretty well! It got the following rankings:

- #10 Overall
- #57 on Mobile
- #15 in WebMonetization
- #7 in Decentralized
- #2 in the Top 5 best controls!



Before the jam

In july, I started preparing this new installment with:

- A list of ideas
- A successful Twitter thread full of JS13k-specific tips and tools
- A SVG creation tool
- A 3D map editor in CSS3D
- A Mini 2D platformer bootstrap
- A Mini 3D platformer bootstrap
- A tool to convert a list of numbers into an ASCII or Unicode string
- One-div CSS3D cubes (while doing them, I found a super simple way to control the "camera" in CSS3D!)
- A Unicode 13 "recap": all chars / all shapes / all emoji (and an emoji webfont useable in JS13k entries)
- An update to my keyboard inputs blog post

All these tools plus all the others I made earlier are available in the JS13k resource page.

But an impressive, game-changing tool also appeared this year, developed by Yurume:
an entry compressor called RoadRoller, allowing to lose an extra 1-2kb in a fully optimized 13kb zip file! 🤯





Day 1: the theme

So the theme is SPACE!

No code today: day one is dedicated to brainstorming!

I kinda had in mind to do a 3D platformer a la Mario 64, but it wouldn't really fit that theme. So let's find something else!

I scribbled a list of ideas, removed the ones that risked to be over-represented among the other entries, and replayed some of my favourite space-themed mobile games, in particular Escape, Space Frontier and Armory & Machine. (you should try them!)

But the last idea I wrote in my notepad was "a sequel to a puzzle game of mine, in space", and that's what I picked:
I'll do a sequel to LOSSST, my entry from 2017!

I was aware that making a sequel of a popular puzzle-game with snakes risks to create a "déjà-vu" impression and rank it lower than the first time, maybe out of the top 10, but at least it will be the game I want to make and it will be publishable on app stores after the compo.

The history of LOSSST

Summer 2017: I got the "make shapes with a snake" idea, and developed my js13k entry LOSSST.
This entry and its making-of were a huge success, though in retrospect, there are many things I would have done differently: the visuals (rooms are too repetitive, snakes made of cubes look weird, tutorial signposts are not visible enough...), the clumsy CSS3D, the controls (backtracking / moving up and down is difficult), the "exploration / eat apples to grow" thing added a huge unnecessary complexity, and most of all, on a more personal note, I kind of burned out and gained too much weight while developing it, and I regret that.

January 2018: during JS1K 2018, I developed a 1kb demake of LOSSST with the help of the Codegolf Team, containing 55 levels.
Some of them were never seen before. It was a very fun compression challenge, and it can be played HERE.

January-June 2018: I start developing a HD remake of LOSSST with new mechanics, new puzzles, better controls, mp3 musics, photorealistic textures, different environments, better controls, and even a boss fight.
The goal was to eventually publish it on Steam and/or mobile app stores.
I also developed a puzzle generator to help me find new ideas.
(until then, all the puzzles, even the 3D ones, were created by hand on a notepad, which was pretty hard).
Unfortunately, the game was handicaped because of the (still clumsy) CSS3D, bad controls and heavy textures, and remained unfinished.
Many lessons were learned though. And it's still playable HERE!

May 2019: bored with all these cubic snakes, I start to think of a way to represent a volumetric snake out of CSS3D circles and rectangles. You can see a live demo of the result HERE (use mouse to rotate camera vertically).


It's a good start! (Even if the body looks a bit flat, the head really looks like a sphere)...
But this simple demo required a large amount of work to position everything correctly, and it would have been a nightmare to animate...
Which gave me the idea to develop...

June-august 2020: ... a CSS3D framework. With it, setting up the camera, a plane, a cube, a sprite (always facing the camera), or moving an object takes a tiny line of code. The framework itself is 1.4kb zipped, and it would literally have saved me dozens of hours (and probably many kbs) while I was developing the first LOSSST game. I used it to make my 2020 entry: Track not found?!


👆 CSS3Dframework's demo: king Bob-omb, made with a plane, 3 rounded divs, 5 emoji and 11 lines of JS

Back to august 13, 2021: the idea to redevelop LOSSST (and expand it) as a mobile game (with a succession of puzzles of increasing difficulty and extra challenges for each) has grown in my head, and instead of doing it on my free time, let it be my 2021 js13k entry!

How I will proceed

I will make the game I want: a lot of puzzles, with quick transitions, various mechanics, environments and musics, a bit of storytelling, and at the end, puzzles that take place in space (to fit the theme)... and I'll do it with CSS3D (but good CSS3D this time).

- No exploration, no apples, no barely-visible tutorial signposts.
- No planning: each day I will work on whatever I feel like working the most.
- No IDE or automation: only Notepad++, my browsers and my favourite online tools.
- No burn out: 2 to 5 hours of work per day, with pauses. Self-care is important. (CSS3Dframework will also help me to iterate quickly)
- No staying stuck for hours because of a problem. Pro tip: if a problem occurs, go take a walk or go to sleep, or work on something else, let your subconscious think about it, and the solution will be trivial when you'll get back.

Stats: every day, I'll record my screen while I code, and share the number of hours spent, the size of my commented code and my progress on Twitter. I'll check out the zipped size once a week.

Last but not least: leave time for beta-testing, debugging and golfing...
And don't fall in the trap of leaving something for the last minute (like mobile controls, or the music... like I do every year)



Day 2: what's on the menu?

Brainstorming continues... my idea for now is to build a rocket from different worlds by completing their puzzles.

I scribbled ideas in my notepad and started coding a first draft of my menu... mobile-first:

I drew the rocket pieces in my SVG creator tool, and made a stars pattern with a tiny SVG snippet inspired by old codegolf projects like miniCliffordAttractor:

<svg fill="#aaa" onload="for(i=500;i--;)innerHTML+=`<text x=${Math.random()*5000} y=${Math.random()*5000}>.</text>`"></svg>
Demo:

To make the page behave well on mobile (and make it installable as an app), I used the following lines at the beginning of my HTML:

<meta name=viewport content="width=device-width,initial-scale=1">
<meta name=apple-mobile-web-app-capable content=yes>
<meta name=mobile-web-app-capable content=yes>

NB: I forgot to add ",user-scalable=0" in the first line.
As a result, my game is zoomable with two fingers on mobile, but not with a double-tap. No big deal. 🤷

Total: 1h30, 1.2kb. Watch timelapse



Day 3: draw me a snake

I started this day by making a cross-browser scrollbar in CSS, for my menus.

Then, I started working on my snake.

I really wanted to find a way to push CSS3D further, like I did every year since 2017, so I started placing CSS3D circles in my scene to represent the joints of my snake (still wondering how I'll do the "cylinders" between the joints)...
But a happy accident occurred while writing my for-loop. I rendered the circles too close from each other, which ended up rendering the volumetric snake I had always wanted, by surprise! yay #serendipity!
So I went with that and never had to implement the cylinders at all :D

The snake above takes "only" 44 divs. In my 2017 game LOSSST, a "cubic" snake with the same length required about 50 divs.
So, against all odds, this snake is better-looking but also more efficient for the DOM!

After I tweeted it, our beloved judge McFunkyPants suggested that I alternate the colors of my circles, and it was an excellent idea.
Doing this allowed me to offset my circles more and use even less divs (26 here):

As you can see in that image (catured on Safari), my old way to do emoji tree shadows (color:transparent; text-shadow:0 0 #0007) doesn't work well with the Twemoji webfont. Instead, Safari continues to show the emoji's colors.

So I searched a different, cross-browser way to shade these emoji, and I finally found it a few days later, by fiddling with Browserstack's remote iPhone devtools:

.emoji.shadow { filter: contrast(0)brightness(0); opacity: .6 }



Total: 3h30, 4.45kb. Watch timelapse



Day 4: new grounds

On day 4 I had the huge chance to find finnhvman's micro SVG patterns on Codepen, and I decided to not only use them in my game, but also contact him to help me make more!

The banded grass looks gorgeous, compared to a simple green radial-gradient:

In my CSS, I applied a transparent-to-black radial background on top of the SVG background to make the ground look less flat, and more like a sphere (but in reality, it's just a rounded div).

Besides that, implementing the camera rotation with the mouse / finger required very little JS code:

See commented code for camera controls
pointerdown = 0;
// Pointer down (mouse or finger)
onmousedown = ontouchstart = e => {

  // Tactile devices: consider the first finger only
  if(e.touches) e = e.touches[0];
  
  // Set pointer down flag
  pointerdown = 1;
  
  // Save pointer position
  px = e.pageX;
  py = e.pageY;
}

// Pointer up
ontouchend = onmouseup = e => {
  
  // Clear pointer down flag
  pointerdown = 0;
}

// Pointer move
onmousemove = ontouchmove = e => {
  var dx, dy;
  
  // Tactile device: consider the first finger only
  if(e.touches) e = e.touches[0];

  // Find cursor delta X/Y since pointer down or last pointer move
  dx = px - e.pageX;
  dy = py - e.pageY;
    
  // Rotate around X axis according to delta Y
  rx += dy / 10;
    
  // Rotate around Z axis according to delta X
  rz += dx / 10;
  
  // Re-set last pointer position using the current ones
  px = e.pageX;
  py = e.pageY;
    
  // Rotate camera using CSS3DFramework
  C.camera({rx,rz});
}

// Disable right click / long touch
oncontextmenu = () => { return false; }

Total: 6h45, 5.5kb. Watch timelapse



Days 5/6: didn't lift a finger

My next goal was to make the snake controllable using the mouse or the finger, by dragging its head on the stage.

Working on this feature took almost two days, because desktops and mobiles had a very weird support for what I was looking for:
To make the snake follow the pointer (mouse or finger), I needed to know where the pointer is on the scene, and compare it to the head's position. But retrieving the mouse coordinates inside a 3D div (the floor div) requires e.layerX/layerY on Firefox and e.offsetX/offsetY on Webkit. Though, touch events don't support this feature at all.

So I went with another idea that I had found while I was working on LOSSST HD: put 4 almost transparent divs around the snake's head, and make it move as soon as one of these divs is touched with the pointer, using document.elementFromPoint(e.clientX,e.clientY)

Unfortunately, this way to control the snake wasn't precise enough on little screens, and even confusing for wall puzzles and 3D puzzles, so a few days later I scraped it entirely to save a few hundred bytes.
Instead, desktop players will use the arrow keys, and mobile players a virtual D-pad.

Like every year, the end of the first week is also the occasion to clean up my code and split my project into multiple files... (getting used to this hierarchy always takes a few days, but in the end it's better than a single, 200kb index.html file...)

I also made a comparison of my scene with and without CSS radial gradients and shadows. Quite impressive:

(The final game has much less shadows than the right image, I used many of them but kept them subtle)

Total: 14h, 20kb. Watch timelapse for day 5 / day 6



Day 7: move your body

I took the time to test different ways to move the snake's body, and asked people which one they prefer.

My favourite approach (#3) was also chosen by the other devs... even if it looks less natural than the others. So I went with it!

Besides that, I implemented collisions (the snake can't move over itself) and backtracking (when pulling the head to the position from which it's coming)...

... and wrote the code responsible to check if the puzzles are solved.

Note from september 13: my snake.js file has become the heaviest of all the project (26.9kb commented, 2.4kb minified/zipped), because it had to handle head movements and rotations, body movements, collisions, smart backtracking, plus all the puzzle mechanics (walls, wraps, teleporters, gravity) and a ton of edge cases. Phew.


Total: 17h30, 26kb, 4kb zipped. Watch timelapse



Days 8/9: puzzled

I developed new puzzle types: the ones with a wall, the ones with floor + wall...

And the ones with wrapping:
(contrary to previous games, the snake can exit wrapping puzzles by backtracking. It's more convenient and much easier to implement!)

This was the moment when I added keyboard controls and realized I'll have to scrap the "drag head to move" mechanic, which will become too complex to maintain and keep intuitive for the player.

Though, despite the hours spent, I still felt that I had absolutely no game yet, only an engine, so I made this meme to represent my impression:

At the end, I started looking for a way to produce music... (super early compared to the other years!)

I started by trying to reproduce classic melodies from their piano partitions, but it ended up being a dead-end. Partitions are an unbelievable mess of complexity, I don't have the time (or the patience) to figure them out and develop a game at the same time!

Total: 27h15, 39kb. Watch timelapse for day 8 / day 9



Day 10: music!

I woke up with a strong determination to produce music for my game... but how?
After thinking about it, I figured out I could try to extract notes from classical music MIDI files instead of their partitions.
I launched the idea on Twitter, and AndreJaenisch pointed me to midi-js, which helped me find an older, unmaintained project (jasmid) that does exactly what I want: list all the notes from all the tracks of a MIDI file.

So I took jasmid with me and spent a few hours creating my new tool: midi2array !
I put buttons and textareas everywhere to navigate between the tracks, play the notes, apply thresholds, and especially, keep the notes I want in a separate array, ready to be used with the micro piano synth I wrote in 2019.

Also, it's sunday, so let's conclude this second week with a little compression test:



Total: 30h30, 41.6kb commented, 5.85kb zipped. Watch timelapse



Day 11: scenery

It becomes urgent to start making puzzles for my... puzzle game.
But before that, a few details need to be completed:
A Virtual D-pad for mobile devices;
Trees and flowers, placed procedurally (pseudo-randomly) on the scene;

And brick blocks, which will have a real importance inside the puzzles, because the snake will collide with them.
It's actually not trivial to design brick block textures. (and I hadn't done that before: in my previous games, I just used grass cubes).
At first I tried to imitate this pot-holder (seen in front of a neighbour's house)...

But it wasn't as good as I hoped. Why is there a hole on top?!


So I took a little help from Slack and from Super Mario 3D World to make a design that's more realistic.

To optimize things, I ended up designing 2 micro-textures in SVG ( A: and B: ),
then I filled the top and front faces of the cubes with A + B + A, and the left and right faces with B + A + B.

And people liked that!
Hmm, almost. Call me a nitpicker, but when I put multiple brick blocks side to side, I find that their textures are not satisfying to watch.
Though, after alternating the top/front textures and the sides textures according to the Y coordinate of the cube, it's cool!

In bonus, since these textures are simple SVG rectangles with a black "stroke", they can be filled with any color we want in CSS.
So I'll customize them in every world of my game.
And in the snow world, I can even make them semi-transparent blue to make them look like ice bricks.
I'm very happy of this little discovery 🥰

Also, every time I make a CSS3D game, a fancy "undefined" pops up in my scene at one moment or another. This year, it was here:

(a little typo in the middle SVG of my top and front faces)

Total: 33h15, 43kb. Watch timelapse



Day 12: animals and music

I wanted to display random animals in my scene, but... I forgot to call Math.random() and they all came together!

Besides that, I spent some time playing with midi2Array, and created the first two melodies of the game: Morning Mood:

and Dance of the mirlitons:

By chance, while working on LOSSST HD, I had made a list of my favourite classical musics, so I just have to pick in that list to choose the soundtrack of my js13k entry.

(These videos were filmed with my phone because I didn't find a good screen capture tool that records audio and exports videos accepted by Twitter. I found a workaround the next day, using Windows 10's Xbox Game Bar recorder: Win + G)

Total: 37h, 46.7kb. Watch timelapse



Day 13: what's on the menu?

I got tired of the menu I made on day 2, so I remade it entirely, by imitating the style of LOSSST 2017:
white text, black background, and a little angle using CSS3D.
Oh, and it's responsive too.

I also added a 3rd song (Alla Turca), debugged mobile controls, and finally implemented my first puzzle (woohoo!)

(Though the "final" first puzzle will be rotated 90° and won't have the wrap walls around it, today they were present for debug purposes.)

Total: 39h30, 50.2kb. Watch timelapse



Day 14: a bit of everything

I spent this day on plenty of little details:
- continued the menus,
- designed the in-game HUD,
- made a puzzle completion animation (with a star, but in the final game we earn coins instead),
- added a 4th song (Eine Kleine Nachtmusik),
- finalized the first 3 puzzles...

... and started the intro animation, because a good game needs to start with a "wow effect".

A friend asked me how I managed to do animations like that, and the answer is: by hand.
More exactly, I abuse the magic of CSS transitions.
Anytime I want to move or rotate an object, or change its size or opacity, I just need to give it the values I want at a moment A, the values I want at a moment B, and let it transition for the time that separates A and B.

And to give the impression that I move the camera, the trick is to move the whole scene.
Scene going up == camera going down, scene going left == camera going right, and vice versa.
CSS3DFramework facilitates these operations with its C.move() and C.camera() methods.

Finally, all the timings are fine-tuned manually using setTimeout's. The final game has 2 cutscenes and 64 setTimeouts.

Here's what the beginning of this intro looks like in my source code
// Move right 7 times
for(i = 0; i < 7; i++){
  setTimeout(()=>{r=1;move_snake();r=0;}, 300 + i * 250);
}
  
// Look up
setTimeout(()=>C.move({n:"head_tilt", z:28,ry:-45}), 3000);
setTimeout(()=>C.camera({rx:120, z:-100,y:-300}),3500);
  
// Look down
setTimeout(()=>{
  C.c({x:-200,y:50,z:-200,rx:50,rz:30});
  C.plane({w:100,h:100,x:397,y:145,z:72,H:svg[1],rx:-90,ry:-22,sx:4,sy:4.5,sz:4});
}, 10200);
  
// Tilt head down
setTimeout(()=>{C.move({n:"head_tilt",ry:0})}, 14000);

// Move right twice
setTimeout(()=>{r=1;move_snake();r=0}, 15500);
setTimeout(()=>{r=1;move_snake();r=0}, 15700);

// Show rocket
setTimeout(()=>{C.camera({x:450,y:-70,z:-100,rx:60,rz:-20})}, 18500);

// Show sign
setTimeout(()=>{C.camera({x:370,y:0,z:-400,rx:60,rz:-40})}, 23500);

(...)



Total: 44h30, 53.1kb. Watch timelapse



Day 15: puzzles for realsies

After completing (more or less) my intro cutscene...

... and writing a few new tips and tricks on Twitter...

... I finally, really, started creating my puzzles, 100% by hand.

I made 26 puzzles for the world 1, and immediately requested beta-testers to check if everything was going in the right direction.
(at this moment, I still imagined I'll be making making a game with 5 worlds and 5 x 100 puzzles :D)
At least, the feedbacks were very good, and the few bugs found on Mac and iOS (ugh, Apple) were quite easy to fix.

A cute detail that appeared randomly: when the snake walks behind a tree, its eyes stand out in front of the tree, and I kept it like that, it makes a nice cartoony effect.

By the way, in the intro cutscene, I first used Twemoji's rocket emoji, thinking it would save me a few bytes, but it turned out that it was a dead-end, because of its angle, and because of the fact that, even after rotating it correctly, it would look super blurry at this size because the webfont I use contains bitmaps, not vectorial art.

At first, I tried to use the official Twemoji SVG file in my source code but it was heavy (499b after a strong optimization) and still had this weird angle...
So I finally redesigned it myself using my MiniSVGCreator tool: correct angle, 344 bytes and still this flame under it (which will stay hidden under the ground during the intro, but visible when the rocket starts moving)

And while we're talking about SVG's, I also added a cheap emoji favicon to my game using this simple trick:

<link rel=icon href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🐍</text></svg>">

I didn't manage to make it use the Twemoji font, but it still looks nice on PC (Windows) and in the mobile web-app (Android):



Total: 49h, 65.1kb. Watch timelapse



Days 16/17/18/19: how many puzzles is too many puzzles?

The puzzle factory now runs pretty well, I take the best puzzles from LOSSST 2017 and LOSSST HD and add many new ones that I invent or generate procedurally.

On day 16, I reached a total of 60 puzzles for the World 1. All coded manually.
And that's when the beta-testers started telling me I should remove a few, to not let my game become too repetitive.
Frank Force suggested that I stick to 30-40. I decided to do 50.
It was hard to remove some of them, but they're not gone forever, you can play them in the bonus page's NEAR shop.

On day 17, I added my "developer records" for all the puzzles. They will add an extra challenge for the best players.
Then, I started working on the second world:
New ambiance (desert texture, cactii instead of trees, rocks instead of flowers, and different animals)...
and a new mechanic invented in LOSSST HD: teleporters!

Teleporters are much harder to implement than the wrap.
Not only can they be placed anywhere (on the floor, on the wall), they also come in two flavours (purple and orange), so the snake can teleport at up to two different places in each puzzle.
The most complex thing with the teleporters, which is not really visible by the player, is that they force the snake to move twice forward:
If the move made by the player places the head on top of a teleporter, it must automatically go through it and reappear on the other end, which is equivalent to a second step forward.

Once the head has been teleported, it must be able to move in the four directions around it, which was not the case until now (one of the directions was reserved for backtracking).

And finally, when the snake has moved past a teleporter, and then decides to backtrack back to it, then the head can't really go back through the teleporter, because the result would be very confusing (the body would need to go back 3 times in total, to leave the head on a tile that doesn't contain a teleporter).

Overall, plenty of little edge cases combined that took a big amount of code to solve, and a decision I had to take (not liked by everyone): the snake's head can't backtrack through a teleporter.

I spent many hours implementing this mechanic on day 17, but continued enhancing and fixing it until the last week of the compo, as a lot of edge cases occurred with the new puzzles. (my testers have been very good at finding them)

I also tried to add some CSS3D pyramids but they didn't look nice enough, and would have wasted too many bytes, so I discarded them.

Finally, I added a 5th song: La Primavera.

It's already the end of the 3rd week, so a little compression test allowed me to see that my zip was 10.5kb... or 9.5kb after using RoadRoller. This tool is crazy! 🤯

On day 18, a weird feeling appeared. I was in holidays, but it was monday, and working on my game felo like "real work", not a hobby. Ew.
To chase that feeling away, I went to the pool and when I got back, I started working on something different: a puzzle editor!
Then I implementied the double-teleporter puzzle mechanic, and continued designing puzzles for the world 2.
I ran out of ideas after 25. So long for my original idea of 100 puzzles per world, hehe...

Thanks to the testers feedbacks, I could also tweak and reorganize many puzzles from World 1, to make their difficulty curve a bit better.

On day 19, I found back my best tool to invent the hardest puzzles for World 2. And this tool is... a notepad.

I was happy to finally have "really hard" puzzles in world 2...
And could even start working on the 3rd world (which is much more inspiring): snow, with pines, snowflakes and polar animals! This world will introduce the "wrapping puzzles" mechanic.

I also added two more songs: In the Hall Of The Mountain King and L'arlésienne.

Oh, and did you notice that the snake has different styles and eyes on each world? (sunglasses in world 2, ski glasses in world 3).



Total: 68h45, 104kb. Watch timelapse for day 16 / day 17 / day 18 / day 19



Days 20/21/22: [edited]

I spent two days making a "good" puzzle editor, able to create puzzles of any size, and with all the worlds/mechanics present in my game.

This editor is 6.9kb minified, but it won't be included in my 13kb entry.
I'll host it on github, and propose to use it as a WebMonetization bonus.

I also made my game able to play any custom level shared through the url's hash.

On top of being a bonus for the players, this tool will help me encode my remaining puzzles much more quickly
(including the ones designed on my notepad).

Speaking of which, my world 3 now has 40 puzzles, the game has a total of 120 puzzles and I recorded dev records for all of them!

Finally, I found a solution to include easter-eggs in my game, like the 2017 ones (for those who have seen them), but with different puzzles!

On a less happy note, I spent a few hours trying to do things for the Decentralized category, but it's super cryptic and an absolute loss of time, which I can't afford right now, so I'll keep that for the post-compo contant.

Total: 78h, 108kb. Watch timelapse for day 20 / day 21 / day 22



Day 23: par ci, par là

It's time to exploit the dev records I've recorded for all my puzzles.
The records in question consist in completing each puzzle with the smallest possible number of moves, and I had to play a lot of puzzles many, many times to record my best score for each.
So I added a little signpost on the side of each puzzle, showing the number of steps done so far, and the "Par" (my score).

I discussed a lot with my fellow gamedevs to find the best name: par? goal? record? a trophy emoji? ...
and finally decided to keep "Par", which is short and also a good Golf reference.

Then I made the cutscene showing the snake fly to the moon and started working on the Moon environment: starry sky, grey shiny ground, craters, and the rocket on the back of the first puzzle (to show a continuity with the cutscene).



Total: 81h15, 111kb. Watch timelapse



Day 24: to the Moon!

I spent most of that sunday to implement my snake's Moon controls:
Moving up and down, feeling gravity, climbing on brick cubes, etc.

And it's the end of the 4th week already!
I start to worry about my byte budget, but fortunately, I'm still under the limit (13.1kb without RoadRoller, 11.3kb with it. Wow).

So, I'll use the remaining space to polish the game with these 4 worlds.
(I initially planned to have 5 worlds, and introduce another new mechanic, but it wouldn't have fitted, so maybe another time!).

No precise planning for the last few days of the compo, but I know I still have to work on:

  • The final puzzles list, and their Par scores
  • Adding musics
  • Adding a game end screen
  • Saving the user's progress in LocalStorage
  • Implementing the easter-eggs
  • Adding decentralized bonuses

Wrapping up won't be easy!

Total: 84h45, 116kb. Watch timelapse



Days 25/26/27/28/29: all the little things

Day 25 was mostly spent recording my final dev scores and improving gameplay and mobile UI.

On day 26, I finally managed to embed all my svg floor textures directly inside my CSS code thanks to this url-encoder tool
This saves a few hundred precious bytes compared to keeping the textures as separate svg files inside my zip.
(zip files add a ~100 bytes overhead for each extra file you put in them, so having very few files - ideally, just an index.html - is important).

I also completed localStorage saving, improved the rhythm of my musics, and displayed the completed puzzles in the menu.

Finally, I worked on improving my Moon craters and shadows, and Finnhvman made me a SVG Moon texture. I liked it but it didn't seem "Moony" enough for the testers.

On day 27, I made the virtual D-pad only visible on mobiles (it was about time), completed the first easter-egg and debugged the snake's controls.

Big shoot-out to the website Unicompat that helped me pick my Unicode arrows and triangles with the best possible browser support.

On day 28, finnhvman came up with a brand new Moon SVG teture, which was absolutely fabulous.

(The craters are added on top of the texture using CSS circles + inset/outset shadows)

I also implemented the final easter-egg (which is also the end of the game), and added two musics (Für Elise and Badinerie).
In bonus, I wanted to show you how I was using midi2array with my few hours of experience, so I recorded it here:

After extracting my notes with midi2array, I insert a few silences in the melody (empty indices), and test it in-game:

Sadly, I'm a bit discouradged by the complexity of the Decentralized features, so I'm still super late on this.

On day 29, I added a "continue" button for returning users, made the worlds 2 to 4 unlockable with coins, made the final music (Blue Danube) and finished including the 4 worlds' mechanics in the puzzle editor:

And it's time for a feature freeze: the game will have 165 puzzles and 10 musics. All the remaining time will be reserved for debug, polish, testing and golfing!

(Replaying my game at 100% made me realize for the first time how long it is. So long that I had to split my playthrough on 2 days :D)

Here's the puzzle screen with all the dev records completed and an example of puzzle of each world:



Total: 100h30h, 127kb. Timelapse for day 25 / day 26 / day 27 / day 28 / day 29



Days 30 / 31: GOLFING

Day 30: it's a luxury to have two full days to finalize my game and golf it a little.
The current size after RoadRoller, Zip and Zopfli is 13.3kb. Shouldn't be too hard, eh?

Step 1: the low-hanging fruits

- Wrote my SVG code in lowercase (suggested by Subzey)
- Removed all the unnecessary spaces and attribute quotes in my HTML code
- Removed unnecessary line jumps in RoadRoller's output
Result: 61,248b minified, 13,611b zipped, exactly 299 bytes to lose.

Step 2: the music

I thought most of the remaining bytes would have been saved by converting (with my tool int2unicode) my long arrays of music notes into printable ASCII chars...

...but unfortunately, Kolmogorov wasn't impressed by this little trick: the minified file lost 2260 bytes, but the zip was only 8 bytes smaller!

Step 3: manual mangling

Mangling is usually the art of renaming long JS varnames or object properties into 1-char to save space.
JS minifiers generally do it automatically inside functions, and we can force them to also do it on global vars and functions (and as always, my entry has a ton of global vars and functions: 94).
And there are other long names that can also be reduced: HTML ids and HTML classes. Some build processes mangle these too, but I don't use any.

Mangling these things is very error-prone, because: HTML ids are also JS global vars, and I abuse that a lot in my code, so I have to avoid having a JS var overwriting an id.
Moreover, CSS classes and ids are case-insensitive, so I must take care to not have, for example, a class .c and a class .C.
Finally, I have to take care to not break inline JS code or eval'd JS code with my mangling.
For all these reasons, I made my mangling manually and very carefully: I made a list of my longest/most used vars/ids/classes, and replaced most of them one by one in my source code.

Mangling the first 26 names of my list made me lose a whopping 7,486 bytes (minified) and 242 bytes (zipped).

Mangling another 34 names made me lose 1,406 extra bytes (minified) and 201 bytes (zipped), which means my zip is finally 140 bytes under the limit! (13,172b)

Step 4 (cancelled): compressing puzzles

My final idea (that I didn't need to try finally) was to encode each level in a little ASCII string instead of a JS object:

// Before: JSON

puzzle2_25 = [
    
  // Floor
  [
    0b1000101, // only the last 3 bits represent the tiles of the current puzzle:
    0b1000101, // the "1" at the beginning is here to have a value between 64 and 127
    0b1000101, // so that each line can be encoded as a printable ASCII char
    0b1000101, // ex: 0b1000101 = "@"
  ],
  
  // Wall
  [
    0b1000000,
    0b1000000,
    0b1000101,
    0b1000101,
  ],
  
  // Width
  3,
  
  // Height
  4,
  
  // Snake length
  13,
  
  // PAR moves
  20,
  
  // Brick blockss
  [[-1,2,0],[3,2,0],[-1,1,0],[3,1,0]],
  
  // Portals 1: [x,y,z] * 2 (z = 0: floor, z>0: wall)
  [[0,0,1],[2,2,0]],
  
  // Portals 2
  [[2,0,1],[0,2,0]],
]

// After: a string containing:
// - Width
// - Height
// - Snake length (2 digits or 1 ASCII char)
// - Par score (2 digits or 1 ASCII char)
// - floor / wall (encoded in ASCII)
// - portals 1 / portals 2 (if any, otherwise use "ZZZ")
// - bricks (coordinates incremented by 1 to avoid negative numbers)

puzzle2_25 = "341320EEEE@@EE001220201020031431021421"

Without this compression, the 165 puzzles encoded in JSON take 7.9kb minified, 2.2kb zipped (about 13 bytes per puzzle).
After the compo, I tried to encode the puzzles in ASCII, and the result was impressive: 2.4kb minified, 1.5kb zipped (~9 bytes per puzzle)
In other words, if I had used this compression trick and had more inspiration, I would have had enough room for about 80 more puzzles!

Day 31: I summonned my beta-testers for a last test, and could fix a couple final bugs...

and I added a link to the (semi-joke) "HARD MODE" once the game is completed at 100%.

(In hard mode, the floor is lava, and the puzzles disappear as soon as you step inside them. But it's the same puzzles as in the main game. You can try it HERE)

As I said earlier, I have absolutely no automatic build process, so I concatenate, minify, RoadRoll, zip and zopflify my game manually. It's a long process, but I only do it a handful of time during the month, so I guess it's not that bad. If you're curious, I recorded it and you can see it here:

Here's a breakdown of the minified source code:



PS: I talk a lot about my byte budget, but another counter is also very important to optimize: the CSS3D divs. And I think I did pretty well: in the biggest puzzle of the game, the scene contains a total of 240 divs, and even there, everything seems super fluid.



Total: 113h45h. Watch timelapse for day 30 / day 31



One week later...

I spent one week working on my post-compo bonuses, especially the Decentralized ones.
Here's a little tour:
- WebMonetization bonus: the puzzle editor
- FLUX bonus: a snake editor (in CSS)
- IPFS bonus: IPFS hosting, jukebox, leaderboards (soon)
- NEAR bonus: an e-shop with coins & extra levels

Unfortulately, I had serious problems with pretty much all of them.

The next section is sponsored by:

  • WebMonetization: according to the doc, enabling WebMonetizarion is as easy as creating a wallet, enabling a browser plug-in and inserting a meta tag in the page's <HEAD>. Then, the JS program can check for a document.monetization object and enable bonus features accordingly. Unfortunately, this never worked on my PC (maybe because of an adblocker or antivirus?). So I decided to enable the puzzle editor for everyone, and in the editor's page, I just added the meta tag, so technically, I can say I used the feature (I will receive credits if people use the editor with their WebMonetization plug-in enabled). I just made it non-blocking.
  • FLUX: the snake editor was made entirely after the compo, but I didn't plan any method to load custom skins inside the game. All I had was the custom puzzle loader that did something like:
    if(location.hash)custom=eval(location.hash.slice(1)),start_puzzle(custom)
    So I had to hack my own game to shoehorn the custom skins loading through the custom puzzle loader. That's why the URLs generated by my skin editor have a hash that looks like this:
    #document.body.insertAdjacentHTML('beforeEnd','<style>(CSS code for the custom skin)</style>; custom=null;world=0;puzzle=0;start_puzzle_backup=start_puzzle;start_puzzle=main_menu;setTimeout(()=>{start_puzzle=start_puzzle_backup,location.hash='';},1000)
    When this code is evaluated, it adds custom CSS inside the page, tell the game that start_puzzle() is now main_menu(), wait for the game to call start_puzzle(), and when the menu is displayed, restore the original start_puzzle() function.
    Besides that, I wanted to enable custom skins sharing / browsing on the FLUX network (because this editor was a FLUX bonus), but sadly I didn't find any decent js api or tutorial explaining how to do that, so I gave up.
  • IPFS: this was the network in which I had the highest hopes, because its official JS api is well presented and seems easy to use. The homepage even contains live examples that seem to work just fine. So I took a few hours to try to do do simple things in JS, like uploading a file to the network, or having a leaderboards folder that anyone can update with thair high scores. Unfortunately, I never found a way to "push" my files to the network, the files were only accessible when my PC was on and my IPFS client was open. "Pinning" the files and waiting for a few hours so they can spread on the network didn't change anything.
    Not only that, but all the online... IPFS... file... uploaders that I found online also didn't seem to work. None of all the solutions I tried gave me a persistent URL that I could easily use and share. But I think it's also my fault. I must be missing something super important but I don't know what yet. So to this day, my leaderboards still isn't useable, and all the files I tried to upload on the IPFS network have a mirror on Github so people can actually see them.
  • NEAR: I also spent many hours trying to use NEAR's JS api. It is probably the best documented of all the Decentralized js13k sponsors, and very kind people like Sasha and Vlad contacted me on Twitter and Discord to offer their help. The thing is, you can use JS to connect to your NEAR wallet pretty easily. You can manage authorizations and show the remaining balance without problem. But as soon as you try to create a "contract" (send NEAR coins so someone or write data on the network), nothing works anymore, the browser console gets filled with cryptic JS errors, and the doc says absolutely nothing about that. After asking a lot of people, the answer seems to be that the contracts can't be signed using JS alone. I must somehow set up a server that will act as an intermediate between the browser and the network. And I clearly don't have the time or the knowledge to do that. Especially if there's no clear doc explaining it! So in my final e-shop, you can log in to your NEAR wallet and see its balance, and that's pretty much all.

So overall, I'm pretty sad because I attempted the four JS13k bonus challenges, spent a gigantic amount of time trying to learn them from scratch with my JS skills only, and I managed to implement properly zero of them.

Fortunately, I still qualified for the WebMonetization and Decentralized categories and won some cool prizes, since all the other competing entries didn't actually manage to achieve much more than me.
But for me it's a sign that these technologies are too hard to use. A lot of people work on these things and want us to adopt them more widely, but in my opinion they should really work on making them much more accessible.
Why does no one provide a simple tutorial / source code / live example package that explains me how to do the most basic stuff (sending data / exchanging currencies) as if I was 5 years old? And if I have to set up a server, explain me how to do that too!

Damn.

</rant>



Two weeks later...

My next goal (for this week and the following ones) is to release LOSSST for free on the Play Store.

Similarly to Decentralized stuff, converting a mobile-friendly HTML5 game into an Android app is unbelievably complicated... or expensive.
The worst part is that it used to be as simple as one click, when Phonegap's free online tools still existed.

So I'm trying many approaches at the same time:

Unfortunately, everything I tried so far either doesn't work at all (at least on my PC), or costs a fortune, or creates an app that is too slow and/or watermarked and/or handicapped with very bad touch inputs (click or touchstart/touchend events don't work or work after a long delay, which makes the game unplayable)

I'll continue to try but it'll take much more efforts than I anticipated :(

PS: I tweeted a list of my 27 super-favoutite entries if you're interested!



One month later...

My game was very well ranked, yay!

As a result, many people contacted me to offer extra help about Decentralized features and mobile app building, and that's super wholesome. I was also offered to promote my game in a youtube video (coming soon) and on Enclave Games.

I also started a new project with Stas, a friend from JS13kGames slack: a micro WebGL library (~1.5kb) as easy to use as WebGLFramework. You can follow its progress here and visit the project's homepage here.

So I'll continue working on all these things and will keep you posted!

PS: after forgetting the puzzles for a whole month, I recorded a 100% playthrough (with all the Par scores beaten) in 1h30. You can see the full video HERE (SPOILERS WARNING), or a sped-up version below (SPOILERS + EPILEPSY WARNING):





Feedbacks

I got a ton of feedbacks this year (thank you so much!)... Here they are:

Feedbacks about my list of tips and tools:
  • Alex_ADEdge: A huge thread of great tips and tricks for #js13k by @MaximeEuziere, defs worth a read through, lots of info to be found!
  • McFunkyPants: AMAZING JS GAMEDEV TIPS EVERY DAY IN THIS THREAD!
  • DennisRamirez: Dang, the tools in this thread are awesome!
  • Slashie: Here's everything you need to become the master of the #js13k or at least finish your entry with dignity :) Thank you @xem for compiling this.
  • MrJoshuaMcLean: This is a thread worth saving if you're into JavaScript/HTML5 game dev!
  • Master_Kehos: Special thanks to @MaximeEuziere for this awesome thread with tips and tricks for this competition, some of the resources have been very useful for me
  • MattiaFortunati (on Twitter): Thanks to @end3r for organizing, @KilledByAPixel for ZzFx the build process, @keithclarkcouk for ZzFXM, @senokay for roadroller and the help he gave me and @maximeeuziere for all the golfing tips and tutorials. Keep up with the great work, guys! :D

Feedbacks about my game when it was a work in progress:
    McFunkypants (on Twitter): Looking for #gamedev inspiration? Check out LOSSST! This entire game fits in a 13kb .zip file! Including the art, which is all done in CSS!!!!!! Not using webGL or canvas etc! Amazing.
  • Herebefrogs (on Slack): I feel your game had an opportunity to make a pun on Samuel L Jackon’s movie Snakes on a Plane… LOSSST: Snake on a Spaceshuttle or something
  • AdLong3232 (on Reddit): This is really cool, thank you!! :)
  • oh4godsake (on Reddit): very cool - love the dedication and love the result
  • Michael Primo (on Slack): Me when I see the intro of LOSSST in SPACE by @xem: https://youtu.be/SvJ9WHb5Px8?t=13
  • nkholski (on Slack): This is really incredible! Great idea with info between the levels.
  • Frank Force (on Slack): wow, really nice presentatioin
  • Cody (on Slack): yeah, this is great, good job @xem! as always 🤗 + this image
  • End3r (on Slack): I wanted to try if it works and realized I have to move on to next ones after 5-6 levels xD
  • Calada2 (on Twitter): woaw, it looks really good! :O
  • Sam (on Whatsapp): Une fois sur silence, ce jeu est un régal
  • Remi D. (at work): Super cool ! Ça me fait penser à snakebird (oui elle était facile celle là)
  • Benjamin B. (at work): C'est génial ! (Même si je vais avoir la musique dans la tête tout l'aprem :D)
  • Christophe T. (at work): C'est vrai qu'il est cool gg !

Feedbacks from the jury experts and the voting page:
  • Sasha Hudzilin: enjoyed the gameplay
  • Joep van Duinen : Really cool puzzler. Love the music integration and the cinematic opening. The difficulty ramps up pretty evenly too. Great work overall!
  • Nathan Lie: Nice and puzzling game with an nice atmosphere that's cool and relaxing. The puzzle editor is a big feature to have as a Web Monetization feature, but since it doesn't affect the gameplay it's effective as a bonus.
  • Ewa Mazur: Although the game is very cute and extremely addictive, I have doubts that the WM implementation is working properly. I appreciate the marking of the bonus items in the main menu, but they are available both when I am logged in to Coil and when I am not, which means the editor is not a bonus for Coil subscribers, but a bonus for everyone.
  • Michelle Mannering: - super cute graphics - snake is adorable - music and sound effects are a nice touch - cross combability is nice - simple graphics, but very effective - very intuitive, takes the user through a journey - camera rotation is awesome (nice addition) - puzzle games are my favourite! - this is very cool - love the fact you can go backwards and take time figuring things out - be cool if you got more coins for finishing in less steps - a reset button might be awesome too; for a cost!
  • Tim Sulmone: Game was much longer than i expected. Enjoyable fun cute challenge. Multiple aspects of decentralized features were implemented in. I can tell that a lot of care/passion went into making this :-)
  • Vlad Grichina: Nice and engaging puzzle game. Integrations are a bit unclear however, e.g. what I'm supposed to do with items purchased in NEAR shop?
  • Johnny Matthews: While the game concept is fairly simple, the implementation is incredibly impressive! The graphics are nice to look at, the sound track in fun, and the gameplay is somewhat addictive! From a decentralized standpoint, it's great to see the NEAR protocol implemented. It also looks like there's a version hosted on IPFS!
  • Ryan Baumann: Very cool game! Loved the opening cutscene and cute atmosphere. The puzzle difficulty is quite low, so I wish there were less puzzles required to be completed to skip ahead. I wasn't able to get any of the decentralised features working though. I did manage to get to the coin purchase page, however the prices are quite steep, and on the mainnet. Still, very clean as a game, and amusing.
  • Paul Gadi: Really engaging game! Great implementation of an in-app store using NEAR
  • Dietrich Ayala: Daaaamn, you did A LOT in this event. I love the developer journal, and really want to discuss the challenges you faced in the decentralization implementation. But anyways, great implementation of the game itself. Even an animated cutscene! Relaxing and not-annoying music. I couldn't get the IPFS bonuses to work, the CIDs were not being provided by anyone on the network so maybe you didn't publish it so a node that's always on? You can push to Pinata/Infura/web3.storage/Fleek and keep it online that way. Would be rad to see NFTs for high scores. Really interested in the leaderboard implementation if you get it working.
  • mxlle: Very cool sound integration! Still thanks for changing the song after a while :D A real nice puzzle game.
  • alfi-s: Pretty fun! Probably an improvement would be to show the entire snake at the beginning so we could judge how long the snake is to plan our steps.
  • robertocapuano: The gameplay is simple but fun. The puzzles are a bit repetitive. The graphics and audio are simple. The theme was not very focused.
  • ibrahim-301: very fun and well made. graphics and performance improved so much.
  • kesiev: I love how complete the package is!
  • robinlamb: Great graphics and fun puzzles!
  • rmkubik: This is awesome! The puzzles are great! Some really good subversions on my expectations and interesting exploration of the puzzle space! Love to see a good usage of the 3d space too!
  • rafaelpernil2: Pretty cool game and I love how the music reacts to the gameplay. Pretty cool
  • frozeeen: I love it.
  • picosonic: A nice looking and well thought out puzzle game. Technically very good as I understand it's using CSS3D. Lots of re-playability, plenty of scope for new levels. I like the textures used for the grass, e.t.c. the shadows and the over look of the game. A lot of similarities with your 2017 entry
  • Antix-Development: Interesting but not really about space?
  • qnp: Could not play...
  • jwigert: A truly great game! Thanks!
  • gagamoto: This is EXTREMELY good. So enjoyable to play. I have so many good things to say about this game, both on game overall and on the small details that makes it so nice to play. Thank you!
  • Rybar: Fun puzzle game, there's SO MANY puzzles! Truly a great feat, getting so much content in.
  • boberrs: The tunes are very fun at the beginning, but soon become too repetitive and annoying. Graphic style is somewhat inconsistent: some elements have plain textures (snake) and some more detailed (stones, grass) or have gradient (teleporters); some elements are always faced in front of the camera (cactile) and some are not ("par" sign) The puzzles are absoultely great: the best I've yet seen on js13k
  • jaburns: One of my faves this year for sure, and thanks for the shout-out! [in the game's readme]
  • Schnark: As this is a remake the game is no longer as impressive as the original was, though of course it is still a great game, and I really like the new design and improvements. So when I now just note the weak points this is just because I don't have enough time to praise the good ones. * The rocket in the intro is awfully blurred (Firefox/Linux). * At least for me there is nothing that really encourages me to solve the puzzles with as few steps as possible. Solving is the challenge, doing this in the fewest steps is usually either "do the same, but without errors" or "do the same, but in the opposite direction". This isn't a real additional challenge. * The music. While playing, the notes sound more or less random. When the music is played continuously, it is recognizable, but the note lengths seem to be wrong in many cases, and sometimes even the frequencies. Anyway, I will certainly play the game completely later, though probably muted.
  • vicksonzero: Super fun puzzle. The idea of fitting the snake in space is fun, but you can also say the idea has already been done >1 time by you. It is still new to me, so it is fun to me. However, this game suffers from too much repetitions. As a game designer i do see that each puzzle is slightly different but as a gamer i still feel the repetitiveness in your levels. You have elements help break up the flavour of the game, but there are not enough puzzle elements like the z-axis and the brick walls. Superb controls and graphics, the transition into the z-axis is super intuitive. Nice tune that plays as the snake moves. I did recognize the change of tune but again, not breaking up frequent enough.
  • BenjaminWFox: Very cute!
  • felladrin: Brilliant game and addicting gameplay! Well done!
  • Michael (during the ceremony) GG Xem :)
  • Saud (during the ceremony) Congrats Xem!
  • Ryan Malm (during the ceremony) XEM!! Woot woot
  • Ben F (during the ceremony) I love this game, it’s so cute!
  • Almut (during the ceremony) Great audio integration!
  • Crystal Parker (during the ceremony) I couldn't beat all the levels. :)
  • Little Stache (during the ceremony) was a lot longer than I thought.
  • Sascha Depold (after the ceremony) great game really
  • Frank Force (after the ceremony) I love the game but i do feel there are too many puzzles. i think it is smart that you made all these levels because that way you can cut like half of them and make the game way better and faster, if that makes sense. one good rule of thumb if you want to keep the gameplay quick is that each puzzle should teach or demonstrate something slightly new or a new combination of things they already know. This way a player never feels like they are repeating something. one kind of problem with your game is it looks cutesy but has really hard puzzles. that is a great vibe but just need to communicate from the start that is not an easy game. the important thing attract players would love your game but make sure they dont mistake it for a kids game

Video tests / feedbacks:
  • Jupiter Hadley found it cute and liked the music

  • Pable Telescopar found it very good and polished and found a fun glitch where you can move the snake during the intro

  • MishManners tested it on Twitch and solved 15 puzzles despite the dark mode that ruins the white tiles (too bad I didn't see that before)...


Wow, that was a lot to read. Thank you so much! Let's answer the main issues:

  • I disliked / muted the music: I get it, I muted it too after hearing it hundreds of times. But I hope you noticed there were 10 tracks though
  • WebMonetization seems broken Yep. It's checked in background but doesn't block the access to the puzzle editor.
  • A reset button would be cool: There is one, at the bottom right... 🤔
  • What am I supposed to do with NEAR purchases? You can buy in-game coins to unlock worlds 2-4 earlier.
  • I wasn't able to get any of the decentralised features working: haha, me neither.
  • Maybe that's because you didn't setup a CID server: most probably. I never found how to do that, and I think it really should be easier to setup, or even better: serverless. (JS only)
  • Would be rad to implement NFTs: I'm not really into money laundering. And I'm afraid of right clicks :P
  • Shop prices are quite steep, and on the mainnet: Too expensive indeed. Besides that, what's the point of having a shop using testnet?
  • Too repetitive: sorry, that's what I tried to avoid, but I didn't succeed entirely.
  • Not in the theme: how can a game where a snake goes on the Moon and plays with the Moon's low gravity not be in the theme?!
  • Too bad we can't see the snale's length at the beginning of a puzzle: exactly! When the puzzles start, I wanted to show the snake entirely, rolled on itself or in a zig-zag shape, so that the player can have an idea of its length, but I never had the time to implement it.
  • Very similar to LOSSST 2017: thanks for remembering it! It's a reboot-sequel of that game, but about half of the puzzles are brand new.
  • Could not play: huh?
  • Graphics are inconsistent: billboard trees vs fixed signpost. Gradient vs textures: Huh. now that you say it... it's true indeed!
  • Reaching Par scores isn't an interesting enough challenge. It consists too much in redoing it without errors: I agree, it should have another goal than just displaying a medal in the puzzle selection screen. Steps backwards (to fix a mistake) should also reduce the steps count to make this challenge less annoying!
  • It was a lot longer than I thought: ugh, same.
  • Too many puzzles / too easy / hard puzzles arrive too late in the game: you're totally right. I've been a bit stubborn to keep most of the easy puzzles in, but the difficulty curve could/should have been much steeper!
    A stricter selection would also have solved the "too repetitive" issue if each new puzzle brought one important change or challenge, instead of having sometimes many puzzles revolving around the same idea.



Conclusion


A huge thank you to everyone involved in the organization, the people making tools, the people making games, the people testing our games... as every year, it was a great pleasure to exchange and play with y'all!

Here are a few highlights:

  • Bence: Thank you so much for your SVG textures, and for playing my entry at 100% while providing precious feedbacks.
  • Jsgreg: thanks for testing the game and showing me how the wall projection's logic could be unintuitive at first.
  • Calada2: thanks for all your help and expertise with CSS3D. Your CSS3D portal is also super impressive!
  • My friends Adrien, Sam, Damien, Victoire, Nghia, Tristan, Anouk and Julien: thanks for all the beta-testing, emotional support and constructive criticism during this month!
  • Sam even designed a tricky puzzle for me (3-25) !
  • Damien helped me design and find the shortest solutions for a puzzle that I spent a lot of time making (1-49)
  • Jaburns: thanks for being present on Slack all this time, for brainstorming new mechanics with me and for all the beta-testing and bug-hunting you did for my game. I really like your game Galaxy rider too!
  • Ed Lynch for using my MP3 collection GameBundleAudioMp3 in his entry Space in space
  • Faisal Rahman for using my miniSoundEditor tool in his entry Fill the space
  • Harsanalif for also using miniSoundEditor in his entry Slip
  • Slashie + Mapedorr + QuietGecko for using my miniSVGcreator tool in their entry Distant friends
  • Johan Wigert for using my tool amphabet-piano in his entry Moon Buggy Racing
  • Mattia Fortunati for mentioning the favicon emoji trick in his game template
  • AndreJaenish: thanks for pointing me to the right midi parsing library!
  • Slashie, Gogoprog, Barhatsor, Cino_power, Matthieu_me, Elsassph, Benjymous: thanks for helping me to build my mobile app
  • Herebefrogs for mentioning my miniSynth tool in the making-of of his game 2001: A space Opera. It made me realize that this tool, that I coded by reverse-engineering an existing JS synth, had been double-reverse-engineered by Vertfromage here to produce a code snippet that was useful for both of them.
  • Sasha, Near and Dietrich (NEAR/IPFS evangelists) that have been super patient and helpful with me despite me being absolutely incompetent with their technologies.

    To conclude, I'm very happy with my tenth game, ranked tenth in the tenth edition of js13kgames. Many things could have been done better with unlimited time and space, but it turned out fine.

    Maybe the daily dev timelapses were quite a waste of time though.
    They took me like 20 minutes each day to create / upload / promote, but barely got any views. Welp, nevermind.

    I hope my next entries (in WebGL this time?) will be as interesting to make and to play.

    And if you read until here, here's a little cheat-code for you: you can use keys N and P in-game to quickly pass to the next or previous puzzle.

    See you next year! (and on the App stores until then, if all goes well)

    Maxime