diff --git a/.gitignore b/client/.gitignore similarity index 100% rename from .gitignore rename to client/.gitignore diff --git a/bun.lockb b/client/bun.lockb similarity index 100% rename from bun.lockb rename to client/bun.lockb diff --git a/index.html b/client/index.html similarity index 79% rename from index.html rename to client/index.html index 3504586..faa4336 100644 --- a/index.html +++ b/client/index.html @@ -4,6 +4,7 @@ ripples | compost.party + diff --git a/package.json b/client/package.json similarity index 100% rename from package.json rename to client/package.json diff --git a/public/vite.svg b/client/public/vite.svg similarity index 100% rename from public/vite.svg rename to client/public/vite.svg diff --git a/src/main.ts b/client/src/main.ts similarity index 55% rename from src/main.ts rename to client/src/main.ts index ec0d437..f086056 100644 --- a/src/main.ts +++ b/client/src/main.ts @@ -1,20 +1,22 @@ -import './style.css' - const canvas = document.querySelector('#canvas')! const ctx = canvas.getContext('2d')! const MIN_RADIUS = 20 const MAX_RADIUS = 200 -const MAX_AGE = 5000 // in milliseconds +const MAX_AGE = 1000 // in milliseconds + +type Point = [number, number] type Particle = { - position: [number, number], + position: Point age: number + maxRadius: number } -const createParticle = (x: number, y: number): Particle => ({ - position: [x, y], +const createParticle = (position: [number, number], maxRadius: number): Particle => ({ + position, + maxRadius, age: 0, }) @@ -24,12 +26,35 @@ let state = { type State = typeof state -canvas.addEventListener('click', (e) => { +canvas.addEventListener('mousedown', (e) => { // TODO Normalize x and y coords - const particle = createParticle(e.clientX, e.clientY) + const particle = createParticle([e.clientX, e.clientY], MAX_RADIUS) state.particles.push(particle) }) +function* minDist(dist: number) { + let prev: Point + while (true) { + yield (cur: Point) => { + if (prev == null || Math.sqrt(Math.pow(prev[0]-cur[0], 2) + Math.pow(prev[1]-cur[1], 2)) >= dist) { + prev = cur + return true + } + return false + } + } +} + +const hasSpace = minDist(70) + +canvas.addEventListener('mousemove', (e) => { + const shouldSpawn = hasSpace.next().value! + if (shouldSpawn([e.clientX, e.clientY])) { + const particle = createParticle([e.clientX, e.clientY], MAX_RADIUS / 3*2) + state.particles.push(particle) + } +}) + const update = (state: State, deltaTime: number): State => ({ particles: state.particles .map(p => ({ @@ -44,12 +69,12 @@ const render = (state: State, ctx: CanvasRenderingContext2D) => { for (const particle of state.particles) { const progress = (particle.age / MAX_AGE) - const opacity = Math.min(1, (1-progress)*(1-progress)) + const opacity = Math.min(1, Math.pow(1-progress, 3)) * (particle.maxRadius / MAX_RADIUS) ctx.beginPath() ctx.strokeStyle = `rgba(40, 40, 40, ${opacity})` const [x, y] = particle.position - const radius = (progress * (MAX_RADIUS - MIN_RADIUS)) + MIN_RADIUS + const radius = (progress * (particle.maxRadius - MIN_RADIUS)) + MIN_RADIUS ctx.ellipse(x, y, radius, radius, 0, 0, Math.PI * 2) ctx.stroke() } diff --git a/src/style.css b/client/src/style.css similarity index 98% rename from src/style.css rename to client/src/style.css index 92912df..38c53a1 100644 --- a/src/style.css +++ b/client/src/style.css @@ -7,5 +7,4 @@ body { } canvas { - } diff --git a/src/vite-env.d.ts b/client/src/vite-env.d.ts similarity index 100% rename from src/vite-env.d.ts rename to client/src/vite-env.d.ts diff --git a/tsconfig.json b/client/tsconfig.json similarity index 100% rename from tsconfig.json rename to client/tsconfig.json