Hacker News new | past | comments | ask | show | jobs | submit login
HTML5 Deck of Cards (pakastin.github.io)
419 points by delambo on Sept 3, 2015 | hide | past | web | favorite | 157 comments

This is similar to something my room mate is working on: https://github.com/thejoshwolfe/board-gamer-2d

The user can create a JSON string that represents a game (checkers, solitare, dominion, smash up, etc). Then the engine creates cards, tokens, dice, etc. It does not enforce rules but it supports multi player and some rules about visibility to other players. Its intended use case is for testing out new games or expansions before printing them.

It's a little bit early in the project though, so you'd have to run it from source if you want a demo.

This is what I've been wanting to make since I first learned about programming 3 years ago. So much effort goes onto enforcing rules, when really, all you need is the virtual pieces.

This is actually something you can do with Tabletop Simulator on steam, as I'm using it for that exact purpose. It even uses JSON as the underlying data structure. Granted, it's proprietary and not free.

My room mate tried to use that and he said it was garbage. The thing that I remember was having to type file paths manually, but there was a bunch of other specific and egregious problems he pointed out. Beyond that though, 3D brings nothing to the table; it's just a gimmick.

proprietary. not free. not standard web tech for use in browser. requires a DRM (with bittorrent client) spyware to be always running.

yeah, not even close i would say.

but the use of JSON is nice.

Hm, cool! My company just started on a Javascript board game engine where the server & client can share the same .js file for rules, and all logic for the game is encoded into the pieces (fat models) instead of controllers, allowing for easy customization and mods.


Had the same idea but I also have a hundred others to distract me, so thanks for the heads up. I'll keep an eye on it.

This seems to be all static html, why doesn't he just turn the branch into a github page?

It is a github page, it's hosted on github.io. The branch is https://github.com/pakastin/deck-of-cards/tree/gh-pages

There's a node server required too, to coordinate the multiple connected clients.

you can still run a demo off github pages without the multiplayer.

Maybe it's a weird takeaway, but this line is really clever:

var suit = i / 13 | 0;

That's such a clean way to get a 0, 1, 2 or 3 from each card's `i` and I never would have thought of it.

If you're referring to |0 then I would disagree. It shows how horrible JavaScript is. This is very confusing if you're not familiar with this trick or strange behavior of the language.

    suit = int(i / 13)
    suit = (int)(i / 13)
    suit = math.floor(i / 13)
Are much easier to understand for someone not familiar with the code.

The behaviour of JavaScript's bitwise operators isn't that unreasonable, but the excessive use of this trick for tiny performance gains at the expense of readability is a shame.

I take your point, but that's some crazy non-JS typecasting in your first two examples :)

Languages are what they are, and if you're going to use one you might as well use it idiomatically. Maybe it's just me, but I see "|0" all the time in JS, not as some kind of crazy performance hack, but used idiomatically to mean "truncate".

And on the flip side with JS's lack of number types, any code that looks like it's doing type casts (rather than math) looks out of place. If one must mess around with JS number types then all you can really do is give hints to the optimizing compiler, in which case "|0" is the standard way to hint that you want a small int.

Obviously what looks clean is a matter of opinion, but FWIW.

suit = Integer(i / 13) suit = Math.floor(i / 13)

1.89% faster than Math.Floor, 100% more hard to read.

I used http://jsperf.com/or-vs-floor/2 in Firefox 40.0.3 and it was only 0.37% faster. Was similar in Chrome.

I think "value | 0" is basically same as "Math.floor(value)"

Yes, but it is 18% faster do run the bitwise or on my machine:


Its because they don't do the same thing

Math.floor() favors the number equal to/less than the parameter, Math.floor(-15.5) is -16 while (-15.5 | 0) is -15

Also because the returned value is int32[0],

Math.floor(2147483648.5) is 2147483648 while (2147483648.5 | 0) is -2147483648

You are fine if you know the input is less than (2^31) + 1 and you want to truncate, rather than floor.

[0]: http://www.ecma-international.org/ecma-262/6.0/#sec-binary-b...

ECMAScript 2016 adds Math.trunc()[0] which should give the same value as | 0 for inputs that fit in 32 bits.

[0] http://www.javascripture.com/Math#trunc

Hmm, pretty sure floor rounds a number downward to its nearest integer. So Math.floor(-15.5) would be 15.


Literally the first example on that page:

> Math.floor( 45.95); // 45

> Math.floor(-45.95); // -46

Its not like its hidden or anything... Its in the center of the page on my 1920x1080 screen.

Nope. Math.floor(-15.5) would be -16. It rounds a number downwards. -16 < -15.

There is no substantial difference in performance on mine (within 2%), although the OR was always a little bit faster.

Chrome 45 on Linux

It's odd that a bitwise operator should have the effect of truncating the float (since X|0 == X)? I'm guessing there's an implicit type conversion to int in the middle?

The bitwise operators don't make sense for floating-point values. So they work by converting to a 32-bit integer first.

i/13|undefined works too


has that "this was originally written in javascript, not ported halfheartedly from some other language" feel. (Well, maybe PHP.)

That's just adding another conversion from undefined to Number to Int32 for the right operand. You could probably use false as well. Or the empty string.

gulp I guess I should stop using parseInt :/

And every time a developer sees that, they're going to google "bar javascript" "single bar javascript" "bitwise or javascript" "bitwise or javascript effect" until they figure out WTF is going on.

This all to save a fraction of a microsecond on an operation that's called 60 times on the page.

Actually only 52 :D

But yeah, I agree about googling part: I remember having Googled "tilde javascript" and "pipe javascript".. :)

Tilde is useful with indexOf:

if (~array.indexOf(item)) {}

..equals to:

if (array.indexOf(item) > -1) {}

This is the sort of thing that makes Perl readable in comparison to Javascript :)

value | 0 will always return a 32 bit integer.

Math.floor(value) can return some weirder values such as: NaN (for anything that isn't a number), and Infinity, -Infinity, -0. And Math.floor(-1e-300); is -1 so care needs to be taken with floating values near zero.

Why not just i % 4?

that would alternate the suit for each card, and all the aces would be the same suit, etc.

If you also take the cards modulo 13 for their face, this approach works.

4 and 13 are relatively prime, so each number between 1 and 52 can be uniquely represented by the function (x) -> (x%13, x%4).

Yes, obviously it's not a drop in replacement as the behavior is different, but it does the same thing, giving you a number from 0 to 3 based on the card number. Pairing it with i%13 works just fine.

on my deck hacks i use proper data structures but on the initializer for the deck i have `suit = i % 4`.

which has the advantage of working with any size of deck. important since in brazillian truco you leave most of the numbers out ;)

In asmjs you see this sort of syntax 'num | 0' a lot [0] to enforce that the number is an int, so that may be where he got the idea.

[0] http://www.sitepoint.com/understanding-asm-js/

It exists in other languages, too, like PHP.

You can do this in PHP, but you shouldn't.

Use (int), like C.

It is not much worse than using it in javascript. People do this in js because it saves a few keystrokes and its faster, not that it matters. Its a small thing. Its dirtier, for sure.

I just tested it in PHP and it seems it is 20% faster in PHP compared to casting to int. Maybe someone out there will have a weird use case for that, or someone doesn't want to put more effort into writing code into terminal and doesn't care about his code being unreadable. I think its useful to know it exists.

Btw, do you or someone else know why its faster in php too? Its a bitwise operation and I assume under the hood its casting to int, its weird to have it faster than casting it to int, why does this happen? It makes sense in javascript to that its faster than functions, but why it is faster than a cast in PHP?

> It is not much worse than using it in javascript.

It is worse because people are even less familiar with this in PHP. It's not idiomatic.

> I just tested it in PHP and it seems it is 20% faster in PHP compared to casting to int.

How rigorous was your testing? Which version of PHP were you using?

> It makes sense in javascript to that its faster than functions, but why it is faster than a cast in PHP?

It shouldn't be. It might save an allocation in older PHP versions, I'm not sure.

Putting aside whether this sort of thing is clever and clean or occult and confusing, another pattern of the same ilk is:


