Gravity Ink

Gravity Ink

In this physically accurate puzzle-drawing game, you are given dynamic pen-drawn lines and special ink physics to draw your way through mind-bending levels. Use unique ink types like Bouncy and Sticky to guide a gravity-affected ball through obstacles, collecting stars and navigating through portals in an ever-evolving, futuristic world.

Helpful?

Was the prompts helpfull?

Case trace

1 creative leap

Step 1 — The master promptCursorSonnet 4.5

Build a fully playable Gravity Painter game as a single React component (.jsx) using Matter.js for physics.

Tech Stack

  • React with hooks (useState, useEffect, useRef, useCallback)

  • Matter.js from CDN: https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js — import via useEffect script injection or assume it's available as window.Matter

  • All rendering done on a <canvas> ref — no external CSS files, all styles inline or via a <style> tag injected in the component

  • Single file, default export, no required props

Game Phases (managed via useState)

  • 'menu' — title screen with level select and instructions

  • 'drawing' — player draws shapes before simulation

  • 'simulating' — physics runs, ball drops

  • 'result' — level outcome shown (win/lose, stars, ink used)

Drawing Phase

  • Canvas ref captures mouse/touch events for freehand drawing

  • Strokes are stored as arrays of points in a drawnShapes ref

  • A toolbar rendered as React JSX (not on canvas) sits beside or above the canvas with:

    • Mode buttons — Solid, Ramp, Eraser (active mode stored in state)

    • Material buttons — Normal, Bouncy, Sticky, Slippery — each with a distinct color

    • Ink budget bar — a <div> progress bar depleting as stroke length accumulates

    • "Drop Ball" button — triggers phase transition to 'simulating'

    • "Clear" button — resets drawnShapes ref and redraws canvas

Physics Simulation

  • On phase change to 'simulating', convert drawnShapes into Matter.js static bodies and add to the world

  • Ball spawns at a fixed top-center position as a dynamic Matter.Bodies.circle

  • Use Matter.Runner and Matter.Events.on(engine, 'afterUpdate') inside a useEffect to drive the render loop

  • Each material maps to Matter.js body options:

    • Normal → { restitution: 0.4, friction: 0.5 }

    • Bouncy → { restitution: 0.95, friction: 0.1 }

    • Sticky → { restitution: 0.1, friction: 0.9 }

    • Slippery → { restitution: 0.3, friction: 0 }

  • Cleanup Matter.js engine and runner in useEffect return function to prevent memory leaks

Level Data

  • Define 6 levels as a plain JS array of objects outside the component:

    js

    const LEVELS = [
    { id: 1, name: 'First Drop', parInk: 200, goal: {x: 0.8, y: 0.85}, hazards: [], gravityY: 1 },
    // ...
    ]

  • Each level defines: goal position (as fraction of canvas size), hazard positions/types, gravity scale, wind force, par ink value, and collectible star positions

  • Current level index stored in state, increments on win

Canvas Rendering (useEffect watching phase + engine updates)

  • Drawing phase: render strokes live as player draws, color-coded by material

  • Simulation phase: clear and redraw each frame —

    • Draw all static shape bodies (player drawings)

    • Draw hazards (red spikes, voids)

    • Draw collectible stars (pulsing yellow circles)

    • Draw goal zone (glowing green circle with animated ring)

    • Draw ball with a fading trail (store last N positions in a ref)

    • Draw faint grid during drawing phase only

HUD (JSX overlay, not canvas)

  • Level name and number

  • Ink budget as an animated <div> bar

  • Star count ⭐ 0 / 3

  • Phase-appropriate action button: "Drop Ball" during drawing, "Retry" and "Next Level" on result screen

  • Result card rendered as JSX overlay on top of canvas when phase is 'result'

Result Phase

  • Triggered when: ball reaches goal zone (win) or ball exits canvas bounds (lose)

  • Show a centered JSX card with: win/lose status, stars collected, ink used vs par, two buttons

  • On "Retry" — reset Matter.js world, clear drawn shapes, go back to 'drawing' phase

  • On "Next Level" — load next level config, reset world and shapes, go to 'drawing'

Polish

  • Ball trail: store last 20 positions in a ref, draw as fading circles each frame

  • Goal zone: animated pulsing ring drawn on canvas each frame using a frameCount ref

  • Particle burst on goal reached: store particles in a ref, update and draw them each frame

  • Hazard spikes: drawn as triangles on canvas, destroy ball on collision via Matter.js collision events

  • Smooth 60fps loop driven by requestAnimationFrame stored in a ref and cancelled on cleanup

  • Dark background (#0f0f1a), neon accent palette: ball = #60d0ff, goal = #40ff90, hazard = #ff4060

Published 2mo ago

Category

Code

Tools used

Cursor

Details

Tech stack

ReactTailwind

Tags

physicspuzzle2dgravity

More from Oni linn

Shards of Her — The Woman Behind the Masks

Shards of Her — The Woman Behind the Masks

A surreal woman holding a cracked porcelain mask in front of her face, her real face partially visible and emotionless, fragments floating, …

Adobe Firefly
Horizon's peak

Horizon's peak

Compose a cinematic orchestral piece inspired by the grandeur of nature. Start with soft ambient textures (wind, distant echoes) and gradual…

Flow Music
Paymark Fintech Landing Page — Dark Luxury UI
100% helpful

Paymark Fintech Landing Page — Dark Luxury UI

Build the hero section only for a fintech landing page called PAYMARK.Background: Near-black (#0d0c0c) with a warm ember/copper radial glow …

StitchDesktop

View similar

Koi Pond — Canvas Simulation

Koi Pond — Canvas Simulation

Build a koi pond simulation using an HTML5 canvas. Fish should flock using boids rules (separation, cohesion, alignment) with wander behavio…

ClaudeHTMLCSS
Animated Northern Lights

Animated Northern Lights

Create a night sky canvas. Fill the background with a deep navy-to-black vertical gradient (#020810 at top, #000508 at bottom). Scatter 180 …

ClaudeHTMLCSS
Physics-Based Fireworks

Physics-Based Fireworks

Build a physics-based fireworks system on HTML5 Canvas. Shells launch from the bottom with upward velocity, explode into 60–80 particles wit…

ClaudeHTMLCSS
Animated Envelope

Animated Envelope

Create the HTML structure for an animated envelope component. Use nested divs for the envelope parts: back-fold, letter, top-fold (flap), bo…

CursorHTMLCSS
TypeBreaker

TypeBreaker

Build a fully playable Brick Breaker game in a single HTML/CSS/JS file with the following features:Pre-Game ScreenDisplay a centered input f…

v0
Liquid Magnetic Button

Liquid Magnetic Button

I want to build a button component in React that behaves like a magnet — when the cursor is within 100px of the button, the button smoothly …

ClaudeReactTailwind