Hacker News new | past | comments | ask | show | jobs | submit login
Cross My Heart – A Frogger Demake in 256 Bytes of HTML/JS (killedbyapixel.github.io)
128 points by KilledByAPixel on Feb 11, 2024 | hide | past | favorite | 47 comments



Checkout other demos by this guy (Frank Force) here https://killedbyapixel.github.io/TinyCode/

His web desktop showcasing his generative stuff https://generative.3d2k.com/

He makes lots of tiny code demos like this and shares on twitter every once in a while https://twitter.com/KilledByAPixel

His dwitter work https://www.dwitter.net/u/KilledByAPixel/top

His games https://killedbyapixel.newgrounds.com/games

His blogposts https://frankforce.com/


Wow. Impressively, ShaderToys → Sierpinski Towers crashes Firefox completely!


Very fun for 256 bytes. The script itself looks beautifully compressed as well. I think gameplay is a bit dampened by the scale of the board vs your character though. In Frogger (at least the one I remember) the cars are the same size as the player. Here they are double height which quickly turns it into a game of trying to tap as fast as possible even when you're only trying to pass one oncoming car a few levels in.

One thing I don't understand is the role of the "</svg>" closing tag. I didn't immediately see any reference to an open or closing svg tag anywhere in the source.


Same with the </canvas> tag. Are these closing tags needed for some "reason"? I suspect the second (and third) line is included by mistake. Also, if we are counting bytes, the closing pre tag is required and should be counted. The game also relies on filtering out non-arrow key presses but this code isn't compressed or counted at all. The instruction "Do not press any other keys" seems superfluous with the extra onkeydown code added.

Why was this code and a lot of similar code posted to github only 2 hours ago?


hey just a quick update from the author. I release3d this just today. Only the top part of the code (256 bytes) is necessary, bottom stuff is just a bit extra to add some context for people going directly to the github version!


Ahh yeah, that makes sense. Cheers for doing that. I enjoyed unwinding it and playing with it.


And now it can be 250 bytes.


I also had performance issues in Firefox, so I tried something else: just holding the up key. It was surprisingly effective. Not that it didn't fail a lot, but it progressed through the levels at a fairly even pace.

Unless I misunderstand the maths, the hold-up strategy has the same probability of winning regardless of which level one is at, since the levels only increase the speed of the obstacles and not their density. I would have thought the difficulty would ramp up such that even stupid strategies get less effective at higher levels, but not this time!


> the levels only increase the speed of the obstacles and not their density.

But your speed is the same at every level.

Instead of looking at the width of each obstacle, instead look at the amount of space that the obstacle covers during the time you are in its path. If it moves faster then it covers more space during the time it takes you to cross, so it is effectively wider.

Imagine if the obstacles moved so fast that they crossed from one side of the screen to the other in the time it takes you to move up one line. You would never be able to pass any obstacle.


I was under the impression my speed was one unit distance per frame. That would mean the speed of the obstacles is irrelevant becuse either they are in my location in that one frame or they are not -- and it doesn't matter how fast they go.

Edit: actually thanks to their double thickness it does matter! I didn't think of that.


I suppose it depends on how collision detection is implemented. Maybe the cars tunnel through the frog at later levels? Although it does not seem to get easier at higher levels (got up to level 62 using the potato method).


Chatgpt 3.5 actually gave a pretty good answer on what the code does: https://chat.openai.com/share/1d55622a-c9cc-4daf-97de-d766e2...


4.0, as expected, even seems aware it's a small code demo and some more insight https://chat.openai.com/c/68a51900-4d33-4d1b-bd14-247a739183...


Google Bard also gave a clear answer: https://imgur.com/a/8HGivir


"The animation has some randomness" - really? Where?


The expression involving Math.sin is acting as a PRNG. The vehicles have randomised sizes and speeds.


Pretty fun until i found out that just holding UP ensures easy statistical progress, made it to level 9 in 3 minutes.


Yeah, I made it to level 150 in 3 minutes, and I can still keep going. If I play the legitimate way, the game becomes impossible at level 20.


