cluster-6-expressive-fireflies.js

total 0
used 0
limit 0
/* title: Cluster 6 - Expressive Firefly Swarm categories: clusters files: ../point_src/core/head.js ../point_src/pointpen.js ../point_src/pointdraw.js ../point_src/extras.js ../point_src/math.js ../point_src/point-content.js ../point_src/stage.js ../point_src/point.js ../point_src/distances.js pointlist ../point_src/events.js dragging ../point_src/cluster.js mouse */ /* * A little orbital ecosystem built on clusterDucks. * Drag the pale beacon to move the swarm. Each firefly follows nearer * neighbours, with its own preferred spacing, speed and attraction. */ class MainStage extends Stage { mounted() { this.beacon = this.center.copy() this.dragging.add(this.beacon) this.t = 0 this.points = PointList.generate.random(90, 500) this.points.forEach((p, i) => { p.vx = 0 p.vy = 0 p.radius = 2 + Math.random() * 2.5 p.minDistance = 25 + Math.random() * 65 p.minVelocity = 0.01 p.maxVelocity = 1.5 + Math.random() * 2 p.damping = 0.93 + Math.random() * 0.055 p.attractionStrength = 0.12 + Math.random() * 0.4 p.repulsionStrength = 50 + Math.random() * 180 p.followNearestCount = 1 + (i % 4) p.phase = Math.random() * Math.PI * 2 p.hue = 36 + Math.random() * 22 }) } draw(ctx) { this.clear(ctx) const center = this.beacon const points = this.points const time = this.t++ * 0.012 // The orbiting target tugs the duckling chains into a gentle dance. const target = { x: center.x + Math.cos(time) * 78, y: center.y + Math.sin(time * 0.73) * 55 } // Snapshot first: clusterDucks chooses neighbours using pre-move positions. // Mirror that exact selection rule for the visual edges. const positions = points.map(p => ({x: p.x, y: p.y})) const distances = positions.map(p => Math.hypot(target.x - p.x, target.y - p.y)) const links = [] for (let i = 0; i < points.length; i++) { const nearer = [] for (let j = 0; j < points.length; j++) { if (i === j || !(distances[j] < distances[i])) continue nearer.push({ index: j, distance: Math.hypot(positions[j].x - positions[i].x, positions[j].y - positions[i].y) }) } nearer.sort((a, b) => a.distance - b.distance) if (!nearer.length) { links.push({from: i, toTarget: true}) } else { const count = Math.min(points[i].followNearestCount ?? 2, nearer.length) for (let k = 0; k < count; k++) { links.push({from: i, to: nearer[k].index}) } } } simpleCluster(points, target, { func: clusterDucks, followNearestCount: 2 }) // Real following edges, drawn from the pre-move snapshot so the // rendered graph matches the neighbours used by this simulation step. ctx.lineWidth = 0.7 ctx.strokeStyle = 'rgba(255, 182, 55, 0.22)' for (const link of links) { const a = positions[link.from] const b = link.toTarget ? target : positions[link.to] ctx.beginPath() ctx.moveTo(a.x, a.y) ctx.lineTo(b.x, b.y) ctx.stroke() } for (const p of points) { const pulse = 0.65 + 0.35 * Math.sin(time * 3 + p.phase) ctx.beginPath() ctx.arc(p.x, p.y, p.radius * (2.1 + pulse), 0, Math.PI * 2) ctx.fillStyle = `hsla(${p.hue}, 95%, 65%, ${0.055 * pulse})` ctx.fill() ctx.beginPath() ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2) ctx.fillStyle = `hsla(${p.hue}, 95%, 73%, ${0.55 + 0.45 * pulse})` ctx.fill() } ctx.strokeStyle = 'rgba(255, 208, 125, 0.25)' ctx.lineWidth = 1 ctx.beginPath() ctx.moveTo(center.x, center.y) ctx.lineTo(target.x, target.y) ctx.stroke() ctx.beginPath() ctx.arc(target.x, target.y, 5, 0, Math.PI * 2) ctx.fillStyle = '#ffda85' ctx.fill() center.pen.indicator(ctx, {color: '#ffffff'}) } } const stage = new MainStage('playspace') stage.loopDraw()
Run
Meta Data
title Cluster 6 - Expressive Firefly Swarm
imports ()
files ('../point_src/core/head.js', '../point_src/pointpen.js', '../point_src/pointdraw.js', '../point_src/extras.js', '../point_src/math.js', '../point_src/point-content.js', '../point_src/stage.js', '../point_src/point.js', '../point_src/distances.js', 'pointlist', '../point_src/events.js', 'dragging', '../point_src/cluster.js', 'mouse')
unused_keys ()
unknown_keys ('categories',)
categories ['clusters']
filepath_exists True
path cluster-6-expressive-fireflies.js
filepath cluster-6-expressive-fireflies.js
clean_files ('../point_src/core/head.js', '../point_src/pointpen.js', '../point_src/pointdraw.js', '../point_src/extras.js', '../point_src/math.js', '../point_src/compass.js', '../point_src/center.js', '../point_src/point-content.js', '../point_src/stage-hooks.js', '../point_src/functions/resolve.js', '../point_src/stage.js', '../point_src/relative-xy.js', '../point_src/pointcast.js', '../point_src/point.js', '../point_src/distances.js', '../point_src/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/pointlistpen.js', '../point_src/events.js', '../point_src/functions/clamp.js', '../point_src/protractor.js', '../point_src/text/beta.js', '../point_src/dragging.js', '../point_src/cluster.js', '../point_src/automouse.js')
markdown {'html': '', 'content': 'title: Cluster 6 - Expressive Firefly Swarm\ncategories: clusters\nfiles:\n ../point_src/core/head.js\n ../point_src/pointpen.js\n ../point_src/pointdraw.js\n ../point_src/extras.js\n ../point_src/math.js\n ../point_src/point-content.js\n ../point_src/stage.js\n ../point_src/point.js\n ../point_src/distances.js\n pointlist\n ../point_src/events.js\n dragging\n ../point_src/cluster.js\n mouse'}