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