Show HN: MineSweeper implemented in 100% CSS and HTML – no JavaScript
github.comI realize this is an absurd thing to do, but it was fun and I wanted to test the limits of CSS again so I could share the results!
I linked to the README since any web devs that see this will probably want to know how buuut here's a link to the game if you want to go hands on:
https://propjockey.github.io/css-sweeper/#randommenu
It's all open source, and I discuss some details of how to do it in that readme, but I am more than happy to answer any questions!
Thanks for checking it out!
No way! I've done exactly the same thing. (https://news.ycombinator.com/item?id=15479160) At first I thought this was my own thread! I guess there's a healthy overlap between loving Minesweeper puzzles and CSS puzzles. :)
I used HTML/CSS so I could implement it on a Neopets page, which meant I couldn't use forms, inputs, or CSS3, which means it's less feature-complete and the approach is completely different. The final result, though, is still the same delightful Minesweeper experience.
Codepen link (so you don't have to be signed into Neopets to see it)
https://codepen.io/qaz/pen/bGEzyrJ
Enjoy!
To emulate Minesweeper's not-a-bomb-on-the-first-click experience, I start the board off with a generous region revealed, and then to emulate flood-filling, I make blank cells sit in an invisible (overflow hidden) scroll box that scrolls to a revealed version of the region when you click the blank cells, which have relative links. That only works for rectangular regions, but I remember having a way to make it work with irregularly shaped regions and being too lazy to implement it because it was going to be even trickier and uglier than what I was already doing. I'll leave that as an exercise for the reader. :P
This is awesome - Could you please explain how you're holding state of each box individually without checkbox:checked? It's not immediately obvious to me how that's possible or where it's happening in your code!
Thanks!
I use scroll position to keep the state. In effect, each square is in a div with overflow:hidden. (In the actual code I used <i>, not <div>, which might've been to save bytes because the server is so slow). It has a fixed visible height, the height of the square. Above the fold (before scrolling) is the un-clicked square, and below the fold (what you see after scrolling) is the clicked square.
Since overflow is hidden, you have to use an in-page anchor link to scroll to the clicked state. The unclicked version of each cell is an anchor to the clicked version.
wow, that's super clever. I was sitting here reading the code and didn't find a negative margin or positional property anywhere, and further, no switches to hold the state. Couldn't for the life of me figure out what you were doing hahaha I love it
Thank you!
That is an amazing hack! Awesome.
both lack the left+right click that reveals tiles around numbers that have the sufficient amount of bomb marked, I'm curious what's the css/html limitation that prevents the implementation of that behavior?
You can't (afaik) tell if it's a right-click vs left-click in HTML+CSS alone that causes the el state to change - that info is part of the JS event :)
thanks
This should make white-boarding interviews a lot more fun. "Please implement Minesweeper, but only using HTML + CSS"
At some point questions like these become more like: Guess which exact sentence I am thinking about
I am very good with HTML and CSS and would definitely be able to solve sth like this. But not on a whiteboard, I would have to be able to fool around with it.
Why would you give "them" ideas?
It's good to see which companies you shouldn't work for.
That is impressive, just impressive. Brought back some fond memories of installing Windows XP over and over again for family and friends with fckgw rhqq2 yxrkt 8tg6w and playing minesweeper before handing it off to them.
Great job!
“fckgw rhqq2 yxrkt 8tg6w. There’s a name I’ve not heard in a long, long time.”
this should be like a secret handshake or even better our version of windmill high-five from Top Gun. Still can't believe that I can enter that S/N without having to even think about it.
Is there something magic about that code?
Yes - https://en.wikipedia.org/wiki/Volume_licensing#Leaked_keys
tl;dr I grew up in India where the Indian Rupee was quite weak compared to the USD. Most people I knew couldn't really afford a legitimate copy of Windows XP - 1 USD was about 48.61 INR in 2002, and average wage was about 120 INR/day[0]. At that price a copy of Windows XP (priced at around $300/$400 ~ INR 14,000) was prohibitively expensive for pretty much everyone I knew. Because of that we ended up using leaked keys to setup new PCs, I did that enough times for my family, friends, and classmates that now I can type that key up as if I'm typing "hello world" :)
[0] https://www.ilo.org/wcmsp5/groups/public/---asia/---ro-bangk...
It’s the most popular Windows 98 cd key back in the old days.
Fantastic! Are you proud that you can call yourself an HTML programmer now?
Technically he's a CSS programmer ;)
lmao, I've come full circle. Excellent callout. hahaha
Doesn’t work on iOS?
The "Play it here" link on the github page works.
Seems like the "click click" message, which is shown only on op's direct link, causes some problems.
OHHH I wish the others would have been more specific other than "it doesn't work". Thank you!
The way that random thing works is:
1) #randommenu:target shows the overlay (based on hash in the url)
2) the overlay has a link to "#" (fullscreen) that says "click-click"
3) Then rendered ontop of the link, all 16 level labels are full screen & transparent
4) Animations loop through them (hard-coded random scramble) to change their z-index to be on top, one at a time, for about 0.25s each
5) Clicking on any of the labels causes that layer to disappear, exposing the "#" link
6) Clicking again changes the url to "#" so #randommenu is no longer :target, thus closing the overlay
My guess is it's probably flashing too fast for iOS/Safari to register a full click.. I could probably fix it by making the random sequence take longer.
Can you confirm the URL never changes to "#" and stays stuck on "#randommenu"?
Yes it’s stuck on #randommenu
Sometimes it works though, needs some „clicking“ (touching), eventually it will (might) work.
Can confirm
This is really cool! I saw your responsive library[0] post [1] the other day, but couldn't quite wrap my head around it.
With this post, I think I am starting to grok the (Space Toggle) trick. The Tweet you linked in your library was really helpful [2].
My current understanding is – in CSS, you can set a variable to nothing (a space). When a property contains that "blank" variable, it is replaced by nothing and so the second, "fallback" value is the default. Because you can update CSS variables within more specific or later CSS, you can update the "blank" variable and give it a new value of "initial", this causes it to switch from the default to the defined override.
I realized, you can even combine this with the CSS checkbox hack. I made a (super hacky) version of CSS-only dark mode toggle based on your JSBin (gotta love an absolute positioned bg, lol) [3]
[0] https://propjockey.github.io/css-media-vars/ [1] https://news.ycombinator.com/item?id=23865900 [2] https://twitter.com/James0x57/status/1283596399196680192/pho... [3] https://jsbin.com/xelufoyoka/1/edit
haha, awesome! You nailed it. It's really cool to see it being tested out in the world! Thank you for sharing!
That's crazy! The large lag between clicking and the UI updating is slightly annoying, but that's just me nitpicking at something other than the cool technical feat.
yeah, i expected it to be instant to be honest, given it's just markup and there's no "thinking"
It's 1.23MB of CSS & HTML - this is meant to be a stress test of the limits, lag is expected for the next several years of average-at-the-time computers!
Or until someone packages your madness as a popular library and browsers are forced to optimize it.
Make it an Electron app!
(I'm joking, please don't. Please.)
that would not speed it up at all.
I'm curious how it performs on a 10x10 or 16x16 grid
yeah fair enough
I think I see my CPU dripping out the side of my laptop.
Indeed. This pegged a CPU core and locked up my browser for over a minute just opening the page.
Syrange, but it works almost without lags on S10 phone.
Same here, page loaded pretty fast and lag is maybe 200ms on my phone using Firefox.
Very cool. CSS can do some amazing stuff these days. I made a game using moving checkboxes recently - https://codepen.io/onion2k/pen/qBbKYee - with a timer and scoring. It's a fun challenge to avoid JS.
I saw that a few days before I started making this actually! https://news.ycombinator.com/item?id=23867569
I always wonder what kind of cool stuff HN inspires. There has to be tons. Is there a list?
Not curated, but found a whole bunch with this search https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...
Good stuff! I made a sudoku in CSS (https://identicalsnowflake.github.io/sudoku.html) a while back, but it looks like the variable trick mentioned in the readme is a more straightforward way to embed logic, so if I were to make something similar today, I'd probably pursue that route.
This is great! I love how there's a bit of a reward for getting past the difficult middle part of gameplay - when there's not many spots left it goes fast and you can click click click to finish up without sitting there cleaning up your notes or counting 1-9 to figure out the last number or two. This is a big improvement haha
Every day we stray further from God's light.
It sort of bothers me how much feature creep CSS itself has undergone. Was it not enough to leave things simpler and just use pre-processors and JavaScript?
What hope does one have to implement the entire CSS spec from scratch now?
I see your point about separation of concerns.
This minesweeper, and the other examples in the comments, seem to capitalize on some hacky aspects of CSS, not features of the CSS spec.
In the real world, I doubt many people rely on CSS for things that JavaScript can do. (but I bet plenty of beginners use JavaScript, when CSS would have been more appropriate, haha)
Very interesting! Can I ask, how did you implement the timer in CSS/HTML?
And also, what causes the lack of responsiveness?
The timer itself is a CSS animation with 1000 keyframes evenly spread, that runs once for 999s (just realized it should be running for 1000s, oops!). I can't link to lines in the source code because of the 1.23MB filesize but you can search for "timer" in the raw source to see the relevant code: https://raw.githubusercontent.com/propjockey/css-sweeper/mas...
Here's the part that controls when the animation is running:
Though the design is responsive to the width of the window, I suspect you mean how slow it is: it's 1.23MB of HTML + CSS, and clicking anything causes almost everything to redraw. It's only a little laggy on my computer but the idea was to test the limits of what's possible and is expected! :)#level-none:not(:checked) ~ #ram #timer::before { animation: timer step-end 1; animation-duration: 999s; animation-fill-mode: forwards; --pause-if-won: var(--win-state) paused; --pause-if-lost: var(--game-over) paused; --pause-if-randommenu: var(--randommenu-visible) paused; animation-play-state: var(--pause-if-won, var(--pause-if-lost, var(--pause-if-randommenu, running))); }Thank you for checking it out!
Can't you simplify this by making each digit a separate animation, with the ones digit running at full speed, the tens digit running at 1/10th speed, and the hundreds digit running at 1/100th speed? Then you'd only need ten keyframe values.
Yes, but I didn't trust them to stay synchronized and it wasn't too difficult to generate the code for 1000 keyframes so I just did that :)
If I understand this timer, is it true that after ~16.5 mins, the game would stop? Are you stopping at 1000 keyframes because of a hard limit or for performance or for?
the timer stops at 999 because that's what it does in the real minesweeper, you can keep playing though!
Ah, that makes sense, it's just for the visual. Thanks for clarifying.
If this took you, ballpark, 1 month to do, what do you think you would be able to do in a year?
This took ~3.25 days. :)
Since I'm brushing up against the limits of CSS, there's not enough room for a full year :P
What inspired the idea and what was your motivation?
I made a Binary Coded Decimal 7 Segment Display Decoder a couple days prior to starting this: https://github.com/propjockey/bcd7sdd
After that blew up on twitter I tried thinking of something else I could test using checkboxes as the state and MineSweeper just popped in my head since it's pretty much 480 fancy checkboxes.
Motivation was just to see if I could, then to see what the limits are once I realized I'd be able to.
Thanks for checking it out!
I was sad to discover that Minesweeper is no longer bundled by default with Windows.
I tried this on a low end smartphone. Might as well have been called MineSwapper
The bombs are fork bombs
Idle question,
is CSS/HTML turing complete?
If so I look forward to a Show HN of a CSS/HTML emulator of JSMESS emulating a 386 running Windows 98.
My understanding is that:
Neither CSS nor HTML is turing complete.
The combination of CSS and HTML together is not quite turing complete either.
The combination of CSS and HTML plus an external source that repeated clicks the mouse is turing complete.
I could be remembering this wrong, however.
It is (and has been since the css 2.0 era) if you include user clicking mouse.
There is a famous demo of rule110 in css at http://eli.fox-epste.in/rule110-full.html
Mouse is not necessary using CSS 3 (animations); Minesweeper[1] is enough to show Turing completeness.
edit: ^ previously said "with css variables to hold state" or something similar (or my wires got crossed and I saw that somewhere else)
CSS variables can't be set by animations yet without JS's CSS Houdini giving them a type - a CSS @ property is in the works to do it without JS though!
I would say no because the core boolean mechanic that allows CSS-Sweeper to exist cannot be inverted directly (NOT, !). In order to invert anything here, you have to start with an inverted copy of every bit and do the opposite calculation at every &, |, etc to always have a "NOT" var to reference. Like a shadowy, anti-vein, copy of the main logic.
There are several edge cases where a sort of simile of NOT is possible though. You can branch from truthy/falsey into falsy/truthy numbers. And if is something is falsey you can "else" into another action.
Just can't "else" from a truthy state without the ...anti-vein... always being present.
It’s not.
Now, which email clients does this render properly in! I'm looking forwards to diving through this.
A 16x16 minesweeper email signature would be a great way to make an impression.
I was so confused why everyone was saying the game is so impressive when all my clicks did nothing but place a ‘?’ where I clicked. Was each ‘?’ an error message? No, it turned out you need to click each square twice to reveal it. The page really needs some instructions, because that is not how normal Minesweeper works.
The other thing you need to know to play is that right-clicking won’t flag a square. Instead, you need to left-click on the flag in the top left to toggle flag mode, then left-click on a square to flag it.
I'm confused -- how do I flag? Right-clicking seems to just bring up the right-click menu.
Edit: Nevermind, figured it out. You click on the flag up top to switch between flagging and clearing.
Now do GPT-3.
Oh my god, this is AWESOME!
haha thanks! :D
Very nice. Thanks for sharing.
doesn't work in Safari
Hmmm... do you know what version you have?
It should work on iOS 11.3 and up... maybe. They might have smaller limits on the number of operations per calc()..? Can't think of anything overtly incompatible.
Unfortunately Safari is today's IE6 in web dev since they're so far behind on so many features. Except it's worse since you can't test without owning their products or paying for a service either... wish I could check it out, there's probably something to learn
Doesn’t work on mobile? Safari / iOS 13.4.1 here.
Any chance you could share a screenshot? I can't test safari without owning apple products or paying for a service :(
as far as I know iOS 13.4.1 should be completely compatible.. there might a smaller limit on the number of calc() operations? The spec says it must support a minimum of 20 operations, but I'm (ab)using almost 1000 in a max()
Why.
This is very slow in my browser, which I don't mean as a criticism. Just refreshing to see something be slow that uses no JS at all :D
It is rather ironic that the chief complaints about JS are how it makes things bloated and unresponsive, yet this is 100x the size of http://www.play-minesweeper.com and the time to interactivity is recognizable by comparison. The HN community is a funny one, sometimes.
The OP is a 1.23MB tech demo in CSS absurdism, not a baseline for performance comparisons. You have the wrong take-away if you think you can squeeze any sort of performance point from this.
It's like seeing that fun tech demo that implements Brainfuck in Rust's type system and going "heh, and they said compiled languages were fast? I can do this faster in PHP!"
You have the wrong take-away if you think the performance points were what I was actually focused on.
The HN community largely rails against the use of JS anywhere, even if not using JS would make things much more difficult. Therefore, it's funny when someone makes a relatively trivial app not using any JS and it exacerbates the problems people cite for JS rather than not.
The whole thing is really cool and I love how they managed to get so far using some cool CSS tricks. But per the community it should also be a godsend because by not using JS it should by default make it faster, smaller, and probably cure cancer or solve for FTL travel or something.
JS is the right tool for the job when you want to make something highly interactive. I can't remember seeing anybody dispute that here. Having said that, I now expect at least one reply from someone who does dispute it.
2003 says "what about Flash, Java Applets, ActiveX controls, VBScript, Silverlight"
Well maybe 2003 didn't mention Silverlight.
Trust me, I have a whole trove of rants about how HN talks about JavaScript. Lotta rants in that trove.