<playing-card>
This project uses modern browser technologies. Open in a 'evergreen' browser
If you want to make it work in outdated browsers see the WebComponents polyfill
License: Unlicense: This is free software released into the public domain - https://choosealicense.com/licenses/unlicense/
SVG data for 52 playing cards - 500 KB painstakingly slimmed
one W3C Autonomous Custom Element : <playing-card cid=Queen-of-Hearts> </playing-card>
52 customized Built-In IMG elements : <img is=queen-of-hearts>
(not supported in Safari; no longer created since 2024)
Total GZip file size: (under) 14 KBΒ² creating 52 playingcards:
A 'Hello World!' with Framework X took hours installing tools and used 95 KiloBytes ... to display 12 characters.
Something did not feel right!
What happened to the days when all you needed were some HTML tags and a text-editor?
I learned to PEEK and POKE at the age of 10 on a TRS-80 and learned HTML (a bit late) at 25
The ability to 'peek at' and learn from someone else's effort was fantastic.
Alas in the past years 'Web Development' has become something For-Rocket-Scientists only
W3C standard Custom ElementsΒΉ make writing semantic HTML as cool as it was in my early days .. without any Framework!
Playingcard(t)s are a good subject to demonstrate the power of a Custom Element
<playing-card>
Custom ElementFeel free to PEEK around, and if you want to POKE, submit an issue.
A special thanks to users Supersharp and Intervalia for their always helpful answers on StackOverflow!
-- Danny Engelman
-- Amsterdam π·π·π· the Netherlands
-- Summer 2019 π΄π½ 25 years after my first HTML page
The terms Custom Elements & Web Components are used interchangeably.
Web Components is the umbrella term for the three main techonologies:
Minified 16 KB GZip
It is a card game .. I cheated ... but can you spot where? (explained in documentation below)
<playing-card>
Custom-Element worksFor an introduction to W3C standard Custom Elements/WebComponents read the excellent Blog by Danny Moerkerke
Like the HTML5 <video>
tag, the Custom Element <playing-card>
abstracts complex functionality into one HTML tag
π‘ Custom Elements must be declared in a Namespace, so require a - hyphen in the tag name
<html>
<head>
<script src="https://github.com/cardmeister/cardmeister.github.io/raw/master/elements.cardmeister.full.js"></script>
</head>
<body>
<playing-card rank="Queen" suit="Hearts"></playing-card>
</body>
</html>
(Autonomous) Custom Element <playing-card>
creates an image with the SVG as data:image
src
Saves you from headaches with SVG in a document (duplicate symbol ids, bleeding CSS etc.)
and makes it easy to add HTML Drag-Drop functionality.
π‘ Autonomous Custom Elements require a closing tag: </playing-card>
52 Custom Elements are also created customizing the IMG element so you can use:
<img is="ten-of-hearts" />
<img is="jack-of-hearts" />
<img is="queen-of-hearts" />
<img is="king-of-hearts" />
<img is="ace-of-hearts" />
The Autonomous Custom Element
<playing-card>
and the Customized Built-In Element<img is=...>
are two different flavours of Custom Elements which (in this case) do the same.
You can pick the one that suits your application. Or use them both in one page: https://cardmeister.github.io
π‘ requires a polyfill in Safari, because Apple does not want to implement this part of the spec.
π‘ declaration must be all lowercase!
π‘ the IMG element is self-closing by default, no closing tag required!
π‘ the is=
declaration only takes effect when the DOM element is created
π‘ on the (customized IMG) element you can use all attributes/properties documented below
π¨βπ» tech: Autonomous Elements can have ShadowDom, Customized Elements can not have ShadowDom
π¨βπ» tech: Because IMG elements don't contain text or have descendants, neither CSS selector img:before
or img:after
can be used
<playing-card>
with CSS:Since <playing-card>
only creates a single IMG no shadow-DOM is required/used, thus IMG can be styled with global CSS:
[rank="queen"] img {
border: 3px solid greenyellow;
transform: rotate(15deg);
}
or for the customized IMG element:
img[is*="queen"] {
border: 3px solid greenyellow;
transform: rotate(15deg);
}
I have the selection and drag/drop part nearly done: https://playing-cards.github.io/Solitaire/
<cardts-game>
<cardts-deck type="frenchdeck"></cardts-deck>
<cardts-pile>
<% 7 times %>
<cardts-pile type="sequence"></cardts-pile>
<%%>
</cardts-pile>
<cardts-pile id="foundation" type="stack">
<% 4 times %>
<cardts-pile></cardts-pile>
<%%>
</cardts-pile>
<cardts-game></cardts-game
></cardts-game>
<playing-card>
games ...What if cardts could:
<playing-card>
attribute/properties syntaxplayingcards Terminology:
π‘ attributes can be written as attributes in HTML:<playing-card id=MyCard cid=Qh ></playing-card>
π‘ attributes can be set as attribute:MyCard.setAttribute('cid','Kh')
π‘ or as property: MyCard.cid='Kh'
(sets the attribute value)
<playing-card>
takes a sh*tload of attributes you can play with:See: https://cardmeister.github.io
cid
- Standard Card ID notation: cid=Qh
= Queen of Heartsletters
- Custom localized court letterscourts
- mix rank/courts imagessuits
- Mix suit/court imagessuitcolor
- Change SHDC suit colorrankcolor
- Change rank colorcardcolor
- card coloropacity
- set card content opacitycourtcolors
- Change court image colorsbordercolor
- set card border colorborderradius
- set card border radiusborderline
- set card border line thicknessbacktext
- card backside textbacktextcolor
- card backside colorsvg
- (undocumented) add attributes to main SVG definition (eg: svg="transform='rotate(5,5,5)'")pips
- (undocumented) custom suitsymbols (pips) on number cardscid
- standard card id notation <playing-card cid=As></playing-card>
<playing-card cid=5d></playing-card>
<playing-card cid=Tc></playing-card>
<playing-card cid=Jh></playing-card>
<playing-card cid=Qc></playing-card>
π‘ overrules rank=
and suit=
notation
π‘ case insensitive: qC
is the same as: Qc
π‘ 10C
is processed as TC
π‘ Queen-of-Clubs
is processed as Qc
π‘ <img is=queen-of-clubs>
uses cid
internally - is=
requires lowercase full Element name!!
letters
- Custom localized court lettersdefault: AJQK
Rename Ace, Jack, Queen, King letters AJQK to Dutch locale 'Aas Boer Vrouw Heer'
<playing-card suit=Spades rank=Ace letters=ABVH></playing-card>
<playing-card suit=Hearts rank=Jack letters=ABVH></playing-card>
<playing-card suit=Diamonds rank=Queen letters=ABVH></playing-card>
<playing-card suit=Clubs rank=King letters=ABVH></playing-card>
π‘ a 4 letter string is used so it can be a global setting for all created cards
π‘ Custom letters
draw all ranks (A,2,3,4 etc.) in Arial font
π‘ letters
can not be Emoji (Unicode strings)
courts
- mix rank/courts imagesdefault: 012
Before anyone complains the Queen is always #2
Rearrange SHDC court images to KJQ = 201 :
<playing-card suit="Hearts" rank="Jack" courts="201"></playing-card>
<playing-card suit="Spades" rank="Queen" courts="201"></playing-card>
<playing-card suit="Diamonds" rank="King" courts="201"></playing-card>
backcolor
- card backside colordefault: #E55 (red)
<playing-card rank="0" backcolor="red"></playing-card>
<playing-card cid="00"></playing-card>
<playing-card
rank="0"
backcolor="#44F"
backtext="COPYRIGHT"
backtextcolor="black"
></playing-card>
suitcolor
- Change SHDC suit colorrankcolor
- Change rank colordefault: #000,red,red,#000
(rankcolor added on request in 2024; can also be a single color value)
cardcolor
- card colordefault: #FFF
<playing-card
rank="1"
suit="0"
suitcolor="#FFF,#FFF,#FFF,red"
cardcolor="red"
></playing-card>
<playing-card
rank="1"
suit="1"
suitcolor="#FFF,yellow,#FFF,red"
cardcolor="green"
></playing-card>
<playing-card
rank="1"
suit="2"
suitcolor="#FFF,#FFF,black,red"
cardcolor="dodgerblue"
></playing-card>
<playing-card
rank="1"
suit="3"
suitcolor="#FFF,#FFF,#FFF,red"
cardcolor="yellow"
></playing-card>
The string (all 4 settings in one string for global declaration!) is converted to an array so can be written as:
<playing-card rank="1" suit="0" suitcolor="#FFF," cardcolor="red"></playing-card>
<playing-card rank="1" suit="1" suitcolor=",yellow" cardcolor="green"></playing-card>
<playing-card rank="1" suit="2" suitcolor=",,black" cardcolor="dodgerblue"></playing-card>
<playing-card rank="1" suit="3" suitcolor=",,,red" cardcolor="yellow"></playing-card>
π‘ You can change one card with: element.suitcolor='blue';
π‘ non-color values will break the SVG suit display
π‘ add attribute norank=true
and only the big center suit remains
opacity
- set card content opacitydefault: 0.8
π‘ 0.8 makes the cards look not too sharp, and you can highlight playing-cards by setting opacity to 1
<playing-card rank="1" suit="0" opacity="1"></playing-card>
<playing-card rank="1" suit="1" opacity=".75"></playing-card>
<playing-card rank="1" suit="2" opacity=".5"></playing-card>
<playing-card rank="1" suit="3" opacity=".1"></playing-card>
π‘ CSS opacity makes the whole IMG transparent! <playing-card opacity=n>
leaves the <playing-card>
backcolor at 100%
bordercolor
- set card border colordefault: #444 (darkgray)
borderradius
- set card border radiusdefault: 12
borderline
- set card border line thicknessdefault: 1
<playing-card
rank="1"
suit="0"
bordercolor="red"
borderradius="12"
borderline="12"
></playing-card>
<playing-card
rank="4"
suit="0"
bordercolor="hotpink"
borderradius="100%"
borderline="20"
></playing-card>
<playing-card
rank="13"
suit="H"
bordercolor="gold"
borderradius="12"
borderline="38"
></playing-card>
courtcolors
- Change court image colorsthis setting will most likely be gone in 'less SVG' version 2
default: #DB3,red,#44F,#000,#000,4 (gold,red,blue,black,blacklines,linethickness)
<playing-card
suit="Hearts"
rank="Jack"
courtcolors="gold,red,blue,black,black,4"
></playing-card>
<playing-card
suit="Spades"
rank="Queen"
courtcolors="#DB3,lightcoral,lightblue,slategray,#000,1"
></playing-card>
<playing-card
suit="Diamonds"
rank="King"
courtcolors="gold,red,green,orange,#000,4"
></playing-card>
π‘ suit decorations are set by the suitcolor
attribute
All good open-source SVG playingcards available are high-precision ready for print.
In the HTML5 deck of cards the single King of Hearts 1_13.svg card is 69 KB
<playing-card>
creates all 52 cards in 16 KBSVGcardt()
function to create an IMG with SVG dataThe SVG can be reduced more using a LZMA compressor
But HTTP requires Base64 encoding.
And the Browser needs to decompress the data which takes a hefty 200ms (and a 6.9KB decoder)
The first PoC did LZMA de-compression and lazy loaded all 12 court images.
Since GZip is a similar LZ compression technique (over the whole file) there is only a gain on slow 3G connections
<playing-card>
A Custom Element requires its own Namespace, so you are stuck to something with a - hyphen.
You can create 52 Autonomous Custom Elements (extend from <playing-card>
):
<queen-of-hearts></queen-of-hearts>
<ten-of-spades></ten-of-spades>
...
But there is little value as you can not use partial Selectors for tag names.
To select all Spades you still need attributes:
<queen-of-hearts hearts></queen-of-hearts>
<ten-of-spades spades></ten-of-spades>
...
Because queen-of-hearts
can either be a 'Autonomous Custom Element' OR a 'Customized Built-In Element'
<playing-card>
creates 52 Customized IMG elements:
<img is="ten-of-hearts" />
<img is="jack-of-hearts" />
<img is="queen-of-hearts" />
<img is="king-of-hearts" />
<img is="ace-of-hearts" />
π‘ declaration must be all lowercase!
π‘ the IMG element is self-closing by default, no closing tag required!
π‘ the is=
declaration only takes effect when the DOM element is created
π‘ on the (customized IMG) element you can use all attributes/properties documented above
Yes, an option is to exclude the (compressed/raw) SVG data from the Element file.
The Element can then fetch the data asynchronous.
This project was about stuffing everything into one file.
If you need an installer to copy one file: elements.cardmeister.min.js
You might find a better career flipping burgers at McDonalds.
Read: I stuck the UNlicense on this code. You can do whatever you want with the code.
I don't want to be responsible for maintaining a dependency for others
SVGcardt()
source?You do NOT need the SVGcardt()
Source Code to use <playing-card>
or <img is=..>
in applications
The <playing-card>
Custom Element declaration in elements.cardmeister.min.js is unlicensed.
You can rename <playing-card>
to anything you want and customize the Custom Element to your liking.
The <img is=..>
declaration is part of the minified SVGcardt() code.
The SVG creation code took some blood, sweat and tears and is closed source for now.
It needs some refactoring and documentation before this is public ready.
Watch this GitHub repo and you will know when it becomes available.
See F12 Network tab, data:image/svg
cardts take 0 milliseconds download time
Note: FireFox is noticeably slower in drawing the cards.
Creating the card does take CPU time. Maybe a WebWorker can improve performance (but I can't stick JScode and a WebWorker in one single file)
π Causing havoc in Gotham City?!
I haven't found a good Joker Card design yet, if you have one let me know
I wanted to learn how far I could go with vanilla JavaScript
Then I wanted to proof you don't need libraries/frameworks
Look closely at the court cards....
The 16 KB version uses the same (JQK Hearts) court image with slightly different colors to distract your eye.
suits
- Mix suit/court imagesdefault: 0123 (defaults to 1111 in the 16 KB version!)
Change Spades=0, Hearts=1, Diamonds=2, Clubs=3 court image:
<playing-card suit=S rank=Queen suits=1111></playing-card>
<playing-card suit=H rank=Queen suits=1111></playing-card>
<playing-card suit=D rank=Queen suits=1111></playing-card>
<playing-card suit=C rank=Queen suits=1111></playing-card>
<playing-card>
version with 12 unique SVG courts:The Full Version elements.cardmeister.full.js with 12 different court images adds 110 KB raw SVG data
Making the single file 60 KB GZipped!
Apart from the court images there are no differences.
It was fun (and took some time) breaking that 16 KB barrier, and helped making the full version smaller as well.
Use the Full version !
The Min version can be used for slow/low-bandwidth applications.
<playing-card>
Create FreeCell with HTML Custom Elements
inspiration: https://www.free-freecell-solitaire.com/freecell.html
(something like) This HTML should create ALL game functionality
<cardts-game>
<cardts-pile id="freecells" type="any">
<% 4 times %>
<cardts-pile max="1"></cardts-pile>
<%%>
</cardts-pile>
<cardts-pile id="foundation" type="stack">
<% 4 times %>
<cardts-pile></cardts-pile>
<%%>
</cardts-pile>
<cardts-pile>
<% 8 times %>
<cardts-pile type="sequence"></cardts-pile>
<%%>
</cardts-pile>
<cardts-deck type="frenchdeck"></cardts-deck>
<cardts-game></cardts-game
></cardts-game>
<playing-card cid="F0"></playing-card>
<playing-card cid="FH"></playing-card>
<playing-card cid="F2"></playing-card>
<playing-card cid="FC"></playing-card>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to http://unlicense.org
https://www.youtube.com/watch?v=7hx4gdlfamo&t=1s
or the Muppets version: https://www.youtube.com/watch?v=kNnrTNFWcsg
Comparison of multiple solutions: https://socialcompare.com/en/comparison/css-playing-cards-pgnq7dx
SVG (server side) Card Creator (I used these and altered them)
https://www.me.uk/cards/makeadeck.cgi
ES6/Polymer WebComponent - separate SVG files for courts (last commit:2017)
https://www.webcomponents.org/element/vpusher/game-card
CSS playing cards - PNG images (over 250 Kb) (last commit: 2012)
https://donpark.github.io/scalable-css-playing-cards/
HTML5 deck of cards (all 52 cards are separate SVG files) (last commit: 2017)
https://github.com/pakastin/deck-of-cards
https://deck-of-cards.js.org/
King of Hearts alone is 69 KB : https://deck-of-cards.js.org/faces/1_13.svg
CSS only (no Court images) (last commit: 2012)
https://github.com/zachwaugh/Helveticards
PNG card background image = https://bfa.github.io/solitaire-js/img/card_back_bg.png
DeckOfCards API - http://deckofcardsapi.com/
Solitaire
Redux,React, the lot https://codepen.io/HunorMarton/details/rwpGXj
(2017) No frameworks/library No drag drop, PNG images for courts
https://bfa.github.io/solitaire-js/
https://github.com/bfa/solitaire-js
Poker API - https://rapidapi.com/danielamitay/api/poker-odds
Yes, I did https://chessmeister.github.io
<img is=white-queen at=D5>
Load SVG content in main document:
<iframe src="https://github.com/cardmeister/cardmeister.github.io/raw/master/file.svg" onload="this.before(this.contentDocument.children[0]); this.remove();"></iframe>
Published: 2020-08-06 17:13