for me I see `~~` and I think coerce to integer value (the result will be an integer regardless of i's value, 0 if it fails a clean coercion)

Similar to seeing `!!` and thinking true/false coercion.

This is very pleasing to the eye to shuffle/sort. Good work.

Now you just need to add a dropdown to select what drinking game you want to play.. ring of fire anyone?..


Any idea why the suits all render as smiley faces in Chrome/Mac?

Inspecting the cards, you can see that they are using the unicode character for spade/heart/etc. But in the browser itself you get nothing but smileys.

Perhaps the font they're using doesn't have those code points?

Edit: Yes, that's the case. Font is not specified, so it comes in as "inherit" by default, using whatever the browser feels like. On Mac Chrome, that must use smileys to represent unknown characters. Switching the document font to Arial in CSS fixes the issue and makes the cards look like cards.

> On Mac Chrome, that must use smileys to represent unknown characters.

You're seeing the Last Resort fallback font, which shows a symbol representative of the codepoint range, and the range's name, so you can identify what type of font you need. Since the suits are in the smiley block, you see a smiley. If you had no Latin alphabet font, you'd see an A.


Fixed now..

Font should be Open Sans.. I have Chrome/Mac and it's working :/

Why spend the time and effort pulling a custom font across the wire if you're only going to use symbols that exist in the web safe fonts included with the browser?

Seems kinda wasteful.

I think the reason for this is to prevent cross browser bug you seemed to be experiencing in the parent comment.

Open Sans is used everywhere in the page. Also the buttons on top..


Great work. There's a couple of small issues. First, regardless of where you click on a card, when you start dragging the card will jump so that its centre is at the cursor position. Second, there is a mismatch on the Z-index used for dragging and that used when a card is dropped into place.

Will fix those.. Actually dragging start is "sort of" fixed already.


There's one card face missing. That's the back! A nice card back might be a more difficult challenge to do in HTML5.

It's done in CSS3 + JS, so it should be pretty easy.


#card.flipped { -webkit-transform: rotateY( 180deg ); -moz-transform: rotateY( 180deg ); -o-transform: rotateY( 180deg ); transform: rotateY( 180deg ); }

Sure but implementing the card back image is more difficult, which is what I think the parent post was getting at, rather than the flipping itself. The rest of the page is implemented without any images, which is neat; you'd have to work some SVG magic or something to create e.g. a Bicycle-esque card back without loading an image.

http://lea.verou.me/css3patterns/ could provide a pretty good source for patterned card backs.

Thanks, that's great source!

Displaying an image on a web page shouldn't be that difficult.

I like the svg suggestion.



It's not about difficulty, it's just fun to try and do it with only web elements, and bonus points for strictly CSS

I don't see any problem using couple of SVG image files for example.. The problem is that I'm not such a great drawer myself. In the first version I just used big J, Q, K like this: http://pakastin.fi/cards_2006

He means drawing the complex decorative design on the back of most cards.

I had the same thought. You could practice magic tricks if you could flip over the deck and then shuffle and fan it! "Pick a card, any card!"

I will add flipping ;)

Only thing about is that it easily looks like crap. I mean if you don't curl & flip the card looks too solid..but I'll check it out.

This would only work for a very small subset of card tricks.

It would be difficult to practice sleight of hand.

The two joker card are also missing for it to be a complete deck.

Try clicking all kings in a row.. ;)


Each of these cards could probably be made with one element and some CSS3 pseudo-element selectors, as opposed to the four elements (wrapper element and three child elements) that are currently used per card.

