@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.
Files changed (51) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +144 -0
  3. package/dist/Snowfall.d.mts +5 -0
  4. package/dist/Snowfall.d.ts +5 -0
  5. package/dist/Snowfall.js +162 -0
  6. package/dist/Snowfall.js.map +1 -0
  7. package/dist/Snowfall.mjs +142 -0
  8. package/dist/Snowfall.mjs.map +1 -0
  9. package/dist/SnowfallProvider.d.mts +32 -0
  10. package/dist/SnowfallProvider.d.ts +32 -0
  11. package/dist/SnowfallProvider.js +89 -0
  12. package/dist/SnowfallProvider.js.map +1 -0
  13. package/dist/SnowfallProvider.mjs +63 -0
  14. package/dist/SnowfallProvider.mjs.map +1 -0
  15. package/dist/index.d.mts +4 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.js +47 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/index.mjs +10 -0
  20. package/dist/index.mjs.map +1 -0
  21. package/dist/utils/snowfall/constants.d.mts +10 -0
  22. package/dist/utils/snowfall/constants.d.ts +10 -0
  23. package/dist/utils/snowfall/constants.js +50 -0
  24. package/dist/utils/snowfall/constants.js.map +1 -0
  25. package/dist/utils/snowfall/constants.mjs +19 -0
  26. package/dist/utils/snowfall/constants.mjs.map +1 -0
  27. package/dist/utils/snowfall/dom.d.mts +11 -0
  28. package/dist/utils/snowfall/dom.d.ts +11 -0
  29. package/dist/utils/snowfall/dom.js +130 -0
  30. package/dist/utils/snowfall/dom.js.map +1 -0
  31. package/dist/utils/snowfall/dom.mjs +113 -0
  32. package/dist/utils/snowfall/dom.mjs.map +1 -0
  33. package/dist/utils/snowfall/draw.d.mts +7 -0
  34. package/dist/utils/snowfall/draw.d.ts +7 -0
  35. package/dist/utils/snowfall/draw.js +160 -0
  36. package/dist/utils/snowfall/draw.js.map +1 -0
  37. package/dist/utils/snowfall/draw.mjs +134 -0
  38. package/dist/utils/snowfall/draw.mjs.map +1 -0
  39. package/dist/utils/snowfall/physics.d.mts +11 -0
  40. package/dist/utils/snowfall/physics.d.ts +11 -0
  41. package/dist/utils/snowfall/physics.js +233 -0
  42. package/dist/utils/snowfall/physics.js.map +1 -0
  43. package/dist/utils/snowfall/physics.mjs +206 -0
  44. package/dist/utils/snowfall/physics.mjs.map +1 -0
  45. package/dist/utils/snowfall/types.d.mts +28 -0
  46. package/dist/utils/snowfall/types.d.ts +28 -0
  47. package/dist/utils/snowfall/types.js +17 -0
  48. package/dist/utils/snowfall/types.js.map +1 -0
  49. package/dist/utils/snowfall/types.mjs +1 -0
  50. package/dist/utils/snowfall/types.mjs.map +1 -0
  51. 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":[]}