From 2c89a4173b5705e329d6a1e1dbdb408ac5a43811 Mon Sep 17 00:00:00 2001 From: Bobby Date: Wed, 22 Apr 2026 09:07:14 +0530 Subject: Redesign leaves with real silhouettes and localized gusts driven by a prevailing wind --- lib/components/LeafScene.svelte | 85 ++++++------- lib/leaves/physics.ts | 124 ++++++------------- lib/leaves/spawn.ts | 57 +++++---- lib/leaves/types.ts | 79 +++++++++--- lib/leaves/variants.ts | 32 ++--- lib/leaves/wind.ts | 259 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 450 insertions(+), 186 deletions(-) create mode 100644 lib/leaves/wind.ts diff --git a/lib/components/LeafScene.svelte b/lib/components/LeafScene.svelte index 2eb1fe2..d60b555 100644 --- a/lib/components/LeafScene.svelte +++ b/lib/components/LeafScene.svelte @@ -3,15 +3,16 @@ import { createRNG } from '@hollowdark/rng/seeded' import { LEAF_VARIANTS } from '@hollowdark/lib/leaves/variants' import { spawnLeaf } from '@hollowdark/lib/leaves/spawn' + import { isLeafOffscreen, stepLeaf } from '@hollowdark/lib/leaves/physics' import { - initialWindState, - isLeafOffscreen, - stepLeaf, - updateWind - } from '@hollowdark/lib/leaves/physics' - import type { Leaf, SceneDimensions, WindState } from '@hollowdark/lib/leaves/types' - - const TARGET_LEAF_COUNT = 12 + initialWindSystem, + particleOpacity, + stepWind, + type IdSource + } from '@hollowdark/lib/leaves/wind' + import type { Leaf, SceneDimensions, WindSystem } from '@hollowdark/lib/leaves/types' + + const TARGET_LEAF_COUNT = 14 const GROUND_Y_RATIO = 0.86 const rng = createRNG(Math.floor(performance.now() * 1000) | 0) @@ -19,13 +20,20 @@ let container: HTMLDivElement | null = null let scene: SceneDimensions = $state({ width: 0, height: 0, groundY: 0 }) let leaves: Leaf[] = $state([]) - let wind: WindState = $state(initialWindState(rng)) + let wind: WindSystem = $state(initialWindSystem(rng)) let rafId: number | null = null let lastTimeMs = 0 let nextLeafId = 0 + let nextGustId = 0 + let nextParticleId = 0 let resizeObserver: ResizeObserver | null = null + const ids: IdSource = { + nextGustId: () => nextGustId++, + nextParticleId: () => nextParticleId++ + } + function measure(): void { if (!container) return const rect = container.getBoundingClientRect() @@ -54,7 +62,7 @@ const dt = dtMs / 1000 const timeS = nowMs / 1000 - wind = updateWind(wind, dtMs, rng) + wind = stepWind(wind, dtMs, scene, rng, ids) const next: Leaf[] = [] for (const leaf of leaves) { @@ -89,7 +97,13 @@ {#each LEAF_VARIANTS as variant (variant.id)} - + {/each} @@ -97,6 +111,19 @@
+ {#if wind.activeGust} + {#each wind.activeGust.particles as particle (particle.id)} +
+ {/each} + {/if} + {#each leaves as leaf (leaf.id)} {/each} - -