Additionally, with three elements (possible just one if you're crazily good at CSS), it'd be possible to have flippable cards. Still just using CSS3.

Edit: Can someone explain these downvotes for me?

I suck at pseudo-elements – that's why.. :)

Great work, I love this. Here is a quick playing card example with pseudo elemenets view-source:http://www.clarkeology.com/card.html

That’s nice CSS but the HTML is so borked… why not

<div class=card data-value="A" data-suit="︎">︎</div>

Or something?

On the "least amount of HTML possible" theme here's a version using only "class", e.g.

<p class="2 ︎"/>


Doesn't include the card centers, but does have top and bottom corners.

EDIT: HN doesn't seem to like unicode characters? The class should include the suit symbol.

I think I'll stick with good old elements :)

Thanks anyway, and I really appreciate true CSS ::-wizards, don't get me wrong.. ;)

I did have that originally, but <card /> worked in my browser so i ran with it... I'm sure card[suit=$] with a unicode character is not super widely supported css anyway...

Browsers implement pseudo elements using actual elements internally, there's no difference in power from using ::before or just putting a <span> as a child. Pseudo elements will probably be a little bit slower though.

I agree. Some people rant about me using "value | 0" instead of "Math.floor(value)" and another would do "::before {content: attr(data-value..." -stuff instead of just using a good old elements..

Go figure :)

Nice animation although card faces need some work.

My own CSS playing cards with proper card faces from 3 years ago is here:


I actually started using same vector faces now!

Wow, those look really nice!

Really nice! An animation for turning the cards and the displaying of the back of the card would be a useful additional feature I guess.

Yes, have to add that!

It'd be perfect if the Z-index updated for card last selected. It looks like they're z-indexed in a specific order at the moment?

I will change it so that z-index is only temporary and when cards are stopped it will reorder them in the DOM.


What is it with cards that everything about them is so satisfying?

Maybe you begin to think about gambling, women, fast cars, Vegas.. :)

This is quite nice! One "intuitive-but-counterintuitive" result -- when the cards are stacked and I drag from the corner, I end up pulling a card from the middle of the deck.

I suppose that's more for a second library that can manage stacks of cards, dealing and interacting with dealt cards, etc.

I will add more power to the API..

This kind of reminds me of something I almost ordered: http://varianto25.com/code-deck.html

Nice work by the way!

Thanks! Cool cards!

What? No 52 pick up? ;-)

Actually there was in the first version of this: http://pakastin.fi/cards_2006 (made with Flash)

Press "Räjäytä" (means "explode" in Finnish) ;)

my thoughts exactly!

Wow! Really nice. I love the animations.

I made an endless random card (and die roll) generator: http://staticresource.com/shuffle.html just tap anywhere to draw a new card.

Seeing what you've done with your Deck of Cards is a big inspiration!

How did you get it to show up at the URL: http://pakastin.github.io/deck-of-cards/?

I thought we needed to make a separate repository for github pages first. My other repo doesn't show at all.

You just need a gh-pages branch on the repo. The separate repo is only for the "root folder" of that subdomain (i.e. the content of the master branch of the repo pakastin/pakastin.github.io shows up at pakastin.github.io/ and the content of the gh-pages branch of the repo pakastin/xyz shows up at pakastin.github.io/xyz).

Thanks. I've been manually copying the directories into my gh-pages repo. lol.

Put some HTML code on the gh-pages branch :)


Very nice! I tried the CSS3 routes for card animations when I first built my card game ( https://solitaire.gg ), but ended up going with WebGL since the cross-browser support for CSS3 animations was so wonky.

Whoa, really smooth animations!

I know the feeling..

the animation is lovely and fluid. bit of a shame that the card faces don't have the pictures for the royal cards and the usual layout of multiple suit signs on the number cards, but this is still super.

Flash version had some of those: http://pakastin.fi/cards_2006

I used 52-framed movieClip as a card, where frames were values.

And then every suit graphic was one movieClip as well with 4 frames: spade, heart, club and diamond

Worked great! Not so easy to do with HTML though. Lots of figuring out coordinates manually.

That's now fixed!

Very neat! Mind if I borrow some of the CSS for my cards trick[0]?

[0] http://cluecode.com/cards/

Go for it! ;)

I wrote a simpler version of very nearly the same thing not long ago. But this one is much nicer. The animations, in particular, add a lot of flash.

Thanks! It's fun to make them as realistic as possible. Usually shuffle animations are a bit plain..

Looks great! Ability to flip cards would be awesome. When the cards are fanned, I'd love to see the end one being flipped and they all domino over :)

That's such a great idea!! :)

