Set up server to relay ripples and presence info

This commit is contained in:
arne 2024-01-27 12:04:46 +01:00
commit 8ccb60de61
7 changed files with 338 additions and 7 deletions

View file

@ -1,4 +1,9 @@
const canvas = document.querySelector<HTMLCanvasElement>('#canvas')!
const socket = new WebSocket(`ws://${window.location.hostname}:3000`)
type Message =
| { type: 'presence-information', others: number }
| { type: 'ripple', position: [number, number], maxRadius: number }
const ctx = canvas.getContext('2d')!
@ -14,24 +19,38 @@ type Particle = {
maxRadius: number
}
const createParticle = (position: [number, number], maxRadius: number): Particle => ({
position,
maxRadius,
age: 0,
})
let state = {
particles: <Particle[]>[]
}
type State = typeof state
canvas.addEventListener('mousedown', (e) => {
// TODO Normalize x and y coords
const particle = createParticle([e.clientX, e.clientY], MAX_RADIUS)
state.particles.push(particle)
const createParticle = (position: [number, number], maxRadius: number): Particle => ({
position,
maxRadius,
age: 0,
})
const makeRipple = (position: [number, number], radius: number): void => {
const particle = createParticle(position, radius)
socket.send(JSON.stringify(<Message>{
type: 'ripple',
position: particle.position,
maxRadius: particle.maxRadius,
}))
state.particles.push(particle)
}
// event handlers
// create a big ripple when touching the screen
canvas.addEventListener('mousedown', (e) => {
// TODO Normalize x and y coords
const radius = MAX_RADIUS
makeRipple([e.clientX, e.clientY], radius)
})
// create a smaller ripple when moving over the screen
function* minDist(dist: number) {
let prev: Point
while (true) {
@ -50,11 +69,33 @@ 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 radius = MAX_RADIUS / 3*2
makeRipple([e.clientX, e.clientY], radius)
}
})
// react to incoming websocket messages
socket.addEventListener('message', (e) => {
console.log('Received websocket message', e)
if (typeof e.data === 'string') {
// TODO: Validate message shape
const message = JSON.parse(e.data)
if (message?.type === 'presence-information') {
const data = <Message & { type: 'presence-information' }>message
console.log(`i'm seeing ${data.others} others around the pond`)
} else if (message?.type === 'ripple') {
const data = <Message & { type: 'ripple' }>message
const particle = createParticle(data.position, data.maxRadius)
state.particles.push(particle)
}
} else {
console.warn('i received an odd message and i don\'t know what to do with it', e.data)
}
})
// main loop
// update the particles and remove them after a certain time
const update = (state: State, deltaTime: number): State => ({
particles: state.particles
.map(p => ({
@ -64,6 +105,7 @@ const update = (state: State, deltaTime: number): State => ({
.filter(p => p.age < MAX_AGE)
})
// draw particles
const render = (state: State, ctx: CanvasRenderingContext2D) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
@ -90,6 +132,7 @@ const loop = () => {
requestAnimationFrame(loop)
}
// start everything
document.addEventListener('DOMContentLoaded', () => {
canvas.width = canvas.parentElement!.clientWidth
canvas.height = canvas.parentElement!.clientHeight