🖥️ Source Code: https://github.com/moksh-jalendra/ziply-puzzel
🎮 Play Ziply Live: https://html5.gamemonetize.co/d7a965ple3vols2kwz51d646oclw79mh/
Whenever we start a new web project today, the immediate reflex is to run npx create-react-app or spin up a Next.js boilerplate. But what happens when you want to build a highly interactive, 1500-level logic puzzle game that needs to run flawlessly on low-end mobile devices?
You drop the frameworks and go back to the basics.
I recently launched Ziply, a line-drawing logic puzzle game. Instead of using a heavy game engine like Unity or a web framework like React, I built it entirely from scratch using Core Vanilla JS, HTML, and CSS.
Here is a breakdown of the architecture, the performance choices I made, and how I used AI to overcome my biggest algorithm roadblock.
- Why Vanilla JS? (Performance & Control) In a game where the user is rapidly dragging their finger across a grid to draw pipes, frame rate is everything.
If I used React, every single tile touch would trigger a state change, potentially causing heavy re-renders of the entire 8x8 grid. By using Vanilla JS, I had absolute control over the event loop and memory management. I could bind touchstart and touchmove events directly to the container, track the exact coordinates of the user's finger, and update the game state in a fraction of a millisecond without any framework overhead.
- The Architecture: A DOM + Canvas Hybrid The biggest visual challenge was rendering the glowing "pipes" as the user swipes.
Building the entire game in means writing custom hit-boxes, event listeners, and UI scaling logic from scratch. But using pure HTML/CSS to draw connecting lines is a nightmare of absolute positioning.
My Solution: A hybrid approach.
I used CSS Grid to generate the actual game board using standard
elements. This gave me built-in responsiveness and dead-simple hit detection using document.elementFromPoint(). Then, I layered a completely transparent element directly on top of the CSS Grid.JavaScript
// The DOM handles the logic and hit detection
let ellement = document.elementFromPoint(clientX, clientY);
let gridx = ellement.dataset.x;
let gridy = ellement.dataset.y;
// The Canvas acts purely as a visual presentation layer
function drawPipe() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
// Loop through the path array and draw lines
// connecting the centers of the DOM nodes
ctx.stroke();
}
The DOM acts as the invisible brain handling touch events, and the Canvas acts as the paint. It is the best of both worlds.
- The Hint System & My AI Pair Programmer The hardest feature to build by far was the Hint System.
The core rule of Ziply is that you must connect the numbers in order and fill every single empty block on the board.
Initially, I tried to write a simple Breadth-First Search (BFS) to find the path to the next number. This was a disaster. The BFS would find the shortest route, but in doing so, it would cut corners and block off empty tiles, giving the player a hint that made the level literally impossible to beat.
I realized I needed a Depth-First Search (DFS) with Backtracking algorithm. It needed to simulate playing the game invisibly, exploring thousands of paths, and backtracking when it got trapped, only stopping when it found a verified 100% win path.
Transparency time: I am a web developer, and advanced pathfinding algorithms aren't my strong suit. I had no idea how to write a Backtracking DFS from scratch.
Instead of letting the feature die, I used Gemini as my pair-programmer. I fed the AI the rules of my game grid, explained why the BFS was failing, and worked with it to generate and refine a DFS solver.
JavaScript
// The Backtracking Solver generated with AI
function solve(currentPath, currentExpected) {
if (bestSolution) return;
// PERFECT WIN CONDITION: Path fills all tiles AND ends on highest number
if (currentPath.length === targetLen && cellVal === maxNum) {
bestSolution = [...currentPath];
return;
}
let neighbors = [`${cx+1}-${cy}`, `${cx-1}-${cy}`, `${cx}-${cy+1}`, `${cx}-${cy-1}`];
for (let n of neighbors) {
if (isValidMove(n)) {
currentPath.push(n);
solve(currentPath, nextExpected); // Recursive dig
currentPath.pop(); // Backtrack if it's a dead end
}
}
}
Integrating the AI-generated algorithm into my existing game loop, connecting it to the UI animations, and debugging the edge cases was an incredible learning experience. It taught me how powerful AI can be when you use it to bridge the gaps in your own knowledge.
Play it for yourself!
Building Ziply was an amazing exercise in pushing the DOM to its limits and learning how to leverage modern AI tools to solve complex computer science problems.
I would love for the DEV community to try it out. See if you can beat Level 10 on the 6x6 Master Mode!
🎮 Play Ziply Live: https://html5.gamemonetize.co/d7a965ple3vols2kwz51d646oclw79mh/
If you have any feedback on the UI, the touch controls, or the code architecture, let me know in the comments!



Top comments (0)