Settings

Theme

HTML5 Deck of Cards

pakastin.github.io

419 points by delambo 11 years ago · 164 comments

Reader

AndyKelley 11 years ago

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.

  • RodericDay 11 years ago

    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.

  • AUmrysh 11 years ago

    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.

    • AndyKelley 11 years ago

      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.

    • gcb0 11 years ago

      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.

  • hellbanner 11 years ago

    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.

    https://github.com/QuantumProductions/tic-tac-toe

  • cableshaft 11 years ago

    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.

  • rw2 11 years ago

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

riebschlager 11 years ago

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.

  • takeda 11 years ago

    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.
    • TazeTSchnitzel 11 years ago

      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.

    • riebschlager 11 years ago

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

    • fenomas 11 years ago

      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.

    • adamkochanowicz 11 years ago

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

  • daok 11 years ago

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

  • pakastin 11 years ago

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

    • ZitchDog 11 years ago

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

      https://jsperf.com/or-vs-floor/2

      • Stormcaller 11 years ago

        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...

      • jpollock 11 years ago

        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?

        • TazeTSchnitzel 11 years ago

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

      • aaronm67 11 years ago

        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.

        • pkstn 11 years ago

          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) {}

      • ldesegur 11 years ago

        i/13|undefined works too

        • logicallee 11 years ago

          plus

            i/13|undefined  
          
          has that "this was originally written in javascript, not ported halfheartedly from some other language" feel. (Well, maybe PHP.)
        • ygra 11 years ago

          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.

      • irascible 11 years ago

        gulp I guess I should stop using parseInt :/

    • robocat 11 years ago

      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.

  • DatBear 11 years ago

    Why not just i % 4?

    • novaleaf 11 years ago

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

      • epyjao 11 years ago

        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).

      • DatBear 11 years ago

        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.

  • gcb0 11 years ago

    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 ;)

  • hacker_9 11 years ago

    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/

    • Stormcaller 11 years ago

      It exists in other languages, too, like PHP.

      • TazeTSchnitzel 11 years ago

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

        Use (int), like C.

        • Stormcaller 11 years ago

          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?

          • TazeTSchnitzel 11 years ago

            > 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.

  • redler 11 years ago

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

      ~~(i/13)
    • tracker1 11 years ago

      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.

hacker_9 11 years ago

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?..

jasonkester 11 years ago

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.

  • TazeTSchnitzel 11 years ago

    > 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.

    https://en.wikipedia.org/wiki/Fallback_font

  • pakastin 11 years ago

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

    • jasonkester 11 years ago

      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.

      • jklein11 11 years ago

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

      • pkstn 11 years ago

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

  • pakastin 11 years ago

    Fixed!

felipeerias 11 years ago

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.

retrogradeorbit 11 years ago

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

thomasfoster96 11 years ago

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?

  • pakastin 11 years ago

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

    • pauly 11 years ago

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

      • indubitably 11 years ago

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

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

        Or something?

        • femto113 11 years ago

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

          <p class="2 ︎"/>

          http://codepen.io/femto113/pen/avzWJq

          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.

          • pakastin 11 years ago

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

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

        • pauly 11 years ago

          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...

  • esprehn 11 years ago

    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.

    • pakastin 11 years ago

      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 :)

donpark 11 years ago

Nice animation although card faces need some work.

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

http://donpark.github.io/scalable-css-playing-cards/

mkorfmann 11 years ago

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.

almightysmudge 11 years ago

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?

halotrope 11 years ago

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

  • pkstn 11 years ago

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

ipsin 11 years ago

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.

snake117 11 years ago

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

Nice work by the way!

linuxlizard 11 years ago

What? No 52 pick up? ;-)

err4nt 11 years ago

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!

kelukelugames 11 years ago

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.

kyle_u 11 years ago

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.

danvesma 11 years ago

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.

  • pakastin 11 years ago

    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.

  • pakastin 11 years ago

    That's now fixed!

habith 11 years ago

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

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

borkabrak 11 years ago

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.

  • pakastin 11 years ago

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

TomGullen 11 years ago

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 :)

saheb37 11 years ago

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.

  • pakastin 11 years ago

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

doug1001 11 years ago

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

hissworks 11 years ago

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

TimJRobinson 11 years ago

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

  • pakastin 11 years ago

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

hotgoldminer 11 years ago

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

mentos 11 years ago

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

voltagex_ 11 years ago

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

mschuster91 11 years ago

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.

tripzilch 11 years ago

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

adam12 11 years ago

More like JS + CSS3 Deck of Cards.

  • pakastin 11 years ago

    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 :)

    • adam12 11 years ago

      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.

      • pkstn 11 years ago

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

adamkochanowicz 11 years ago

Mesmerizing.

kachnuv_ocasek 11 years ago

What's so HTML5 about this?

  • pakastin 11 years ago

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

  • Mahn 11 years ago

    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.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection