bsmnt 0.3.0 → 0.3.2
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/dist/helpers/create/setup-sanity.d.ts.map +1 -1
- package/dist/helpers/create/setup-sanity.js +19 -1
- package/dist/helpers/create/setup-sanity.js.map +1 -1
- package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
- package/dist/helpers/integrate/sanity/config.js +11 -2
- package/dist/helpers/integrate/sanity/config.js.map +1 -1
- package/index.js +2 -2
- package/package.json +1 -1
- package/src/templates/next-default/.vscode/settings.json +1 -1
- package/src/templates/next-default/README.md +6 -7
- package/src/templates/next-default/app/layout.tsx +17 -4
- package/src/templates/next-default/biome.json +1 -1
- package/src/templates/next-default/css.d.ts +1 -0
- package/src/templates/next-default/lib/README.md +4 -8
- package/src/templates/next-default/lib/hooks/use-media.ts +3 -1
- package/src/templates/next-default/lib/styles/global.css +182 -0
- package/src/templates/next-default/lib/utils/json-ld.tsx +13 -18
- package/src/templates/next-default/lib/utils/portable-text-to-markdown.ts +83 -0
- package/src/templates/next-default/package.json +3 -3
- package/src/templates/next-experiments/.vscode/settings.json +1 -1
- package/src/templates/next-experiments/README.md +6 -7
- package/src/templates/next-experiments/app/layout.tsx +17 -4
- package/src/templates/next-experiments/biome.json +1 -1
- package/src/templates/next-experiments/css.d.ts +1 -0
- package/src/templates/next-experiments/lib/README.md +4 -8
- package/src/templates/next-experiments/lib/hooks/use-media.ts +3 -1
- package/src/templates/next-experiments/lib/styles/global.css +182 -0
- package/src/templates/next-experiments/lib/utils/json-ld.tsx +13 -18
- package/src/templates/next-experiments/lib/utils/portable-text-to-markdown.ts +83 -0
- package/src/templates/next-experiments/package.json +3 -3
- package/src/templates/next-webgl/.vscode/settings.json +1 -1
- package/src/templates/next-webgl/README.md +6 -7
- package/src/templates/next-webgl/app/layout.tsx +17 -4
- package/src/templates/next-webgl/biome.json +1 -1
- package/src/templates/next-webgl/css.d.ts +1 -0
- package/src/templates/next-webgl/lib/README.md +4 -8
- package/src/templates/next-webgl/lib/hooks/use-media.ts +3 -1
- package/src/templates/next-webgl/lib/styles/global.css +182 -0
- package/src/templates/next-webgl/lib/utils/json-ld.tsx +13 -18
- package/src/templates/next-webgl/lib/utils/portable-text-to-markdown.ts +83 -0
- package/src/templates/next-webgl/package.json +3 -3
- package/src/templates/next-default/lib/scripts/dev.ts +0 -32
- package/src/templates/next-default/lib/styles/README.md +0 -13
- package/src/templates/next-default/lib/styles/fonts.ts +0 -20
- package/src/templates/next-default/lib/styles/index.css +0 -3
- package/src/templates/next-default/lib/styles/tokens.css +0 -179
- package/src/templates/next-default/lib/utils/README.md +0 -40
- package/src/templates/next-default/lib/utils/easings.ts +0 -240
- package/src/templates/next-default/lib/utils/fetch.ts +0 -84
- package/src/templates/next-default/lib/utils/global-css.d.ts +0 -1
- package/src/templates/next-default/lib/utils/math.ts +0 -236
- package/src/templates/next-default/lib/utils/strings.ts +0 -246
- package/src/templates/next-default/lib/utils/types.d.ts +0 -15
- package/src/templates/next-default/lib/utils/viewport.ts +0 -199
- package/src/templates/next-experiments/lib/scripts/dev.ts +0 -32
- package/src/templates/next-experiments/lib/styles/README.md +0 -13
- package/src/templates/next-experiments/lib/styles/fonts.ts +0 -20
- package/src/templates/next-experiments/lib/styles/index.css +0 -3
- package/src/templates/next-experiments/lib/styles/tokens.css +0 -179
- package/src/templates/next-experiments/lib/utils/README.md +0 -40
- package/src/templates/next-experiments/lib/utils/easings.ts +0 -240
- package/src/templates/next-experiments/lib/utils/fetch.ts +0 -84
- package/src/templates/next-experiments/lib/utils/global-css.d.ts +0 -1
- package/src/templates/next-experiments/lib/utils/math.ts +0 -236
- package/src/templates/next-experiments/lib/utils/strings.ts +0 -246
- package/src/templates/next-experiments/lib/utils/types.d.ts +0 -15
- package/src/templates/next-experiments/lib/utils/viewport.ts +0 -199
- package/src/templates/next-webgl/lib/scripts/dev.ts +0 -32
- package/src/templates/next-webgl/lib/styles/README.md +0 -13
- package/src/templates/next-webgl/lib/styles/fonts.ts +0 -20
- package/src/templates/next-webgl/lib/styles/index.css +0 -3
- package/src/templates/next-webgl/lib/styles/tokens.css +0 -179
- package/src/templates/next-webgl/lib/utils/README.md +0 -40
- package/src/templates/next-webgl/lib/utils/easings.ts +0 -240
- package/src/templates/next-webgl/lib/utils/fetch.ts +0 -84
- package/src/templates/next-webgl/lib/utils/global-css.d.ts +0 -1
- package/src/templates/next-webgl/lib/utils/math.ts +0 -236
- package/src/templates/next-webgl/lib/utils/strings.ts +0 -246
- package/src/templates/next-webgl/lib/utils/types.d.ts +0 -15
- package/src/templates/next-webgl/lib/utils/viewport.ts +0 -199
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Utils
|
|
2
|
-
|
|
3
|
-
Pure utility functions organized by concern.
|
|
4
|
-
|
|
5
|
-
Use explicit imports for clarity and better tree-shaking:
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { clamp, lerp, mapRange } from '@/utils/math'
|
|
9
|
-
import { slugify } from '@/utils/strings'
|
|
10
|
-
import { generatePageMetadata } from '@/utils/metadata'
|
|
11
|
-
import { tovw, torem, toem } from '@/utils/viewport'
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Modules
|
|
15
|
-
|
|
16
|
-
| Module | Functions |
|
|
17
|
-
|--------|-----------|
|
|
18
|
-
| `math` | `clamp`, `lerp`, `mapRange`, `modulo`, `normalize`, `distance` |
|
|
19
|
-
| `easings` | All easing functions (`easeOutCubic`, etc.) |
|
|
20
|
-
| `viewport` | `tovw`, `torem`, `toem` |
|
|
21
|
-
| `strings` | `slugify`, `mergeRefs`, `capitalizeFirstLetter` |
|
|
22
|
-
| `metadata` | `generatePageMetadata` |
|
|
23
|
-
|
|
24
|
-
## Common Patterns
|
|
25
|
-
|
|
26
|
-
```tsx
|
|
27
|
-
// Math
|
|
28
|
-
clamp(0, value, 100)
|
|
29
|
-
lerp(0, 100, 0.5) // → 50
|
|
30
|
-
mapRange(0, 1000, scrollY, 0, 1)
|
|
31
|
-
|
|
32
|
-
// Viewport units
|
|
33
|
-
tovw(100, 50, 'desktop') // → "max(50px, 6.94vw)"
|
|
34
|
-
tovw(16, undefined, 'mobile') // → "4.27vw"
|
|
35
|
-
torem(24) // → "1.5rem"
|
|
36
|
-
toem(16, 14) // → "1.14em"
|
|
37
|
-
|
|
38
|
-
// SEO
|
|
39
|
-
export const metadata = generatePageMetadata({ title: 'About' })
|
|
40
|
-
```
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Easing Functions
|
|
3
|
-
*
|
|
4
|
-
* A complete collection of easing curves for animations.
|
|
5
|
-
* All functions take a progress value (0-1) and return an eased value (0-1).
|
|
6
|
-
*
|
|
7
|
-
* @see https://easings.net for visual references
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { easings, type EasingName } from '@/utils/easings'
|
|
12
|
-
*
|
|
13
|
-
* // Direct usage
|
|
14
|
-
* const eased = easings.easeOutCubic(0.5)
|
|
15
|
-
*
|
|
16
|
-
* // With a variable easing name
|
|
17
|
-
* const easingName: EasingName = 'easeInOutQuart'
|
|
18
|
-
* const value = easings[easingName](progress)
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* ## Choosing an Easing
|
|
22
|
-
*
|
|
23
|
-
* | Category | Use Case |
|
|
24
|
-
* |----------|----------|
|
|
25
|
-
* | `easeOut*` | UI feedback, appearing elements (most common) |
|
|
26
|
-
* | `easeIn*` | Exiting elements, building tension |
|
|
27
|
-
* | `easeInOut*` | State transitions, loading indicators |
|
|
28
|
-
* | `*Cubic/Quart` | Natural, balanced motion |
|
|
29
|
-
* | `*Expo` | Dramatic, snappy motion |
|
|
30
|
-
* | `*Elastic/Bounce` | Playful, attention-grabbing |
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
const pow = Math.pow
|
|
34
|
-
const sqrt = Math.sqrt
|
|
35
|
-
const sin = Math.sin
|
|
36
|
-
const cos = Math.cos
|
|
37
|
-
const PI = Math.PI
|
|
38
|
-
|
|
39
|
-
// Easing constants
|
|
40
|
-
const c1 = 1.70158
|
|
41
|
-
const c2 = c1 * 1.525
|
|
42
|
-
const c3 = c1 + 1
|
|
43
|
-
const c4 = (2 * PI) / 3
|
|
44
|
-
const c5 = (2 * PI) / 4.5
|
|
45
|
-
|
|
46
|
-
/** Bounce out helper (used by bounce easings) */
|
|
47
|
-
const bounceOut = (x: number): number => {
|
|
48
|
-
const n1 = 7.5625
|
|
49
|
-
const d1 = 2.75
|
|
50
|
-
|
|
51
|
-
if (x < 1 / d1) {
|
|
52
|
-
return n1 * x * x
|
|
53
|
-
}
|
|
54
|
-
if (x < 2 / d1) {
|
|
55
|
-
return n1 * (x - 1.5 / d1) * x + 0.75
|
|
56
|
-
}
|
|
57
|
-
if (x < 2.5 / d1) {
|
|
58
|
-
return n1 * (x - 2.25 / d1) * x + 0.9375
|
|
59
|
-
}
|
|
60
|
-
return n1 * (x - 2.625 / d1) * x + 0.984375
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Collection of easing functions.
|
|
65
|
-
* Each function takes progress (0-1) and returns eased value (0-1).
|
|
66
|
-
*/
|
|
67
|
-
export const easings = {
|
|
68
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
69
|
-
// Linear (no easing)
|
|
70
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
/** No easing - constant speed */
|
|
73
|
-
linear: (x: number): number => x,
|
|
74
|
-
|
|
75
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
76
|
-
// Quadratic (power of 2)
|
|
77
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
|
-
|
|
79
|
-
/** Slow start */
|
|
80
|
-
easeInQuad: (x: number): number => x * x,
|
|
81
|
-
|
|
82
|
-
/** Slow end */
|
|
83
|
-
easeOutQuad: (x: number): number => 1 - (1 - x) * (1 - x),
|
|
84
|
-
|
|
85
|
-
/** Slow start and end */
|
|
86
|
-
easeInOutQuad: (x: number): number =>
|
|
87
|
-
x < 0.5 ? 2 * x * x : 1 - pow(-2 * x + 2, 2) / 2,
|
|
88
|
-
|
|
89
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
|
-
// Cubic (power of 3) - Most commonly used
|
|
91
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
92
|
-
|
|
93
|
-
/** Slow start, natural feel */
|
|
94
|
-
easeInCubic: (x: number): number => x * x * x,
|
|
95
|
-
|
|
96
|
-
/** Slow end, natural feel - great for UI interactions */
|
|
97
|
-
easeOutCubic: (x: number): number => 1 - pow(1 - x, 3),
|
|
98
|
-
|
|
99
|
-
/** Smooth start and end - great for transitions */
|
|
100
|
-
easeInOutCubic: (x: number): number =>
|
|
101
|
-
x < 0.5 ? 4 * x * x * x : 1 - pow(-2 * x + 2, 3) / 2,
|
|
102
|
-
|
|
103
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
104
|
-
// Quartic (power of 4)
|
|
105
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
/** Slower start than cubic */
|
|
108
|
-
easeInQuart: (x: number): number => x * x * x * x,
|
|
109
|
-
|
|
110
|
-
/** Slower end than cubic */
|
|
111
|
-
easeOutQuart: (x: number): number => 1 - pow(1 - x, 4),
|
|
112
|
-
|
|
113
|
-
/** More pronounced ease than cubic */
|
|
114
|
-
easeInOutQuart: (x: number): number =>
|
|
115
|
-
x < 0.5 ? 8 * x * x * x * x : 1 - pow(-2 * x + 2, 4) / 2,
|
|
116
|
-
|
|
117
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
118
|
-
// Quintic (power of 5)
|
|
119
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
120
|
-
|
|
121
|
-
/** Very slow start */
|
|
122
|
-
easeInQuint: (x: number): number => x * x * x * x * x,
|
|
123
|
-
|
|
124
|
-
/** Very slow end */
|
|
125
|
-
easeOutQuint: (x: number): number => 1 - pow(1 - x, 5),
|
|
126
|
-
|
|
127
|
-
/** Very pronounced ease */
|
|
128
|
-
easeInOutQuint: (x: number): number =>
|
|
129
|
-
x < 0.5 ? 16 * x * x * x * x * x : 1 - pow(-2 * x + 2, 5) / 2,
|
|
130
|
-
|
|
131
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
132
|
-
// Sinusoidal - Gentle, wave-like
|
|
133
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
134
|
-
|
|
135
|
-
/** Gentle slow start */
|
|
136
|
-
easeInSine: (x: number): number => 1 - cos((x * PI) / 2),
|
|
137
|
-
|
|
138
|
-
/** Gentle slow end */
|
|
139
|
-
easeOutSine: (x: number): number => sin((x * PI) / 2),
|
|
140
|
-
|
|
141
|
-
/** Gentle ease both ends */
|
|
142
|
-
easeInOutSine: (x: number): number => -(cos(PI * x) - 1) / 2,
|
|
143
|
-
|
|
144
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
145
|
-
// Exponential - Dramatic, snappy
|
|
146
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
147
|
-
|
|
148
|
-
/** Dramatic slow start - almost stationary then fast */
|
|
149
|
-
easeInExpo: (x: number): number => (x === 0 ? 0 : pow(2, 10 * x - 10)),
|
|
150
|
-
|
|
151
|
-
/** Dramatic slow end - fast then almost stops */
|
|
152
|
-
easeOutExpo: (x: number): number => (x === 1 ? 1 : 1 - pow(2, -10 * x)),
|
|
153
|
-
|
|
154
|
-
/** Dramatic both ends */
|
|
155
|
-
easeInOutExpo: (x: number): number => {
|
|
156
|
-
if (x === 0) return 0
|
|
157
|
-
if (x === 1) return 1
|
|
158
|
-
if (x < 0.5) return pow(2, 20 * x - 10) / 2
|
|
159
|
-
return (2 - pow(2, -20 * x + 10)) / 2
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
163
|
-
// Circular - Based on circle quarter
|
|
164
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
165
|
-
|
|
166
|
-
/** Circular slow start */
|
|
167
|
-
easeInCirc: (x: number): number => 1 - sqrt(1 - pow(x, 2)),
|
|
168
|
-
|
|
169
|
-
/** Circular slow end */
|
|
170
|
-
easeOutCirc: (x: number): number => sqrt(1 - pow(x - 1, 2)),
|
|
171
|
-
|
|
172
|
-
/** Circular both ends */
|
|
173
|
-
easeInOutCirc: (x: number): number =>
|
|
174
|
-
x < 0.5
|
|
175
|
-
? (1 - sqrt(1 - pow(2 * x, 2))) / 2
|
|
176
|
-
: (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2,
|
|
177
|
-
|
|
178
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
179
|
-
// Back - Overshoots then returns
|
|
180
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
181
|
-
|
|
182
|
-
/** Pulls back before accelerating */
|
|
183
|
-
easeInBack: (x: number): number => c3 * x * x * x - c1 * x * x,
|
|
184
|
-
|
|
185
|
-
/** Overshoots target then settles */
|
|
186
|
-
easeOutBack: (x: number): number =>
|
|
187
|
-
1 + c3 * pow(x - 1, 3) + c1 * pow(x - 1, 2),
|
|
188
|
-
|
|
189
|
-
/** Pulls back, overshoots, settles */
|
|
190
|
-
easeInOutBack: (x: number): number =>
|
|
191
|
-
x < 0.5
|
|
192
|
-
? (pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2
|
|
193
|
-
: (pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2,
|
|
194
|
-
|
|
195
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
196
|
-
// Elastic - Spring-like oscillation
|
|
197
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
198
|
-
|
|
199
|
-
/** Wobbles at start */
|
|
200
|
-
easeInElastic: (x: number): number => {
|
|
201
|
-
if (x === 0) return 0
|
|
202
|
-
if (x === 1) return 1
|
|
203
|
-
return -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c4)
|
|
204
|
-
},
|
|
205
|
-
|
|
206
|
-
/** Wobbles at end - great for attention */
|
|
207
|
-
easeOutElastic: (x: number): number => {
|
|
208
|
-
if (x === 0) return 0
|
|
209
|
-
if (x === 1) return 1
|
|
210
|
-
return pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1
|
|
211
|
-
},
|
|
212
|
-
|
|
213
|
-
/** Wobbles both ends */
|
|
214
|
-
easeInOutElastic: (x: number): number => {
|
|
215
|
-
if (x === 0) return 0
|
|
216
|
-
if (x === 1) return 1
|
|
217
|
-
if (x < 0.5) return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c5)) / 2
|
|
218
|
-
return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c5)) / 2 + 1
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
222
|
-
// Bounce - Ball bouncing effect
|
|
223
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
/** Bounces at start */
|
|
226
|
-
easeInBounce: (x: number): number => 1 - bounceOut(1 - x),
|
|
227
|
-
|
|
228
|
-
/** Bounces at end - like a ball settling */
|
|
229
|
-
easeOutBounce: bounceOut,
|
|
230
|
-
|
|
231
|
-
/** Bounces both ends */
|
|
232
|
-
easeInOutBounce: (x: number): number =>
|
|
233
|
-
x < 0.5 ? (1 - bounceOut(1 - 2 * x)) / 2 : (1 + bounceOut(2 * x - 1)) / 2,
|
|
234
|
-
} as const
|
|
235
|
-
|
|
236
|
-
/** All available easing function names */
|
|
237
|
-
export type EasingName = keyof typeof easings
|
|
238
|
-
|
|
239
|
-
/** An easing function signature */
|
|
240
|
-
export type EasingFunction = (progress: number) => number
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fetch Utilities
|
|
3
|
-
*
|
|
4
|
-
* Wrapper around fetch that adds timeout protection to prevent hanging requests.
|
|
5
|
-
* Use this for all external API calls to improve reliability.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export interface FetchWithTimeoutOptions extends RequestInit {
|
|
9
|
-
timeout?: number // Timeout in milliseconds (default: 10000ms)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Fetch with automatic timeout protection
|
|
14
|
-
*
|
|
15
|
-
* @param url - The URL to fetch
|
|
16
|
-
* @param options - Fetch options with optional timeout
|
|
17
|
-
* @returns Promise<Response>
|
|
18
|
-
* @throws AbortError if timeout is reached
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* try {
|
|
23
|
-
* const response = await fetchWithTimeout('https://api.example.com/data', {
|
|
24
|
-
* timeout: 5000, // 5 second timeout
|
|
25
|
-
* method: 'POST',
|
|
26
|
-
* body: JSON.stringify(data)
|
|
27
|
-
* })
|
|
28
|
-
* const result = await response.json()
|
|
29
|
-
* } catch (error) {
|
|
30
|
-
* if (error.name === 'AbortError') {
|
|
31
|
-
* console.error('Request timed out')
|
|
32
|
-
* }
|
|
33
|
-
* }
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export async function fetchWithTimeout(
|
|
37
|
-
url: string,
|
|
38
|
-
options: FetchWithTimeoutOptions = {}
|
|
39
|
-
): Promise<Response> {
|
|
40
|
-
const { timeout = 10000, signal: externalSignal, ...fetchOptions } = options
|
|
41
|
-
|
|
42
|
-
const controller = new AbortController()
|
|
43
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
|
44
|
-
|
|
45
|
-
// If an external signal is provided, listen to it and abort our controller
|
|
46
|
-
if (externalSignal) {
|
|
47
|
-
externalSignal.addEventListener("abort", () => controller.abort())
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const response = await fetch(url, {
|
|
52
|
-
...fetchOptions,
|
|
53
|
-
signal: controller.signal,
|
|
54
|
-
})
|
|
55
|
-
return response
|
|
56
|
-
} finally {
|
|
57
|
-
clearTimeout(timeoutId)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Fetch JSON with timeout protection
|
|
63
|
-
*
|
|
64
|
-
* Convenience wrapper that automatically parses JSON and handles errors
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```ts
|
|
68
|
-
* const data = await fetchJSON<{ name: string }>('https://api.example.com/user', {
|
|
69
|
-
* timeout: 5000
|
|
70
|
-
* })
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
export async function fetchJSON<T = unknown>(
|
|
74
|
-
url: string,
|
|
75
|
-
options: FetchWithTimeoutOptions = {}
|
|
76
|
-
): Promise<T> {
|
|
77
|
-
const response = await fetchWithTimeout(url, options)
|
|
78
|
-
|
|
79
|
-
if (!response.ok) {
|
|
80
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return response.json() as Promise<T>
|
|
84
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare module "@/lib/styles/index.css";
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Math Utilities
|
|
3
|
-
*
|
|
4
|
-
* Pure mathematical functions with no side effects.
|
|
5
|
-
* These are the building blocks for animations, layouts, and data transformations.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { clamp, lerp, mapRange } from '@/utils/math'
|
|
10
|
-
*
|
|
11
|
-
* // Constrain a value
|
|
12
|
-
* const bounded = clamp(0, value, 100)
|
|
13
|
-
*
|
|
14
|
-
* // Interpolate between values
|
|
15
|
-
* const mid = lerp(0, 100, 0.5) // 50
|
|
16
|
-
*
|
|
17
|
-
* // Map scroll position to opacity
|
|
18
|
-
* const opacity = mapRange(0, 500, scrollY, 0, 1, true)
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Constrains a value between a minimum and maximum.
|
|
24
|
-
*
|
|
25
|
-
* @param min - Lower bound
|
|
26
|
-
* @param input - Value to constrain
|
|
27
|
-
* @param max - Upper bound
|
|
28
|
-
* @returns The clamped value
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```ts
|
|
32
|
-
* clamp(0, -5, 100) // 0
|
|
33
|
-
* clamp(0, 50, 100) // 50
|
|
34
|
-
* clamp(0, 150, 100) // 100
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export function clamp(min: number, input: number, max: number): number {
|
|
38
|
-
return Math.max(min, Math.min(input, max))
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Linear interpolation between two values.
|
|
43
|
-
*
|
|
44
|
-
* @param start - Starting value
|
|
45
|
-
* @param end - Ending value
|
|
46
|
-
* @param amount - Interpolation factor (0 = start, 1 = end)
|
|
47
|
-
* @returns The interpolated value
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```ts
|
|
51
|
-
* lerp(0, 100, 0) // 0
|
|
52
|
-
* lerp(0, 100, 0.5) // 50
|
|
53
|
-
* lerp(0, 100, 1) // 100
|
|
54
|
-
* lerp(0, 100, 0.25) // 25
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export function lerp(start: number, end: number, amount: number): number {
|
|
58
|
-
return (1 - amount) * start + amount * end
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Maps a value from one range to another.
|
|
63
|
-
*
|
|
64
|
-
* @param inMin - Input range minimum
|
|
65
|
-
* @param inMax - Input range maximum
|
|
66
|
-
* @param input - Value to map
|
|
67
|
-
* @param outMin - Output range minimum
|
|
68
|
-
* @param outMax - Output range maximum
|
|
69
|
-
* @param shouldClamp - Whether to clamp output to range (default: false)
|
|
70
|
-
* @returns The mapped value
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```ts
|
|
74
|
-
* // Map scroll (0-1000) to opacity (0-1)
|
|
75
|
-
* mapRange(0, 1000, 500, 0, 1) // 0.5
|
|
76
|
-
*
|
|
77
|
-
* // Map with clamping (won't exceed bounds)
|
|
78
|
-
* mapRange(0, 100, 150, 0, 1, true) // 1
|
|
79
|
-
*
|
|
80
|
-
* // Inverted ranges work too
|
|
81
|
-
* mapRange(0, 100, 50, 1, 0) // 0.5
|
|
82
|
-
* ```
|
|
83
|
-
*/
|
|
84
|
-
export function mapRange(
|
|
85
|
-
inMin: number,
|
|
86
|
-
inMax: number,
|
|
87
|
-
input: number,
|
|
88
|
-
outMin: number,
|
|
89
|
-
outMax: number,
|
|
90
|
-
shouldClamp = false
|
|
91
|
-
): number {
|
|
92
|
-
const result =
|
|
93
|
-
((input - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin
|
|
94
|
-
|
|
95
|
-
if (!shouldClamp) return result
|
|
96
|
-
|
|
97
|
-
const isInverted = outMin > outMax
|
|
98
|
-
return isInverted
|
|
99
|
-
? clamp(outMax, result, outMin)
|
|
100
|
-
: clamp(outMin, result, outMax)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Truncates a number to a specified number of decimal places.
|
|
105
|
-
*
|
|
106
|
-
* @param value - Number to truncate
|
|
107
|
-
* @param decimals - Number of decimal places
|
|
108
|
-
* @returns The truncated number
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```ts
|
|
112
|
-
* truncate(3.14159, 2) // 3.14
|
|
113
|
-
* truncate(3.14159, 0) // 3
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
export function truncate(value: number, decimals: number): number {
|
|
117
|
-
return Number.parseFloat(value.toFixed(decimals))
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* True modulo operation (handles negative numbers correctly).
|
|
122
|
-
*
|
|
123
|
-
* JavaScript's % operator is remainder, not modulo.
|
|
124
|
-
* This function returns a value in [0, d) for positive divisors.
|
|
125
|
-
*
|
|
126
|
-
* @param n - Dividend
|
|
127
|
-
* @param d - Divisor (must be positive)
|
|
128
|
-
* @returns The modulo result
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* ```ts
|
|
132
|
-
* // JavaScript remainder vs true modulo
|
|
133
|
-
* -1 % 3 // -1 (remainder)
|
|
134
|
-
* modulo(-1, 3) // 2 (modulo)
|
|
135
|
-
*
|
|
136
|
-
* // Useful for wrapping array indices
|
|
137
|
-
* modulo(index - 1, array.length)
|
|
138
|
-
* ```
|
|
139
|
-
*/
|
|
140
|
-
export function modulo(n: number, d: number): number {
|
|
141
|
-
if (d === 0) return n
|
|
142
|
-
if (d < 0) return Number.NaN
|
|
143
|
-
return ((n % d) + d) % d
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Rounds a number to the nearest multiple.
|
|
148
|
-
*
|
|
149
|
-
* @param value - Number to round
|
|
150
|
-
* @param multiple - Multiple to round to
|
|
151
|
-
* @returns The rounded value
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* ```ts
|
|
155
|
-
* roundTo(23, 10) // 20
|
|
156
|
-
* roundTo(27, 10) // 30
|
|
157
|
-
* roundTo(0.23, 0.1) // 0.2
|
|
158
|
-
* ```
|
|
159
|
-
*/
|
|
160
|
-
export function roundTo(value: number, multiple: number): number {
|
|
161
|
-
return Math.round(value / multiple) * multiple
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Converts degrees to radians.
|
|
166
|
-
*
|
|
167
|
-
* @param degrees - Angle in degrees
|
|
168
|
-
* @returns Angle in radians
|
|
169
|
-
*
|
|
170
|
-
* @example
|
|
171
|
-
* ```ts
|
|
172
|
-
* degToRad(180) // Math.PI
|
|
173
|
-
* degToRad(90) // Math.PI / 2
|
|
174
|
-
* ```
|
|
175
|
-
*/
|
|
176
|
-
export function degToRad(degrees: number): number {
|
|
177
|
-
return (degrees * Math.PI) / 180
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Converts radians to degrees.
|
|
182
|
-
*
|
|
183
|
-
* @param radians - Angle in radians
|
|
184
|
-
* @returns Angle in degrees
|
|
185
|
-
*
|
|
186
|
-
* @example
|
|
187
|
-
* ```ts
|
|
188
|
-
* radToDeg(Math.PI) // 180
|
|
189
|
-
* radToDeg(Math.PI / 2) // 90
|
|
190
|
-
* ```
|
|
191
|
-
*/
|
|
192
|
-
export function radToDeg(radians: number): number {
|
|
193
|
-
return (radians * 180) / Math.PI
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Calculates the distance between two 2D points.
|
|
198
|
-
*
|
|
199
|
-
* @param x1 - First point X
|
|
200
|
-
* @param y1 - First point Y
|
|
201
|
-
* @param x2 - Second point X
|
|
202
|
-
* @param y2 - Second point Y
|
|
203
|
-
* @returns The distance
|
|
204
|
-
*
|
|
205
|
-
* @example
|
|
206
|
-
* ```ts
|
|
207
|
-
* distance(0, 0, 3, 4) // 5
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
|
-
export function distance(
|
|
211
|
-
x1: number,
|
|
212
|
-
y1: number,
|
|
213
|
-
x2: number,
|
|
214
|
-
y2: number
|
|
215
|
-
): number {
|
|
216
|
-
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Normalizes a value to a 0-1 range.
|
|
221
|
-
*
|
|
222
|
-
* @param min - Range minimum
|
|
223
|
-
* @param max - Range maximum
|
|
224
|
-
* @param value - Value to normalize
|
|
225
|
-
* @returns Normalized value (0-1)
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* ```ts
|
|
229
|
-
* normalize(0, 100, 50) // 0.5
|
|
230
|
-
* normalize(0, 100, 0) // 0
|
|
231
|
-
* normalize(0, 100, 100) // 1
|
|
232
|
-
* ```
|
|
233
|
-
*/
|
|
234
|
-
export function normalize(min: number, max: number, value: number): number {
|
|
235
|
-
return (value - min) / (max - min)
|
|
236
|
-
}
|