Loved it :).Animations are beautiful, will be using them soon in card game I am developing. Thanks for releasing it at the right time for me.

Glad to hear! Would love if you'd share your work with me. I'm on Twitter @pakastin ;)

gorgeous! really fine work. (granted i have no design talent, though i did work for an online poker shop for six years and i have played a lot of poker with friends and a lot house poker in casinos.

particularly awesome is "sort", which i think really nicely simulates a (reverse) shuffle; it seemed like i could see the top edge of the cards lift as they rotated along the bottom edge

Thanks! Next I need to make a game out of this :)

Way cool! Echoing the sentiments of others who've commented on the fluidity of the motions on display here.


This would be awesome for playing Magic The Gathering, grabbing the card art off of the gatherer site.

I don't know anything about Magic the Gathering, but I will make the API better and the faces more customizable.

I want to deal a card game and play with someone. The cards need to be face down though.

Yeah, would be fun!

Would be cool if you could drag select multiple cards to move hands around in the demo.

You mean dragging would support multiple touch points..? sounds fun!

I'd love to build a cribbage game with this as the basis for the UI.

I have to work hard on API, it's really just barebones at the moment :/

nitpick: when fanning out the cards and then clicking on one it should stay in the orientation it was in the fan, it jumps weirdly around.

same when clicking on the top card of a stack, it jumps ~40px.

That's already on the "todo" list - check out readme ;)

Kudos for making this run smoothly on my three year old laptop!

My MacBook Pro is even older - 3 years is not that much.. But thanks! :)

More like JS + CSS3 Deck of Cards.

I used HTML5 just because the original version was made with Flash back in 2006 (http://pakastin.fi/cards_2006). Then I made a Angular.js version, which is lost, but was featured on Chrome Experiments. This is actually HTML5 Deck of Cards 2 :)

Anyway, great job. This the best deck of cards I've seen on the web. I'm pretty sure it won't be long before we see a Meteor app that uses this.

Thanks! I look forward to seeing what other people make out of it.. :)



What's so HTML5 about this?

<!DOCTYPE html> – that's about it :D

As far as I can tell, it uses 2d transforms, which are usually considered part of HTML5. The animation would probably be a bit jerkier and slower if done with absolute positioning instead.

Yeah, translates and transitions.. Both are CSS3


Maybe instead of trashing other people's work you could just link to yours instead.

This is the real world: just because you do work doesn't mean you were working on the right thing, the right way, at the right time, for the right people, etc.

Maybe pretending everything is awesome feels good now, but it won't feel good when you're in your 40s with nothing lasting to show for 20 years of professional development work.

I won't be linking to my work for 2 reasons:

1. I say unpopular things with this account and value my anonymity. 2. It's completely irrelevant. Posting my work would neither prove that I'm justified in what I said nor disprove what you say.

But hey: https://www.youtube.com/watch?v=gSjLiQxEZlM

It's easy to say unpopular things with an anonymous account, but it kind of takes the weight out of them IMO. Own your opinions, I say.

It's easy to speak with your real name when don't think for yourself and instead only follow popular opinions, but that makes your opinions kind of worthless IMO. The truth is not always what's popular, I say.

something to hook it up with : http://deckofcardsapi.com/

Okay, but that doesn't address that it still doesn't have faces on face cards, different numbers of suit icons on each card, etc. There are off-the-shelf stock photo sets that make it easier to tell the difference between the cards.

See the thing you don't get here is that none of what you say justifies posting these comments just to shit on something. It makes a negative contribution to the conversation, which HN explicitly does not want.

I get that you (and a lot of other people) think that, I just don't care. In general, you should disabuse yourself of the notion that a) you speak for HN, and b) that I care what you want.

Other HN users can have their opinions on what they want from HN, and can downvote accordingly. But I'd like HN to be a place where people can learn about reality instead of just go to get some false positive feedback, and I'm going to act accordingly.

If you want a place where you can get unconditional approval, you might want to try your mother. She'll always approve of what you do even if it's terrible.

And in general, you're not going to gain much traction talking to me as long as you think people are obligated to care when someone gets offended.

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