Inspiration

Zhan-Shan-Shui (Blade & Brush) was inspired by traditional Chinese shan shui landscape paintings and a desire to make a piece of art that you can actually play. We were captivated by the concept of infinite procedurally generated scrolling landscapes (https://github.com/LingDong-/shan-shui-inf ), but we wanted to take it a step further: what if the canvas was a live, destructible physics simulation? We wanted to combine the serene, poetic nature of traditional ink wash painting with chaotic, Noita-style elemental sandbox mechanics.

What it does

Blade & Brush is a procedurally generated web puzzle game where players shape a living scroll. At the start of a level, a poem sets a specific set of goals (e.g., creating 2 waterfalls, leaving exactly 1 tall mountain). The landscape then begins to paint itself from left to right.

While the algorithm draws, players use an action budget to interact with the canvas. They can Slash to delete pixels and leave jagged plateau edges, drop Water that respects gravity and flows down slopes, or use Fire to spread through and burn down forests. When the painting is complete, a custom "raycasting" pixel scanner reads the literal visual output of the canvas to determine if the landscape matches the poem's riddle.

How we built it

We built the game from scratch without a traditional game engine using TypeScript, Vite, and HTML5 Canvas 2D. To ensure zero-overhead, we avoided heavy UI frameworks entirely.

Instead of standard vector drawing, the core of the game is a custom cellular physics engine. We used memory-efficient Typed Arrays (Uint8Array, Int8Array) to simulate falling water, spreading fire, and terrain destruction across a 960x256 grid (over 245,000 cells) at a smooth 60fps. To ensure puzzles were fair and replayable, we engineered the engine to be perfectly deterministic, utilizing a fixed-timestep clock and a custom seeded RNG (mulberry32) tested via Vitest.

Challenges we ran into

The Fidelity Risk: A cellular grid is naturally chunkier than delicate vector strokes. To keep the ink-painting aesthetic while using grid physics, we had to invent a hybrid rendering system.

Evaluating the Win Conditions: Tracking the state of hundreds of thousands of dynamic cells to see if a player successfully built a waterfall or a plateau is incredibly complex. We solved this with the "Data Hack": instead of a complex object tree, we built a vertical pixel scanner that simply reads the final canvas top-to-bottom, grading the literal visual output exactly as the player sees it.

Architecture Collisions: In a fast-paced hackathon, multiple people touching the physics engine is a recipe for merge conflicts. We strictly separated the codebase into a gen (generator) folder and a sim (simulation) folder, united by a frozen core contract, allowing us to build the generator and the abilities entirely in parallel.

Accomplishments that we're proud of

Successfully marrying the calm, beautiful aesthetics of procedural ink generation with violently fun, destructive sandbox mechanics.

What we learned

How to leverage Structure-of-Arrays (SoA) and Typed Arrays for massive performance gains in Vanilla Web applications.

How to use Canvas globalCompositeOperation to bridge the gap between static vector art and live pixel destruction.

The value of modular architecture and auto-discovery registries (where dropping a new ability file into a folder automatically adds it to the UI), which hackathon-proofed our codebase against last-minute feature additions.

What's next for Blade&Brush

New Elements and New Abilities

Built With

Share this project:

Updates

Submission history