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.
Files changed (80) hide show
  1. package/dist/helpers/create/setup-sanity.d.ts.map +1 -1
  2. package/dist/helpers/create/setup-sanity.js +19 -1
  3. package/dist/helpers/create/setup-sanity.js.map +1 -1
  4. package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
  5. package/dist/helpers/integrate/sanity/config.js +11 -2
  6. package/dist/helpers/integrate/sanity/config.js.map +1 -1
  7. package/index.js +2 -2
  8. package/package.json +1 -1
  9. package/src/templates/next-default/.vscode/settings.json +1 -1
  10. package/src/templates/next-default/README.md +6 -7
  11. package/src/templates/next-default/app/layout.tsx +17 -4
  12. package/src/templates/next-default/biome.json +1 -1
  13. package/src/templates/next-default/css.d.ts +1 -0
  14. package/src/templates/next-default/lib/README.md +4 -8
  15. package/src/templates/next-default/lib/hooks/use-media.ts +3 -1
  16. package/src/templates/next-default/lib/styles/global.css +182 -0
  17. package/src/templates/next-default/lib/utils/json-ld.tsx +13 -18
  18. package/src/templates/next-default/lib/utils/portable-text-to-markdown.ts +83 -0
  19. package/src/templates/next-default/package.json +3 -3
  20. package/src/templates/next-experiments/.vscode/settings.json +1 -1
  21. package/src/templates/next-experiments/README.md +6 -7
  22. package/src/templates/next-experiments/app/layout.tsx +17 -4
  23. package/src/templates/next-experiments/biome.json +1 -1
  24. package/src/templates/next-experiments/css.d.ts +1 -0
  25. package/src/templates/next-experiments/lib/README.md +4 -8
  26. package/src/templates/next-experiments/lib/hooks/use-media.ts +3 -1
  27. package/src/templates/next-experiments/lib/styles/global.css +182 -0
  28. package/src/templates/next-experiments/lib/utils/json-ld.tsx +13 -18
  29. package/src/templates/next-experiments/lib/utils/portable-text-to-markdown.ts +83 -0
  30. package/src/templates/next-experiments/package.json +3 -3
  31. package/src/templates/next-webgl/.vscode/settings.json +1 -1
  32. package/src/templates/next-webgl/README.md +6 -7
  33. package/src/templates/next-webgl/app/layout.tsx +17 -4
  34. package/src/templates/next-webgl/biome.json +1 -1
  35. package/src/templates/next-webgl/css.d.ts +1 -0
  36. package/src/templates/next-webgl/lib/README.md +4 -8
  37. package/src/templates/next-webgl/lib/hooks/use-media.ts +3 -1
  38. package/src/templates/next-webgl/lib/styles/global.css +182 -0
  39. package/src/templates/next-webgl/lib/utils/json-ld.tsx +13 -18
  40. package/src/templates/next-webgl/lib/utils/portable-text-to-markdown.ts +83 -0
  41. package/src/templates/next-webgl/package.json +3 -3
  42. package/src/templates/next-default/lib/scripts/dev.ts +0 -32
  43. package/src/templates/next-default/lib/styles/README.md +0 -13
  44. package/src/templates/next-default/lib/styles/fonts.ts +0 -20
  45. package/src/templates/next-default/lib/styles/index.css +0 -3
  46. package/src/templates/next-default/lib/styles/tokens.css +0 -179
  47. package/src/templates/next-default/lib/utils/README.md +0 -40
  48. package/src/templates/next-default/lib/utils/easings.ts +0 -240
  49. package/src/templates/next-default/lib/utils/fetch.ts +0 -84
  50. package/src/templates/next-default/lib/utils/global-css.d.ts +0 -1
  51. package/src/templates/next-default/lib/utils/math.ts +0 -236
  52. package/src/templates/next-default/lib/utils/strings.ts +0 -246
  53. package/src/templates/next-default/lib/utils/types.d.ts +0 -15
  54. package/src/templates/next-default/lib/utils/viewport.ts +0 -199
  55. package/src/templates/next-experiments/lib/scripts/dev.ts +0 -32
  56. package/src/templates/next-experiments/lib/styles/README.md +0 -13
  57. package/src/templates/next-experiments/lib/styles/fonts.ts +0 -20
  58. package/src/templates/next-experiments/lib/styles/index.css +0 -3
  59. package/src/templates/next-experiments/lib/styles/tokens.css +0 -179
  60. package/src/templates/next-experiments/lib/utils/README.md +0 -40
  61. package/src/templates/next-experiments/lib/utils/easings.ts +0 -240
  62. package/src/templates/next-experiments/lib/utils/fetch.ts +0 -84
  63. package/src/templates/next-experiments/lib/utils/global-css.d.ts +0 -1
  64. package/src/templates/next-experiments/lib/utils/math.ts +0 -236
  65. package/src/templates/next-experiments/lib/utils/strings.ts +0 -246
  66. package/src/templates/next-experiments/lib/utils/types.d.ts +0 -15
  67. package/src/templates/next-experiments/lib/utils/viewport.ts +0 -199
  68. package/src/templates/next-webgl/lib/scripts/dev.ts +0 -32
  69. package/src/templates/next-webgl/lib/styles/README.md +0 -13
  70. package/src/templates/next-webgl/lib/styles/fonts.ts +0 -20
  71. package/src/templates/next-webgl/lib/styles/index.css +0 -3
  72. package/src/templates/next-webgl/lib/styles/tokens.css +0 -179
  73. package/src/templates/next-webgl/lib/utils/README.md +0 -40
  74. package/src/templates/next-webgl/lib/utils/easings.ts +0 -240
  75. package/src/templates/next-webgl/lib/utils/fetch.ts +0 -84
  76. package/src/templates/next-webgl/lib/utils/global-css.d.ts +0 -1
  77. package/src/templates/next-webgl/lib/utils/math.ts +0 -236
  78. package/src/templates/next-webgl/lib/utils/strings.ts +0 -246
  79. package/src/templates/next-webgl/lib/utils/types.d.ts +0 -15
  80. 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
- }