Build a Memory Card Matching Game with HTML5 Canvas and JavaScript
Build a shuffled deck, a two-card state machine, Canvas rendering, and keyboard controls using the working Memory Match project.
HoloViral articles
Canvas, animation, input, and game rules, explained through the projects on this site.
35 published articles about building, testing, and sharing browser games.
Build a shuffled deck, a two-card state machine, Canvas rendering, and keyboard controls using the working Memory Match project.
A synthesized game effect needs more than an oscillator frequency.
A Canvas context remembers more than the pixels you just drew.
Changing a canvas from 960 pixels wide to 390 pixels wide sounds like a responsive layout change.
A collector that follows your finger on a desktop can jump away from it on a phone.
A more precise collision test is useful when the visual corners of a paddle matter.
Gem Collector does not use a physics library.
A plain HTML site does not need a framework build directory merely because the hosting dashboard says “build output.” On Cloudflare Pages, the directory containing your finished HTML and assets can be the upload directory itself.
A difficulty selector becomes hard to maintain when every option is a separate game page with a few constants changed.
Randomizing a memory board is an algorithm problem before it is a visual one.
The shared HoloViral loop advances each engine once per animation callback using a capped variable delta.
A game's internal state can change every frame without requiring every number to be announced or every label to be rebuilt.
Use the Gem Collector engine to build a delta-time loop with safe pause, restart, input, spawning, and collision behavior.
Continuous movement should depend on how long a direction is held, not how frequently the operating system repeats keydown events.
A canvas can have correct proportions and still look softer than nearby text.
Drawing a button-shaped rectangle on Canvas does not create a keyboard-accessible button.
A memory game does not need a large state-machine library to benefit from explicit states.
A delayed card flip is an easy place to introduce a stale callback.
Holding an arrow key should not send the car repeatedly across all three lanes.
A source download is useful only if it contains everything required to run the example.
The most visible pause bug is a large jump on resume.
A movement button can work perfectly until a finger slides outside it.
A small Canvas game can feel uneven even when its source looks simple.
Lane Racer's counter is labeled progress rather than pure distance because collecting a coin increases the same value that grows with driving time.
A gem that touches the paddle remains near it for more than one animation frame.
Restart is more than setting score to zero.
A failing collision test is difficult to debug if the next run creates different objects.
Gem Collector displays a 75-second limit, but under a severe rendering slowdown a round can last longer than 75 seconds on a stopwatch.
A collector catches its final required gem in the same update that a hazard removes its last life.
Timing Tap moves its ring without storing a separate horizontal velocity or bouncing it off invisible walls.
The collector creates an object when its spawn timer crosses an interval, then resets the timer to zero.
A swipe is not just a click with a large coordinate.
Waiting for real animation frames makes scheduler tests slow and unreliable.
The highlighted zone in Timing Tap is a promise about a rule.
The four game demos are silent by default.