JS13k'24: GREAT PLUMBER 65, EMOJIPHOBIA & O HIII BAD SKATEPARK
August-September 2024

Hello! It's the 13th edition of JS13KGames. The theme is Triskaidekaphobia (the phobia of number 13).
TL;DR
This year I released 3 new tools:
- Pxtex: a random pixelized texture generator
- MicroW: a basic WebGL renderer in less than 1kb
- MiniGameTemplate: a modern, editable HTML5 game template in just 100 lines of code
... and 3 games:
- GREAT PLUMBER 65, a 3D platformer tech demo inspired by a childhood game...
Ranked 100th on mobile and 50th on mobile
See the source code on Github!
- EMOJIPHOBIA, a quiz game about phobias and emoji, with more than 280 to discover...
Ranked 63rd overall, 32nd on mobile, 3rd on Avalanche and 6th on Thirdweb
See the source code on Github!
- O HIII BAD SKATEPARK, a "Line Rider" clone with skates, balls and extra challenges...
ranked 110th overall and 1st in OP Guild challenge
See the source code on Github!
The full story (with spoilers)
SUMMARY
- Introduction
- Days 1-11: GREAT PLUMBER 65
- Days 12-21: EMOJIPHOBIA
- Days 22-31: O HIII BAD SKATEPARK
- Conclusion
Introduction
At the beginning of July 2024, I hadn't really been able to enjoy coding for a couple years, and had serious doubts about competing in js13kgames this year. Focusing on code had become too hard for me.
By chance, I stumbled upon JaidenAnimations video "I found out I have ADHD.", which made me decide to consult a specialist, get an actual ADHD diagnosis, and the appropriate medication.
And it was exactly what I needed. After a couple days, my brain was fixed and I was again (actually, more than ever) able to think, focus and create stuff, many hours a day... and do it with actual pleasure!
JS13K 2024 is officially uncancelled! Get ready for an unusually productive summer...
While waiting for JS13k to start, I spent most of July replaying every single JS game I had made for the past 10 years, in the form of an X thread. The playthroughs durations range from a couple minutes to almost 3 hours (for my 2021 entry LOSSST).
On august 13th starts the 13th edition of @js13kGames.
— xem 🔵 (@MaximeEuziere) July 1, 2024
I've also been making code golfed JS games for 10 years.
Instead of a tips/tools thread, I will do a thread of me replaying all the games that I have developed so far and see if thay still work and if I can beat them in 2024!
I was overall very pleased to rediscover my old creations, most of them being playable in 2024 and offering a real experience to the player (that's the case of all the js13k entries made since 2015, but more particularly the ones made after I got into CSS3D and emoji).
August 2024
August has arrived, and there are another 13 days to wait until the start of the jam. How about working on tools that could become handy if I make an actual 3D WebGL entry this year? (after 7 years of making all my 3D games with CSS3D)
The vague idea of an entry inspired by Mario 64 has been in my head for many years, and if I actually try to do it in this edition of JS13K, one thing I will need for sure is a tiny pixelized texture generator to represent surfaces like rock, grass, sand or water. LOSSST 2021 used Bence's amazing SVG textures, but this time I want something much, much smaller, more generic, and pixel-y!
And that's how I invented ptex: a 228 bytes long JS function that takes a HTML canvas, a HSL color, a noise coefficient and a size, and outputs some yummy randomized pixel-art textures ready to use as base64 pngs.
The tool is actually as simple as it sounds (it draws colored squares on a canvas), but was still very well received in the js13k community:
- It was featured in GamedevJS's newsletter and on X:
Just before the start of @js13kGames tomorrow, long time participant and legendary creator of multiple useful mini tools, @MaximeEuziere, released another one: Pxtex – mini randomized pixel-art textures.https://t.co/6PKkqfZsyB#js13k #gamedev #gamedevjs #JavaScript #codegolf
— Gamedev.js (@Gamedevjs) August 12, 2024
- And another dev, Lewis Nakao, made a cool UI around it:
Just so I could play around with #pxtex by @MaximeEuziere, I made a tool and figured it might be useful to others in the #js13k. I had to figure out the "max" values for each parameter. The Hue value wraps at 360.
— Lewis Nakao (@lewdev) August 19, 2024
⛏️ https://t.co/PH0IJ7OgRN
Source Code: https://t.co/bNfMNPXFgJ pic.twitter.com/PpBB7np7Zz
The second tool that I wanted to make was an absolute minimal WebGL boilerplate to display 3D shapes on screen.
I created W.js in 2020 with the help of @Stas and @Kchplr, which was full of cool features and as small as possible (2kb zipped), but I wanted to see how low we could go by keeping only the bare essentials:
- Render planes and cubes out-of-the-box
- Render custom 3D models based on vertex / uv arrays
- Coloring, texturing and support for transparency
- Easily set camera and objects' position, rotation and scale.
- Automatic shading from diffuse and ambient light
The features left out are: billboards, animations, smooth shading, normal arrays, indexed models and groups.
They were amazing features of course, but took too much space.
I first tried to start from W's source code and trim everything I didn't need, but the result remained too verbose. So I restarted from scratch, with a different model.
Now, the scene (with its clear color, camera, light and 3D objects) is entirely defined in a JSON object.
WebGL's z-index is not friends with transparency. W.js had a built-in function reordering every item on-the-fly, but here, to make things simpler, the objects with transparency just need to be declared in the correct order (from back to front) to be displayed properly.
The library only contains a function called W.render(), which can easily be called once, or 60 times per second for a game loop, and the cube's 3D model. (the plane model comes for free, by ony rendering the front face of a cube).
Thanks to these extreme simplifications, I was very proud to see the result fit in 1kb zipped.
I released it with 3 interactive demos and called it MicroW.
New mini gamedev resource for @gamedevjs & @js13kgames 2024...
— xem 🔵 (@MaximeEuziere) August 13, 2024
MicroW: a WebGL renderer in less than 1kb!
- Built-in shapes (cube, plane)
- Custom shapes
- Coloring, texturing, alpha-blending, lighting
- Free position, transformation for camera & objectshttps://t.co/X422ZQrODB pic.twitter.com/I7GE5ZOPsA
Some feedbacks on MicroW:
@mcfunkypants: "WOW!!! amazing work!"
@joao: "Awesome :) i used your W in my gamedevjs entry this year"
@mvasilkov: "Epic as always :) I pledged I'd learn WebGL for this year's compo but alas :("
@FrankForce: "amazing work! i will be using this for reference as i am planning to go 3d this year!"
@soylentgraham showed me an even more compact way to declare the vertex coordinates of my 3D models, using gl_vertexid (skipping attribute buffers entirely):
// GLSL cube
vec3 GetLocalPosition(int v){
int x = ivec4(915775499,923195439,642272978,49129)[v/30]>>v%30;
return sign(vec3(x&1,x&2,x&4));
}
Seems magic. I'll look into this!
Another challenge I started at the end of July is implementing my own 3D physics engine in JS (because all the existing ones weigh more than 100kb). I've bought and read some books and ebooks related to this topic but didn't manage to get past collision detection yet.
This project shows how far I could get while waiting for js13k to start.
It's incomplete, but I will try again later. In the meantime, I shared my favourite books with @cody who will try to use it for his own entry... good luck to him !
In early August, @end3r advertised js13kgames 2024 on Dwitter with a 140b countdown.
It gave me the idea to make a series of little Dweets to advertize the jam, too:
- What are 13,312 bytes?
- Typical js13k project size
- JS13k logo (using a Path2D)
- JS13k 2024 tshirt (using a black t-shirt emoji and little red Unicode characters that look like gamepads)
While doing these, I also contributed to Dwitter with an easier-than-ever Dweet packer: paste your code in the field (up to 194 ASCII chars) and it's instantly converted into a 140-chars snippet...
...and a dweet about olympic games held in my country at that moment (I didn't have enough room to make the rings overlap correctly).
DAYS 1-11: GREAT PLUMBER 65
DAY 1
It's finally August 13th! The theme is Tristaidekaphobia and... it gives me no ideas at all.
I scribbled some vague ideas on my notepad such as "maths game", "fear game", "puzzle with 13 pieces", "puzzle where you're limited to 13 moves", "Apollo 13", "avoid number 13", "avoid good luck"...
But nothing clicked so far.
(At the end of the jam, I was pleased to see that other contestants had made very good games based on some of these ideas, and much better than I would have done myself.)
I looked on Wordsmith.org if there were good anagrams of the theme.
Triskaidekaphobia contains the letters of interesting words such as skateboard, skatepark, karate kid, bishop, parakite, parasitoid, idiopathies, apartheids, editorship and database...
It's hard to make a full sentence with these letters though.
We can write weird things like:
"I, bishop, karate kaid"
"I'd hoist a bike parka"
"A pariah debit kiosk"
"It spied a khaki bro"
... or even...
"Bad skatepark, o hiii".
None of these phrases really inspire me. The last one could maybe be a pretext to do a Line Rider clone...
While waiting for a better idea to come, I tried to make a quick prototype of 2D skate simulation based on my Mini2DPhysics engine, with the skate and the skater being two different entities, and found that it worked quite well! Who knows, it could become my plan B...
DAY 2
Hmm. Yeah, there's that skate idea, but it lacks some "Wow effect".
I'd like to do something more impressive... such as the Mario 64 demake idea I've had for years...
Then it hit me: Nintendo sometimes strikes the fan games that infringe their IPs. A deformed version of the theme could look like "Strika-Nintendoka-Phobia", which would be a made-up fear of being striked by Nintendo. Okay, let's do that!
Let's make a pact with the devil @end3r to launch the project!
Ideally, I'd like to do a complete demake of Mario 64 in 5 chapters, five actual JS13K entries that would be able to share data and assets with each other, and I would call the game something like "GREAT PLUMBER 65", because 65kb = 5 x 13kb. Though, I know the task would be too immense for a single dev, with such size and time constraints, so I'll probably go with something much smaller, in a single entry, but as impressive as possible. The intro and castle's outdoors will certainly be enough.
I started by unearthing and connecting together two of the tools I invented a few years ago:
- 3Dmapeditor
- Mini3DPlatformer
Both tools weren't made to communicate with each other, and do not share any code whatsoever (the former is made in CSS3D and the latter in WebGL), but I made them communicate through a common ASCII export that represents the level. 3Dmapeditor outputs it, and Mini3Dplatformer parses it to construct its scene.
I'll show my progress on X and Slack, but I will hide all the Mario references, to avoid spoilers! (even the Mario 3D model present in Mini3Dplatformer got replaced by a brown parallelepiped).
To make this (rather unholy) communication work as I want, I first had to make Mini3DPlatformer able to display different kinds of cubes (grass, sand, rock, roof and water).
Then, I added slope blocks in both tools:
In 3Dmapeditor, the edits made to my generic 200*200*200px cube consisted of hiding the up face, slanting the front face, and clipping the left and right faces as triangles, with CSS:
/* slope */
.s3 .up { display: none }
.s3 .front { height: 282px; transform: translate3D(0,-82px,0) rotateX(-45deg) }
.s3 .left { clip-path: path('M0 0L200 200L0 200Z') }
.s3 .right { clip-path: path('M200 0L200 200L0 200Z') }
In Mini3DPlatformer, which is based on W.js, I added the slope 3D model manually:
// SLOPE
//
// /\
// |\ \
// | \ \
// | \ \
// |___\/
W.add("slope", {
vertices: [
.5, .5,-.5, -.5, .5,-.5, -.5,-.5, .5, // front
.5, .5,-.5, -.5,-.5, .5, .5,-.5, .5,
.5, .5,-.5, .5,-.5, .5, .5,-.5,-.5, // right
-.5,-.5,-.5, -.5, -.5, .5, -.5, .5,-.5, // left
-.5, .5,-.5, .5, .5,-.5, .5,-.5,-.5, // back
-.5, .5,-.5, .5,-.5,-.5, -.5,-.5,-.5,
.5,-.5, .5, -.5,-.5, .5, -.5,-.5,-.5, // down
.5,-.5, .5, -.5,-.5,-.5, .5,-.5,-.5
],
uv: [
1, 1, 0, 1, 0, 0, // front
1, 1, 0, 0, 1, 0,
1, 1, 0, 0, 0, 1, // right
0, 1, 0, 0, 1, 1, // left
1, 1, 0, 1, 0, 0, // back
1, 1, 0, 0, 1, 0,
1, 1, 0, 1, 0, 0, // down
1, 1, 0, 0, 1, 0
]
});
I ended the day by making a little sample level containing pretty much all the items I'll need in my entry: ground (made of grass, sand and water blocks), obstacles (walls and slopes) made of rock, and a billboard tree.
This area will be my 3D platforming playfield for a few days!
So I'm unearthing the 3D map editor (in CSS) & the 3D platformer template (in WebGL) that I started making years ago, and trying to connect the two.
— xem 🔵 (@MaximeEuziere) August 14, 2024
If I don't get stuck, I'll try to make a 3D platformer that could maybe fit the theme.
Otherwise... I'll need a plan B!#js13k pic.twitter.com/m2P16YR9UY
DAY 3
After yesterday's quick prototyping, let's include the unminified version of W.js and the code of mini3Dplatformer with my little sample level into my index.html file. Bam! It's already 31kb.
Here, my little PoC (Proof of Concept) is taking shape, with ground collisions, (buggy) wall collisions, plus some basic character movement and rotations.
Contrary to Mario 64, I took the liberty to always have the camera behind the character, otherwise the code required to make pleasant and fluid controls would have been too complex to implement.
By the way, I'll keep using W.js (instead of MicroW) in my code because this project requires groups, animations and billboards, which are only present in W.js.
DAY 3
— xem 🔵 (@MaximeEuziere) August 15, 2024
Added movement, rotation, cube collisions and billboards (the tree plane always facing the camera).
Since it's a PoC, my collision code is still hacky.
To makes the slopes work, I have to rewrite it in a more clean and generic way.
Hopefully it'll be done tomorrow!#js13k pic.twitter.com/mznhUdf5WA
In the meantime, I secretly worked on the title screen of my entry. I wanted it to look like Super Mario 64's title, but with a different name (Great Plumber 65). Instead of drawing it on a canvas or using SVG, I decided to use a Web font that I found online, specially created for this: Typeface Mario 64.
The font is in otf, weighs 10kb and contains way more characters than I actually need, so I searched (and found) a great software called FontForge, which allowed me to edit the font, delete all the chars I didn't need and save it in woff2 format, reducing it to just 1.5kb!
With some HTML and CSS on top of this font (namely, custom colors, scale, letter-spacing, text-stroke and multiple text-shadows for the depth effect), I managed to make this (very convincing ?) title screen!
(I realize a bit late that I could have added a bit of CSS3D to slant the text a little...)
(click to start! As a bonus, you'll see a little entrance animation and hear a coin sound from MiniSoundEditor).
The whole intro weighs 2.4kb zipped.
I tried another version, spelling the word StrikaNintendokaPhobia, but it was not as good.
In a desperate hope to save a few hundred bytes in my zip, I suggested @end3r to do a poll about allowing to load Webfonts for free, but it didn't convince enough people. So I'll keep my woff2 file on board!
I also made some quick tests of speech synth with a male and a female voice (before realizing how deep the rabbit hole of speech synth voices can be):
DAY 4
On day 4, I had so much progress to share that I made four X posts, instead of the usual 1 or 2.
The first one shows how I added black debug spheres on every integer coordinate of the ground, and red ones at the corners of my hero. These spheres not only ensure that all the assets are well aligned with their coordinates (a 0.5 or 1 unit offset offset can easily go unnoticed!), they also surround the hero with an axis-aligned box (if you look closely, the red spheres never rotate with the hero, they stay aligned with the integer grid. This is the first step towards good collision detection.
The second post shows a new set of (blue) debug spheres at the bottom of the hero. In fact, I implemented a "collision()" function that tells for any (x, z) coordinates, what's the height of the level geometry at these exact coordinates. The four blue spheres that follow the hero's bounding box, represent the result of this function. That's why you can see these spheres climb on slopes and cubes in the video (collisions were removed entirely at this moment).
DAY 4
— xem 🔵 (@MaximeEuziere) August 16, 2024
I added a blue set of debug spheres at the bottom corners of the AABB: at each frame, I place them at the height of the scenery block present at their coordinates (1 for cubes, 0 to 1 for slopes).
Now let's use that data to do the collisions and slopes work properly.#js13k pic.twitter.com/0SY7vs02ks
The "collision" function that computes the level's height at given coordinates was surprisingly easy to implement (it always returns 1 for cubes, and the decimal part of the X coordinate for a slope going to the east. the 3 other slopes directions are computed in a similar way, by using the decimal part of Z for a slope going to the south, and by substracting these values to 1 for the east and north slopes).
The next step was to use the height of the blue spheres to interact with the environment:
- hero.y represent the height of the hero's bottom (hero.y = 0 means that he's standing on the ground)
- If a blue sphere has a height > hero.y + 0.2, a wall is hit. Stop moving.
- If a blue sphere has a height between hero.y and hero.y + 0.2, we're at the beginning of a slope. Set hero.y to the height of the highest blue sphere.
hero.y = Math.max(nw, ne, sw, se);
I spent the rest of the day trying to make "sliding" wall collisions, because it feels weird to be completely stopped when we touch a wall in a platform game. It's much more pleasant to see the hero slide against it. To do so, I tried to apply an opposite force every time we try to walk against a wall. Unfortunately, it gets buggy every time we walk into a cube's corner. Both adjacent faces fail to properly reject the hero at the same time and he's able to walk inside the cube...
DAY 4, part 4:
— xem 🔵 (@MaximeEuziere) August 16, 2024
Sliding collisions against walls work almost fine, as well as going up and down slopes, and all it took was that small code on the left.
It's not perfect though (see at the end of the video, it still bugs a little from certain angles)
But enough for today!#js13k pic.twitter.com/7lEsbItZys
DAY 5
It took me many, many hours between days 4 and 5 to find the correct way to implement these (damned) sliding collisions, but I finally managed to do it. The good and probably unique way to do this properly and without bugs is this one:
// At each frame
// (...)
// Save previous hero X and Z coordinates
lastx = hero.x;
lastz = hero.z;
// Go front / back
if(keys.u || keys.d){
// Compute new deltaX and deltaZ based on hero's angle and walk speed
dz = (-keys.u + keys.d) * Math.cos(-hero.rcamera*Math.PI/180) / 20;
dx = (-keys.u + keys.d) * Math.sin(-hero.rcamera*Math.PI/180) / 20;
// Add deltaX do hero.x
hero.x += dx;
// Check collisions all around the hero
nw = (collision(hero.x-.15, hero.y, hero.z-.15));
ne = (collision(hero.x+.15, hero.y, hero.z-.15));
sw = (collision(hero.x-.15, hero.y, hero.z+.15));
se = (collision(hero.x+.15, hero.y, hero.z+.15));
// If one collision is with a wall ( > hero.y + 0.2 )
if(
nw > hero.y + .2 || ne > hero.y + .2 || sw > hero.y + .2 || se > hero.y + .2
){
// Go back to the last non-colliding x position
hero.x = lastx;
}
// Then do exactly the same with deltaZ and hero.z
hero.z += dz;
nw = (collision(hero.x-.15, hero.y, hero.z-.15));
ne = (collision(hero.x+.15, hero.y, hero.z-.15));
sw = (collision(hero.x-.15, hero.y, hero.z+.15));
se = (collision(hero.x+.15, hero.y, hero.z+.15));
if(
nw > hero.y + .2 || ne > hero.y + .2 || sw > hero.y + .2 || se > hero.y + .2
){
hero.z = lastz;
}
}
// (...)
This problem being out of the way, I could finally start working on my textures!
I generated four 20x20px textures with pxtex and put them in <img> elements at the end of my html page, as well as a <svg> element containing a tree emoji 🌳. It was super easy to tell W.js use these 5 textures in my scene instead of flat colors.
I also had the idea to make the grass, sand and water blocks have slightly different heights, to make the ground look less flat. Since their hit boxes aren't modified, it will even give the impression that the hero's feet go deeper in the grass than they do in the sand.
(As you can see, I tried different textures for the water until I found the one that I liked)
DAY 5, part 2:
— xem 🔵 (@MaximeEuziere) August 17, 2024
Micro texturing time!
- Removed the debug spheres.
- Stylized my grass/sand/rock pieces with different heights and four 20*20px textures generated with pxtex (featured in GameDevJS newsletter!).
- Used <svg><text>🌳</text></svg> in an img as my tree texture.#js13k pic.twitter.com/UuhvNB1UQh
I spent the rest of the day making a different level, with more "layers" of cubes, more slopes, and red pyramids (to represent the castle's roofs). By chance, pyramids already existed in 3Dmapeditor and W.js.
To make things simpler, these pyramids don't have collision boxes at all. You can walk through them.
I also made the jumps smoother and added a basic swimming state (the hero's height gets a bit lower when its four blue hit spheres touch water).
In the end, the thing that took most of my time that day was the tree. I've been doing js13k entries with emoji since 2017, and every time they cause problems. The main problem being that they don't appear with the same graphics on every OS and browser. Some OS will only show them in black and white, or not at all. Worse even, depending on the OS and browser used, they will have different horizontal and vertical offsets. The same tree could be fine on Windows, buried in the ground on Mac or flying in the air on Android.
The solution I found in 2018 was to convince @end3r to allow emoji webfonts polyfills for free in the jam's rules. Ever since, I've released many projects aiming to democratize uniformized emoji for js13k entries, the latest being soberly named unicode13 (the polyfill itself can be found in the unicode13/emoji page).
So, I loaded this polyfill in my game and wanted to use it for the tree texture. I couldn't make it work while the tree texture was a svg, so I reused pxtex's canvas to draw a big emoji tree with the right font, on a transparent background, export this canvas as a png image, and use this image as a WebGL texture. That's the tree you can see in the video below.
DAY 5, part 3:
— xem 🔵 (@MaximeEuziere) August 17, 2024
- Changed the map
- Added pyramids and a roof texture
- Added swimming
- Replaced svg emoji textures with emoji rendered on a canvas with the Twemoji webfont (for cross-browser consistency)
- Trees are bigger
- Your feet get lower than the grass surface#js13k pic.twitter.com/ooXSSIuUtd
Here's my texture atlas so far: five 20x20 pxtex images, and one 200x200px tree emoji. Thanks to them, the scene will look the same for everyone! (the tree doesn't touch the bottom of the image to compensate the grass's extra height.)
DAY 6
Here's the last public update made on X about this entry: it contains a new map with more trees, doors, fences and a flag.
DAY 6:
— xem 🔵 (@MaximeEuziere) August 18, 2024
- Added new elements (fence, flag, doors)
- Made trees and hero bigger, compared to the scene
- When swimming, movement speed and jump height are lower.
- On land, it's possible to double-jump (the second jump is a bit higher).
No more spoilers until release! 👋#js13k pic.twitter.com/ZkYrKsIJC7
The doors and flag are generated from the emoji webfont. The fence is drawn on a canvas with "fillrect()" (and enhanced with a horizontal gradient a bit later).
Fences and doors are fixed planes, contrary to the trees and flags that are billboards (always facing the camera).
The left door is the same as the right one, but flipped horizontally. The left door is aligned on the right and the right door to the left, so they can easily be applied as textures over two neighbour blocks.
I also added hitboxes to the fences, but here too, it's very basic. The collision function says that their height is 1 if the decimal part of the Z coordinate is over 0.8, and 0 otherwise.
You can see in the video that the fences don't have back faces: they become invisible when you walk behind them. To fix that, I had to use two planes, one for the front, and one for the back (rotated 180 degrees).
A weird Webkit bug occurred while setting ids for my fence texture image:
HTML:
<img src="..." id=fence>
JS:
console.log(fence) // null
console.log(window.fence) // null
fence = "test";
console.log(fence) // null
Yup. "fence" is somehow a reserved word in Webkit browsers, you can't use it as a variable. It's always null. It took a lot of head-scratching before figuring this out (I thought the problem came from my texture), but when I finally realized what it really was, I just renamed my fence as "fenc". Suddenly, everything worked fine.
This is the texture atlas at the end of day 6:
DAYS 7 to 11
The last 5 days of development were not shared publicly. I'm gonna tell you here what happened during that period. I worked on a bunch of things simultaneously, so I'll present them to you in 10 chapters...
1) Speech synth: while I was working on the title screen, I made a few tests of Speech Synth, and started explaining that it was a deep rabbit hole. It became even deeper when I started working on the second screen, where the princess reads the letter. The thing you need to know about the JS Speech Synth API is that the browsers barely have control on it. The only thing browsers do is request the OS to read a given text using a given voice. Many problems can occur at this point:
- Warm-up delay: some browsers (especially Firefox and Android's mobile browsers) can't request the OS's list of voices and return them instantly.
speechSynthesis.getVoices()
will return an empty array on the first call, and an actual list if it's called again a few seconds later.

- The list of available voices is pretty much unpredictable, as it depends entirely on the OS. The list returned by the API includes names and language codes, but there's no way to know if a voice is male or female. I can only try to predict if a voice is male or female based on its name.
So I asked on js13k's slack for volunteers to execute this line of JavaScript on their setup and show me the results:
speechSynthesis.getVoices().filter(a=>a.lang.startsWith("en"))
.I received enough samples to create a list of 21 female and 16 male english voices, which I put in two regexes.
// Known male/memale speech synth voices (thanks to people on Slack for giving me theirs)
female = /Female|Google US English|Susan|Hazel|Zira|Shelley|Grandma|Sandy|Martha|Aria|Priya|Heather|Hayley|Samantha|Catherine|Karen|Tessa|Moira|Kathy|Rishi|Libby/;
male = /Male|George|Rocko|Daniel|Grandpa|Eddy|Reed|Fred|Ralph|Mark|David|Arthur|Guy|Aaron|Albert|Jester/;
When I have a text to read with a male voice (ex: "It's a me, the great plumber"), I check if any of the available voice matches the male regex. If one does, use it. Else, use the first english voice available by default (even if it's female). The same thing goes for when I need a female voice (ex: "Dear plumber, please come to the castle...") and the female regex.
2) The princess' letter: Between the title screen and the introduction, I wanted to reproduce the scene from Mario 64 where princess Peach reads a letter to Mario. I decided to reproduce this scene with HTML, emoji and CSS.
The thing is, there's no emoji that represents a side view of a princess. My friend @KorHosik and I looked through all the emoji available, and found the crown emoji (already used in my 2023 entry) and an emoji representing a blonde woman, looking down, in side view, holding/feeding a baby. After some resizing, positioning, rotation and cropping, I think I managed to do something quite resembling!
Another thing I needed to do well was the letter's font. There's no system font using pixel-art and I don't want to draw one by hand. Thankfully, the game's font is also available in ttf format (and weighs 15kb).
After a bit of trimming with FontForge (and editing the lowercase L that was strangely too much on the left - so much that "click to start" written in this font really looked like "dick to start" - by chance FontForge includes a very nice glyph editor too), I could export a 2.1kb woff2 file containing all the letters I needed for my game.
The rest of the letter is basic HTML and CSS.
3) The final map
When I considered my platformer engine good enough, it was finally time to create the actual princess castle...
I started by making sketches on paper, with the help of the amazing noclip.website visualizer, to determine the size of my map, which was initially 28x25 blocks, then reduced to 25x20, when seen from above.
Of course, it's a demake, so a lot of details will be omitted to make it fit in 13kb, and everything will look more flat and cubic than in the original, however I already knew that it could look good because I had already made a (much smaller) 1kb Peach Castle demo for js1k 2019:
Then, I drew my castle with 3Dmapeditor, layer by layer, by leaving every invisible block (inside the castle and below the ground) empty to save space and improve rendering performances. It took me half a day, and initially took 21 layers. (Later, after realizing that my slopes collision detection didn't work well on heights higher than 1, I edited it down to 18 layers, reducing the ground's height to a single layer, at water level.
I was surprised to see 3Dmapeditor, made in CSS3D, support very well the creation of such a big map. Below are some work-in-progress screenshots. You can remark that I added basic window 🪟, fence 🚧 and princess 👸 emoji in the editor and that the roofs are in "ice" color instead of red. The roof pyramids are also shown as one little block, but in the final entry, they will be scaled up to cover a larger area (like I had done in JS1K, by the way).
After copying the editor's ASCII output into my index.html, feeding it to my 3D platformer's renderer and making dozens of little adjustments manually, it was indeed much more pleasant to look at!
Oops, that's an off-by-one error. Here it is:
Ah, that's a good first draft. Take a look at the water pool blending with the background sea, compared to the original on N64:
I iterated on the castle's map, textures and overall rendering for 5 days to reach the version that you can see in the final release.
After showing the first draft (using W.js's directional light) to my friend Julien, he suggested that I improve the light, because everything looked too flat.
So I reopened my WebGL tutorial from 2020 and used it to replace W's directional with a point light, placed in the sky, near the entrance of the castle. I also added a little offset to the 3 roofs of the castle, to have them stand out a little from the walls below them.
It's a few small changes overall, but I believe it makes the scene look much, much better, so thanks for the idea!
4) The performance issues
The castle's map contained more than 1200 blocks in the first version, and 1003 after removing a few layers. Each block represents either a cube, a slope, a plane or a billboard, with textures and transparency (for the planes and billboards). W.js had never been tested with such a charge, and performance was crawling, even on my high-end PC.
But I've never optimized a game! How do we do that? where should I start?
Oh, I know, sorting things is expensive. I remembered that W.js reorders all textured objects from back to front before drawing the scene (because WebGL needs that to handle transparency). But in my scene, everything is textured, and it's ridiculous to reorder 1003 elements 60 times per second!
So I plunged into W's source code and created a "transparent" array containing only the planes and billboards of my scene. Suddenly, the sorting was done on 49 items instead of 1003 (yeah, the trees, doors, windows, flags and double-sided fences represent 49 elements).
The second improvement I could think of was to perform the sorting once per second (i.e. once every 60 frames) instead of doing it at each frame, which is largely enough, as the transparent elements order doesn't change very quickly when we walk through the map.
After that, the game became fluid on my PC, but also on my phone, so I didn't bother looking further.
I know that a huge improvement could have been to do some sort of batch rendering instead of doing 1003 draw calls at each frame, but unfortunately, I haven't learned how to do that yet and didn't want to lose time learning that during the jam, so I stopped there for the optimizations!
Note: it's still possible to see the effect of this 60-frame refresh time when you go between two trees and rotate the camera quickly: the "far" one will overlap the "close" one for a few frames.
5) Background and extra textures
While experimenting with my 3D platformer engine, I got bored with my blue uniform background color, so I wondered if it would be difficult to do some kind of skybox, or skysphere, like the ones present in Mario 64.
I set my texture canvas size to 512 x 512 px, filled the bottom half with the same pxtex formula used for the water (most of the entry's loading time is spent generating it, by the way), and the top half with a blue gradient with some cloud emoji.
I tried applying this texture to a big sphere, 5 times bigger than the level, but there was a problem called backface culling! In other words, the sphere is made of triangles whose normals point to the exterior, making the exterior of the sphere textured and the interior transparent (similarly to fences planes only visible from one side).
And how do we invert the normal of a triangle? Easy (when we know it): declare the triangle's vertices in reverse order. If the triangle ABC points to the exterior, then the triangle ACB points to the interior.
So, I edited the W.js function that generates spheres to make it output the vertices coordinates in reverse order, and it worked like a charm on the first try! (NB: this function is not written by me, I understand very little of how it works).
To make the sphere look good visually in real conditions, I had to adjust some cloud positions, as close to the horizon as possible, so they don't get cut because of a triangle edge, or distorted because of their closeness to the sphere's north pole.
Fun fact: during development, I couldn't understand why the cloud emoji were cut when they were placed too close to the edge of a triangle, but I realize it now while writing these lines: I reversed the triangles vertices coordinates, but forgot to reverse the uv (texture) coordinates. This means that every triangle of my sky sphere has its texture flipped horizontally! Fortunately, with every cloud carefully positioned, this has no incidence on the final result.
Other fun fact: I had to make the sky sphere immune to the scene's point light, otherwise it would have been weirdly shaded. Thankfully, W.js got me covered, as it supported a "ns" (no shading) property, that I used on the sky sphere to avoid this:
The other items that were made immune to shadting are the trees, because I didn't want them to become randomly lighter or darker when ther rotate to face the camera.
The castle's walls still looked too monotonous for me. On N64, the bricks are visible.
After many attempts, my solution was to make the brick's pxtex texture 40 x 40px, and trace light gray lines over it with a repeating pattern:
For the princess mosaic, once again, I was ready to put a basic princess emoji there, but my friend @KorHosik was here to motivate me to do something better.
So I combined a crown 👑, a kneeling woman 🧎♀️ and a flower emojis 💐, and with the correct position, rotation, scale and cropping, plus a golden ellipse and a blue background, it made a mosaic pattern that I enjoy a lot!
(I don't know why I made an ellipse instead of this pointy shape... I guess in my memories it was an ellipse and I forgot to double-check when I coded it!)
I created a gradient texture very close to the one used for the fence, to apply on the wooden bridge:
On the last day of the project, I had a few dozen free bytes and decided to use them to represent the closed cannon near the lake, with a custom texture (it kinda looks 3D but it's just made of a circle and a few lines)
Last but not least (it's actually my favourite one!), I browsed the emoji list one more time to look for an emoji that could resemble Mario 64's windows a little, and stumbled upon... the pie emoji! 🥧
With the Twemoji Webfont polyfill, it can totally pass as a window, so I decided to use it with a bit of rotation and scaling, and a lot of amusement! There are pies on walls in my js13k entry and no one will remark it unless I tell them, haha!
Here's the full texture atlas at the end of the development:
You can remark that there are two wall textures (I kept one without bricks to put around the mosaic), and that the roof texture is bigger than the others (because the roof pyramids are scaled up).
6) The intro sequence
In my 3D platformer engine, the camera is placed in the same group as the hero, to follow him "for free".
But if I want to make an intro sequence that looks like the original, I must move the camera freely from the sky, to the ground, up to the hero's spawning point.
And, as you may know, in gamedev, dirty coding tricks are often the best solutions for a problem, so instead of finding a way to detach the camera from the hero's group until the end of the cutscene, I simply moved the hero's group around the map, just to have the camera follow it, and the hero's geometry was simply moved 10 units downwards on the Y axis to stay off-screen.
W.js already has an animation feature allowing to move/rotate an item from a position to another. I "only" had to find a way to chain animations in a fluid way to make the camera move between 12 different positions without any glitch (such as frame drops or animation overlaps). The implementation I ended up doing was rather elegant, where the animation code itself determines when the animation is complete and triggers the next one instantly.
It was also quite easy to make the 3D platform engine start at the end of the sequence (it would have been weird if the gravity, collisions and keyboard controls worked during the intro). The whole platformer engine code is simply placed in the 12th and final step of the intro, just when the hero appears on screen and the green pipe disappears. You can see the engine kick in when the hero falls on the ground.
// Intro animation
introstep = -1;
// intro() is called by W.js at the end of the animation routine, while introstep is < 12
intro = () => {
introstep++;
if(introstep === 0){
// Hide princess letter
princess.style.opacity = letter.style.opacity = 0;
// Move hero/camera at the top of the castle (hero is hidden)
hero.y = 12;
hero.z = -.5;
hero.x = 10;
W.move({n: "H", x: hero.x, y: hero.y, z: hero.z, a: 5000}) // move hero group for 5 seconds
}
else if(introstep === 1){
// ...
}
else if(introstep === 2){
//...
}
// etc...
else if(introstep === 12){
// Hide pipe
W.move({n: "pipe", y: -100, size: .01, a: 1});
// End of intro, start game loop
setInterval(()=>{
// entire game engine here...
}, 16);
}
}
At first I wasn't motivated to make the green pipe thing (I just wanted to make the hero fall from the sky), but my friends @KorHosik and Mia convinced me to do it and I must admit that it's much better like that... (It's just two green cubes, though, not what I'd call a lot of work).
One thing I voluntatily didn't include in my intro is the Lakitu (the little guy flying on a cloud with a camera).
When I made the intro's music afterwards, I adjusted the intro's timing so that it synchronizes perfectly with the duration of the melody.
At the end of the intro, mobile controls appear on mobiles and tablets. Making the buttons was not difficult, but detecting mobiles and tablets has become difficult in 2024, since Android browsers stopped including "Android" or "Mobile" in their user-agents.
I searched for a reliable way to detect handheld devices, but didn't find a lot of solutions (most of the StackOverflow answers still rely on user-agent). I ended up finding a window property that seems to be undefined on most desktops and an integer >= 0 on most mobiles and tablets: window.orientation, so I used that. I guess it works fine, as no one has complained since.
7) The hero
It was finally time to replace my brown elongated cube with a real character that looks like Mario. I coded it from top to bottom, with a bunch of cubes: 3 for the hat and head, 3 for the body and arms, 4 for the legs and shoes, colored with flat colors. I didn't bother modeling or texturing the hero's face as it's almost never visible.
When the hero moves to the front or the back, a walk frame counter is incremented, and the arms and legs receive an angle proportional to the cosine of this counter, making them swing from front to back and giving a good illusion of walk animation.
KorHosik suggested that an arm of the hero should stay in the air when he jumps. I guess it's a reference to Hitler the jump sprite in Super Mario Bros. Anyway, I implemented it.
When the hero jumps three times consecutively in a short period, I implemented a triple-jump system similar to the one in Mario 64: the second jump is a bit higher and the third one is even higher and adds a "roulade" in the air. It's the kind of small additions that add very few bytes and act as a fun easter-egg for people who discover it.
I also added colisions to the trees because it was weird to see the hero walking through them. However, to keep things simple, they have the same hitbox than a cube.
Finally, there's the question of water. I already implemented a basic "swim" position in my platformer prototype, but I enhanced it a little here, by adding an animation between the "standing up" and "swimming" positions. I also made the movement in water slower than on land, and the jumps from water reach a lower height.
I showed the result to @end3r, and he didn't judge that my work deserved a strike... I don't know how I should take it, haha! (For his defense, the castle's lacked its final mosaic and a few windows when I show it to him. It's probably more realistic now!)
8) Inside the castle
My entry needed some sort of ending, besides wandering around the castle. I first imagined modeling the interior of the castle with my map editor, but it would have taken a lot of time and a lot of bytes, for virtually no advantage (even if the castle's interior existed, it wouldn't have lead to any rooms or stages from Mario 64, it would just have been an empty room).
So I decided to do something simpler: I remembered that we talk to a Toad when we enter the castle in Mario 64, so I made a fixed screen containing a talking mushroom. It is composited in HTML using mushroom 🍄, mouth 👅 and eyes 👀 emojis.
I made it read a letter with a high-pitch female voice and a fast voice. Overall, a lot of the code from the princess' letter could be reused there. This letter was a good way to mention that the mushroom is a NPC (one of the decentralized challenges was to use NPCs) and to mention the strika-nintendoka-phobia (which is the only link between my entry and the theme of the jam!).
So yeah, it could have looked much better, but I chose to end up like that and use the remaining time to go work on other entries.
9) The audio
The audio part takes an important place in this entry:
- Speech synth was used for the title screen, the princess' letter and the mushroom's dialogue, but also for the plumber's triple jumps. Most of the players found these little "woo", "hoohoo" and "yahoo" voice clips funny, so I'm glad I kept them in.
- Both music tracks (the one you can hear during the intro, and the one you can hear after the mushroom's speech) were made from a list of notes extracted from Mario 64 MIDI files that I found online, using my midi2array tool. The first song has two instruments playing together, and the second, just one. The final song was 45 seconds long at the beginning, but I extended it to 1min35 before release because I had enough room to include the extra notes. The tracks are played using my mini piano synth.
- Finally, the sound effects. There are 7 of them: the coin sound (for the title screen), the wobwobby sound (for the pipe animation), the step soud (when the hero walks), the splash sound (when he enters water), the mini splash (when he swims), the water jump sound (when he jumps out of water) and the door opening sound (when he enters the castle). All of them come from my beloved tool MiniSoundEditor, created by Anders Kaare in 2016 and maintained by me since then.
10) Golfing and release
Keep in mind that besides prototypes, all my entry has been developed in a single index.html file. It is 2263 lines long. 636 lines are used by W.js and its shapes, 415 lines by the ASCII map, 223 lines by the 3D platformer engine and 170 lines by music, sounds and voices. All the rest was coded by me during the jam.
This year, I got no trouble navigating and editing this long file for 10 days. The same thing actually happened with my two other entries. After 10 years of competing with a ton of JS and CSS files, 2024 seems to be the year of the monolith.
Anyways, I knew the weight of my custom fonts (3.6kb) and I knew that W.js was about 2kb zipped. I didn't really keep track of my project size until the last day of development, imagining that there would always be enough time to golf and apply extreme compression tricks afterwards if needed. As a result, index.html is 71kb, and when I minified and zipped it for the first time on day 10, the index.html got reduced to 31kb, and the zip file reached 13,654b (13.3kb).
I thought I would have to golf my code a little (at least rename some variables names to 1 char), but I remembered that multi-file zips were optimizable with ECT, and when I used it, my zip containing the minified index.html and two woff2 fonts suddenly dropped to 13,302b (12.9kb).
DAY 10 (update):
— xem 🔵 (@MaximeEuziere) August 22, 2024
I forgot to run ECT on my zip. I won't need to golf it finally. It's already 10 bytes under the 13kb budget with a simple command line.
Also, it doesn't use Roadroller because it needs to do stuff as soon as the page opens, and other things after onload.#js13k pic.twitter.com/0bj54COoLv
I actually ended up renaming a few variables to have enough room for tiny improvements here and there (the pipe, the cannon, the grid texture and the extended final music), but nothing very complex.
One thing I did not use for once was RoadRoller. As I explained on X, my entry had to execute some JS code instantly when the page loads (preheat the Speech synth, preload the fonts, display the pre-title "loading" screen), and the rest of the code after the fonts were entirely loaded.
For the record, I forced the loading of the title font "m" and the twemoji webfont "emoji" by using them at the end of the "loading..." message (just hidden from plain sight, but here anyway):
<h2 id=load>loading...<span style='font:1px emoji;opacity:0'>🌳</span><span style='font:1px m;opacity:0'>G</h2>
Thanks to these two spans at the end of my loading title, the window.onload event didn't trigger until all the fonts were entirely loaded!
If I had really wanted to incorporate more content into my game, such as other areas to explore, it would have been quite easy to save at least two kilobytes. RoadRoaller would have been useable if I had tweaked my code a little to make it work with it, but most importantly, the two woff2 custom fonts could have been removed entirely: the title screen would have easily been drawable as a single svg file, and the alphabet pixel font, used for all the other text present in the game, could have been reproduced with some basic JS code (each character being represented by a grid of 5x7 monochrome pixels, easily encodable on 5 ASCII chars).
But on day 10, I had to make a choice: continue to compress and improve / augment my game until the end of the jam, or make another entry?
I chose to stop there, comment my code to help curious visitors understand how it was done, and then make another entry... because whatever I could have done in it for the remaining 20 days, my GREAT PLUMBER 65 entry would have remained a tech demo, only a slightly more impressive one. But if I made another entry, then it would be an opportunity to make a real and original game. And that's what I decided.
I released GREAT PLUMBER 65 right when the submit form opened, making it the very first and most visible entry in the list! I felt a bit lonely at first, but other entries quickly joined me in the games list.
DAY 11:
— xem 🔵 (@MaximeEuziere) August 23, 2024
After adding a few details, longer musics, commenting my code and golfing/optimizing my zip, I'm once again a few bytes below budget and ready to release my "tech demo" entry!
Does someone recognize this hint?
I'll spend the next 20 days on my second game! :3#js13k pic.twitter.com/distwibG4s
DAYS 12-21: EMOJIPHOBIA
Brainstorming
On day 12, I asked my friend @KorHosik if he had an idea for my next game. Something with actual gameplay and a strong link with the theme. We brainstormed for a bit about a game where we would hold some kind of shop where people could come and buy things that scare them. For example, someone enters and asks for a cynophobia, and if we give them a dog, it scares them and we score points.
I said I'll try to do something like that, and started by imagining how phobias could be represented in such a game. Naturally, the answer that came to me was EMOJI.
Listing
I spent about 5 days (on and off), constituting a list of 700+ real phobias from different online sources.
For each phobia of the list, I had the name, the definition, and little by little, I took the time to manually add an emoji for every phobia that could be represented by an emoji.
You may have heard of the wiki of phobias Phobiapedia, containing more than 5300 articles. This website is NOT a reliable source of information, as it allows real and made-up phobias. My list was only comprised of phobias found in at least 2 other sources than this wiki, to ensure that they are legit.
Emojification
After adding an emoji everywhere I could, I remarked a few things:
- There are a lot of duplicates. More precisely, a single phobia could have 2, 3, 4 or more different names. For example: "Cryophobia, Frigophobia, Cheimaphobia, Psychrophobia: fear of cold".
- I was sad to see that many emoji from my emoji list didn't appear on my list. So I took the most interesting ones, and googled them one by one: "Fear of ears", "fear of suitcases", etc. Most of them actually existed! This process allowed me to add an extra 44 elements to my list, mostly phobias specific to some animals (there are pretty much no animals that no one fears), but a few interesting others too. It also allowed me to create a separate list of phobias that DO NOT exist, which could be used in the game too. (For these made-up phobias, I invented the name myself based on the latin translation of the emoji name).
- Fears of colors are a thing that exists. I listed 11 of them, and since only 9 had a corresponding emoji (🔴⚪⚫🟣🟡🟠🔵🟤🟢), I cheated a little and added pink and gray as two rounded divs.
- Fears of numbers are in vast majority, almost every number has its phobia. To not bloat my game with such phobias, I kept the list simple: every number from 0 to 20, plus 30, 69, 99, 100 and 666. I represented them with Emoji digits.
- Some phobias could not be easily represented by a single emoji, but sometimes a non-emoji unicode character could do the trick (ex: wind ࿓༄ , stairs 𓊍...), or a combination of multiple emoji (ex: accidents 🚗💥🚗, being tickled 👣🪶, constipation 💩❌...), or even a mix of emoji and non-emoji characters (ex: dust .・:・🧹). Many combos were found thanks to the help of emojidb.
Final list and categorization
After cleaning up the majority of phobias that didn't correspond to an emoji (for example: fear of imperfection,
fear of being forgotten, fear of missiles, fear of coitus, fear of hearing good news, fear of novelty, etc...), and gathering together the ones that had multiple names, I arrived to a total of 280 emoji, with corresponding name(s) and definitions.
After adding them into different categories (Easy / medium / hard / colors / animals / numbers / countries), they formed my final list, and I was finally ready to start working on my game!
New game design
While working on my list, I thought about this shop idea and wondered how long it would be fun to play it... For me, it would be too limited or repetitive. But if we reduce the concept to its simplest form possible, what is the game about? It's about matching phobias and emoji. In that case, why not drop the shop idea completely and make a quiz game?
Sure, a quiz game where we match emoji and phobia names can be repetitive too, but I can surely find 13 original ways to ask my questions.
Here's my original ideas list:
- Name my phobia! You see an emoji and need to find the right name among 3.
- Scare me! You see a name and must pick the correct emoji among 3
- Save me! You see a phobia name and must find its solution
- Which phobia exists? You see 3 phobias emoji and find the real one
- Which phobia doesn't exist? You see 3 phobias emoji and find the false one
- Which phobia exists? You see 3 phobias names and find the real one
- Which phobia doesn't exist? You see 3 phobias names and find the false one
- name that phobia: rearrange syllabs
- Who do I scare? see a phobia name and pick who is affected by it
- Xenophobia: find the correct flag
- name my phobia: rearrange letters
- Scare me! You see a name and must pick the correct emoji in all the keyboard
- name that phobia: type the phobia name
- Associate 3 phobias with the right name (3 vs 3)
- find the phobia accociated to the right name (2 wrong / 1 correct)
- Numerophobia: fear of numbers
- Chromophobia: fear of colors
The best (and most doable) ideas ended up in the final game, with a few additions (to address the easy, medium and hard categories more explicitly).
The ideas where we have to rearrange letters or syllabs to form words, or to match N emoji with N names on the same screen were too complicated. I liked the ideas of "finding the solution to that phobia" or "find who is affected by that phobia" but in practice, these questions were too vague and not super interesting to answer.
Development
I spent the last 5 days creating the visual identity of the entry, and implementing the title screen, the encyclophobia, the 13 questions one by one, the sudden death part and the score screen (with a basic web3 leaderboard).
The leaderboards implementation was very hacky to be honest, using a bit of Thirdweb's SDK and a bit of Avalanche's network, plus some local JS stuff to work properly. I didin't make it super foolproof against forged urls, but besides one or two little jokers, people used it nicely and I was surprised to see a list with more than 300 high scores one month after release (corresponding to more than 1300 entries before deduplication, as I only keep the best score when a single person submits multiple times).
To be a bit more technical on the game itself, there's no canvas, it's all HTML and CSS.
It's fully responsive and (as always) uses the Twemoji webfont polyfill to ensure a similar display on all devices and OS's.
It's playable on mobiles too, but a weird bug happens on iPhones, on the title screen. Even if I force my title's text to be written in black with CSS, for some reason, the characters placed after an emoji get colored with the main color of the emoji. That's unexplainable, and probably unfixable in a reasonable amount of time, so I kept it like that.
I remarked after the release that the title is too big for some Linux players (but not on all browsers). I don't understand how it's possible, since the title is supposed to be centered. For these people, the title screen will stay like that:
Besides that, the only little challenge that I encountered in this entry was data management. Each question displays one or many emoji plus one or many phobias names, but I didn't want them to appear twice in the game.
So after each question, all the randomly chosen phobias that appeared in the question (with their name or their emoji) get deleted from the global data object.
When the 13 questions have passed, 250 phobias remain in the "data" object, still grouped by categories.
At this moment, I gather the categories by increasing order of difficulty, then order these super-groups randomly, and put them in a big "suddendeathquestions" array:
suddendeathquestions = [];
// All the easy ones
suddendeathquestions.push(...[...data.easy, ...data.animaleasy, ...data.numbereasy].sort((a,b)=>0.5 - Math.random()))
// All the medium ones
suddendeathquestions.push(...[...data.medium, ...data.color, ...data.country].sort((a,b)=>0.5 - Math.random()))
// All the hard ones
suddendeathquestions.push(...[...data.hard, ...data.numberhard].sort((a,b)=>0.5 - Math.random()))
After that, sudden death mode starts, and questions are taken 3 by 3 in this array, and deleted after each correct alswer, allowing for about 80 good answers before the game runs out of questions and displays the final score.
Release
As for my first entry, 10 days were enough to complete and polish my quiz.
This time, no golf or minification were needed at all, since the unminified file (containing 1451 lines of code) was 51kb unzipped and 10.7 kb zipped. As a result, the released entry contains my raw source code.
This edition of #js13kgames definitely can't keep me occupied for more than 10 days at a time. So I'll make 3 entries!
— xem 🔵 (@MaximeEuziere) September 4, 2024
- Days 1-11: GREAT PLUMBER 65 (preview: https://t.co/EwVwQBynTO)
- Days 11-22: EMOJIPHOBIA (https://t.co/FE24Xv46uh)
- Days 22-31: 🛹🤫
Feedbacks welcome! pic.twitter.com/4Ro1yFqjDz
Let's go for a third entry? Slack was amused by this idea...
DAYS 22-31: O HIII BAD SKATEPARK
A new tool approaches
Before starting my third game, I realized that my two first entries and had a similar structure:
- Single-file
- SVG favicon
- Emoji polyfill
- State management
- Click handler
- Disabled touch/text-select events
Great Plumber 65 also has a useful keyboard management system and a 60 fps game loop.
So before starting my third game, I wanted to try making a game template with all these features in a small package.
It took me a few hours to make MiniGameTemplate, 100 lines long with comments, 0.8kb minified, and 0.6kb zipped.
I think it has everything needed to start making a game in great conditions, and I'll definitely use it for my future games!
I wrote a 2024 update for my 100-lines HTML5 game template:https://t.co/6DgTELfrRp
— xem 🔵 (@MaximeEuziere) September 5, 2024
- Standalone
- SVG favicon
- Twemoji polyfill
- Disable text select & touch gestures crap
- Keyboard input manager
- State machine + 60fps game loop/click handler
- 0.8kb minified#js13k #gamedev pic.twitter.com/6VtDuBtPin
Title screen
Let's start my skate entry with a title screen showing that the game's name is an annagram of the theme! (it wouldn't have much interest otherwise).
I wrote TRISKAIDEKAPHOBIA and O HIII BAD SKATEPARK on a 2D canvas, as a model.
Then for each letter, I measured and saved in a JS array its X position in the first text and in the second one.
(Note: the upppercase "i" didn't have dots by default. I added a white rectangle on each "i" myself to make the "HIII" / "Hiii" more readable)
I first tried making all the letters move straight to their final position at the same time, with a lerp (linear interpolation), but it wasn't clear enough and the movement was too rigid.
So I found a smooth lerp function online, and used it to make each letter move one after another, as if they were pushed by a man on a skate (represented by a dancer emoji and a skate emoji).
Then, to add the idea that the levels will be drawable with the mouse, I added a crayon drawing a line, and made the skater ride on that line (as you can see in the final game, with the proper emoji webfont and a subtle radial gradient in the background).
To conclude this screen, I wanted to add a cool 3D shadow effect on the text. 2D canvases can't do that natively, but the "drawImage()" function can be used to isolate a line of pixels and redraw it in another place, with a different scale and a different opacity, just like a "Mode 7" game would have done on the Super Nintendo!
After a few hours of trial and error, I managed to make a convincing shadow for the title and the "PLAY" button using this technique. I even made it appear progressively at the end of the intro.
Unfortunately, after developing my title screen with Chrome, I tested it on Firefox and the browser got completely stuck when the shadows appeared. It wouldn't even accept click events on the "PLAY" button anymore. A complete freeze, everytime. I even tried disabling the game loop entirely, but no luck: Firefox even froze if the shadows were drawn during a single frame.
I concluded that Firefox probably has a bug or a memory leak that prevents to do so many "Mode 7"-ish things on its 2D canvas without freezing. As a result, I added a Firefox user-agent check in my code. Every browser gets the shadows, and Firefox doesn't get any.
Editor and player
Little by little, I made my editor interface, with a basic JS state machine allowing me to activate buttons, draw lines and circles with the mouse, scroll with the arrow keys, then undo, clear, load, save (in JSON)... and finally, a "play" button to launch the 2D physics simulation, and a "return to editor" button to stop it.
I hesitated a lot about keeping the skater and the skate as two separate entities or keep them glued together, but when I finally made the final graphics for the skate and the skater, it appeared obvious that it was much more interesting to see them being independant.
The biggest "math" challenge I had to face was: how to convert a line drawn in my editor (going from a point A to a point B) into an equivalent rectangle (with a center position, width, height and angle) compatible with Mini2DPhysics?
The solution arrived relatively quickly, by taking each item separately:
- the rectangle's center point is at the middle of points A and B: center.x = (A.x+B.x) / 2; center.y = (A.y+B.y) / 2.
- the rectangle's width can be measured with the dist() finction already present in the physics engine: w = dist(A, B)
- the height is a constant, equal to the line's width: h = 8
- and finally, the angle is Math.atan2(B.y-A.y, B.x-A.x).
(the atan2 method is magic for finding angles based on slanted lines! It's just super weird that its parameters are atan2(y,x) and not atan2(x,y) ...?!)
Once again, I asked my friend KorHosik what else could be added to offer a better experience to the player, and he hit me with some good ideas:
- Allowing to scroll vertically using the mouse wheel
- Replacing the "undo" button with an "erase" tool.
- Showing a ghost of the skater in the editor to see where we should place the next lines
- Add some kind of missions, such as reaching a certain zone or using a limited set of items to do something... to have a real game and not a "basic" Line Rider clone.
I implemented all these ideas, the most complex being the "missions" (or "challenges", as I called them). I had to invent them, make sure they were doable, then implement all the tests in the simulation to check if a challenge is cleared or not.
I started with 3, then with my friend's help, I ended up with 10 challenges in total, from very easy ones to super difficult.
To match the theme a little more, I decided that all these challenges had to be completed under 13 seconds, and with a maximum of 13 drawn items.
Some of them were actually hard to achieve AND hard to check for their completion, like this one where we must return the skate and land the skater, standing up, on it.
Challenge solution (SPOILERS)
JS code to check its completion:
// Check challenge 3 completion
if(
challenge3 == 0 // challenge not yet completed
&& objects.length <= 15 // less than 13 items drawn (15 simulated objects including skater and skate)
&& frame < 13*60 // less than 13 seconds
&& objects[0].G > 2.7 && objects[0].G < 3.5 // skater is standing up (-ish)
&& (objects[1].G > 5.5 || objects[1].G < .5) // skate is upside-down (-ish)
&& distance(Vec2(objects[0].C.x, objects[0].C.y), Vec2(objects[1].C.x, objects[1].C.y)) < 35 // skater is close to the skate
&& objects[1].C.y < objects[0].C.y // skater is on top of the skate
){
challenge3 = 1; // Challenge 3 is completed
localStorage.hiii_3 = 1; // save in local storage
ch3.setAttribute("checked", "true"); // check box in the challenge page
challengeok.className = ""; // show popup
challengeok.innerHTML += "Challenge cleared: flip the skate upside-down then make the skater stand up on it";
}
Since some of these challenges involved touching a certain number of balls with the skater, with limited time and items drawn, my friend suggested that I show the number of items drawn in the editor and the elapsed time in the simulation, and color the balls differently when they get touched, so we can see more clearly how many balls are completing the "touch X balls" challenges. (this "blue balls" thing ended up becoming a joke in the game's feedbacks).
Release
After doing all the debugging and polishing I was able to make, I zipped my unminified 1412 lines, 44kb index.html (which was also developed as a single-file) into a 11.2kb zip and released it like that, the day before the deadline!
My friends and I tried it with many, MANY items and I was pleased to see that the simulation remained super stable and fluid, even in a pool full of balls or a big track with plenty of lines.
I was especially proud of the challenges that were kind of added in the last minute, because without them the game would have been much less fun to play.
My three entries are released, here are the final links to test them
— xem 🔵 (@MaximeEuziere) September 13, 2024
- GREAT PLUMBER 65: https://t.co/IndmLmSyx0
- EMOJIPHOBIA: https://t.co/DnlVJgdYwG
- O HIII BAD SKATEPARK: https://t.co/atCn9M6oeZ
(also available on https://t.co/Pxww9vnFai & https://t.co/jpaqewsvdT)#js13k pic.twitter.com/P2NAiVfnDV
CONCLUSION
Productivity
I believe 2024 was the year where I produced the most lines of code for js13k: 3 tools, 3 entries, 4 dweets and this (too long?) making-of!
The ADHD medicine has probably made me much more productive than I've ever been, and I've started making games with pleasure again.
A game studio?
In parallel of this jam, September 2024 is also the month when I officialize my very own web dev / indie game studio, XEM STUDIO!
Maybe one day, I'll be selling games under that name! Peope on slack have already started asking me if they could buy shares, and end3r suggested that they cost 13€ each. We'll see!
The sound of JS13k24
- I contributed to the js13k24 soundtrack album with my GREAT PLUMBER 65 intro and outro, and my EMOJIPHOBIA classical music (stolen from LOSSST 2021). I didn't add O HIII BAD SKATEPARK's music because it was already present in EMOJIPHOBIA (I realized AFTER the jam that I used the same song twice, once taken from a preious entry, and the other one... recreated from a MIDI file. 🤦)
- end3r showed us suna.com, an AI site that generates songs from a prompt: lyrics, music, vocals, rhymes, everything. I tried it myself with a prompt containing js13k24's theme (phobia of thirteen), and a few details about the jam (theme announcement, limited time and space, creating tools, VR, AI, 3D, procedural generation, coding, creating assets, using emoji, debugging, playtesting, voting, rankings and finally, writing post-mortems.)
I was extremely impressed by the song that came out of this prompt. You can find it here, or play it below:
Some feedbacks on the song:
CarelessLabs: That’s awesome. It’s so catchy!
John Edvard: 13 bytes and sleepless nights. Quite accurate.
Tricsi: catchy
end3r: damn that's so good!
My favourite entries
I spent the days following september 13th testing and voting for all the entries submitted during the jam. When Alkor released some stats at the end of september, I was the top 1 voter on the app! Here's the discussion that ensued:
I remarked that the overall quality was pretty high this year. I found 24 outstanding games, and posted them on X:
- Economy of motion (One of my ideas this year was to make a game where we're limited to 13 moves. Glad to see this entry achieve it as a 2D platformer!)
- Cooler (Nice controls & music!)
- Squad 13 (Amazing helico simulation, particles system and audio, reminds me old Choplifter games.)
- Dimension 13 (Difficult and sadly WASD-only, but retro-pigeon delivers really impressive visuals in 13kb and at 13yo!)
- Ghosted (I hate sokoban but love good twists on sokoban's rules. Well done. A bit hard.)
- Those final seconds (The graphics are amazing)
- Brewing Disaster (Simple concept, good variety of characters, items, effects and challenges)
- Unloved 13 (Lovely idea, cute graphics, story and music)
- Dungeon of Curse (Impressive graphics)
- Kyabetsu (Yay, a cute point&click game)
- Coup Ahoo (A kind of game I hadn't seen before, cute and nice music)
- Escape from planet XIII (Super impressive graphics and tech.)
- Cool dolphin (I liked the graphics and controls)
- SUP3RFR1GHT VR (Couldn't play it as it's VR but seems amazing)
- Cursed Elevator (Wow, an impressive entry using my tools W and pxtex! Graphics, sounds and ambiance are amazing. Boss fight is a bit long.)
- The king's crowns (Incredible graphics and ambiance)
- 13th floor (Incredible graphics and ambiance. "it" made me chilly!)
- Deep13 (Here too, amazing visuals and atmosphere)
- Phantomicus (Amazing hommage to Luigi Mansion, is that a real 3D physics engine?! I want to see its source code with a standalone demo!)
- Bubble burst (Curious to know how the bubble is implemented!)
- King LongLegs (Very interesting platformer with some depth)
- Sub13 (Awesome 3D ans music, too bad the power ups look like walls)
- Do not make 13 (Very original concept with maths and drawings)
- Dr1v3n wild (Spectacular "false" 3D graphics with a lot of variety. Convincing gameplay and sound. Cute billboards.)
A working 3D physics engine?!
Cody Ebberson, author of Phantomicus, actually implemented 3D physics in his entry. That's exactly what I wanted. I DM'd him to ask for details and he explained me that he only implemented cube-cube collisions (which is already a huge achievement) and has a some performance/stability limitations.
He had the kindness to publish the engine as a standalone project, with a falling cubes demo and a quite readable build.js file. Thanks and congrats to him! I'll inspect this closely! 🔎
My games appeared on live streams
- Dobuki part 1 / part 2 (these streams made me realize that Linux browsers break my HTML layouts, and that items tended to disappear in my skate game for some reason... that's too weird, I've never encountered this issue on my side)
- Invadium tried my entries on Twitch but didn't record the video... they seemed to have fun though.
A new js13k website!
Thanks to Alkor, the js13kgames.com submit process and games pages have greatly improved this year, and after consulting the community, he added 3 new URL fields in every game's page: "director's cut version", "post-mortem" and "gameplay video".
To celebrate these additions, I have updated the pages of my 17 entries developed between 2014 and 2024. Now all of them have a direct link to their making-of, playthrough and a better version of the game (when available):
- 2024 #1: GREAT PLUMBER 65
- 2024 #2: EMOJIPHOBIA
- 2024 #3: O HIII BAD SKATEPARK
- 2023: Castle Escape
- 2022 #1: 10 years of game golfing
- 2022 #2: PUZZLATORY
- 2021: LOSSST a snake in space
- 2020: Track not found ?!
- 2019: Back on track (mania)
- 2018 #1: GEOQUIZ 2
- 2018 #2: Envelope
- 2018 #3: Man on wire
- 2017: LOSSST
- 2016: Super Chrono Portal Maker
- 2015: Geoquiz
- 2014 #1: Quintessence
- 2014 #2: AlcheMixer
While recording the video of O HIII BAD SKATEPARK, I managed to do a great stunt on the first try: make the skater stand up on the flipped skate, with just 3 lines:
All the feedbacks received on my 3 entries
GREAT PLUMBER 65
- Cody (during playtest phase): Very impressive opening sequence. He does flips and yahoos! Looking great! 😍
- Remvst (during playtest phase): the sound effect when you hit "start" really hurts my ears (...) the rest of the demo is super impressive
- Joao (during playtest phase): pretty amazing :sourire: a bit too much for my poor computer maybe
- Curtastic (during playtest phase): The raw emotion in Plumber's voice when he says woohoo is the best part
- Herebefrogs (during playtest phase): I love it that you still manage to sneak emoji everywhere
- bb (during playtest phase): Wow, Great Plumber 65 is a work of art... Amazing
- Ewa Mazur: GREAT PLUMBER 65 brings a lovely dose of nostalgia with its retro-inspired 3D platforming aesthetic, reminiscent of classic games from the 90s. The bright and colorful palette, along with the simplified character models and blocky environments, immediately transports players back to the days of early 3D gaming. The attention to detail in the castle and surrounding area makes the world feel familiar and welcoming, capturing the playful charm of the genre. While the overall aesthetic successfully evokes nostalgia, the visual experience could be improved with more dynamic textures and shading to enhance the depth of the environment. Adding a bit of variety in the terrain or background could also make the game world feel more alive and less repetitive. Additionally, smoother character animations would help elevate the game's immersion, making the gameplay feel more fluid. The visual style is a delightful throwback that will undoubtedly resonate with fans of classic platformers. The vibrant colors and simple yet effective design are perfect for a game that prioritizes fun and accessibility. With some small adjustments to textures and animations, GREAT PLUMBER 65 could become an even more engaging experience.
- Christoph Schansky: Great display of the power of your libraries! Interesting level-format (in the code) - everyting created from smaller blocks.
- Jasper Renow-Clarke: For me the game doesn’t work on mobile at all I’m afraid. It just gets stuck saying “Start”. I had played it on desktop already previously and it’s a pretty impressive tech demo to fit in 13k. Only criticism was it was pretty slow.
- Frank Force: Great work, this one made me laugh the most so far! I loved all the details you managed to capture here. On the tech side, the rendering is very slow that makes it difficult to play. That could be due to a large number of draw calls but I'm not sure. For example static environments could be combined into a single mesh. It will be cool to see how you improve w based on your learnings from this one!
- Christer Kaitila: incredible! the logo looks so fabulous... and then an entire cinematic intro??? with voiceover?!?! and then a world full of textures and detail and fade-to-black and animated pipe entry? with music?! so polished. I love all the little extras! like the three jump sounds woo hoo. all I can say is WOW
- Richard Chung: Just wait for the strike from the Ninten lawyers. Gameplay wise. The character movement is not that smooth and it updates pretty slow.
- John Edvard: Nice intro, and fun dialogs. Impressive being able to recreate the classic Mario level. I was also surprised that I could swim in the water. That was fun
- Adrien Guéret: A very nice and impressive demake of one of my favorite games, very well done! Please continue this entry after the competition, I would love to see a full game from this proof of concept :D
- kennyfully1988: I have to admit that this put a smile on my face. It nearly felt like when I played SM64 for the 1st time. I would had enjoyed more content.
- m-nakasato: Great technique! But it's too slow on my Mac (Safari). I couldn't find the 13 tricks.
- Alexander Petrov: Great intro to no game. I guess it indeed can be a good showcase of your (awesome) libs. But would feel much better if there were actually some gameplay.
- Zachary Rankin: nice graphics, crazy for the 13k limit :O
- Matt Light: This is amazing for 13k! It made me nostalgic for Mario 64. I ran straight to the corner left of the castle by the water fall and tried to run up that hill. Being able to go in the water and run around outside was fun. I was excited to go inside the castle! Maybe we'll see some more outside of the competition?!
- Daniel Whiffing: Impressive demo! I'm looking forward to digging into the source to see how it was done :)
- aselitto: Fantastic for 13k! I am amazed that you have 3d and the camera movement!
- kruffin: Impressive for 13kb, just wish there was more to do. Congrats on submitting and getting this much squeezed into a small package.
- Zark Attack: I enjoyed the triple jump audio.
- Mohammad Jawad: the demo is awsome, jumping and swimming work well. it have lot of potential if it wasn't for limit.
- Javi Agenjo: Funny tech demo and nice use of the emojis. Maybe adding some simpel gameplay would had make it more interesting.
- Nicolò Giuggiola: It is so fascinating how people can crank a 3d game in only 13kb. I hope to be this proficient, on day.
- Alex Delderfield: Great music and 3D here. Surprised to find speech audio in a js13k entry - I do wonder how that was done. A nice surprise to find you can swim, I always have to jump into water in a game to see what happens. But I need to deduct points here - about 4 hours in, in the snow level - I found myself with a deep, longing desire to pick up the baby penguins and yeet them off the edge of the cliff into the infinite void - in direct view of their family. But it seems like there is no pickup function implemented to do this, so for now they live on. 🐧 -1 ⭐
- Raptor Dev: Impressive to fit in 13k, but as the info says this is really a tech demo (sorta) and not really a game. Also just an attempted clone of the beginning of Mario 64 so arguable whether it qualifies via the submission rules.
- Michał Budzyński: This is probably a joke I just don't get.
- Rémi Vansteelandt: Really impressive tech demo. Unfortunately the audio didn't work really well on OSX, but it almost made it even funnier (especially when jumping). Wish there were actual platforming levels, then it could easily be one of my favorite entries. Next year maybe? :)
- João Lopes: It's really impressive what can be done with such limited resources. Not a lot of gameplay per se. The movements were quite sluggish.
- Ryan Malm: This immediately made me nostalgic for Super Mario 64! It's a shame you couldn't have crammed a tiny bit more content in here, it was enjoyable to play through this tech demo, impressive as usual!
- Cody Ebberson: It's a me, Mario! Fun! You've been building up to Mario 64 for years, great to see so much progress
- WHITE6982: Great Game!!!, Fellow Plumber (we all love super mario)
- Feenposhleen: Very impressive demo with textures, audio samples and stuff that you don't normally see in these entries. The gameplay isn't really there, but the humor definitely is.
- Homer Dilpleu: Great 3d demo, very impressive. I particularly love the cinematics with the camera movement around the scene
- Cliff Earl: Nicely done. I look forward to seeing how your 3D engine progresses :)
- Miguel Ángel Pérez Martínez: Awesome intro sequence!! Cool demo!
- Rob Louie: Cool tech demo, really appreciate the attention to detail!
- Jonathan Vallet: Not really a game, but nice work indeed. It's really like Mario 64 intro!
- Ryan Tyler: Very cool tech demo, always impressed to see 3D in under 13kb. I liked the jump sound, quite comical!
EMOJIPHOBIA
- Cody (during playtest phase): fun quick game, I feel like I learned something
- Ewa Mazur: The concept of using emojis to represent phobias is creative and fun! The clean design of the quiz interface, with a minimalistic layout, helps keep the focus on the gameplay. The large, central emoji image is easy to recognize, and the simplicity of the color palette—mainly white with light accents—helps create a sense of clarity, which is great for a quiz-style game. While the interface is clean, it could benefit from a bit more visual flair to enhance the player's engagement. Adding subtle animations, such as a slight bounce effect when a player selects the correct answer, or a visual indicator of the difficulty level (since the game mentions "easy"), could make the game feel more dynamic. Additionally, some more vivid background elements or gradients could bring a bit more personality to the overall aesthetic. The simplicity of the design is its strength, keeping the user focused on the game without unnecessary distractions. The idea of tying the gameplay to emojis makes it feel accessible to a wide audience. With just a few additional visual cues, this game could be even more immersive and fun to play. Great job bringing an innovative concept to life!
- Zark Attack: Refreshing little entry! My middle-school Latin came in handy AGAIN today 😎. Fun little trivia/guessing game. Rad Dictionary!
- Raptor Dev: Ok this is a lot more fun that I thought it was going to be going into it. I figured out a lot more of these than I thought I ever would, and even broke into the top 50 my second time around, thanks to some luck in sudden death! Very cool comfy entry.
- Jasper Renow-Clarke: A fun little game, although at times turned into a bit of a guessing game. Some of these are tricky to work out, and almost impossible for kids without some fairly advanced linguistic skills. Nice to see the leaderboard too, although with my scores I don't need them putting up there :) Funky soundtrack.
- Frank Force: That was fun and interesting use of the theme. I liked how you even included a leaderboard, great job!
- Christer Kaitila: some of those questions were super hard!!! but I did okay, 8 of 13 and 4 bonus points lol nice job!! I like the nice text tweens, so smooth
- Alex Delderfield: Nice work with the leaderboard setup, I always like to see those in a gamejam game, it adds a good challenge & urge to replay to score higher. So many phobias... I like how clean and neat the graphics are for this game, and the idea to pair up emojis and phobias works really well.
- Cody Ebberson: This is such a xem game, haha. You are always educating the js13k community on the immense power of emoji! And now I know "pogonophobia" 🤣 Well done!
- Homer Dilpleu: Very polished game, I loved the leaderboard concept and had fun to discover the phobias. I also liked the "In the Hall of the Mountain King" and "The blue danube waltz" musics (if I'm not wrong )
- Ryan Malm: Had more fun with this than I thought I would, the phobia to emoji matching made me chuckle to myself more than once. Got 13th on your leaderboard! Good game.
- Ryan Tyler: Simple, funky, fun and informative, just what the jam needed to increase all of our theme knowledge!
- Isaac Benitez: Simple game, but kind of fun. Interesting questions. I got most wrong, but hey, I didn't google anything. Lol.
- aselitto: The game was fun to play and played on the theme of Phobias nicely. Great work getting this up and working!
- Mohammad Jawad: phobia wiki would help here haha
- WHITE6982: hm if someone has any phobia ,this will surely be nightmare for them, Great Game!!
- João Lopes: Entertaining quizz, and fits well with the theme. I learned a lot.
- Jonathan Vallet: Really interesting game. Loved the intro screen, encyclopedia and multiple type of questions to avoid repetitivity. You found many phobia linked to emojis!
- Miguel Ángel Pérez Martínez: Cool concept! Had fun for a while guessing phobias!
- Cliff Earl: Very cool use of Emoji's and phobias. You fit a whole lot in there for sure :)
- Adrien Guéret: A very impressive quiz: so much phobias in only one game! The way you've matched emojis with phobias is very smart. Love the idea of the sudden death at the end. Well done :)
O HIII BAD SKATEPARK
- Ewa Mazur: The simplicity of O HIII BAD SKATEPARK works in its favor, giving it an accessible and minimalistic vibe. The clean, white background and basic stick-figure-like character emphasize the focus on gameplay and mechanics, which is a great starting point for players looking for a straightforward experience. The customizable aspect of drawing lines and manipulating the environment adds an interactive and creative element that enhances user engagement. While the minimalist style can work well, the game could benefit from a bit more visual variety or flair to keep players visually engaged. Even small touches like adding color accents or dynamic animations could make the world feel more lively without detracting from the clean aesthetic. Adding textures or patterns to the background or elements on screen might help break the monotony and provide a better sense of immersion. The creative freedom of drawing and customizing the skatepark is a brilliant idea, and the simplicity leaves room for expansion. It’s great to see a game that encourages users to experiment with the environment. Keep building on the strong interactive element, and with a few visual tweaks, your game could offer both a creative and visually dynamic experience!
- Michael M.: A fun little game! I succeeded with 6 of the challenges, but speaking of the challenges, they overflow the popup in an ugly way for me.
- Christer Kaitila: the physics are really great! I like trying to make little jumps after a steep ramp, then bounce off a ball for xtreme style!!! I kept losing my level creation progress, with lines vanishing, but maybe my levels were too complex! I wanted to share a cool level with a house, air trick, and a pool full of balls lol but I lost half the level on my two separate tries at making a level. this game would be super fun with a tiny bit more editor polish where a map of 100+ lines and balls was possible (and grid snapping for verts so lines were perfectly connected without fuss! that would be cool)!! =) but for 13kb this is so fun and I enjoyed making my skater bail in humorous ways! imagine if you recorded the physics velocity when the skater collides and call that total the "how much damage you took on this run!" stat, for funny fail highscores! very nice work.
- Ryan Tyler: Clever physics, the shot rider is handy for planning out where to put the next line to keep the lil guy skating along. Being able to control the gravity / speed would have been great! Good work!
- Jasper Renow-Clarke: An interesting concept for a game, definite linerider vibes. The physics are good and the objects interacted well. I like the way you've taken the theme and broken it apart (literally) to form the new word and take inspiration from a skate park. It would be cool to be able to control the level you've drawn (e.g. to rock it from side to side). The challenges were fun, some tricky ones in there.
- ckolin: Cool little game with fun challenges. Drawing the lines was a bit awkward but I loved the soundtrack and the intro animation, as well as the ghost feature. Also, how did you even come up with that name - you must be really good at scrabble!
- John Edvard: Interesting twist on Line Rider. The challenges are a great way to keep the player invested in the game. The Ghost feature is also a great addition. Makes it easier to compose course
- Steven Lambert: I loved the idea of challenges. I'm terrible at completing them, but they were interesting to attempt nonetheless. I also liked the ghost feature. It took me longer than it should have to realize that the line I was drawing was a straight line and not one that followed my mouse. There were also some challenges where I thought I had completed them but the game didn't think so. For example where the skater can only touch balls and the skate only lines. I drew a line under the skate, then small lines on either side of skate to keep it from moving, then placed a ball so it would hit the skater and bounce away and not hit the skate. Would be nice if there was some way to track which challenge you're working on and have the game give feedback on what didn't work (similar to how the balls turn blue when they hit you).
- Alexey Kalmakov: As always, perfect use of emojis, Xem. Great entry! I did 5 challenges and stuck on 5x rotation with the skate. I'm pretty bad designing tracks, so it would be cool to have prepared lvls in the game, so I could do one or two edits to help the skater to complete the level and achieve some height or POI. PS: The balls become blue when the skater touches them. This is the best joke in js13k 2024.
- Mark Vasilkov: Using challenges for progression is a neat idea, need to remember to steal it if I ever make a sandbox game :) "The balls become blue" is a fantastic description fitting many situations in life. Seriously though, there's so much potential here! Great job as always :)
- Cody Ebberson: Line rider + ball physics, awesome! I'm still working on the challenges, but this is fun. Clever use of emoji for the skater. Love that the title is an anagram. Fun, well done!
- Christoph Schansky: Definitely linerider :-) The ghost-feature is great for drawing ramps where they need to be. The music choice (hall of the mountain king) is nice. Sometimes, when returning to the editor, the game removed one of my lines? Strange... Regarding the theme... ahem... well... i drew a "13" for the skater at the end of my course, where he had a terrible crash. ;-)
- Adrien Guéret: Well done, you really followed my advice to make it a fun game rather than just a demo :p The quality and accuracy of the physics are pretty amazing. The game could use a bit of graphical polish, but as it stands, it does the job and is really fun.
Thanks a lot for everyone who voted and commented!
We had a bit of fun on Slack about Ewa Mazur's (End3r's wife) feedbacks, which looked a bit automated. Fortunately, she also took it with a good dose of humor:
Rankings
My first two games ended up in the top 100 overall, and in the top 50 on mobile.
The third game arrived 110th overall.
My friend KorHosik arrived in the top 10 overall for the first time!
I also got 3 prizes in the Decentralized categories:
- O HIII BAD SKATEPARK was ranked #1 for the OP Games NPC challenge (yay!)
- EMOJIPHOBIA was ranked #3 in Avalanche challenge and #6 in Thirdweb challenge (yay.)
Another fun fact is that GREAT PLUMBER 65 has had exactly 64 votes.
Conclusion
The lesson learned from this edition is that next time, I should focus on one big game instead of 3 little experiences. It was still a very pleasant couple of months preparing, competing to this jam and writing this making-of :)
See you next year!
Xem
PS: as a little bonus, I tried feeding Google's NotebookLM with this making-of and it generated this podcast!