@hdcodedev/snowfall 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +144 -0
- package/dist/Snowfall.d.mts +5 -0
- package/dist/Snowfall.d.ts +5 -0
- package/dist/Snowfall.js +162 -0
- package/dist/Snowfall.js.map +1 -0
- package/dist/Snowfall.mjs +142 -0
- package/dist/Snowfall.mjs.map +1 -0
- package/dist/SnowfallProvider.d.mts +32 -0
- package/dist/SnowfallProvider.d.ts +32 -0
- package/dist/SnowfallProvider.js +89 -0
- package/dist/SnowfallProvider.js.map +1 -0
- package/dist/SnowfallProvider.mjs +63 -0
- package/dist/SnowfallProvider.mjs.map +1 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/dist/utils/snowfall/constants.d.mts +10 -0
- package/dist/utils/snowfall/constants.d.ts +10 -0
- package/dist/utils/snowfall/constants.js +50 -0
- package/dist/utils/snowfall/constants.js.map +1 -0
- package/dist/utils/snowfall/constants.mjs +19 -0
- package/dist/utils/snowfall/constants.mjs.map +1 -0
- package/dist/utils/snowfall/dom.d.mts +11 -0
- package/dist/utils/snowfall/dom.d.ts +11 -0
- package/dist/utils/snowfall/dom.js +130 -0
- package/dist/utils/snowfall/dom.js.map +1 -0
- package/dist/utils/snowfall/dom.mjs +113 -0
- package/dist/utils/snowfall/dom.mjs.map +1 -0
- package/dist/utils/snowfall/draw.d.mts +7 -0
- package/dist/utils/snowfall/draw.d.ts +7 -0
- package/dist/utils/snowfall/draw.js +160 -0
- package/dist/utils/snowfall/draw.js.map +1 -0
- package/dist/utils/snowfall/draw.mjs +134 -0
- package/dist/utils/snowfall/draw.mjs.map +1 -0
- package/dist/utils/snowfall/physics.d.mts +11 -0
- package/dist/utils/snowfall/physics.d.ts +11 -0
- package/dist/utils/snowfall/physics.js +233 -0
- package/dist/utils/snowfall/physics.js.map +1 -0
- package/dist/utils/snowfall/physics.mjs +206 -0
- package/dist/utils/snowfall/physics.mjs.map +1 -0
- package/dist/utils/snowfall/types.d.mts +28 -0
- package/dist/utils/snowfall/types.d.ts +28 -0
- package/dist/utils/snowfall/types.js +17 -0
- package/dist/utils/snowfall/types.js.map +1 -0
- package/dist/utils/snowfall/types.mjs +1 -0
- package/dist/utils/snowfall/types.mjs.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PhysicsConfig } from '../../SnowfallProvider.js';
|
|
2
|
+
import { Snowflake, SnowAccumulation, ElementSurface } from './types.js';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
import 'react';
|
|
5
|
+
|
|
6
|
+
declare const createSnowflake: (canvasWidth: number, config: PhysicsConfig, isBackground?: boolean) => Snowflake;
|
|
7
|
+
declare const initializeAccumulation: (accumulationMap: Map<Element, SnowAccumulation>, config: PhysicsConfig) => void;
|
|
8
|
+
declare const updateSnowflakes: (snowflakes: Snowflake[], elementRects: ElementSurface[], config: PhysicsConfig, dt: number, canvasWidth: number, canvasHeight: number) => void;
|
|
9
|
+
declare const meltAndSmoothAccumulation: (elementRects: ElementSurface[], config: PhysicsConfig, dt: number) => void;
|
|
10
|
+
|
|
11
|
+
export { createSnowflake, initializeAccumulation, meltAndSmoothAccumulation, updateSnowflakes };
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var physics_exports = {};
|
|
20
|
+
__export(physics_exports, {
|
|
21
|
+
createSnowflake: () => createSnowflake,
|
|
22
|
+
initializeAccumulation: () => initializeAccumulation,
|
|
23
|
+
meltAndSmoothAccumulation: () => meltAndSmoothAccumulation,
|
|
24
|
+
updateSnowflakes: () => updateSnowflakes
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(physics_exports);
|
|
27
|
+
var import_dom = require("./dom");
|
|
28
|
+
var import_constants = require("./constants");
|
|
29
|
+
const createSnowflake = (canvasWidth, config, isBackground = false) => {
|
|
30
|
+
if (isBackground) {
|
|
31
|
+
const radius = Math.random() * 0.8 + 0.3;
|
|
32
|
+
return {
|
|
33
|
+
x: Math.random() * canvasWidth,
|
|
34
|
+
y: window.scrollY - 5,
|
|
35
|
+
radius,
|
|
36
|
+
speed: radius * 0.3 + Math.random() * 0.2 + 0.2,
|
|
37
|
+
wind: (Math.random() - 0.5) * (config.WIND_STRENGTH * 0.625),
|
|
38
|
+
opacity: Math.random() * 0.2 + 0.2,
|
|
39
|
+
wobble: Math.random() * Math.PI * 2,
|
|
40
|
+
wobbleSpeed: Math.random() * 0.015 + 5e-3
|
|
41
|
+
};
|
|
42
|
+
} else {
|
|
43
|
+
const radius = Math.random() * 2 + 0.5;
|
|
44
|
+
return {
|
|
45
|
+
x: Math.random() * canvasWidth,
|
|
46
|
+
y: window.scrollY - 5,
|
|
47
|
+
radius,
|
|
48
|
+
speed: radius * 0.5 + Math.random() * 0.3 + 0.5,
|
|
49
|
+
wind: (Math.random() - 0.5) * config.WIND_STRENGTH,
|
|
50
|
+
opacity: Math.random() * 0.3 + 0.5,
|
|
51
|
+
wobble: Math.random() * Math.PI * 2,
|
|
52
|
+
wobbleSpeed: Math.random() * 0.02 + 0.01
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const initializeAccumulation = (accumulationMap, config) => {
|
|
57
|
+
const elements = (0, import_dom.getAccumulationSurfaces)();
|
|
58
|
+
for (const [el] of accumulationMap.entries()) {
|
|
59
|
+
if (!el.isConnected) {
|
|
60
|
+
accumulationMap.delete(el);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
elements.forEach(({ el, type, isFixed }) => {
|
|
64
|
+
const existing = accumulationMap.get(el);
|
|
65
|
+
const rect = el.getBoundingClientRect();
|
|
66
|
+
const width = Math.ceil(rect.width);
|
|
67
|
+
const isBottom = type === import_constants.VAL_BOTTOM;
|
|
68
|
+
if (existing && existing.heights.length === width) {
|
|
69
|
+
existing.type = type;
|
|
70
|
+
existing.isFixed = isFixed;
|
|
71
|
+
if (existing.borderRadius !== void 0) {
|
|
72
|
+
const styleBuffer = window.getComputedStyle(el);
|
|
73
|
+
existing.borderRadius = parseFloat(styleBuffer.borderTopLeftRadius) || 0;
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const height = Math.ceil(rect.height);
|
|
78
|
+
const baseMax = isBottom ? config.MAX_DEPTH.HEADER_TOP : config.MAX_DEPTH.CARD_TOP;
|
|
79
|
+
const styles = window.getComputedStyle(el);
|
|
80
|
+
const borderRadius = parseFloat(styles.borderTopLeftRadius) || 0;
|
|
81
|
+
let maxHeights = new Array(width);
|
|
82
|
+
for (let i = 0; i < width; i++) {
|
|
83
|
+
let edgeFactor = 1;
|
|
84
|
+
if (!isBottom && borderRadius > 0) {
|
|
85
|
+
if (i < borderRadius) {
|
|
86
|
+
edgeFactor = Math.pow(i / borderRadius, 1.2);
|
|
87
|
+
} else if (i > width - borderRadius) {
|
|
88
|
+
edgeFactor = Math.pow((width - i) / borderRadius, 1.2);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
maxHeights[i] = baseMax * edgeFactor * (0.85 + Math.random() * 0.15);
|
|
92
|
+
}
|
|
93
|
+
const smoothPasses = 4;
|
|
94
|
+
for (let p = 0; p < smoothPasses; p++) {
|
|
95
|
+
const smoothed = [...maxHeights];
|
|
96
|
+
for (let i = 1; i < width - 1; i++) {
|
|
97
|
+
smoothed[i] = (maxHeights[i - 1] + maxHeights[i] + maxHeights[i + 1]) / 3;
|
|
98
|
+
}
|
|
99
|
+
maxHeights = smoothed;
|
|
100
|
+
}
|
|
101
|
+
accumulationMap.set(el, {
|
|
102
|
+
heights: existing?.heights.length === width ? existing.heights : new Array(width).fill(0),
|
|
103
|
+
maxHeights,
|
|
104
|
+
leftSide: existing?.leftSide.length === height ? existing.leftSide : new Array(height).fill(0),
|
|
105
|
+
rightSide: existing?.rightSide.length === height ? existing.rightSide : new Array(height).fill(0),
|
|
106
|
+
maxSideHeight: isBottom ? 0 : config.MAX_DEPTH.CARD_SIDE,
|
|
107
|
+
borderRadius,
|
|
108
|
+
type,
|
|
109
|
+
isFixed
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const accumulateSide = (sideArray, rectHeight, localY, maxSideHeight, borderRadius, config) => {
|
|
114
|
+
const spread = 4;
|
|
115
|
+
const addHeight = config.ACCUMULATION.SIDE_RATE * (0.8 + Math.random() * 0.4);
|
|
116
|
+
for (let dy = -spread; dy <= spread; dy++) {
|
|
117
|
+
const y = localY + dy;
|
|
118
|
+
if (y >= 0 && y < sideArray.length) {
|
|
119
|
+
const inTop = y < borderRadius;
|
|
120
|
+
const inBottom = y > rectHeight - borderRadius;
|
|
121
|
+
if (borderRadius > 0 && (inTop || inBottom)) continue;
|
|
122
|
+
const normalizedDist = Math.abs(dy) / spread;
|
|
123
|
+
const falloff = (Math.cos(normalizedDist * Math.PI) + 1) / 2;
|
|
124
|
+
sideArray[y] = Math.min(maxSideHeight, sideArray[y] + addHeight * falloff);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const updateSnowflakes = (snowflakes, elementRects, config, dt, canvasWidth, canvasHeight) => {
|
|
129
|
+
for (let i = snowflakes.length - 1; i >= 0; i--) {
|
|
130
|
+
const flake = snowflakes[i];
|
|
131
|
+
flake.wobble += flake.wobbleSpeed * dt;
|
|
132
|
+
flake.x += (flake.wind + Math.sin(flake.wobble) * 0.5) * dt;
|
|
133
|
+
flake.y += (flake.speed + Math.cos(flake.wobble * 0.5) * 0.1) * dt;
|
|
134
|
+
let landed = false;
|
|
135
|
+
for (const { rect, acc } of elementRects) {
|
|
136
|
+
const isBottom = acc.type === import_constants.VAL_BOTTOM;
|
|
137
|
+
if (!landed && acc.maxSideHeight > 0 && !isBottom) {
|
|
138
|
+
const isInVerticalBounds = flake.y >= rect.top && flake.y <= rect.bottom;
|
|
139
|
+
if (isInVerticalBounds) {
|
|
140
|
+
const localY = Math.floor(flake.y - rect.top);
|
|
141
|
+
const borderRadius = acc.borderRadius;
|
|
142
|
+
const isInTopCorner = localY < borderRadius;
|
|
143
|
+
const isInBottomCorner = localY > rect.height - borderRadius;
|
|
144
|
+
const isCorner = borderRadius > 0 && (isInTopCorner || isInBottomCorner);
|
|
145
|
+
if (flake.x >= rect.left - 5 && flake.x < rect.left + 3) {
|
|
146
|
+
if (!isCorner) {
|
|
147
|
+
accumulateSide(acc.leftSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);
|
|
148
|
+
landed = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!landed && flake.x > rect.right - 3 && flake.x <= rect.right + 5) {
|
|
152
|
+
if (!isCorner) {
|
|
153
|
+
accumulateSide(acc.rightSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);
|
|
154
|
+
landed = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (landed) break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (flake.x >= rect.left && flake.x <= rect.right) {
|
|
161
|
+
const localX = Math.floor(flake.x - rect.left);
|
|
162
|
+
const currentHeight = acc.heights[localX] || 0;
|
|
163
|
+
const maxHeight = acc.maxHeights[localX] || 5;
|
|
164
|
+
const surfaceY = isBottom ? rect.bottom - currentHeight : rect.top - currentHeight;
|
|
165
|
+
if (flake.y >= surfaceY && flake.y < surfaceY + 10 && currentHeight < maxHeight) {
|
|
166
|
+
const shouldAccumulate = isBottom ? Math.random() < 0.15 : true;
|
|
167
|
+
if (shouldAccumulate) {
|
|
168
|
+
const baseSpread = Math.ceil(flake.radius);
|
|
169
|
+
const spread = baseSpread + Math.floor(Math.random() * 2);
|
|
170
|
+
const accumRate = isBottom ? config.ACCUMULATION.TOP_HEADER_RATE : config.ACCUMULATION.TOP_CARD_RATE;
|
|
171
|
+
const centerOffset = Math.floor(Math.random() * 3) - 1;
|
|
172
|
+
for (let dx = -spread; dx <= spread; dx++) {
|
|
173
|
+
if (Math.random() < 0.15) continue;
|
|
174
|
+
const idx = localX + dx + centerOffset;
|
|
175
|
+
if (idx >= 0 && idx < acc.heights.length) {
|
|
176
|
+
const dist = Math.abs(dx);
|
|
177
|
+
const pixelMax = acc.maxHeights[idx] || 5;
|
|
178
|
+
const normDist = dist / spread;
|
|
179
|
+
const falloff = (Math.cos(normDist * Math.PI) + 1) / 2;
|
|
180
|
+
const baseAdd = 0.3 * falloff;
|
|
181
|
+
const randomFactor = 0.8 + Math.random() * 0.4;
|
|
182
|
+
const addHeight = baseAdd * randomFactor * accumRate;
|
|
183
|
+
if (acc.heights[idx] < pixelMax && addHeight > 0) {
|
|
184
|
+
acc.heights[idx] = Math.min(pixelMax, acc.heights[idx] + addHeight);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (isBottom) {
|
|
189
|
+
landed = true;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (!isBottom) {
|
|
194
|
+
landed = true;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (landed || flake.y > canvasHeight + 10 || flake.x < -20 || flake.x > canvasWidth + 20) {
|
|
201
|
+
snowflakes.splice(i, 1);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const meltAndSmoothAccumulation = (elementRects, config, dt) => {
|
|
206
|
+
for (const { acc } of elementRects) {
|
|
207
|
+
const meltRate = config.MELT_SPEED * dt;
|
|
208
|
+
const len = acc.heights.length;
|
|
209
|
+
if (len > 2) {
|
|
210
|
+
for (let i = 1; i < len - 1; i++) {
|
|
211
|
+
if (acc.heights[i] > 0.05) {
|
|
212
|
+
const avg = (acc.heights[i - 1] + acc.heights[i + 1]) / 2;
|
|
213
|
+
acc.heights[i] = acc.heights[i] * 0.99 + avg * 0.01;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
for (let i = 0; i < acc.heights.length; i++) {
|
|
218
|
+
if (acc.heights[i] > 0) acc.heights[i] = Math.max(0, acc.heights[i] - meltRate);
|
|
219
|
+
}
|
|
220
|
+
for (let i = 0; i < acc.leftSide.length; i++) {
|
|
221
|
+
if (acc.leftSide[i] > 0) acc.leftSide[i] = Math.max(0, acc.leftSide[i] - meltRate);
|
|
222
|
+
if (acc.rightSide[i] > 0) acc.rightSide[i] = Math.max(0, acc.rightSide[i] - meltRate);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
227
|
+
0 && (module.exports = {
|
|
228
|
+
createSnowflake,
|
|
229
|
+
initializeAccumulation,
|
|
230
|
+
meltAndSmoothAccumulation,
|
|
231
|
+
updateSnowflakes
|
|
232
|
+
});
|
|
233
|
+
//# sourceMappingURL=physics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/snowfall/physics.ts"],"sourcesContent":["import { PhysicsConfig } from '../../SnowfallProvider';\nimport { Snowflake, SnowAccumulation, ElementSurface } from './types';\nimport { getAccumulationSurfaces } from './dom';\nimport { VAL_BOTTOM } from './constants';\n\nexport const createSnowflake = (\n canvasWidth: number,\n config: PhysicsConfig,\n isBackground: boolean = false\n): Snowflake => {\n if (isBackground) {\n const radius = Math.random() * 0.8 + 0.3;\n return {\n x: Math.random() * canvasWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.3 + Math.random() * 0.2 + 0.2,\n wind: (Math.random() - 0.5) * (config.WIND_STRENGTH * 0.625),\n opacity: Math.random() * 0.2 + 0.2,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.015 + 0.005,\n };\n } else {\n const radius = Math.random() * 2 + 0.5;\n return {\n x: Math.random() * canvasWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.5 + Math.random() * 0.3 + 0.5,\n wind: (Math.random() - 0.5) * config.WIND_STRENGTH,\n opacity: Math.random() * 0.3 + 0.5,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.02 + 0.01,\n };\n }\n};\n\nexport const initializeAccumulation = (\n accumulationMap: Map<Element, SnowAccumulation>,\n config: PhysicsConfig\n) => {\n const elements = getAccumulationSurfaces();\n // Prune disconnected elements\n for (const [el] of accumulationMap.entries()) {\n if (!el.isConnected) {\n accumulationMap.delete(el);\n }\n }\n\n elements.forEach(({ el, type, isFixed }) => {\n const existing = accumulationMap.get(el);\n const rect = el.getBoundingClientRect();\n const width = Math.ceil(rect.width);\n const isBottom = type === VAL_BOTTOM;\n\n if (existing && existing.heights.length === width) {\n existing.type = type;\n existing.isFixed = isFixed;\n if (existing.borderRadius !== undefined) {\n const styleBuffer = window.getComputedStyle(el); // Potentially slow in loop, strictly necessary?\n existing.borderRadius = parseFloat(styleBuffer.borderTopLeftRadius) || 0;\n }\n return;\n }\n\n const height = Math.ceil(rect.height);\n const baseMax = isBottom ? config.MAX_DEPTH.HEADER_TOP : config.MAX_DEPTH.CARD_TOP;\n\n const styles = window.getComputedStyle(el);\n const borderRadius = parseFloat(styles.borderTopLeftRadius) || 0;\n\n let maxHeights = new Array(width);\n for (let i = 0; i < width; i++) {\n let edgeFactor = 1.0;\n if (!isBottom && borderRadius > 0) {\n if (i < borderRadius) {\n edgeFactor = Math.pow(i / borderRadius, 1.2);\n } else if (i > width - borderRadius) {\n edgeFactor = Math.pow((width - i) / borderRadius, 1.2);\n }\n }\n maxHeights[i] = baseMax * edgeFactor * (0.85 + Math.random() * 0.15);\n }\n\n // Smooth maxHeights\n const smoothPasses = 4;\n for (let p = 0; p < smoothPasses; p++) {\n const smoothed = [...maxHeights];\n for (let i = 1; i < width - 1; i++) {\n smoothed[i] = (maxHeights[i - 1] + maxHeights[i] + maxHeights[i + 1]) / 3;\n }\n maxHeights = smoothed;\n }\n\n accumulationMap.set(el, {\n heights: existing?.heights.length === width ? existing.heights : new Array(width).fill(0),\n maxHeights,\n leftSide: existing?.leftSide.length === height ? existing.leftSide : new Array(height).fill(0),\n rightSide: existing?.rightSide.length === height ? existing.rightSide : new Array(height).fill(0),\n maxSideHeight: isBottom ? 0 : config.MAX_DEPTH.CARD_SIDE,\n borderRadius,\n type,\n isFixed,\n });\n });\n};\n\nconst accumulateSide = (\n sideArray: number[],\n rectHeight: number,\n localY: number,\n maxSideHeight: number,\n borderRadius: number,\n config: PhysicsConfig\n) => {\n const spread = 4;\n const addHeight = config.ACCUMULATION.SIDE_RATE * (0.8 + Math.random() * 0.4);\n\n for (let dy = -spread; dy <= spread; dy++) {\n const y = localY + dy;\n if (y >= 0 && y < sideArray.length) {\n const inTop = y < borderRadius;\n const inBottom = y > rectHeight - borderRadius;\n if (borderRadius > 0 && (inTop || inBottom)) continue;\n\n const normalizedDist = Math.abs(dy) / spread;\n const falloff = (Math.cos(normalizedDist * Math.PI) + 1) / 2;\n sideArray[y] = Math.min(maxSideHeight, sideArray[y] + addHeight * falloff);\n }\n }\n};\n\nexport const updateSnowflakes = (\n snowflakes: Snowflake[],\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number,\n canvasWidth: number,\n canvasHeight: number\n) => {\n for (let i = snowflakes.length - 1; i >= 0; i--) {\n const flake = snowflakes[i];\n\n flake.wobble += flake.wobbleSpeed * dt;\n flake.x += (flake.wind + Math.sin(flake.wobble) * 0.5) * dt;\n flake.y += (flake.speed + Math.cos(flake.wobble * 0.5) * 0.1) * dt;\n\n let landed = false;\n\n for (const { rect, acc } of elementRects) {\n const isBottom = acc.type === VAL_BOTTOM;\n\n // Side collisions\n if (!landed && acc.maxSideHeight > 0 && !isBottom) {\n const isInVerticalBounds = flake.y >= rect.top && flake.y <= rect.bottom;\n\n if (isInVerticalBounds) {\n const localY = Math.floor(flake.y - rect.top);\n const borderRadius = acc.borderRadius;\n\n const isInTopCorner = localY < borderRadius;\n const isInBottomCorner = localY > rect.height - borderRadius;\n const isCorner = borderRadius > 0 && (isInTopCorner || isInBottomCorner);\n\n if (flake.x >= rect.left - 5 && flake.x < rect.left + 3) {\n if (!isCorner) {\n accumulateSide(acc.leftSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (!landed && flake.x > rect.right - 3 && flake.x <= rect.right + 5) {\n if (!isCorner) {\n accumulateSide(acc.rightSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (landed) break;\n }\n }\n\n // Top accumulation\n if (flake.x >= rect.left && flake.x <= rect.right) {\n const localX = Math.floor(flake.x - rect.left);\n const currentHeight = acc.heights[localX] || 0;\n const maxHeight = acc.maxHeights[localX] || 5;\n\n const surfaceY = isBottom ? rect.bottom - currentHeight : rect.top - currentHeight;\n\n if (flake.y >= surfaceY && flake.y < surfaceY + 10 && currentHeight < maxHeight) {\n const shouldAccumulate = isBottom ? Math.random() < 0.15 : true;\n\n if (shouldAccumulate) {\n const baseSpread = Math.ceil(flake.radius);\n const spread = baseSpread + Math.floor(Math.random() * 2);\n const accumRate = isBottom ? config.ACCUMULATION.TOP_HEADER_RATE : config.ACCUMULATION.TOP_CARD_RATE;\n const centerOffset = Math.floor(Math.random() * 3) - 1;\n\n for (let dx = -spread; dx <= spread; dx++) {\n if (Math.random() < 0.15) continue;\n const idx = localX + dx + centerOffset;\n if (idx >= 0 && idx < acc.heights.length) {\n const dist = Math.abs(dx);\n const pixelMax = acc.maxHeights[idx] || 5;\n\n const normDist = dist / spread;\n const falloff = (Math.cos(normDist * Math.PI) + 1) / 2;\n const baseAdd = 0.3 * falloff;\n\n const randomFactor = 0.8 + Math.random() * 0.4;\n const addHeight = baseAdd * randomFactor * accumRate;\n\n if (acc.heights[idx] < pixelMax && addHeight > 0) {\n acc.heights[idx] = Math.min(pixelMax, acc.heights[idx] + addHeight);\n }\n }\n }\n\n if (isBottom) {\n landed = true;\n break;\n }\n }\n\n if (!isBottom) {\n landed = true;\n break;\n }\n }\n }\n }\n\n if (landed || flake.y > canvasHeight + 10 || flake.x < -20 || flake.x > canvasWidth + 20) {\n snowflakes.splice(i, 1);\n }\n }\n};\n\nexport const meltAndSmoothAccumulation = (\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number\n) => {\n for (const { acc } of elementRects) {\n const meltRate = config.MELT_SPEED * dt;\n const len = acc.heights.length;\n\n // Smooth\n if (len > 2) {\n for (let i = 1; i < len - 1; i++) {\n if (acc.heights[i] > 0.05) {\n const avg = (acc.heights[i - 1] + acc.heights[i + 1]) / 2;\n acc.heights[i] = acc.heights[i] * 0.99 + avg * 0.01;\n }\n }\n }\n\n // Melt\n for (let i = 0; i < acc.heights.length; i++) {\n if (acc.heights[i] > 0) acc.heights[i] = Math.max(0, acc.heights[i] - meltRate);\n }\n for (let i = 0; i < acc.leftSide.length; i++) {\n if (acc.leftSide[i] > 0) acc.leftSide[i] = Math.max(0, acc.leftSide[i] - meltRate);\n if (acc.rightSide[i] > 0) acc.rightSide[i] = Math.max(0, acc.rightSide[i] - meltRate);\n }\n }\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { getAccumulationSurfaces } from "./dom";
|
|
2
|
+
import { VAL_BOTTOM } from "./constants";
|
|
3
|
+
const createSnowflake = (canvasWidth, config, isBackground = false) => {
|
|
4
|
+
if (isBackground) {
|
|
5
|
+
const radius = Math.random() * 0.8 + 0.3;
|
|
6
|
+
return {
|
|
7
|
+
x: Math.random() * canvasWidth,
|
|
8
|
+
y: window.scrollY - 5,
|
|
9
|
+
radius,
|
|
10
|
+
speed: radius * 0.3 + Math.random() * 0.2 + 0.2,
|
|
11
|
+
wind: (Math.random() - 0.5) * (config.WIND_STRENGTH * 0.625),
|
|
12
|
+
opacity: Math.random() * 0.2 + 0.2,
|
|
13
|
+
wobble: Math.random() * Math.PI * 2,
|
|
14
|
+
wobbleSpeed: Math.random() * 0.015 + 5e-3
|
|
15
|
+
};
|
|
16
|
+
} else {
|
|
17
|
+
const radius = Math.random() * 2 + 0.5;
|
|
18
|
+
return {
|
|
19
|
+
x: Math.random() * canvasWidth,
|
|
20
|
+
y: window.scrollY - 5,
|
|
21
|
+
radius,
|
|
22
|
+
speed: radius * 0.5 + Math.random() * 0.3 + 0.5,
|
|
23
|
+
wind: (Math.random() - 0.5) * config.WIND_STRENGTH,
|
|
24
|
+
opacity: Math.random() * 0.3 + 0.5,
|
|
25
|
+
wobble: Math.random() * Math.PI * 2,
|
|
26
|
+
wobbleSpeed: Math.random() * 0.02 + 0.01
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const initializeAccumulation = (accumulationMap, config) => {
|
|
31
|
+
const elements = getAccumulationSurfaces();
|
|
32
|
+
for (const [el] of accumulationMap.entries()) {
|
|
33
|
+
if (!el.isConnected) {
|
|
34
|
+
accumulationMap.delete(el);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
elements.forEach(({ el, type, isFixed }) => {
|
|
38
|
+
const existing = accumulationMap.get(el);
|
|
39
|
+
const rect = el.getBoundingClientRect();
|
|
40
|
+
const width = Math.ceil(rect.width);
|
|
41
|
+
const isBottom = type === VAL_BOTTOM;
|
|
42
|
+
if (existing && existing.heights.length === width) {
|
|
43
|
+
existing.type = type;
|
|
44
|
+
existing.isFixed = isFixed;
|
|
45
|
+
if (existing.borderRadius !== void 0) {
|
|
46
|
+
const styleBuffer = window.getComputedStyle(el);
|
|
47
|
+
existing.borderRadius = parseFloat(styleBuffer.borderTopLeftRadius) || 0;
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const height = Math.ceil(rect.height);
|
|
52
|
+
const baseMax = isBottom ? config.MAX_DEPTH.HEADER_TOP : config.MAX_DEPTH.CARD_TOP;
|
|
53
|
+
const styles = window.getComputedStyle(el);
|
|
54
|
+
const borderRadius = parseFloat(styles.borderTopLeftRadius) || 0;
|
|
55
|
+
let maxHeights = new Array(width);
|
|
56
|
+
for (let i = 0; i < width; i++) {
|
|
57
|
+
let edgeFactor = 1;
|
|
58
|
+
if (!isBottom && borderRadius > 0) {
|
|
59
|
+
if (i < borderRadius) {
|
|
60
|
+
edgeFactor = Math.pow(i / borderRadius, 1.2);
|
|
61
|
+
} else if (i > width - borderRadius) {
|
|
62
|
+
edgeFactor = Math.pow((width - i) / borderRadius, 1.2);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
maxHeights[i] = baseMax * edgeFactor * (0.85 + Math.random() * 0.15);
|
|
66
|
+
}
|
|
67
|
+
const smoothPasses = 4;
|
|
68
|
+
for (let p = 0; p < smoothPasses; p++) {
|
|
69
|
+
const smoothed = [...maxHeights];
|
|
70
|
+
for (let i = 1; i < width - 1; i++) {
|
|
71
|
+
smoothed[i] = (maxHeights[i - 1] + maxHeights[i] + maxHeights[i + 1]) / 3;
|
|
72
|
+
}
|
|
73
|
+
maxHeights = smoothed;
|
|
74
|
+
}
|
|
75
|
+
accumulationMap.set(el, {
|
|
76
|
+
heights: existing?.heights.length === width ? existing.heights : new Array(width).fill(0),
|
|
77
|
+
maxHeights,
|
|
78
|
+
leftSide: existing?.leftSide.length === height ? existing.leftSide : new Array(height).fill(0),
|
|
79
|
+
rightSide: existing?.rightSide.length === height ? existing.rightSide : new Array(height).fill(0),
|
|
80
|
+
maxSideHeight: isBottom ? 0 : config.MAX_DEPTH.CARD_SIDE,
|
|
81
|
+
borderRadius,
|
|
82
|
+
type,
|
|
83
|
+
isFixed
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const accumulateSide = (sideArray, rectHeight, localY, maxSideHeight, borderRadius, config) => {
|
|
88
|
+
const spread = 4;
|
|
89
|
+
const addHeight = config.ACCUMULATION.SIDE_RATE * (0.8 + Math.random() * 0.4);
|
|
90
|
+
for (let dy = -spread; dy <= spread; dy++) {
|
|
91
|
+
const y = localY + dy;
|
|
92
|
+
if (y >= 0 && y < sideArray.length) {
|
|
93
|
+
const inTop = y < borderRadius;
|
|
94
|
+
const inBottom = y > rectHeight - borderRadius;
|
|
95
|
+
if (borderRadius > 0 && (inTop || inBottom)) continue;
|
|
96
|
+
const normalizedDist = Math.abs(dy) / spread;
|
|
97
|
+
const falloff = (Math.cos(normalizedDist * Math.PI) + 1) / 2;
|
|
98
|
+
sideArray[y] = Math.min(maxSideHeight, sideArray[y] + addHeight * falloff);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const updateSnowflakes = (snowflakes, elementRects, config, dt, canvasWidth, canvasHeight) => {
|
|
103
|
+
for (let i = snowflakes.length - 1; i >= 0; i--) {
|
|
104
|
+
const flake = snowflakes[i];
|
|
105
|
+
flake.wobble += flake.wobbleSpeed * dt;
|
|
106
|
+
flake.x += (flake.wind + Math.sin(flake.wobble) * 0.5) * dt;
|
|
107
|
+
flake.y += (flake.speed + Math.cos(flake.wobble * 0.5) * 0.1) * dt;
|
|
108
|
+
let landed = false;
|
|
109
|
+
for (const { rect, acc } of elementRects) {
|
|
110
|
+
const isBottom = acc.type === VAL_BOTTOM;
|
|
111
|
+
if (!landed && acc.maxSideHeight > 0 && !isBottom) {
|
|
112
|
+
const isInVerticalBounds = flake.y >= rect.top && flake.y <= rect.bottom;
|
|
113
|
+
if (isInVerticalBounds) {
|
|
114
|
+
const localY = Math.floor(flake.y - rect.top);
|
|
115
|
+
const borderRadius = acc.borderRadius;
|
|
116
|
+
const isInTopCorner = localY < borderRadius;
|
|
117
|
+
const isInBottomCorner = localY > rect.height - borderRadius;
|
|
118
|
+
const isCorner = borderRadius > 0 && (isInTopCorner || isInBottomCorner);
|
|
119
|
+
if (flake.x >= rect.left - 5 && flake.x < rect.left + 3) {
|
|
120
|
+
if (!isCorner) {
|
|
121
|
+
accumulateSide(acc.leftSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);
|
|
122
|
+
landed = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (!landed && flake.x > rect.right - 3 && flake.x <= rect.right + 5) {
|
|
126
|
+
if (!isCorner) {
|
|
127
|
+
accumulateSide(acc.rightSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);
|
|
128
|
+
landed = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (landed) break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (flake.x >= rect.left && flake.x <= rect.right) {
|
|
135
|
+
const localX = Math.floor(flake.x - rect.left);
|
|
136
|
+
const currentHeight = acc.heights[localX] || 0;
|
|
137
|
+
const maxHeight = acc.maxHeights[localX] || 5;
|
|
138
|
+
const surfaceY = isBottom ? rect.bottom - currentHeight : rect.top - currentHeight;
|
|
139
|
+
if (flake.y >= surfaceY && flake.y < surfaceY + 10 && currentHeight < maxHeight) {
|
|
140
|
+
const shouldAccumulate = isBottom ? Math.random() < 0.15 : true;
|
|
141
|
+
if (shouldAccumulate) {
|
|
142
|
+
const baseSpread = Math.ceil(flake.radius);
|
|
143
|
+
const spread = baseSpread + Math.floor(Math.random() * 2);
|
|
144
|
+
const accumRate = isBottom ? config.ACCUMULATION.TOP_HEADER_RATE : config.ACCUMULATION.TOP_CARD_RATE;
|
|
145
|
+
const centerOffset = Math.floor(Math.random() * 3) - 1;
|
|
146
|
+
for (let dx = -spread; dx <= spread; dx++) {
|
|
147
|
+
if (Math.random() < 0.15) continue;
|
|
148
|
+
const idx = localX + dx + centerOffset;
|
|
149
|
+
if (idx >= 0 && idx < acc.heights.length) {
|
|
150
|
+
const dist = Math.abs(dx);
|
|
151
|
+
const pixelMax = acc.maxHeights[idx] || 5;
|
|
152
|
+
const normDist = dist / spread;
|
|
153
|
+
const falloff = (Math.cos(normDist * Math.PI) + 1) / 2;
|
|
154
|
+
const baseAdd = 0.3 * falloff;
|
|
155
|
+
const randomFactor = 0.8 + Math.random() * 0.4;
|
|
156
|
+
const addHeight = baseAdd * randomFactor * accumRate;
|
|
157
|
+
if (acc.heights[idx] < pixelMax && addHeight > 0) {
|
|
158
|
+
acc.heights[idx] = Math.min(pixelMax, acc.heights[idx] + addHeight);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (isBottom) {
|
|
163
|
+
landed = true;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (!isBottom) {
|
|
168
|
+
landed = true;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (landed || flake.y > canvasHeight + 10 || flake.x < -20 || flake.x > canvasWidth + 20) {
|
|
175
|
+
snowflakes.splice(i, 1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const meltAndSmoothAccumulation = (elementRects, config, dt) => {
|
|
180
|
+
for (const { acc } of elementRects) {
|
|
181
|
+
const meltRate = config.MELT_SPEED * dt;
|
|
182
|
+
const len = acc.heights.length;
|
|
183
|
+
if (len > 2) {
|
|
184
|
+
for (let i = 1; i < len - 1; i++) {
|
|
185
|
+
if (acc.heights[i] > 0.05) {
|
|
186
|
+
const avg = (acc.heights[i - 1] + acc.heights[i + 1]) / 2;
|
|
187
|
+
acc.heights[i] = acc.heights[i] * 0.99 + avg * 0.01;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (let i = 0; i < acc.heights.length; i++) {
|
|
192
|
+
if (acc.heights[i] > 0) acc.heights[i] = Math.max(0, acc.heights[i] - meltRate);
|
|
193
|
+
}
|
|
194
|
+
for (let i = 0; i < acc.leftSide.length; i++) {
|
|
195
|
+
if (acc.leftSide[i] > 0) acc.leftSide[i] = Math.max(0, acc.leftSide[i] - meltRate);
|
|
196
|
+
if (acc.rightSide[i] > 0) acc.rightSide[i] = Math.max(0, acc.rightSide[i] - meltRate);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
export {
|
|
201
|
+
createSnowflake,
|
|
202
|
+
initializeAccumulation,
|
|
203
|
+
meltAndSmoothAccumulation,
|
|
204
|
+
updateSnowflakes
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=physics.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/snowfall/physics.ts"],"sourcesContent":["import { PhysicsConfig } from '../../SnowfallProvider';\nimport { Snowflake, SnowAccumulation, ElementSurface } from './types';\nimport { getAccumulationSurfaces } from './dom';\nimport { VAL_BOTTOM } from './constants';\n\nexport const createSnowflake = (\n canvasWidth: number,\n config: PhysicsConfig,\n isBackground: boolean = false\n): Snowflake => {\n if (isBackground) {\n const radius = Math.random() * 0.8 + 0.3;\n return {\n x: Math.random() * canvasWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.3 + Math.random() * 0.2 + 0.2,\n wind: (Math.random() - 0.5) * (config.WIND_STRENGTH * 0.625),\n opacity: Math.random() * 0.2 + 0.2,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.015 + 0.005,\n };\n } else {\n const radius = Math.random() * 2 + 0.5;\n return {\n x: Math.random() * canvasWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.5 + Math.random() * 0.3 + 0.5,\n wind: (Math.random() - 0.5) * config.WIND_STRENGTH,\n opacity: Math.random() * 0.3 + 0.5,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.02 + 0.01,\n };\n }\n};\n\nexport const initializeAccumulation = (\n accumulationMap: Map<Element, SnowAccumulation>,\n config: PhysicsConfig\n) => {\n const elements = getAccumulationSurfaces();\n // Prune disconnected elements\n for (const [el] of accumulationMap.entries()) {\n if (!el.isConnected) {\n accumulationMap.delete(el);\n }\n }\n\n elements.forEach(({ el, type, isFixed }) => {\n const existing = accumulationMap.get(el);\n const rect = el.getBoundingClientRect();\n const width = Math.ceil(rect.width);\n const isBottom = type === VAL_BOTTOM;\n\n if (existing && existing.heights.length === width) {\n existing.type = type;\n existing.isFixed = isFixed;\n if (existing.borderRadius !== undefined) {\n const styleBuffer = window.getComputedStyle(el); // Potentially slow in loop, strictly necessary?\n existing.borderRadius = parseFloat(styleBuffer.borderTopLeftRadius) || 0;\n }\n return;\n }\n\n const height = Math.ceil(rect.height);\n const baseMax = isBottom ? config.MAX_DEPTH.HEADER_TOP : config.MAX_DEPTH.CARD_TOP;\n\n const styles = window.getComputedStyle(el);\n const borderRadius = parseFloat(styles.borderTopLeftRadius) || 0;\n\n let maxHeights = new Array(width);\n for (let i = 0; i < width; i++) {\n let edgeFactor = 1.0;\n if (!isBottom && borderRadius > 0) {\n if (i < borderRadius) {\n edgeFactor = Math.pow(i / borderRadius, 1.2);\n } else if (i > width - borderRadius) {\n edgeFactor = Math.pow((width - i) / borderRadius, 1.2);\n }\n }\n maxHeights[i] = baseMax * edgeFactor * (0.85 + Math.random() * 0.15);\n }\n\n // Smooth maxHeights\n const smoothPasses = 4;\n for (let p = 0; p < smoothPasses; p++) {\n const smoothed = [...maxHeights];\n for (let i = 1; i < width - 1; i++) {\n smoothed[i] = (maxHeights[i - 1] + maxHeights[i] + maxHeights[i + 1]) / 3;\n }\n maxHeights = smoothed;\n }\n\n accumulationMap.set(el, {\n heights: existing?.heights.length === width ? existing.heights : new Array(width).fill(0),\n maxHeights,\n leftSide: existing?.leftSide.length === height ? existing.leftSide : new Array(height).fill(0),\n rightSide: existing?.rightSide.length === height ? existing.rightSide : new Array(height).fill(0),\n maxSideHeight: isBottom ? 0 : config.MAX_DEPTH.CARD_SIDE,\n borderRadius,\n type,\n isFixed,\n });\n });\n};\n\nconst accumulateSide = (\n sideArray: number[],\n rectHeight: number,\n localY: number,\n maxSideHeight: number,\n borderRadius: number,\n config: PhysicsConfig\n) => {\n const spread = 4;\n const addHeight = config.ACCUMULATION.SIDE_RATE * (0.8 + Math.random() * 0.4);\n\n for (let dy = -spread; dy <= spread; dy++) {\n const y = localY + dy;\n if (y >= 0 && y < sideArray.length) {\n const inTop = y < borderRadius;\n const inBottom = y > rectHeight - borderRadius;\n if (borderRadius > 0 && (inTop || inBottom)) continue;\n\n const normalizedDist = Math.abs(dy) / spread;\n const falloff = (Math.cos(normalizedDist * Math.PI) + 1) / 2;\n sideArray[y] = Math.min(maxSideHeight, sideArray[y] + addHeight * falloff);\n }\n }\n};\n\nexport const updateSnowflakes = (\n snowflakes: Snowflake[],\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number,\n canvasWidth: number,\n canvasHeight: number\n) => {\n for (let i = snowflakes.length - 1; i >= 0; i--) {\n const flake = snowflakes[i];\n\n flake.wobble += flake.wobbleSpeed * dt;\n flake.x += (flake.wind + Math.sin(flake.wobble) * 0.5) * dt;\n flake.y += (flake.speed + Math.cos(flake.wobble * 0.5) * 0.1) * dt;\n\n let landed = false;\n\n for (const { rect, acc } of elementRects) {\n const isBottom = acc.type === VAL_BOTTOM;\n\n // Side collisions\n if (!landed && acc.maxSideHeight > 0 && !isBottom) {\n const isInVerticalBounds = flake.y >= rect.top && flake.y <= rect.bottom;\n\n if (isInVerticalBounds) {\n const localY = Math.floor(flake.y - rect.top);\n const borderRadius = acc.borderRadius;\n\n const isInTopCorner = localY < borderRadius;\n const isInBottomCorner = localY > rect.height - borderRadius;\n const isCorner = borderRadius > 0 && (isInTopCorner || isInBottomCorner);\n\n if (flake.x >= rect.left - 5 && flake.x < rect.left + 3) {\n if (!isCorner) {\n accumulateSide(acc.leftSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (!landed && flake.x > rect.right - 3 && flake.x <= rect.right + 5) {\n if (!isCorner) {\n accumulateSide(acc.rightSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (landed) break;\n }\n }\n\n // Top accumulation\n if (flake.x >= rect.left && flake.x <= rect.right) {\n const localX = Math.floor(flake.x - rect.left);\n const currentHeight = acc.heights[localX] || 0;\n const maxHeight = acc.maxHeights[localX] || 5;\n\n const surfaceY = isBottom ? rect.bottom - currentHeight : rect.top - currentHeight;\n\n if (flake.y >= surfaceY && flake.y < surfaceY + 10 && currentHeight < maxHeight) {\n const shouldAccumulate = isBottom ? Math.random() < 0.15 : true;\n\n if (shouldAccumulate) {\n const baseSpread = Math.ceil(flake.radius);\n const spread = baseSpread + Math.floor(Math.random() * 2);\n const accumRate = isBottom ? config.ACCUMULATION.TOP_HEADER_RATE : config.ACCUMULATION.TOP_CARD_RATE;\n const centerOffset = Math.floor(Math.random() * 3) - 1;\n\n for (let dx = -spread; dx <= spread; dx++) {\n if (Math.random() < 0.15) continue;\n const idx = localX + dx + centerOffset;\n if (idx >= 0 && idx < acc.heights.length) {\n const dist = Math.abs(dx);\n const pixelMax = acc.maxHeights[idx] || 5;\n\n const normDist = dist / spread;\n const falloff = (Math.cos(normDist * Math.PI) + 1) / 2;\n const baseAdd = 0.3 * falloff;\n\n const randomFactor = 0.8 + Math.random() * 0.4;\n const addHeight = baseAdd * randomFactor * accumRate;\n\n if (acc.heights[idx] < pixelMax && addHeight > 0) {\n acc.heights[idx] = Math.min(pixelMax, acc.heights[idx] + addHeight);\n }\n }\n }\n\n if (isBottom) {\n landed = true;\n break;\n }\n }\n\n if (!isBottom) {\n landed = true;\n break;\n }\n }\n }\n }\n\n if (landed || flake.y > canvasHeight + 10 || flake.x < -20 || flake.x > canvasWidth + 20) {\n snowflakes.splice(i, 1);\n }\n }\n};\n\nexport const meltAndSmoothAccumulation = (\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number\n) => {\n for (const { acc } of elementRects) {\n const meltRate = config.MELT_SPEED * dt;\n const len = acc.heights.length;\n\n // Smooth\n if (len > 2) {\n for (let i = 1; i < len - 1; i++) {\n if (acc.heights[i] > 0.05) {\n const avg = (acc.heights[i - 1] + acc.heights[i + 1]) / 2;\n acc.heights[i] = acc.heights[i] * 0.99 + avg * 0.01;\n }\n }\n }\n\n // Melt\n for (let i = 0; i < acc.heights.length; i++) {\n if (acc.heights[i] > 0) acc.heights[i] = Math.max(0, acc.heights[i] - meltRate);\n }\n for (let i = 0; i < acc.leftSide.length; i++) {\n if (acc.leftSide[i] > 0) acc.leftSide[i] = Math.max(0, acc.leftSide[i] - meltRate);\n if (acc.rightSide[i] > 0) acc.rightSide[i] = Math.max(0, acc.rightSide[i] - meltRate);\n }\n }\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface Snowflake {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
radius: number;
|
|
5
|
+
speed: number;
|
|
6
|
+
wind: number;
|
|
7
|
+
opacity: number;
|
|
8
|
+
wobble: number;
|
|
9
|
+
wobbleSpeed: number;
|
|
10
|
+
}
|
|
11
|
+
type SnowfallSurface = 'top' | 'bottom';
|
|
12
|
+
interface SnowAccumulation {
|
|
13
|
+
heights: number[];
|
|
14
|
+
maxHeights: number[];
|
|
15
|
+
leftSide: number[];
|
|
16
|
+
rightSide: number[];
|
|
17
|
+
maxSideHeight: number;
|
|
18
|
+
borderRadius: number;
|
|
19
|
+
type: SnowfallSurface;
|
|
20
|
+
isFixed: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface ElementSurface {
|
|
23
|
+
el: Element;
|
|
24
|
+
rect: DOMRect;
|
|
25
|
+
acc: SnowAccumulation;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type { ElementSurface, SnowAccumulation, SnowfallSurface, Snowflake };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface Snowflake {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
radius: number;
|
|
5
|
+
speed: number;
|
|
6
|
+
wind: number;
|
|
7
|
+
opacity: number;
|
|
8
|
+
wobble: number;
|
|
9
|
+
wobbleSpeed: number;
|
|
10
|
+
}
|
|
11
|
+
type SnowfallSurface = 'top' | 'bottom';
|
|
12
|
+
interface SnowAccumulation {
|
|
13
|
+
heights: number[];
|
|
14
|
+
maxHeights: number[];
|
|
15
|
+
leftSide: number[];
|
|
16
|
+
rightSide: number[];
|
|
17
|
+
maxSideHeight: number;
|
|
18
|
+
borderRadius: number;
|
|
19
|
+
type: SnowfallSurface;
|
|
20
|
+
isFixed: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface ElementSurface {
|
|
23
|
+
el: Element;
|
|
24
|
+
rect: DOMRect;
|
|
25
|
+
acc: SnowAccumulation;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type { ElementSurface, SnowAccumulation, SnowfallSurface, Snowflake };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
var types_exports = {};
|
|
16
|
+
module.exports = __toCommonJS(types_exports);
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/snowfall/types.ts"],"sourcesContent":["export interface Snowflake {\n x: number;\n y: number;\n radius: number;\n speed: number;\n wind: number;\n opacity: number;\n wobble: number;\n wobbleSpeed: number;\n}\n\nexport type SnowfallSurface = 'top' | 'bottom';\n\nexport interface SnowAccumulation {\n heights: number[];\n maxHeights: number[]; // Max height per pixel column\n leftSide: number[];\n rightSide: number[];\n maxSideHeight: number;\n borderRadius: number;\n type: SnowfallSurface;\n isFixed: boolean;\n}\n\nexport interface ElementSurface {\n el: Element;\n rect: DOMRect;\n acc: SnowAccumulation;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|