@vived/core 2.0.1 → 2.0.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.
@@ -0,0 +1,478 @@
1
+ # Utilities
2
+
3
+ The Utilities folder provides a collection of general-purpose helper functions for common programming tasks. These utilities cover color manipulation, animations, unit conversions, file operations, and mathematical transformations.
4
+
5
+ ## Overview
6
+
7
+ Utilities are standalone functions that:
8
+ - **Have no dependencies** on other application features
9
+ - **Solve specific problems** with a focused API
10
+ - **Are highly reusable** across different contexts
11
+ - **Include proper validation** with warnings for invalid inputs
12
+
13
+ ## Animation & Interpolation
14
+
15
+ ### LerpNumber
16
+
17
+ Smooth animation class for interpolating numeric values over time using `requestAnimationFrame`.
18
+
19
+ ```typescript
20
+ import { LerpNumber, quintInOut } from "@vived/core";
21
+
22
+ const lerper = new LerpNumber();
23
+
24
+ // Set defaults (optional)
25
+ lerper.defaultDurationMS = 1000;
26
+ lerper.defaultEase = quintInOut;
27
+
28
+ // Animate from 0 to 100 over 2 seconds
29
+ await lerper.lerp({
30
+ start: 0,
31
+ end: 100,
32
+ durationMS: 2000,
33
+ update: (value) => {
34
+ console.log(`Current value: ${value}`);
35
+ },
36
+ onComplete: () => {
37
+ console.log("Animation complete!");
38
+ }
39
+ });
40
+
41
+ // With custom easing
42
+ await lerper.lerp({
43
+ start: 0,
44
+ end: 100,
45
+ ease: quadInOut,
46
+ update: (value) => updateUI(value)
47
+ });
48
+
49
+ // Cancel animation
50
+ if (lerper.isLerping)
51
+ {
52
+ lerper.cancel();
53
+ }
54
+ ```
55
+
56
+ **Configuration Options:**
57
+ - `start` - Starting value
58
+ - `end` - Target value
59
+ - `update` - Callback receiving interpolated values
60
+ - `durationMS` - Animation duration (default: 1000ms)
61
+ - `ease` - Easing function (default: quintInOut)
62
+ - `onComplete` - Called when animation completes naturally
63
+ - `onCancel` - Called when animation is cancelled
64
+
65
+ ### Easing Functions
66
+
67
+ Comprehensive collection of easing functions for smooth animations. All functions accept input from 0-1 and return output from 0-1, with automatic clamping.
68
+
69
+ ```typescript
70
+ import {
71
+ easeLinear,
72
+ quadIn, quadOut, quadInOut,
73
+ cubicIn, cubicOut, cubicInOut,
74
+ quartIn, quartOut, quartInOut,
75
+ quintIn, quintOut, quintInOut,
76
+ sinIn, sinOut, sinInOut,
77
+ expoIn, expoOut, expoInOut,
78
+ circIn, circOut, circInOut
79
+ } from "@vived/core";
80
+
81
+ // Linear (constant speed)
82
+ const linear = easeLinear(0.5); // 0.5
83
+
84
+ // Quadratic (x²)
85
+ const easeIn = quadIn(0.5); // 0.25
86
+ const easeOut = quadOut(0.5); // 0.75
87
+ const easeInOut = quadInOut(0.5); // 0.5
88
+
89
+ // Cubic (x³)
90
+ const cubic = cubicInOut(0.5);
91
+
92
+ // Quartic (x⁴)
93
+ const quart = quartInOut(0.5);
94
+
95
+ // Quintic (x⁵)
96
+ const quint = quintInOut(0.5);
97
+
98
+ // Sine wave
99
+ const sine = sinInOut(0.5);
100
+
101
+ // Exponential
102
+ const expo = expoInOut(0.5);
103
+
104
+ // Circular
105
+ const circ = circInOut(0.5);
106
+
107
+ // Use with animations
108
+ const progress = 0.5; // 50% through animation
109
+ const easedProgress = quintInOut(progress);
110
+ const currentValue = start + (end - start) * easedProgress;
111
+ ```
112
+
113
+ **Easing Types:**
114
+ - **In** - Slow start, accelerating
115
+ - **Out** - Fast start, decelerating
116
+ - **InOut** - Slow start and end, fast middle
117
+
118
+ **Available Easings:**
119
+ - `easeLinear` - No easing
120
+ - `quad*` - Quadratic (power of 2)
121
+ - `cubic*` - Cubic (power of 3)
122
+ - `quart*` - Quartic (power of 4)
123
+ - `quint*` - Quintic (power of 5)
124
+ - `sin*` - Sine wave
125
+ - `expo*` - Exponential
126
+ - `circ*` - Circular
127
+
128
+ ### interpolateNumber
129
+
130
+ Basic numeric interpolation with optional clamping.
131
+
132
+ ```typescript
133
+ import { interpolateNumber } from "@vived/core";
134
+
135
+ // Basic interpolation
136
+ const value = interpolateNumber(0, 100, 0.5); // 50
137
+
138
+ // Allow values outside range
139
+ const unclamped = interpolateNumber(0, 100, 1.5); // 150
140
+
141
+ // Clamp to 0-1 range
142
+ const clamped = interpolateNumber(0, 100, 1.5, true); // 100
143
+
144
+ // Negative percent
145
+ const negative = interpolateNumber(0, 100, -0.5); // -50
146
+ const clampedNeg = interpolateNumber(0, 100, -0.5, true); // 0
147
+ ```
148
+
149
+ ## Color Utilities
150
+
151
+ ### addAlphaToHex
152
+
153
+ Add an alpha channel to a hex color code.
154
+
155
+ ```typescript
156
+ import { addAlphaToHex } from "@vived/core";
157
+
158
+ // Full hex with alpha
159
+ const color1 = addAlphaToHex("#ffffff", 0.5); // "#ffffff80"
160
+ const color2 = addAlphaToHex("#ff0000", 1); // "#ff0000ff"
161
+ const color3 = addAlphaToHex("#000000", 0); // "#00000000"
162
+
163
+ // Short hex (automatically expanded)
164
+ const color4 = addAlphaToHex("#fff", 0.5); // "#ffffff80"
165
+ const color5 = addAlphaToHex("#f00", 0.25); // "#ff000040"
166
+
167
+ // Invalid hex returns "#000" with warning
168
+ const invalid = addAlphaToHex("#gggggg", 0.5); // "#000"
169
+ const invalid2 = addAlphaToHex("ffffff", 0.5); // "#000" (missing #)
170
+ ```
171
+
172
+ **Alpha Values:**
173
+ - `0` - Fully transparent
174
+ - `0.5` - Semi-transparent
175
+ - `1` - Fully opaque
176
+
177
+ ### alphaToHex
178
+
179
+ Convert alpha value (0-1) to hex string.
180
+
181
+ ```typescript
182
+ import { alphaToHex } from "@vived/core";
183
+
184
+ const hex1 = alphaToHex(1); // "ff"
185
+ const hex2 = alphaToHex(0.5); // "80"
186
+ const hex3 = alphaToHex(0); // "00"
187
+ const hex4 = alphaToHex(0.25); // "40"
188
+
189
+ // Out of range returns "00" with warning
190
+ const invalid = alphaToHex(1.5); // "00"
191
+ const invalid2 = alphaToHex(-0.1); // "00"
192
+ ```
193
+
194
+ ## Mathematical Conversions
195
+
196
+ ### degreesToRadians
197
+
198
+ Convert degrees to radians.
199
+
200
+ ```typescript
201
+ import { degreesToRadians } from "@vived/core";
202
+
203
+ const rad1 = degreesToRadians(180); // ~3.14159 (π)
204
+ const rad2 = degreesToRadians(90); // ~1.5708 (π/2)
205
+ const rad3 = degreesToRadians(45); // ~0.7854 (π/4)
206
+ const rad4 = degreesToRadians(0); // 0
207
+ ```
208
+
209
+ ### Length Converters
210
+
211
+ Convert between metric and imperial units.
212
+
213
+ ```typescript
214
+ import {
215
+ inchesToMeters,
216
+ metersToInches,
217
+ feetToMeters,
218
+ metersToFeet
219
+ } from "@vived/core";
220
+
221
+ // Inches ↔ Meters
222
+ const meters1 = inchesToMeters(39.37); // ~1
223
+ const inches = metersToInches(1); // ~39.37
224
+
225
+ // Feet ↔ Meters
226
+ const meters2 = feetToMeters(3.28); // ~1
227
+ const feet = metersToFeet(1); // ~3.28
228
+
229
+ // Practical examples
230
+ const screenWidth = 27; // inches
231
+ const screenWidthM = inchesToMeters(screenWidth); // ~0.686 meters
232
+
233
+ const roomLength = 5; // meters
234
+ const roomLengthFt = metersToFeet(roomLength); // ~16.4 feet
235
+ ```
236
+
237
+ **Conversion Factors:**
238
+ - 1 meter = 39.3701 inches
239
+ - 1 meter = 3.28084 feet
240
+
241
+ ## File Operations
242
+
243
+ ### downloadFile
244
+
245
+ Trigger a browser download for a Blob.
246
+
247
+ ```typescript
248
+ import { downloadFile } from "@vived/core";
249
+
250
+ // Download text file
251
+ const textBlob = new Blob(["Hello World"], { type: "text/plain" });
252
+ downloadFile("hello.txt", textBlob);
253
+
254
+ // Download JSON
255
+ const data = { name: "John", age: 30 };
256
+ const jsonBlob = new Blob([JSON.stringify(data)], { type: "application/json" });
257
+ downloadFile("data.json", jsonBlob);
258
+
259
+ // Download image
260
+ const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
261
+ canvas.toBlob((blob) => {
262
+ if (blob)
263
+ {
264
+ downloadFile("image.png", blob);
265
+ }
266
+ });
267
+
268
+ // Download CSV
269
+ const csvContent = "Name,Age\nJohn,30\nJane,25";
270
+ const csvBlob = new Blob([csvContent], { type: "text/csv" });
271
+ downloadFile("data.csv", csvBlob);
272
+ ```
273
+
274
+ **How it works:**
275
+ 1. Creates a temporary anchor element
276
+ 2. Creates an object URL from the Blob
277
+ 3. Triggers a download
278
+ 4. Cleans up the anchor and URL
279
+
280
+ ## ID Generation
281
+
282
+ ### generateUniqueID
283
+
284
+ Generate a universally unique identifier (UUID v4).
285
+
286
+ ```typescript
287
+ import { generateUniqueID } from "@vived/core";
288
+
289
+ const id1 = generateUniqueID(); // "a3bb189e-8bf9-3888-9912-ace4e6543002"
290
+ const id2 = generateUniqueID(); // "f8e7d5c6-9a4b-4c5d-8e6f-7a8b9c0d1e2f"
291
+
292
+ // Use for entity IDs
293
+ const userId = generateUniqueID();
294
+ const sessionId = generateUniqueID();
295
+
296
+ // Use for tracking
297
+ const eventId = generateUniqueID();
298
+ const transactionId = generateUniqueID();
299
+ ```
300
+
301
+ **Properties:**
302
+ - RFC 4122 compliant UUID v4
303
+ - 122 bits of randomness
304
+ - Extremely low collision probability
305
+ - Safe for distributed systems
306
+
307
+ ## Usage Patterns
308
+
309
+ ### Smooth Property Animation
310
+
311
+ ```typescript
312
+ import { LerpNumber, quintInOut } from "@vived/core";
313
+
314
+ class AnimatedObject
315
+ {
316
+ private lerper = new LerpNumber();
317
+ private _opacity = 1;
318
+
319
+ async fadeOut()
320
+ {
321
+ await this.lerper.lerp({
322
+ start: this._opacity,
323
+ end: 0,
324
+ durationMS: 500,
325
+ ease: quintInOut,
326
+ update: (value) => {
327
+ this._opacity = value;
328
+ this.render();
329
+ }
330
+ });
331
+ }
332
+
333
+ async fadeIn()
334
+ {
335
+ await this.lerper.lerp({
336
+ start: this._opacity,
337
+ end: 1,
338
+ durationMS: 500,
339
+ ease: quintInOut,
340
+ update: (value) => {
341
+ this._opacity = value;
342
+ this.render();
343
+ }
344
+ });
345
+ }
346
+
347
+ render()
348
+ {
349
+ // Update visual representation
350
+ }
351
+ }
352
+ ```
353
+
354
+ ### Color with Transparency
355
+
356
+ ```typescript
357
+ import { addAlphaToHex } from "@vived/core";
358
+
359
+ function createOverlay(baseColor: string, opacity: number): string
360
+ {
361
+ return addAlphaToHex(baseColor, opacity);
362
+ }
363
+
364
+ const overlay = createOverlay("#000000", 0.7); // Semi-transparent black
365
+ document.body.style.backgroundColor = overlay;
366
+ ```
367
+
368
+ ### Unit Conversion in VR
369
+
370
+ ```typescript
371
+ import { feetToMeters, metersToFeet } from "@vived/core";
372
+
373
+ class VRRoom
374
+ {
375
+ // User inputs in feet
376
+ setDimensions(widthFeet: number, heightFeet: number, depthFeet: number)
377
+ {
378
+ // Convert to meters for internal use
379
+ this.width = feetToMeters(widthFeet);
380
+ this.height = feetToMeters(heightFeet);
381
+ this.depth = feetToMeters(depthFeet);
382
+ }
383
+
384
+ // Display in feet for user
385
+ getDimensionsDisplay(): string
386
+ {
387
+ const w = metersToFeet(this.width).toFixed(1);
388
+ const h = metersToFeet(this.height).toFixed(1);
389
+ const d = metersToFeet(this.depth).toFixed(1);
390
+ return `${w}' × ${h}' × ${d}'`;
391
+ }
392
+
393
+ private width = 0;
394
+ private height = 0;
395
+ private depth = 0;
396
+ }
397
+ ```
398
+
399
+ ### Export Application Data
400
+
401
+ ```typescript
402
+ import { downloadFile, generateUniqueID } from "@vived/core";
403
+
404
+ function exportUserData(userData: any)
405
+ {
406
+ const exportData = {
407
+ id: generateUniqueID(),
408
+ timestamp: new Date().toISOString(),
409
+ data: userData
410
+ };
411
+
412
+ const json = JSON.stringify(exportData, null, 2);
413
+ const blob = new Blob([json], { type: "application/json" });
414
+ downloadFile(`export-${Date.now()}.json`, blob);
415
+ }
416
+ ```
417
+
418
+ ### Custom Easing with Interpolation
419
+
420
+ ```typescript
421
+ import { interpolateNumber, expoOut } from "@vived/core";
422
+
423
+ function animateWithEasing(
424
+ start: number,
425
+ end: number,
426
+ progress: number
427
+ ): number
428
+ {
429
+ const easedProgress = expoOut(progress);
430
+ return interpolateNumber(start, end, easedProgress);
431
+ }
432
+
433
+ // Use in animation loop
434
+ let progress = 0;
435
+ const interval = setInterval(() => {
436
+ progress += 0.01;
437
+ const value = animateWithEasing(0, 100, progress);
438
+ updateUI(value);
439
+
440
+ if (progress >= 1)
441
+ {
442
+ clearInterval(interval);
443
+ }
444
+ }, 16); // ~60fps
445
+ ```
446
+
447
+ ## Validation & Error Handling
448
+
449
+ Most utilities include validation with console warnings:
450
+
451
+ ```typescript
452
+ // Invalid hex returns fallback with warning
453
+ addAlphaToHex("invalid", 0.5); // "#000" + console.warn()
454
+
455
+ // Out of range returns fallback with warning
456
+ alphaToHex(1.5); // "00" + console.warn()
457
+
458
+ // Interpolation with clamping prevents out-of-range
459
+ interpolateNumber(0, 100, 1.5, true); // 100 (clamped)
460
+ ```
461
+
462
+ ## Performance Considerations
463
+
464
+ - **LerpNumber** - Uses `requestAnimationFrame` for smooth animations aligned with browser repaints
465
+ - **Easing functions** - Optimized mathematical operations with early returns for edge cases
466
+ - **UUID generation** - Uses native crypto APIs for secure random numbers
467
+ - **Interpolation** - Simple arithmetic operations with minimal overhead
468
+ - **Color conversion** - String operations are lightweight but use sparingly in tight loops
469
+
470
+ ## Use Cases
471
+
472
+ - **UI Animations** - Smooth transitions for opacity, position, scale
473
+ - **Color Manipulation** - Dynamic theming with transparency
474
+ - **Data Export** - Download user-generated content or reports
475
+ - **Unit Conversion** - VR/AR applications with real-world measurements
476
+ - **Game Development** - Custom easing curves for game feel
477
+ - **Entity Management** - Unique IDs for tracking objects
478
+ - **Chart Animations** - Smooth value changes in data visualizations