@shopify/klint 0.3.0 → 0.4.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.
@@ -1,4 +1,4 @@
1
- import { K as KlintContext } from '../Klint-CsVzll4n.cjs';
1
+ import { K as KlintContext } from '../Klint-DqYL-aGU.cjs';
2
2
  import 'react';
3
3
 
4
4
  interface FontPoint {
@@ -209,158 +209,6 @@ declare class CatmullRom {
209
209
  }): Path2D;
210
210
  }
211
211
 
212
- /**
213
- * Configuration options for Things plugin
214
- */
215
- interface ThingsConfig {
216
- maxThings?: number;
217
- defaultSize?: number;
218
- defaultColor?: string;
219
- }
220
- /**
221
- * Individual Thing interface
222
- */
223
- interface Thing {
224
- id: string;
225
- x: number;
226
- y: number;
227
- width: number;
228
- height: number;
229
- rotation: number;
230
- scale: number;
231
- color: string;
232
- data?: any;
233
- }
234
- /**
235
- * Static Things Plugin
236
- *
237
- * Manages a collection of "things" - generic objects that can be positioned,
238
- * transformed, and rendered without requiring Klint context initialization.
239
- * Context is only passed when drawing operations are needed.
240
- *
241
- * @example
242
- * ```tsx
243
- * import { Things } from '@shopify/klint/plugins';
244
- *
245
- * // Create things
246
- * Things.create({ x: 100, y: 100 });
247
- * Things.create({ x: 200, y: 200, color: '#ff0066' });
248
- *
249
- * // Update and draw
250
- * Things.animatePhysics(deltaTime);
251
- * Things.draw(K);
252
- * ```
253
- */
254
- declare class Things {
255
- private static things;
256
- private static config;
257
- private static idCounter;
258
- /**
259
- * Configure the plugin
260
- */
261
- static configure(config: ThingsConfig): void;
262
- /**
263
- * Create a new thing
264
- */
265
- static create(options?: Partial<Thing>): Thing;
266
- /**
267
- * Get a thing by ID
268
- */
269
- static get(id: string): Thing | undefined;
270
- /**
271
- * Get all things
272
- */
273
- static getAll(): Thing[];
274
- /**
275
- * Update a thing's properties
276
- */
277
- static update(id: string, updates: Partial<Thing>): void;
278
- /**
279
- * Remove a thing
280
- */
281
- static remove(id: string): boolean;
282
- /**
283
- * Clear all things
284
- */
285
- static clear(): void;
286
- /**
287
- * Move a thing
288
- */
289
- static move(id: string, dx: number, dy: number): void;
290
- /**
291
- * Rotate a thing
292
- */
293
- static rotate(id: string, angle: number): void;
294
- /**
295
- * Scale a thing
296
- */
297
- static scale(id: string, factor: number): void;
298
- /**
299
- * Find things within a radius
300
- */
301
- static findNear(x: number, y: number, radius: number): Thing[];
302
- /**
303
- * Find things that overlap with a rectangle
304
- */
305
- static findInRect(x: number, y: number, width: number, height: number): Thing[];
306
- /**
307
- * Apply a function to all things
308
- */
309
- static forEach(fn: (thing: Thing) => void): void;
310
- /**
311
- * Map things to a new array
312
- */
313
- static map<T>(fn: (thing: Thing) => T): T[];
314
- /**
315
- * Filter things
316
- */
317
- static filter(fn: (thing: Thing) => boolean): Thing[];
318
- /**
319
- * Sort things by a property or function
320
- */
321
- static sort(fn: (a: Thing, b: Thing) => number): Thing[];
322
- /**
323
- * Draw all things
324
- */
325
- static draw(ctx: KlintContext, options?: {
326
- customDraw?: (ctx: KlintContext, thing: Thing) => void;
327
- filter?: (thing: Thing) => boolean;
328
- }): void;
329
- /**
330
- * Default drawing method for a thing
331
- */
332
- private static drawThing;
333
- /**
334
- * Animate things with a simple physics update
335
- */
336
- static animatePhysics(deltaTime: number, options?: {
337
- gravity?: number;
338
- friction?: number;
339
- bounds?: {
340
- x: number;
341
- y: number;
342
- width: number;
343
- height: number;
344
- };
345
- }): void;
346
- /**
347
- * Get the count of things
348
- */
349
- static count(): number;
350
- /**
351
- * Check if a thing exists
352
- */
353
- static has(id: string): boolean;
354
- /**
355
- * Utility: Get distance between two things
356
- */
357
- static distance(id1: string, id2: string): number;
358
- /**
359
- * Utility: Check collision between two things
360
- */
361
- static collides(id1: string, id2: string): boolean;
362
- }
363
-
364
212
  /**
365
213
  * Sprite configuration
366
214
  */
@@ -557,4 +405,442 @@ declare class SpriteAnimation {
557
405
  isPlaying(): boolean;
558
406
  }
559
407
 
560
- export { CatmullRom, Delaunay, type FontData, type FontLetter, type FontLetterWithPath, type FontLetterWithPoints, FontParser, type FontPathsResult, type FontPoint, type FontPointsResult, type FontTextBlock, type FontTextOptions, Sprites, Things };
408
+ /**
409
+ * Body reference tracked by MatterPhysics
410
+ */
411
+ interface MatterBody {
412
+ id: string;
413
+ body: any;
414
+ label?: string;
415
+ }
416
+ /**
417
+ * Configuration for MatterPhysics initialization
418
+ */
419
+ interface MatterPhysicsConfig {
420
+ gravity?: {
421
+ x: number;
422
+ y: number;
423
+ scale?: number;
424
+ };
425
+ enableSleeping?: boolean;
426
+ constraintIterations?: number;
427
+ positionIterations?: number;
428
+ velocityIterations?: number;
429
+ }
430
+ /**
431
+ * Options for body creation
432
+ */
433
+ interface BodyOptions {
434
+ id?: string;
435
+ label?: string;
436
+ isStatic?: boolean;
437
+ restitution?: number;
438
+ friction?: number;
439
+ frictionAir?: number;
440
+ density?: number;
441
+ angle?: number;
442
+ isSensor?: boolean;
443
+ chamfer?: {
444
+ radius: number;
445
+ };
446
+ [key: string]: any;
447
+ }
448
+ /**
449
+ * Options for constraint creation
450
+ */
451
+ interface ConstraintOptions {
452
+ id?: string;
453
+ stiffness?: number;
454
+ damping?: number;
455
+ length?: number;
456
+ pointA?: {
457
+ x: number;
458
+ y: number;
459
+ };
460
+ pointB?: {
461
+ x: number;
462
+ y: number;
463
+ };
464
+ [key: string]: any;
465
+ }
466
+ /**
467
+ * Debug draw options
468
+ */
469
+ interface DrawOptions {
470
+ showBodies?: boolean;
471
+ showConstraints?: boolean;
472
+ showBounds?: boolean;
473
+ bodyStroke?: string;
474
+ bodyFill?: string;
475
+ staticFill?: string;
476
+ constraintStroke?: string;
477
+ lineWidth?: number;
478
+ }
479
+ /**
480
+ * MatterPhysics Plugin
481
+ *
482
+ * Wrapper around Matter.js for 2D physics simulation.
483
+ * Requires matter-js — either pass the module at init, or use load() to dynamically import it.
484
+ *
485
+ * @example
486
+ * ```tsx
487
+ * import { MatterPhysics } from '@shopify/klint/plugins';
488
+ *
489
+ * // Option 1: Dynamic import (recommended)
490
+ * await MatterPhysics.load({ gravity: { x: 0, y: 1 } });
491
+ *
492
+ * // Option 2: Pass module directly
493
+ * import Matter from 'matter-js';
494
+ * MatterPhysics.init(Matter, { gravity: { x: 0, y: 1 } });
495
+ *
496
+ * MatterPhysics.addRect(400, 550, 800, 50, { isStatic: true });
497
+ * MatterPhysics.addCircle(400, 100, 25);
498
+ *
499
+ * const draw = (K) => {
500
+ * MatterPhysics.update(K.deltaTime);
501
+ * MatterPhysics.draw(K);
502
+ * };
503
+ * ```
504
+ */
505
+ declare class MatterPhysics {
506
+ private static Matter;
507
+ private static engine;
508
+ private static world;
509
+ private static bodies;
510
+ private static constraints;
511
+ private static idCounter;
512
+ private static constraintIdCounter;
513
+ private static _loaded;
514
+ /** Matter.js version loaded from CDN when not installed locally */
515
+ static MATTER_VERSION: string;
516
+ /** CDN URL template — version is interpolated */
517
+ static MATTER_CDN: string;
518
+ /**
519
+ * Dynamically load matter-js and initialize the engine.
520
+ * Tries a local `import("matter-js")` first — if that fails (package not installed),
521
+ * falls back to loading from CDN via a script tag.
522
+ * @param config - Engine configuration
523
+ * @returns Promise that resolves when ready
524
+ *
525
+ * @example
526
+ * ```tsx
527
+ * // In preload or setup:
528
+ * await MatterPhysics.load({ gravity: { x: 0, y: 1 } });
529
+ * ```
530
+ */
531
+ static load(config?: MatterPhysicsConfig): Promise<void>;
532
+ /**
533
+ * Load Matter.js from CDN by injecting a script tag.
534
+ * Resolves with the global `Matter` object.
535
+ */
536
+ private static _loadFromCDN;
537
+ /**
538
+ * Check if MatterPhysics has been loaded and initialized.
539
+ */
540
+ static get isLoaded(): boolean;
541
+ /**
542
+ * Initialize the physics engine with a Matter.js module reference.
543
+ * Prefer `load()` for dynamic import. Use this if you want to pass the module directly.
544
+ * @param matterModule - The Matter.js module (import Matter from 'matter-js')
545
+ * @param config - Engine configuration
546
+ */
547
+ static init(matterModule: any, config?: MatterPhysicsConfig): void;
548
+ private static ensureInit;
549
+ private static generateId;
550
+ /**
551
+ * Add a rectangle body.
552
+ * @param x - Center X
553
+ * @param y - Center Y
554
+ * @param width - Width
555
+ * @param height - Height
556
+ * @param options - Body options
557
+ * @returns Body reference with id
558
+ */
559
+ static addRect(x: number, y: number, width: number, height: number, options?: BodyOptions): MatterBody;
560
+ /**
561
+ * Add a circle body.
562
+ * @param x - Center X
563
+ * @param y - Center Y
564
+ * @param radius - Radius
565
+ * @param options - Body options
566
+ * @returns Body reference with id
567
+ */
568
+ static addCircle(x: number, y: number, radius: number, options?: BodyOptions): MatterBody;
569
+ /**
570
+ * Add a polygon body.
571
+ * @param x - Center X
572
+ * @param y - Center Y
573
+ * @param sides - Number of sides
574
+ * @param radius - Radius
575
+ * @param options - Body options
576
+ * @returns Body reference with id
577
+ */
578
+ static addPolygon(x: number, y: number, sides: number, radius: number, options?: BodyOptions): MatterBody;
579
+ /**
580
+ * Add a body from custom vertices.
581
+ * @param x - Center X
582
+ * @param y - Center Y
583
+ * @param vertices - Array of {x, y} points
584
+ * @param options - Body options
585
+ * @returns Body reference with id
586
+ */
587
+ static addFromVertices(x: number, y: number, vertices: Array<{
588
+ x: number;
589
+ y: number;
590
+ }>, options?: BodyOptions): MatterBody;
591
+ /**
592
+ * Add a constraint between two bodies.
593
+ * @param bodyIdA - First body ID
594
+ * @param bodyIdB - Second body ID
595
+ * @param options - Constraint options
596
+ * @returns Constraint ID
597
+ */
598
+ static addConstraint(bodyIdA: string, bodyIdB: string, options?: ConstraintOptions): string;
599
+ /**
600
+ * Add a constraint anchored to a world point.
601
+ * @param bodyId - Body ID
602
+ * @param worldPoint - World anchor point {x, y}
603
+ * @param options - Constraint options
604
+ * @returns Constraint ID
605
+ */
606
+ static addWorldConstraint(bodyId: string, worldPoint: {
607
+ x: number;
608
+ y: number;
609
+ }, options?: ConstraintOptions): string;
610
+ /**
611
+ * Apply force to a body.
612
+ * @param bodyId - Body ID
613
+ * @param force - Force vector {x, y}
614
+ */
615
+ static applyForce(bodyId: string, force: {
616
+ x: number;
617
+ y: number;
618
+ }): void;
619
+ /**
620
+ * Set velocity of a body.
621
+ * @param bodyId - Body ID
622
+ * @param velocity - Velocity vector {x, y}
623
+ */
624
+ static setVelocity(bodyId: string, velocity: {
625
+ x: number;
626
+ y: number;
627
+ }): void;
628
+ /**
629
+ * Set position of a body.
630
+ * @param bodyId - Body ID
631
+ * @param position - Position {x, y}
632
+ */
633
+ static setPosition(bodyId: string, position: {
634
+ x: number;
635
+ y: number;
636
+ }): void;
637
+ /**
638
+ * Set gravity.
639
+ * @param x - Horizontal gravity
640
+ * @param y - Vertical gravity
641
+ */
642
+ static setGravity(x: number, y: number): void;
643
+ /**
644
+ * Get a body reference by ID.
645
+ */
646
+ static getBody(id: string): MatterBody | undefined;
647
+ /**
648
+ * Get all body references.
649
+ */
650
+ static getAllBodies(): MatterBody[];
651
+ /**
652
+ * Remove a body.
653
+ * @param id - Body ID
654
+ */
655
+ static removeBody(id: string): boolean;
656
+ /**
657
+ * Remove a constraint.
658
+ * @param id - Constraint ID
659
+ */
660
+ static removeConstraint(id: string): boolean;
661
+ /**
662
+ * Step the physics engine.
663
+ * @param deltaTime - Time step in milliseconds
664
+ */
665
+ static update(deltaTime: number): void;
666
+ /**
667
+ * Debug draw all bodies and constraints using Klint drawing primitives.
668
+ * @param ctx - Klint context
669
+ * @param options - Drawing options
670
+ */
671
+ static draw(ctx: KlintContext, options?: DrawOptions): void;
672
+ /**
673
+ * Iterate over all bodies with their position and angle.
674
+ * Convenience method for syncing physics bodies to visual objects.
675
+ * @param fn - Callback receiving body data
676
+ */
677
+ static forEach(fn: (data: {
678
+ id: string;
679
+ x: number;
680
+ y: number;
681
+ angle: number;
682
+ velocity: {
683
+ x: number;
684
+ y: number;
685
+ };
686
+ body: any;
687
+ label?: string;
688
+ }) => void): void;
689
+ /**
690
+ * Register a collision callback.
691
+ * @param event - Event type: 'collisionStart', 'collisionActive', 'collisionEnd'
692
+ * @param callback - Callback receiving collision pairs
693
+ */
694
+ static onCollision(event: "collisionStart" | "collisionActive" | "collisionEnd", callback: (pairs: any[]) => void): void;
695
+ /**
696
+ * Get the raw Matter.js engine for advanced usage.
697
+ */
698
+ static getEngine(): any;
699
+ /**
700
+ * Get the raw Matter.js world for advanced usage.
701
+ */
702
+ static getWorld(): any;
703
+ /**
704
+ * Clear all bodies, constraints, and reset the engine.
705
+ */
706
+ static clear(): void;
707
+ /**
708
+ * Destroy the engine entirely.
709
+ */
710
+ static destroy(): void;
711
+ }
712
+
713
+ /**
714
+ * A 3D point in world space.
715
+ */
716
+ interface Point3D {
717
+ x: number;
718
+ y: number;
719
+ z: number;
720
+ }
721
+ /**
722
+ * A projected 2D point with depth info.
723
+ * - `x`, `y`: screen coordinates (centered at 0,0)
724
+ * - `z`: transformed depth (use for sorting, back-to-front)
725
+ * - `scale`: perspective foreshortening factor (use for sizing elements by depth)
726
+ */
727
+ interface ProjectedPoint {
728
+ x: number;
729
+ y: number;
730
+ z: number;
731
+ scale: number;
732
+ }
733
+ /**
734
+ * 3D transform operations available inside the transform callback.
735
+ * All angles are in radians. Transforms are applied in the order you call them.
736
+ */
737
+ interface Transform3D {
738
+ rotateX(radians: number): void;
739
+ rotateY(radians: number): void;
740
+ rotateZ(radians: number): void;
741
+ translate(x: number, y: number, z: number): void;
742
+ scale(x: number, y?: number, z?: number): void;
743
+ }
744
+ /**
745
+ * Projector — 3D to 2D projection for canvas2D creative coding.
746
+ *
747
+ * Projects 3D points onto a 2D plane using DOMMatrix for transforms
748
+ * and custom perspective division for depth foreshortening.
749
+ *
750
+ * @example
751
+ * ```tsx
752
+ * const projector = new Projector({ perspective: 2, radius: 200 });
753
+ *
754
+ * // In draw loop:
755
+ * const projected = projector.project(
756
+ * { x: 1, y: 0, z: -1 },
757
+ * (t) => {
758
+ * t.rotateX(K.time * 0.5);
759
+ * t.rotateY(K.time * 0.3);
760
+ * }
761
+ * );
762
+ * K.circle(projected.x, projected.y, 10 * projected.scale);
763
+ * ```
764
+ */
765
+ declare class Projector {
766
+ /** Perspective strength. 0 = orthographic, higher = stronger foreshortening. */
767
+ perspective: number;
768
+ /** Output scale — controls how far from center projected points spread. */
769
+ radius: number;
770
+ constructor(options?: {
771
+ perspective?: number;
772
+ radius?: number;
773
+ });
774
+ /**
775
+ * Build a DOMMatrix from a transform callback.
776
+ * The callback receives a Transform3D object — call rotateX, rotateY, etc.
777
+ * in the order you want them applied.
778
+ */
779
+ private buildMatrix;
780
+ /**
781
+ * Apply perspective projection to a transformed 3D point.
782
+ * Returns 2D coordinates + depth + scale factor.
783
+ */
784
+ private projectPoint;
785
+ /**
786
+ * Project a single 3D point.
787
+ *
788
+ * @param point - The 3D point to project.
789
+ * @param transforms - Optional callback to apply 3D transforms before projection.
790
+ * @returns Projected 2D point with depth and scale info.
791
+ *
792
+ * @example
793
+ * ```tsx
794
+ * const p = projector.project({ x: 0, y: 1, z: 0 }, (t) => {
795
+ * t.rotateY(angle);
796
+ * });
797
+ * K.circle(p.x, p.y, 8 * p.scale);
798
+ * ```
799
+ */
800
+ project(point: Point3D, transforms?: (t: Transform3D) => void): ProjectedPoint;
801
+ /**
802
+ * Project an array of 3D points with the same transform.
803
+ * The transform matrix is built once and reused for all points.
804
+ *
805
+ * @param points - Array of 3D points.
806
+ * @param transforms - Optional transform callback (applied identically to all points).
807
+ * @returns Array of projected points (same order as input).
808
+ *
809
+ * @example
810
+ * ```tsx
811
+ * const projected = projector.projectAll(cubeVertices, (t) => {
812
+ * t.rotateX(K.time);
813
+ * t.rotateY(K.time * 0.7);
814
+ * });
815
+ * for (const p of projected) {
816
+ * K.circle(p.x, p.y, 6 * p.scale);
817
+ * }
818
+ * ```
819
+ */
820
+ projectAll(points: Point3D[], transforms?: (t: Transform3D) => void): ProjectedPoint[];
821
+ /**
822
+ * Project and depth-sort an array of 3D points (back-to-front).
823
+ * Each result includes `index` — the original index in the input array,
824
+ * so you can map back to colors, labels, etc.
825
+ *
826
+ * @param points - Array of 3D points.
827
+ * @param transforms - Optional transform callback.
828
+ * @returns Depth-sorted array of projected points with original indices.
829
+ *
830
+ * @example
831
+ * ```tsx
832
+ * const sorted = projector.projectSorted(points, (t) => {
833
+ * t.rotateX(K.time);
834
+ * });
835
+ * for (const p of sorted) {
836
+ * K.fillColor(colors[p.index]);
837
+ * K.circle(p.x, p.y, 10 * p.scale);
838
+ * }
839
+ * ```
840
+ */
841
+ projectSorted(points: Point3D[], transforms?: (t: Transform3D) => void): (ProjectedPoint & {
842
+ index: number;
843
+ })[];
844
+ }
845
+
846
+ export { CatmullRom, Delaunay, type FontData, type FontLetter, type FontLetterWithPath, type FontLetterWithPoints, FontParser, type FontPathsResult, type FontPoint, type FontPointsResult, type FontTextBlock, type FontTextOptions, MatterPhysics, type Point3D, type ProjectedPoint, Projector, Sprites, type Transform3D };