Memory Koningsdag 2026
by Dutton
HTML
<div class="stageWrap">
<div class="stage">
<div class="layoutBg" style="background-image:url('https://i.imgur.com/7IZQ1JV.png');"></div>
<div class="gameSlot">
<div id="app">
<div class="winOverlay" id="winOverlay" style="display:none;">
<div class="winBox">
<span class="claimCode" id="claimCode">Y@YK!ngsD@Y2026!!</span>
</div>
</div>
<div class="info">
<div>Tijd: <span id="time">01:00</span></div>
<div>Beurten: <span id="turns">0</span></div>
<div>Levens: <span id="lives">2</span> ❤️</div>
</div>
<div class="cards" id="cards"></div>
<canvas id="confetti" class="confetti"></canvas>
</div>
</div>
</div>
</div>
CSS
.stageWrap{
--s: 1;
width: calc(688px * var(--s));
height: calc(800px * var(--s));
margin: 0 auto;
}
.stage{
position: relative;
width: 688px;
height: 800px;
transform: scale(var(--s));
transform-origin: top center;
}
@media (max-width: 720px){
.stageWrap{
--s: calc((100vw - 20px) / 688);
}
}
.layoutBg{
position: absolute;
inset: 0;
background-size: 100% 100%;
background-repeat: no-repeat;
}
.gameSlot{
position: absolute;
left: 344px;
top: 500px;
width: 660px;
transform: translate(-50%, -50%);
}
#app{
width: 100%;
font-family: Arial, sans-serif;
}
.info{
width: 588px;
margin: 0 auto 12px;
padding: 10px 0;
background: rgba(255,255,255,0.95);
border-radius: 12px;
text-align:center;
font-weight:bold;
}
.cards{
display:grid;
grid-template-columns: repeat(5, 110px);
grid-auto-rows: 100px;
gap: 14px;
width: 588px;
margin: 0 auto;
}
.card{
position:relative;
width:100px;
height:100px;
cursor:pointer;
perspective: 800px;
}
.card .front,
.card .back{
position:absolute;
inset:0;
border-radius:10px;
backface-visibility:hidden;
transition: transform .6s, opacity .25s;
transform-style: preserve-3d;
overflow: hidden;
}
.card .back{
background: linear-gradient(#ffb66d, #ff7b00);
display:grid;
place-items:center;
font-size:34px;
color:white;
}
.card .back::after{
content:"👑";
}
.card .front{
transform: rotateY(-180deg);
background-size:85%;
background-repeat:no-repeat;
background-position:center;
background-color:white;
}
.card.flipped .back,
.card.found .back{ transform: rotateY(180deg); }
.card.flipped .front,
.card.found .front{ transform: rotateY(0deg); }
.card.found{
pointer-events: none;
cursor: default;
}
.card.found .front{
opacity: 0.35;
}
.card.found .front::after{
content:"";
position:absolute;
inset:0;
...
JavaScript
(function(){
var GAME_SECONDS = 60;
var START_LIVES = 2;
var CLAIM_CODE = "Y@YK!ngsD@Y2026!!";
var images = [
"https://i.imgur.com/uC8DFjY.png",
"https://i.imgur.com/YCz5KY9.png",
"https://i.imgur.com/hsCxIGP.png",
"https://i.imgur.com/a7YkNKf.png",
"https://i.imgur.com/6mGpWdN.png",
"https://i.imgur.com/VMxznfZ.png",
"https://i.imgur.com/2qAMuXY.png",
"https://i.imgur.com/TGXR92E.png",
"https://i.imgur.com/lghoztW.png",
"https://i.imgur.com/xfEan69.png"
];
var cardsEl = document.getElementById("cards");
var timeEl = document.getElementById("time");
var turnsEl = document.getElementById("turns");
var livesEl = document.getElementById("lives");
var winOverlay = document.getElementById("winOverlay");
var claimCodeEl = document.getElementById("claimCode");
var confettiCanvas = document.getElementById("confetti");
var confettiCtx = confettiCanvas.getContext("2d");
var confettiParts = [];
var confettiEnd = 0;
var confettiRAF = 0;
claimCodeEl.textContent = CLAIM_CODE;
var state = {
deck: [],
first: null,
lock: false,
turns: 0,
lives: START_LIVES,
timer: null,
started: false,
startTime: 0,
timeLeft: GAME_SECONDS
};
function shuffle(a){
for(var i=a.length-1;i>0;i--){
var j=Math.floor(Math.random()*(i+1));
var t=a[i]; a[i]=a[j]; a[j]=t;
}
return a;
}
function build(){
var d=[];
for(var i=0;i<images.length;i++){
d.push({img:images[i],name:i,flipped:false,found:false});
d.push({img:images[i],name:i,flipped:false,found:false});
}
return shuffle(d);
}
function render(){
cardsEl.innerHTML="";
state.deck.forEach(function(c,i){
var div=document.createElement("div");
div.className="card"+(c.flipped?" flipped":"")+(c.found?" found":"");
var back=document.createElement("div");
...