Here is the entire script of the game (I added line breaks, I hope in places that don't break the code):

   X=Y=V=U=Z=t=1;onkeydown=e=>(k=e.which)&1?X-=k-38:Y-=k-39;
   setInterval("for(++t,o=Z,i=50;i--;)for(b.innerText=o+='\\n',j=99;
   j--;Y>49?Z+=Y=1:o+=i-Y|j-X-50?q?'.':'':q?'♥':Y=1)
   q=((j+t*Math.sin(A=i>>1)/9*Z>>3)*A*Z)**4%97<89",9)
The obstacle generation code is very strange and deserves more study. But really remarkable - a tour de force.


You can replace the two " with ` so that the code in setInterval is still treated as a string.

Also, see the section:

q?'♥':Y=1

The code is minimized by setting Y back to 1 instead of providing a character to display but this has the visual side effect of "squashing" the player when they are run over.


In Firefox, I'm getting ~500ms GC pauses every few seconds which make it pretty difficult to play. It works fine in Chromium, though.

Edit: Firefox 122.0 on aarch64 (fedora asahi)


From the source the only thing I can see that would make garbage is b.innerText=o which is set 50 times each frame.

But even then it's just one giant text node, not html elements so it's surprising this is causing so much GC in Firefox.


Looks like a job for the new profiler.firefox.com


Here's a profile of the freeze being caused the GC if anyone wants to try and debug: https://share.firefox.dev/487vDxG


The profile actually shows the freeze is not caused by normal JS garbage collection, but by cycle collection. So probably something related to DOM nodes.


By the way, here's my simplified/annotated version of the code https://gist.github.com/DavidBuchanan314/13f4c4e8d9573108ff9...


Looks like the lag can be fixed by only updating b.innerText once per frame. This seems like a ff bug to be honest, but it appears that rapidly updating the size of innerText is the culprit.


Actually I'm using Chrome and I also got some random lag spikes


> Do not move off the left or right side

Turns out if you do this, then hold the up key, it would appear that you avoid collision detection. Also, it appears your X position is preserved between levels, allowing you to hold the up arrow to rapidly advance levels.


For extra fun, remove the "uncompressed" onkeydown added at the end, then you can hold down the spacebar to do big jumps.


Got to 45 level, just by pressing arrow up for 15 minutes. There is no penalty for loosing a life, so - it's not a game per se, as you can't lose.


Since this respawns really fast and there's no life limit, I wanted to see how far I could get through the mere persistence strategy of holding the up key. I automated this with an ethernet crimping tool whose weight and shape is ideal for pressing it down. After about 40 minutes it's at level 38


Pretty cute, and it gets super fast pretty quickly.

I got to level six on the first go, but after that I noticed if you move one pixel off the side of the screen you could just hold down "UP" to advance levels every few seconds.


If you're patient, you can just hold 'up' anywhere and it will eventually clear the level. It started taking quite awhile at level 20 or so - I got bored and gave up.


For fun you should also release it as an Electron app, without even a hint of irony.


The fact that it consumes 145MB or RAM (firefox) is quite impressive too!


Pretty good for 256 Bytes!


I like this, except I'm really not a fan of needing to rapidly tap a key to move repeatedly in one direction. I don't know how many shortcuts were needed to get to 256 bytes, but I think the game would benefit from significantly shorter key repeat.


The repeat delay is actually controlled by your OS here because it's just a simple onkeydown event. Implementing movement rate would require far more code because you need up and down listeners and a state.


That's pretty cool


This is cool but it's not a Frogger demake!


How to move on a touchscreen?


It depends on an up arrow keystroke, so technically you could use Android Debug Bridge... Unless there is a way to overlay a software button in the foreground on a phone that I'm not aware of.


This is more fun than a lot of gigabyte-oozing brainless ego-shooters, and a fantastic engineering accomplishment on top of that!

Thanks for sharing!


crashed chrome :)


Another game ruined by garbage collection. At least run the gc on every frame.


I don't think there is a way to do that on a standard browser setup (nor would I want the browser trying to assume this kind of output should be collected every frame itself). Not to mention even if there was it'd probably not be worth the extra bytes in this kind of demo.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: