@mcptoolshop/physics-svg 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mcp-tool-shop
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var h=Object.defineProperty;var l=(i,t,e)=>t in i?h(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var a=(i,t,e)=>l(i,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./svg-renderer-CiwhJO3-.cjs");class p{constructor(){a(this,"canvas",null);a(this,"ctx",null)}init(t){this.canvas=document.createElement("canvas"),this.canvas.width=t.clientWidth||800,this.canvas.height=t.clientHeight||600,this.ctx=this.canvas.getContext("2d"),t.appendChild(this.canvas)}render(t,e){if(!(!this.ctx||!this.canvas)){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);for(const s of t){switch(this.ctx.save(),this.ctx.translate(s.position.x,s.position.y),this.ctx.fillStyle="#6366f1",s.shape.type){case"circle":this.ctx.beginPath(),this.ctx.arc(0,0,s.shape.radius,0,Math.PI*2),this.ctx.fill();break;case"rect":this.ctx.fillRect(-s.shape.width/2,-s.shape.height/2,s.shape.width,s.shape.height);break;case"polygon":{const o=s.shape.vertices;if(o.length<2)break;this.ctx.beginPath(),this.ctx.moveTo(o[0].x,o[0].y);for(let n=1;n<o.length;n++)this.ctx.lineTo(o[n].x,o[n].y);this.ctx.closePath(),this.ctx.fill();break}}this.ctx.restore()}}}destroy(){var t;(t=this.canvas)==null||t.remove(),this.canvas=null,this.ctx=null}}class c{constructor(t,e){a(this,"currentState");a(this,"transitions");a(this,"listeners",[]);this.currentState=t,this.transitions=e}send(t){var o;const e=this.transitions.find(n=>n.from===this.currentState&&n.on===t&&(n.guard?n.guard():!0));if(!e)return;const s=this.currentState;this.currentState=e.to,(o=e.action)==null||o.call(e);for(const n of this.listeners)n(s,e.to)}getState(){return this.currentState}onTransition(t){this.listeners.push(t)}}function d(){const i=[{from:"idle",to:"picked-up",on:"GRAB"},{from:"picked-up",to:"moving",on:"MOVE"},{from:"moving",to:"dropping",on:"RELEASE"},{from:"dropping",to:"bouncing",on:"BOUNCE_START"},{from:"dropping",to:"settled",on:"SETTLE"},{from:"bouncing",to:"settled",on:"BOUNCE_END"},{from:"settled",to:"picked-up",on:"GRAB"}];return new c("idle",i)}function u(){const i=[{from:"reserve",to:"deploying",on:"DEPLOY"},{from:"deploying",to:"landing",on:"LAND"},{from:"landing",to:"settled",on:"SETTLE"}];return new c("reserve",i)}function f(i){typeof window>"u"||(window.__PHYSICS_SVG_DEVTOOLS_HOOK__=i)}class g{constructor(){a(this,"subscribers",[])}emit(t){for(const e of this.subscribers)e(t)}subscribe(t){return this.subscribers.push(t),()=>{const e=this.subscribers.indexOf(t);e!==-1&&this.subscribers.splice(e,1)}}}exports.PhysicsEngine=r.PhysicsEngine;exports.SvgRenderer=r.SvgRenderer;exports.Vec2=r.vec2;exports.applyAttraction=r.applyAttraction;exports.applyDrag=r.applyDrag;exports.applyForceFields=r.applyForceFields;exports.applyGravity=r.applyGravity;exports.applyWind=r.applyWind;exports.createBody=r.createBody;exports.createConstraint=r.createConstraint;exports.wakeBody=r.wakeBody;exports.AnimationEmitter=g;exports.CanvasRenderer=p;exports.StateMachine=c;exports.createDeployMachine=u;exports.createPickupDropMachine=d;exports.installDevToolsHook=f;
@@ -0,0 +1,179 @@
1
+ import { BodyShape } from '@mcp-tool-shop/siege-types';
2
+ import { Constraint } from '@mcp-tool-shop/siege-types';
3
+ import { Context } from 'react';
4
+ import { ForceField } from '@mcp-tool-shop/siege-types';
5
+ import { JSX } from 'react/jsx-runtime';
6
+ import { PhysicsBody } from '@mcp-tool-shop/siege-types';
7
+ import { ReactNode } from 'react';
8
+ import { Vec2 } from '@mcp-tool-shop/siege-types';
9
+ import { WorldConfig } from '@mcp-tool-shop/siege-types';
10
+
11
+ /**
12
+ * Body — declarative React component that registers a physics body with
13
+ * the engine on mount and removes it on unmount.
14
+ *
15
+ * Renders nothing to the DOM. Visual representation is handled entirely
16
+ * by the {@link SvgRenderer}.
17
+ */
18
+ declare function Body_2(props: BodyProps): null;
19
+ export { Body_2 as Body }
20
+
21
+ /** Props for the {@link Body} component. */
22
+ export declare interface BodyProps {
23
+ /** Shape of the physics body. */
24
+ shape?: BodyShape;
25
+ /** Mass (kg). Default 1. */
26
+ mass?: number;
27
+ /** Initial position. */
28
+ position?: Vec2;
29
+ /** Initial velocity. */
30
+ velocity?: Vec2;
31
+ /** Coefficient of restitution (bounciness). 0-1. */
32
+ restitution?: number;
33
+ /** Friction coefficient. */
34
+ friction?: number;
35
+ /** If true, the body is immovable. */
36
+ isStatic?: boolean;
37
+ /** Arbitrary user data attached to the body. */
38
+ userData?: Record<string, unknown>;
39
+ }
40
+
41
+ /**
42
+ * React context that provides the {@link PhysicsEngine} instance to
43
+ * descendant components and hooks.
44
+ */
45
+ export declare const PhysicsContext: Context<PhysicsEngine | null>;
46
+
47
+ /**
48
+ * PhysicsEngine — top-level facade for the physics-svg simulation.
49
+ *
50
+ * Features:
51
+ * - Fixed-timestep simulation with accumulator
52
+ * - Interpolated body positions for smooth rendering
53
+ * - Body and constraint management
54
+ * - Force field system
55
+ * - Sleep/wake management
56
+ */
57
+ declare class PhysicsEngine {
58
+ private world;
59
+ private accumulator;
60
+ private _alpha;
61
+ constructor(config: WorldConfig);
62
+ /**
63
+ * Advance the simulation by `frameTime` seconds.
64
+ *
65
+ * Uses Glenn Fiedler's fixed-timestep-with-accumulator pattern:
66
+ * - Clamp frame time to prevent spiral of death
67
+ * - Step physics at fixed 60Hz intervals
68
+ * - Store interpolation alpha for smooth rendering
69
+ */
70
+ update(frameTime: number): void;
71
+ /**
72
+ * Get the interpolation alpha for the current frame.
73
+ *
74
+ * Use this to blend between previousPosition and position:
75
+ * renderPos = lerp(body.previousPosition, body.position, alpha)
76
+ */
77
+ get alpha(): number;
78
+ /**
79
+ * Get the interpolated render position for a body.
80
+ */
81
+ getInterpolatedPosition(body: PhysicsBody): Vec2;
82
+ /** Register a body and return its id. */
83
+ addBody(body: PhysicsBody): string;
84
+ /** Remove a body by id. */
85
+ removeBody(id: string): void;
86
+ /** Look up a single body. */
87
+ getBody(id: string): PhysicsBody | undefined;
88
+ /** Return every body currently in the world. */
89
+ getBodies(): PhysicsBody[];
90
+ /** Apply an instantaneous impulse to a body. */
91
+ applyImpulse(id: string, impulse: Vec2): void;
92
+ /** Set a body's position directly (teleport). */
93
+ setPosition(id: string, position: Vec2): void;
94
+ /** Set a body's velocity directly. */
95
+ setVelocity(id: string, velocity: Vec2): void;
96
+ /** Register a constraint and return its id. */
97
+ addConstraint(constraint: Constraint): string;
98
+ /** Remove a constraint by id. */
99
+ removeConstraint(id: string): void;
100
+ /** Return every constraint currently in the world. */
101
+ getConstraints(): Constraint[];
102
+ /** Add a force field to the world. */
103
+ addForceField(field: ForceField): void;
104
+ /** Remove all force fields of a given type. */
105
+ removeForceFields(type: ForceField['type']): void;
106
+ /** Access the underlying world config. */
107
+ getConfig(): WorldConfig;
108
+ }
109
+
110
+ /**
111
+ * PhysicsScene — root React component that owns the physics engine and SVG
112
+ * renderer.
113
+ *
114
+ * Provides the engine via React context so child components and hooks can
115
+ * register bodies and constraints.
116
+ *
117
+ * Runs a `requestAnimationFrame` loop that steps the simulation and renders
118
+ * each frame.
119
+ */
120
+ export declare function PhysicsScene({ config, width, height, children, }: PhysicsSceneProps): JSX.Element;
121
+
122
+ /** Props for the {@link PhysicsScene} component. */
123
+ export declare interface PhysicsSceneProps {
124
+ /** World configuration for the physics engine. */
125
+ config?: Partial<WorldConfig>;
126
+ /** Width of the SVG viewport. */
127
+ width?: number | string;
128
+ /** Height of the SVG viewport. */
129
+ height?: number | string;
130
+ /** Child components (e.g. `<Body>`, `<Spring>`). */
131
+ children?: ReactNode;
132
+ }
133
+
134
+ /**
135
+ * Spring — declarative React component that registers a spring constraint
136
+ * between two bodies on mount and removes it on unmount.
137
+ *
138
+ * Renders nothing to the DOM.
139
+ */
140
+ export declare function Spring(props: SpringProps): null;
141
+
142
+ /** Props for the {@link Spring} component. */
143
+ export declare interface SpringProps {
144
+ /** ID of the first body. */
145
+ bodyA: string;
146
+ /** ID of the second body. */
147
+ bodyB: string;
148
+ /** Spring stiffness. Default 0.5. */
149
+ stiffness?: number;
150
+ /** Damping coefficient. Default 0.1. */
151
+ damping?: number;
152
+ /** Anchor point on body A (local coords). */
153
+ anchorA?: Vec2;
154
+ /** Anchor point on body B (local coords). */
155
+ anchorB?: Vec2;
156
+ /** Rest length. If omitted, computed from initial body positions. */
157
+ length?: number;
158
+ }
159
+
160
+ /**
161
+ * Hook to create and manage a physics body imperatively.
162
+ *
163
+ * The body is added to the engine on mount and removed on unmount.
164
+ *
165
+ * @param config - Partial body configuration.
166
+ * @returns The created {@link PhysicsBody} (stable reference).
167
+ */
168
+ export declare function useBody(config: Partial<PhysicsBody>): PhysicsBody;
169
+
170
+ /**
171
+ * Hook to access the nearest {@link PhysicsEngine} from context.
172
+ *
173
+ * Must be used inside a `<PhysicsScene>` provider.
174
+ *
175
+ * @throws If no PhysicsEngine is found in context.
176
+ */
177
+ export declare function usePhysics(): PhysicsEngine;
178
+
179
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,142 @@
1
+ var c = Object.defineProperty;
2
+ var h = (e, t, s) => t in e ? c(e, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : e[t] = s;
3
+ var o = (e, t, s) => h(e, typeof t != "symbol" ? t + "" : t, s);
4
+ import { P as b, S as m, v as y, a as S, b as E, c as w, d as T, e as k, f as O, g as P, w as _ } from "./svg-renderer-BOSG5i9F.js";
5
+ class d {
6
+ constructor() {
7
+ o(this, "canvas", null);
8
+ o(this, "ctx", null);
9
+ }
10
+ init(t) {
11
+ this.canvas = document.createElement("canvas"), this.canvas.width = t.clientWidth || 800, this.canvas.height = t.clientHeight || 600, this.ctx = this.canvas.getContext("2d"), t.appendChild(this.canvas);
12
+ }
13
+ render(t, s) {
14
+ if (!(!this.ctx || !this.canvas)) {
15
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
16
+ for (const i of t) {
17
+ switch (this.ctx.save(), this.ctx.translate(i.position.x, i.position.y), this.ctx.fillStyle = "#6366f1", i.shape.type) {
18
+ case "circle":
19
+ this.ctx.beginPath(), this.ctx.arc(0, 0, i.shape.radius, 0, Math.PI * 2), this.ctx.fill();
20
+ break;
21
+ case "rect":
22
+ this.ctx.fillRect(
23
+ -i.shape.width / 2,
24
+ -i.shape.height / 2,
25
+ i.shape.width,
26
+ i.shape.height
27
+ );
28
+ break;
29
+ case "polygon": {
30
+ const r = i.shape.vertices;
31
+ if (r.length < 2) break;
32
+ this.ctx.beginPath(), this.ctx.moveTo(r[0].x, r[0].y);
33
+ for (let n = 1; n < r.length; n++)
34
+ this.ctx.lineTo(r[n].x, r[n].y);
35
+ this.ctx.closePath(), this.ctx.fill();
36
+ break;
37
+ }
38
+ }
39
+ this.ctx.restore();
40
+ }
41
+ }
42
+ }
43
+ destroy() {
44
+ var t;
45
+ (t = this.canvas) == null || t.remove(), this.canvas = null, this.ctx = null;
46
+ }
47
+ }
48
+ class a {
49
+ constructor(t, s) {
50
+ o(this, "currentState");
51
+ o(this, "transitions");
52
+ o(this, "listeners", []);
53
+ this.currentState = t, this.transitions = s;
54
+ }
55
+ /** Send an event to the machine. If a valid transition matches, it fires. */
56
+ send(t) {
57
+ var r;
58
+ const s = this.transitions.find(
59
+ (n) => n.from === this.currentState && n.on === t && (n.guard ? n.guard() : !0)
60
+ );
61
+ if (!s) return;
62
+ const i = this.currentState;
63
+ this.currentState = s.to, (r = s.action) == null || r.call(s);
64
+ for (const n of this.listeners)
65
+ n(i, s.to);
66
+ }
67
+ /** Get the current state. */
68
+ getState() {
69
+ return this.currentState;
70
+ }
71
+ /** Register a callback invoked on every successful transition. */
72
+ onTransition(t) {
73
+ this.listeners.push(t);
74
+ }
75
+ }
76
+ function p() {
77
+ const e = [
78
+ { from: "idle", to: "picked-up", on: "GRAB" },
79
+ { from: "picked-up", to: "moving", on: "MOVE" },
80
+ { from: "moving", to: "dropping", on: "RELEASE" },
81
+ { from: "dropping", to: "bouncing", on: "BOUNCE_START" },
82
+ { from: "dropping", to: "settled", on: "SETTLE" },
83
+ { from: "bouncing", to: "settled", on: "BOUNCE_END" },
84
+ // Allow re-grab from settled
85
+ { from: "settled", to: "picked-up", on: "GRAB" }
86
+ ];
87
+ return new a(
88
+ "idle",
89
+ e
90
+ );
91
+ }
92
+ function u() {
93
+ const e = [
94
+ { from: "reserve", to: "deploying", on: "DEPLOY" },
95
+ { from: "deploying", to: "landing", on: "LAND" },
96
+ { from: "landing", to: "settled", on: "SETTLE" }
97
+ ];
98
+ return new a("reserve", e);
99
+ }
100
+ function f(e) {
101
+ typeof window > "u" || (window.__PHYSICS_SVG_DEVTOOLS_HOOK__ = e);
102
+ }
103
+ class g {
104
+ constructor() {
105
+ o(this, "subscribers", []);
106
+ }
107
+ /** Emit an animation event to all current subscribers. */
108
+ emit(t) {
109
+ for (const s of this.subscribers)
110
+ s(t);
111
+ }
112
+ /**
113
+ * Subscribe to animation events.
114
+ *
115
+ * @returns An unsubscribe function.
116
+ */
117
+ subscribe(t) {
118
+ return this.subscribers.push(t), () => {
119
+ const s = this.subscribers.indexOf(t);
120
+ s !== -1 && this.subscribers.splice(s, 1);
121
+ };
122
+ }
123
+ }
124
+ export {
125
+ g as AnimationEmitter,
126
+ d as CanvasRenderer,
127
+ b as PhysicsEngine,
128
+ a as StateMachine,
129
+ m as SvgRenderer,
130
+ y as Vec2,
131
+ S as applyAttraction,
132
+ E as applyDrag,
133
+ w as applyForceFields,
134
+ T as applyGravity,
135
+ k as applyWind,
136
+ O as createBody,
137
+ P as createConstraint,
138
+ u as createDeployMachine,
139
+ p as createPickupDropMachine,
140
+ f as installDevToolsHook,
141
+ _ as wakeBody
142
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react/jsx-runtime"),t=require("react"),u=require("../svg-renderer-CiwhJO3-.cjs"),l=t.createContext(null),v={gravity:{x:0,y:980},substeps:4,velocityIterations:6};function R({config:e,width:r="100%",height:n="100%",children:s}){const d=t.useRef(null),y=t.useMemo(()=>({...v,...e}),[]),i=t.useMemo(()=>new u.PhysicsEngine(y),[y]),o=t.useRef(null);return t.useEffect(()=>{if(!d.current)return;const c=new u.SvgRenderer;return c.init(d.current),o.current=c,()=>{c.destroy(),o.current=null}},[]),t.useEffect(()=>{let c=performance.now(),f;const m=g=>{const B=Math.min((g-c)/1e3,.05);c=g,i.update(B),o.current&&(o.current.alpha=i.alpha,o.current.render(i.getBodies(),i.getConstraints())),f=requestAnimationFrame(m)};return f=requestAnimationFrame(m),()=>{cancelAnimationFrame(f)}},[i]),h.jsx(l.Provider,{value:i,children:h.jsx("div",{ref:d,style:{width:r,height:n,position:"relative"},children:s})})}function a(){const e=t.useContext(l);if(!e)throw new Error("usePhysics() must be used inside a <PhysicsScene> component.");return e}function b(e){const r=a(),n=t.useRef(null);return n.current||(n.current=u.createBody({shape:e.shape,mass:e.mass,position:e.position,velocity:e.velocity,restitution:e.restitution,friction:e.friction,isStatic:e.isStatic,userData:e.userData})),t.useEffect(()=>{const s=n.current;return r.addBody(s),()=>{r.removeBody(s.id)}},[r]),null}function P(e){const r=a(),n=t.useRef(null);return n.current||(n.current=u.createConstraint({type:"spring",bodyA:e.bodyA,bodyB:e.bodyB,stiffness:e.stiffness,damping:e.damping,anchorA:e.anchorA,anchorB:e.anchorB,length:e.length})),t.useEffect(()=>{const s=n.current;return r.addConstraint(s),()=>{r.removeConstraint(s.id)}},[r]),null}function C(e){const r=a(),n=t.useRef(null);return n.current||(n.current=u.createBody(e)),t.useEffect(()=>{const s=n.current;return r.addBody(s),()=>{r.removeBody(s.id)}},[r]),n.current}exports.Body=b;exports.PhysicsContext=l;exports.PhysicsScene=R;exports.Spring=P;exports.useBody=C;exports.usePhysics=a;
@@ -0,0 +1,2 @@
1
+ export * from './src/index'
2
+ export {}
@@ -0,0 +1,107 @@
1
+ import { jsx as g } from "react/jsx-runtime";
2
+ import { createContext as C, useRef as s, useMemo as h, useEffect as u, useContext as A } from "react";
3
+ import { P, S as R, f as v, g as S } from "../svg-renderer-BOSG5i9F.js";
4
+ const B = C(null), x = {
5
+ gravity: { x: 0, y: 980 },
6
+ substeps: 4,
7
+ velocityIterations: 6
8
+ };
9
+ function D({
10
+ config: n,
11
+ width: t = "100%",
12
+ height: e = "100%",
13
+ children: r
14
+ }) {
15
+ const a = s(null), f = h(
16
+ () => ({ ...x, ...n }),
17
+ // eslint-disable-next-line react-hooks/exhaustive-deps
18
+ []
19
+ ), i = h(() => new P(f), [f]), c = s(null);
20
+ return u(() => {
21
+ if (!a.current) return;
22
+ const o = new R();
23
+ return o.init(a.current), c.current = o, () => {
24
+ o.destroy(), c.current = null;
25
+ };
26
+ }, []), u(() => {
27
+ let o = performance.now(), d;
28
+ const y = (m) => {
29
+ const b = Math.min((m - o) / 1e3, 0.05);
30
+ o = m, i.update(b), c.current && (c.current.alpha = i.alpha, c.current.render(
31
+ i.getBodies(),
32
+ i.getConstraints()
33
+ )), d = requestAnimationFrame(y);
34
+ };
35
+ return d = requestAnimationFrame(y), () => {
36
+ cancelAnimationFrame(d);
37
+ };
38
+ }, [i]), /* @__PURE__ */ g(B.Provider, { value: i, children: /* @__PURE__ */ g(
39
+ "div",
40
+ {
41
+ ref: a,
42
+ style: { width: t, height: e, position: "relative" },
43
+ children: r
44
+ }
45
+ ) });
46
+ }
47
+ function l() {
48
+ const n = A(B);
49
+ if (!n)
50
+ throw new Error(
51
+ "usePhysics() must be used inside a <PhysicsScene> component."
52
+ );
53
+ return n;
54
+ }
55
+ function I(n) {
56
+ const t = l(), e = s(null);
57
+ return e.current || (e.current = v({
58
+ shape: n.shape,
59
+ mass: n.mass,
60
+ position: n.position,
61
+ velocity: n.velocity,
62
+ restitution: n.restitution,
63
+ friction: n.friction,
64
+ isStatic: n.isStatic,
65
+ userData: n.userData
66
+ })), u(() => {
67
+ const r = e.current;
68
+ return t.addBody(r), () => {
69
+ t.removeBody(r.id);
70
+ };
71
+ }, [t]), null;
72
+ }
73
+ function q(n) {
74
+ const t = l(), e = s(null);
75
+ return e.current || (e.current = S({
76
+ type: "spring",
77
+ bodyA: n.bodyA,
78
+ bodyB: n.bodyB,
79
+ stiffness: n.stiffness,
80
+ damping: n.damping,
81
+ anchorA: n.anchorA,
82
+ anchorB: n.anchorB,
83
+ length: n.length
84
+ })), u(() => {
85
+ const r = e.current;
86
+ return t.addConstraint(r), () => {
87
+ t.removeConstraint(r.id);
88
+ };
89
+ }, [t]), null;
90
+ }
91
+ function M(n) {
92
+ const t = l(), e = s(null);
93
+ return e.current || (e.current = v(n)), u(() => {
94
+ const r = e.current;
95
+ return t.addBody(r), () => {
96
+ t.removeBody(r.id);
97
+ };
98
+ }, [t]), e.current;
99
+ }
100
+ export {
101
+ I as Body,
102
+ B as PhysicsContext,
103
+ D as PhysicsScene,
104
+ q as Spring,
105
+ M as useBody,
106
+ l as usePhysics
107
+ };
@@ -0,0 +1,636 @@
1
+ var O = Object.defineProperty;
2
+ var N = (t, e, i) => e in t ? O(t, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[e] = i;
3
+ var y = (t, e, i) => N(t, typeof e != "symbol" ? e + "" : e, i);
4
+ function L(t = 0, e = 0) {
5
+ return { x: t, y: e };
6
+ }
7
+ function V() {
8
+ return { x: 0, y: 0 };
9
+ }
10
+ function d(t, e) {
11
+ return { x: t.x + e.x, y: t.y + e.y };
12
+ }
13
+ function S(t, e) {
14
+ return { x: t.x - e.x, y: t.y - e.y };
15
+ }
16
+ function g(t, e) {
17
+ return { x: t.x * e, y: t.y * e };
18
+ }
19
+ function _(t) {
20
+ return { x: -t.x, y: -t.y };
21
+ }
22
+ function X(t, e, i) {
23
+ return t.x = e.x + i.x, t.y = e.y + i.y, t;
24
+ }
25
+ function j(t, e, i) {
26
+ return t.x = e.x - i.x, t.y = e.y - i.y, t;
27
+ }
28
+ function Y(t, e, i) {
29
+ return t.x = e.x * i, t.y = e.y * i, t;
30
+ }
31
+ function C(t, e) {
32
+ return t.x += e.x, t.y += e.y, t;
33
+ }
34
+ function U(t, e) {
35
+ return t.x -= e.x, t.y -= e.y, t;
36
+ }
37
+ function $(t, e) {
38
+ return t.x *= e, t.y *= e, t;
39
+ }
40
+ function A(t, e) {
41
+ return t.x * e.x + t.y * e.y;
42
+ }
43
+ function H(t, e) {
44
+ return t.x * e.y - t.y * e.x;
45
+ }
46
+ function z(t, e) {
47
+ return { x: -t * e.y, y: t * e.x };
48
+ }
49
+ function Q(t, e) {
50
+ return { x: e * t.y, y: -e * t.x };
51
+ }
52
+ function P(t) {
53
+ return t.x * t.x + t.y * t.y;
54
+ }
55
+ function m(t) {
56
+ return Math.sqrt(t.x * t.x + t.y * t.y);
57
+ }
58
+ function R(t, e) {
59
+ const i = e.x - t.x, s = e.y - t.y;
60
+ return i * i + s * s;
61
+ }
62
+ function W(t, e) {
63
+ return Math.sqrt(R(t, e));
64
+ }
65
+ function Z(t) {
66
+ const e = m(t);
67
+ return e < 1e-10 ? { x: 0, y: 0 } : { x: t.x / e, y: t.y / e };
68
+ }
69
+ function G(t) {
70
+ const e = m(t);
71
+ return e < 1e-10 ? (t.x = 0, t.y = 0) : (t.x /= e, t.y /= e), t;
72
+ }
73
+ function J(t) {
74
+ return { x: -t.y, y: t.x };
75
+ }
76
+ function K(t) {
77
+ return { x: t.y, y: -t.x };
78
+ }
79
+ function F(t, e, i) {
80
+ return {
81
+ x: t.x + (e.x - t.x) * i,
82
+ y: t.y + (e.y - t.y) * i
83
+ };
84
+ }
85
+ function b(t, e) {
86
+ const i = P(t);
87
+ if (i > e * e) {
88
+ const s = Math.sqrt(i);
89
+ return { x: t.x / s * e, y: t.y / s * e };
90
+ }
91
+ return { x: t.x, y: t.y };
92
+ }
93
+ function tt(t, e) {
94
+ const i = A(e, e);
95
+ if (i < 1e-10) return { x: 0, y: 0 };
96
+ const s = A(t, e) / i;
97
+ return { x: e.x * s, y: e.y * s };
98
+ }
99
+ function et(t, e) {
100
+ const i = 2 * A(t, e);
101
+ return { x: t.x - i * e.x, y: t.y - i * e.y };
102
+ }
103
+ function it(t, e) {
104
+ return t.x = e.x, t.y = e.y, t;
105
+ }
106
+ function st(t) {
107
+ return { x: t.x, y: t.y };
108
+ }
109
+ function nt(t, e, i = 1e-6) {
110
+ return Math.abs(t.x - e.x) < i && Math.abs(t.y - e.y) < i;
111
+ }
112
+ function ot(t, e) {
113
+ const i = Math.cos(e), s = Math.sin(e);
114
+ return {
115
+ x: t.x * i - t.y * s,
116
+ y: t.x * s + t.y * i
117
+ };
118
+ }
119
+ const It = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
120
+ __proto__: null,
121
+ add: d,
122
+ addMut: X,
123
+ addTo: C,
124
+ approxEqual: nt,
125
+ clampLength: b,
126
+ clone: st,
127
+ copy: it,
128
+ cross: H,
129
+ crossSV: z,
130
+ crossVS: Q,
131
+ distance: W,
132
+ distanceSq: R,
133
+ dot: A,
134
+ length: m,
135
+ lengthSq: P,
136
+ lerp: F,
137
+ negate: _,
138
+ normalize: Z,
139
+ normalizeMut: G,
140
+ perpL: J,
141
+ perpR: K,
142
+ project: tt,
143
+ reflect: et,
144
+ rotate: ot,
145
+ scale: g,
146
+ scaleBy: $,
147
+ scaleMut: Y,
148
+ sub: S,
149
+ subFrom: U,
150
+ subMut: j,
151
+ vec2: L,
152
+ zero: V
153
+ }, Symbol.toStringTag, { value: "Module" }));
154
+ function rt(t, e) {
155
+ t.previousPosition.x = t.position.x, t.previousPosition.y = t.position.y, t.velocity.x += t.acceleration.x * e, t.velocity.y += t.acceleration.y * e, t.position.x += t.velocity.x * e, t.position.y += t.velocity.y * e, t.acceleration.x = 0, t.acceleration.y = 0;
156
+ }
157
+ function ct(t, e, i = 4) {
158
+ for (let s = 0; s < i; s++)
159
+ for (const r of t.values()) {
160
+ const o = e.get(r.bodyA), n = e.get(r.bodyB);
161
+ if (!(!o || !n))
162
+ switch (r.type) {
163
+ case "spring":
164
+ at(o, n, r);
165
+ break;
166
+ case "distance":
167
+ lt(o, n, r);
168
+ break;
169
+ case "pin":
170
+ ut(o, n, r);
171
+ break;
172
+ }
173
+ }
174
+ }
175
+ function at(t, e, i) {
176
+ const s = d(t.position, i.anchorA), r = d(e.position, i.anchorB), o = S(r, s), n = m(o);
177
+ if (n < 1e-10) return;
178
+ const a = g(o, 1 / n), c = i.length ?? n, u = n - c, l = S(e.velocity, t.velocity), h = A(l, a), p = i.stiffness * u + i.damping * h, f = g(a, p);
179
+ t.isStatic || (t.acceleration.x += f.x * t.invMass, t.acceleration.y += f.y * t.invMass), e.isStatic || (e.acceleration.x -= f.x * e.invMass, e.acceleration.y -= f.y * e.invMass);
180
+ }
181
+ function lt(t, e, i) {
182
+ const s = d(t.position, i.anchorA), r = d(e.position, i.anchorB), o = S(r, s), n = m(o);
183
+ if (n < 1e-10) return;
184
+ const a = i.length ?? 0, c = n - a, u = g(o, 1 / n), l = t.invMass + e.invMass;
185
+ if (l < 1e-10) return;
186
+ const h = i.stiffness;
187
+ if (!t.isStatic) {
188
+ const p = c * t.invMass * h / l;
189
+ t.position.x += u.x * p, t.position.y += u.y * p;
190
+ }
191
+ if (!e.isStatic) {
192
+ const p = c * e.invMass * h / l;
193
+ e.position.x -= u.x * p, e.position.y -= u.y * p;
194
+ }
195
+ }
196
+ function ut(t, e, i) {
197
+ const s = d(e.position, i.anchorB), r = d(t.position, i.anchorA), o = S(s, r), n = g(o, i.stiffness);
198
+ t.isStatic || (C(t.position, n), t.velocity.x += n.x * i.damping, t.velocity.y += n.y * i.damping);
199
+ }
200
+ function k(t, e) {
201
+ t.acceleration.x += e.x, t.acceleration.y += e.y;
202
+ }
203
+ function D(t, e) {
204
+ t.invMass <= 0 || (t.acceleration.x += -e * t.velocity.x * t.invMass, t.acceleration.y += -e * t.velocity.y * t.invMass);
205
+ }
206
+ function ht(t, e, i) {
207
+ t.invMass <= 0 || (t.acceleration.x += e.x * i * t.invMass, t.acceleration.y += e.y * i * t.invMass);
208
+ }
209
+ function pt(t, e, i, s = "quadratic") {
210
+ if (t.invMass <= 0) return;
211
+ const r = S(e, t.position), o = P(r), a = Math.max(o, 100), c = Math.sqrt(a), u = g(r, 1 / c);
212
+ let l;
213
+ switch (s) {
214
+ case "none":
215
+ l = i;
216
+ break;
217
+ case "linear":
218
+ l = i / c;
219
+ break;
220
+ case "quadratic":
221
+ l = i / a;
222
+ break;
223
+ }
224
+ t.acceleration.x += u.x * l * t.invMass, t.acceleration.y += u.y * l * t.invMass;
225
+ }
226
+ function ft(t, e, i) {
227
+ for (const s of e)
228
+ switch (s.type) {
229
+ case "gravity":
230
+ k(t, s.vector ?? i);
231
+ break;
232
+ case "drag":
233
+ D(t, s.strength ?? 0.01);
234
+ break;
235
+ case "wind":
236
+ s.vector && ht(t, s.vector, s.strength ?? 1);
237
+ break;
238
+ case "attraction":
239
+ s.vector && pt(t, s.vector, s.strength ?? 100, s.falloff ?? "quadratic");
240
+ break;
241
+ }
242
+ }
243
+ function yt(t) {
244
+ const e = [];
245
+ for (let i = 0; i < t.length; i++)
246
+ for (let s = i + 1; s < t.length; s++) {
247
+ const r = t[i], o = t[s];
248
+ if (r.isStatic && o.isStatic || r.isSleeping && o.isSleeping) continue;
249
+ const n = xt(r, o);
250
+ n && e.push(n);
251
+ }
252
+ return e;
253
+ }
254
+ function xt(t, e) {
255
+ const i = t.shape.type, s = e.shape.type;
256
+ if (i === "circle" && s === "circle")
257
+ return dt(t, e);
258
+ if (i === "circle" && s === "rect")
259
+ return I(t, e);
260
+ if (i === "rect" && s === "circle") {
261
+ const r = I(e, t);
262
+ return r ? {
263
+ bodyA: t.id,
264
+ bodyB: e.id,
265
+ normal: _(r.normal),
266
+ penetration: r.penetration,
267
+ overlap: _(r.overlap)
268
+ } : null;
269
+ }
270
+ return i === "rect" && s === "rect" ? gt(t, e) : null;
271
+ }
272
+ function dt(t, e) {
273
+ if (t.shape.type !== "circle" || e.shape.type !== "circle") return null;
274
+ const i = e.position.x - t.position.x, s = e.position.y - t.position.y, r = i * i + s * s, o = t.shape.radius + e.shape.radius;
275
+ if (r >= o * o) return null;
276
+ const n = Math.sqrt(r), a = n < 1e-10 ? { x: 0, y: 1 } : { x: i / n, y: s / n }, c = o - n;
277
+ return {
278
+ bodyA: t.id,
279
+ bodyB: e.id,
280
+ normal: a,
281
+ penetration: c,
282
+ overlap: g(a, c)
283
+ };
284
+ }
285
+ function I(t, e) {
286
+ if (t.shape.type !== "circle" || e.shape.type !== "rect") return null;
287
+ const i = e.shape.width / 2, s = e.shape.height / 2, r = t.position.x - e.position.x, o = t.position.y - e.position.y, n = Math.max(-i, Math.min(i, r)), a = Math.max(-s, Math.min(s, o)), c = r - n, u = o - a, l = c * c + u * u, h = t.shape.radius;
288
+ if (l >= h * h) return null;
289
+ const p = Math.sqrt(l);
290
+ let f, x;
291
+ if (p < 1e-10) {
292
+ const w = i - Math.abs(r), T = s - Math.abs(o);
293
+ w < T ? f = { x: r > 0 ? 1 : -1, y: 0 } : f = { x: 0, y: o > 0 ? 1 : -1 }, x = h + Math.min(w, T);
294
+ } else
295
+ f = { x: c / p, y: u / p }, x = h - p;
296
+ return {
297
+ bodyA: t.id,
298
+ bodyB: e.id,
299
+ normal: f,
300
+ penetration: x,
301
+ overlap: g(f, x)
302
+ };
303
+ }
304
+ function gt(t, e) {
305
+ if (t.shape.type !== "rect" || e.shape.type !== "rect") return null;
306
+ const i = t.shape.width / 2, s = t.shape.height / 2, r = e.shape.width / 2, o = e.shape.height / 2, n = e.position.x - t.position.x, a = e.position.y - t.position.y, c = i + r - Math.abs(n);
307
+ if (c <= 0) return null;
308
+ const u = s + o - Math.abs(a);
309
+ if (u <= 0) return null;
310
+ let l, h;
311
+ return c < u ? (l = { x: n > 0 ? 1 : -1, y: 0 }, h = c) : (l = { x: 0, y: a > 0 ? 1 : -1 }, h = u), {
312
+ bodyA: t.id,
313
+ bodyB: e.id,
314
+ normal: l,
315
+ penetration: h,
316
+ overlap: g(l, h)
317
+ };
318
+ }
319
+ const vt = 0.5, Mt = 0.4, St = 0.5;
320
+ function mt(t, e, i) {
321
+ const { normal: s, penetration: r } = i, o = e.velocity.x - t.velocity.x, n = e.velocity.y - t.velocity.y, a = o * s.x + n * s.y;
322
+ if (a > 0) return;
323
+ let c = Math.min(t.restitution, e.restitution);
324
+ Math.abs(a) < St && (c = 0);
325
+ const u = t.invMass + e.invMass;
326
+ if (u < 1e-10) return;
327
+ const l = -(1 + c) * a / u;
328
+ t.velocity.x -= l * t.invMass * s.x, t.velocity.y -= l * t.invMass * s.y, e.velocity.x += l * e.invMass * s.x, e.velocity.y += l * e.invMass * s.y;
329
+ let h = o - a * s.x, p = n - a * s.y;
330
+ const f = Math.sqrt(h * h + p * p);
331
+ if (f > 1e-10) {
332
+ h /= f, p /= f;
333
+ const w = Math.sqrt(t.friction * e.friction);
334
+ let v = -(o * h + n * p) / u;
335
+ Math.abs(v) > Math.abs(l * w) && (v = l * w * Math.sign(v)), t.velocity.x -= v * t.invMass * h, t.velocity.y -= v * t.invMass * p, e.velocity.x += v * e.invMass * h, e.velocity.y += v * e.invMass * p;
336
+ }
337
+ const x = Math.max(r - vt, 0) * Mt / u;
338
+ t.position.x -= x * t.invMass * s.x, t.position.y -= x * t.invMass * s.y, e.position.x += x * e.invMass * s.x, e.position.y += x * e.invMass * s.y;
339
+ }
340
+ const wt = 0.5, At = 30;
341
+ function Et(t) {
342
+ if (t.isStatic) return;
343
+ m(t.velocity) < wt ? (t.sleepTimer++, t.sleepTimer >= At && (t.isSleeping = !0, t.velocity.x = 0, t.velocity.y = 0)) : (t.sleepTimer = 0, t.isSleeping = !1);
344
+ }
345
+ function M(t) {
346
+ t.isSleeping = !1, t.sleepTimer = 0;
347
+ }
348
+ function Tt(t, e) {
349
+ t.isSleeping && !e.isSleeping && !e.isStatic && M(t), e.isSleeping && !t.isSleeping && !t.isStatic && M(e);
350
+ }
351
+ class Bt {
352
+ constructor(e) {
353
+ y(this, "bodies", /* @__PURE__ */ new Map());
354
+ y(this, "constraints", /* @__PURE__ */ new Map());
355
+ y(this, "forces", []);
356
+ y(this, "config");
357
+ this.config = e;
358
+ }
359
+ /**
360
+ * Advance the world by `dt` seconds.
361
+ *
362
+ * Pipeline per substep:
363
+ * 1. Apply forces (gravity, drag, custom force fields)
364
+ * 2. Integrate positions (semi-implicit Euler)
365
+ * 3. Solve constraints (spring, distance, pin)
366
+ * 4. Detect & resolve collisions
367
+ * 5. Enforce world bounds
368
+ * 6. Update sleep states
369
+ */
370
+ step(e) {
371
+ const i = e / this.config.substeps;
372
+ for (let s = 0; s < this.config.substeps; s++) {
373
+ for (const n of this.constraints.values()) {
374
+ const a = this.bodies.get(n.bodyA), c = this.bodies.get(n.bodyB);
375
+ a && !a.isStatic && a.isSleeping && M(a), c && !c.isStatic && c.isSleeping && M(c);
376
+ }
377
+ for (const n of this.bodies.values())
378
+ n.isStatic || n.isSleeping || (k(n, this.config.gravity), D(n, 0.01), this.forces.length > 0 && ft(n, this.forces, this.config.gravity));
379
+ for (const n of this.bodies.values())
380
+ n.isStatic || n.isSleeping || rt(n, i);
381
+ ct(
382
+ this.constraints,
383
+ this.bodies,
384
+ this.config.velocityIterations
385
+ );
386
+ const r = Array.from(this.bodies.values()), o = yt(r);
387
+ for (const n of o) {
388
+ const a = this.bodies.get(n.bodyA), c = this.bodies.get(n.bodyB);
389
+ a && c && (Tt(a, c), mt(a, c, n));
390
+ }
391
+ this.config.bounds && this.enforceBounds();
392
+ for (const n of this.bodies.values())
393
+ n.isStatic || Et(n);
394
+ }
395
+ }
396
+ /** Clamp bodies within configured world bounds. */
397
+ enforceBounds() {
398
+ const e = this.config.bounds;
399
+ if (e)
400
+ for (const i of this.bodies.values()) {
401
+ if (i.isStatic) continue;
402
+ let s = 0;
403
+ i.shape.type === "circle" ? s = i.shape.radius : i.shape.type === "rect" && (s = Math.max(i.shape.width, i.shape.height) / 2), i.position.x - s < e.min.x && (i.position.x = e.min.x + s, i.velocity.x = Math.abs(i.velocity.x) * i.restitution), i.position.x + s > e.max.x && (i.position.x = e.max.x - s, i.velocity.x = -Math.abs(i.velocity.x) * i.restitution), i.position.y - s < e.min.y && (i.position.y = e.min.y + s, i.velocity.y = Math.abs(i.velocity.y) * i.restitution), i.position.y + s > e.max.y && (i.position.y = e.max.y - s, i.velocity.y = -Math.abs(i.velocity.y) * i.restitution);
404
+ }
405
+ }
406
+ /** Add a force field. */
407
+ addForceField(e) {
408
+ this.forces.push(e);
409
+ }
410
+ /** Remove all force fields of a given type. */
411
+ removeForceFields(e) {
412
+ for (let i = this.forces.length - 1; i >= 0; i--)
413
+ this.forces[i].type === e && this.forces.splice(i, 1);
414
+ }
415
+ }
416
+ const E = 1 / 60, _t = 0.25;
417
+ class qt {
418
+ // interpolation factor for rendering
419
+ constructor(e) {
420
+ y(this, "world");
421
+ y(this, "accumulator", 0);
422
+ y(this, "_alpha", 0);
423
+ this.world = new Bt(e);
424
+ }
425
+ // ---- Simulation ----------------------------------------------------------
426
+ /**
427
+ * Advance the simulation by `frameTime` seconds.
428
+ *
429
+ * Uses Glenn Fiedler's fixed-timestep-with-accumulator pattern:
430
+ * - Clamp frame time to prevent spiral of death
431
+ * - Step physics at fixed 60Hz intervals
432
+ * - Store interpolation alpha for smooth rendering
433
+ */
434
+ update(e) {
435
+ const i = Math.min(e, _t);
436
+ for (this.accumulator += i; this.accumulator >= E; )
437
+ this.world.step(E), this.accumulator -= E;
438
+ this._alpha = this.accumulator / E;
439
+ }
440
+ /**
441
+ * Get the interpolation alpha for the current frame.
442
+ *
443
+ * Use this to blend between previousPosition and position:
444
+ * renderPos = lerp(body.previousPosition, body.position, alpha)
445
+ */
446
+ get alpha() {
447
+ return this._alpha;
448
+ }
449
+ /**
450
+ * Get the interpolated render position for a body.
451
+ */
452
+ getInterpolatedPosition(e) {
453
+ return F(e.previousPosition, e.position, this._alpha);
454
+ }
455
+ // ---- Body Management -----------------------------------------------------
456
+ /** Register a body and return its id. */
457
+ addBody(e) {
458
+ return this.world.bodies.set(e.id, e), e.id;
459
+ }
460
+ /** Remove a body by id. */
461
+ removeBody(e) {
462
+ this.world.bodies.delete(e);
463
+ }
464
+ /** Look up a single body. */
465
+ getBody(e) {
466
+ return this.world.bodies.get(e);
467
+ }
468
+ /** Return every body currently in the world. */
469
+ getBodies() {
470
+ return Array.from(this.world.bodies.values());
471
+ }
472
+ /** Apply an instantaneous impulse to a body. */
473
+ applyImpulse(e, i) {
474
+ const s = this.world.bodies.get(e);
475
+ !s || s.isStatic || (M(s), s.velocity.x += i.x * s.invMass, s.velocity.y += i.y * s.invMass);
476
+ }
477
+ /** Set a body's position directly (teleport). */
478
+ setPosition(e, i) {
479
+ const s = this.world.bodies.get(e);
480
+ s && (M(s), s.position.x = i.x, s.position.y = i.y, s.previousPosition.x = i.x, s.previousPosition.y = i.y);
481
+ }
482
+ /** Set a body's velocity directly. */
483
+ setVelocity(e, i) {
484
+ const s = this.world.bodies.get(e);
485
+ !s || s.isStatic || (M(s), s.velocity.x = i.x, s.velocity.y = i.y);
486
+ }
487
+ // ---- Constraint Management -----------------------------------------------
488
+ /** Register a constraint and return its id. */
489
+ addConstraint(e) {
490
+ return this.world.constraints.set(e.id, e), e.id;
491
+ }
492
+ /** Remove a constraint by id. */
493
+ removeConstraint(e) {
494
+ this.world.constraints.delete(e);
495
+ }
496
+ /** Return every constraint currently in the world. */
497
+ getConstraints() {
498
+ return Array.from(this.world.constraints.values());
499
+ }
500
+ // ---- Force Fields --------------------------------------------------------
501
+ /** Add a force field to the world. */
502
+ addForceField(e) {
503
+ this.world.addForceField(e);
504
+ }
505
+ /** Remove all force fields of a given type. */
506
+ removeForceFields(e) {
507
+ this.world.removeForceFields(e);
508
+ }
509
+ // ---- Config --------------------------------------------------------------
510
+ /** Access the underlying world config. */
511
+ getConfig() {
512
+ return this.world.config;
513
+ }
514
+ }
515
+ const B = { x: 0, y: 0 }, Pt = { type: "circle", radius: 10 };
516
+ function Ct(t = {}) {
517
+ const e = t.isStatic ?? !1, i = e ? 0 : t.mass ?? 1, s = t.position ?? { ...B };
518
+ return {
519
+ id: t.id ?? crypto.randomUUID(),
520
+ position: { ...s },
521
+ previousPosition: t.previousPosition ?? { ...s },
522
+ velocity: t.velocity ?? { ...B },
523
+ acceleration: t.acceleration ?? { ...B },
524
+ mass: i,
525
+ invMass: i > 0 ? 1 / i : 0,
526
+ restitution: t.restitution ?? 0.5,
527
+ friction: t.friction ?? 0.3,
528
+ isStatic: e,
529
+ isSleeping: t.isSleeping ?? !1,
530
+ sleepTimer: t.sleepTimer ?? 0,
531
+ shape: t.shape ?? { ...Pt },
532
+ userData: t.userData
533
+ };
534
+ }
535
+ const q = { x: 0, y: 0 };
536
+ function Rt(t) {
537
+ return {
538
+ id: t.id ?? crypto.randomUUID(),
539
+ type: t.type ?? "spring",
540
+ bodyA: t.bodyA,
541
+ bodyB: t.bodyB,
542
+ anchorA: t.anchorA ?? { ...q },
543
+ anchorB: t.anchorB ?? { ...q },
544
+ stiffness: t.stiffness ?? 0.5,
545
+ damping: t.damping ?? 0.1,
546
+ length: t.length
547
+ };
548
+ }
549
+ class kt {
550
+ constructor() {
551
+ y(this, "svg", null);
552
+ y(this, "elementMap", /* @__PURE__ */ new Map());
553
+ y(this, "constraintMap", /* @__PURE__ */ new Map());
554
+ /** Interpolation alpha (0 = previous state, 1 = current state). */
555
+ y(this, "alpha", 1);
556
+ }
557
+ init(e) {
558
+ this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"), this.svg.setAttribute("width", "100%"), this.svg.setAttribute("height", "100%"), this.svg.style.overflow = "visible", e.appendChild(this.svg);
559
+ }
560
+ render(e, i) {
561
+ this.svg && (this.renderConstraints(i, e), this.renderBodies(e));
562
+ }
563
+ destroy() {
564
+ var e;
565
+ (e = this.svg) == null || e.remove(), this.svg = null, this.elementMap.clear(), this.constraintMap.clear();
566
+ }
567
+ // ---- Body Rendering ------------------------------------------------------
568
+ renderBodies(e) {
569
+ const i = /* @__PURE__ */ new Set();
570
+ for (const s of e) {
571
+ i.add(s.id);
572
+ let r = this.elementMap.get(s.id);
573
+ r || (r = this.createElement(s), this.elementMap.set(s.id, r), this.svg.appendChild(r));
574
+ const o = this.interpolate(s);
575
+ r.setAttribute(
576
+ "transform",
577
+ `translate(${o.x}, ${o.y})`
578
+ ), r.setAttribute("opacity", s.isSleeping ? "0.5" : "1");
579
+ }
580
+ for (const [s, r] of this.elementMap)
581
+ i.has(s) || (r.remove(), this.elementMap.delete(s));
582
+ }
583
+ /** Interpolate between previous and current position. */
584
+ interpolate(e) {
585
+ return this.alpha >= 1 ? e.position : F(e.previousPosition, e.position, this.alpha);
586
+ }
587
+ /** Create the appropriate SVG element for a body's shape. */
588
+ createElement(e) {
589
+ const i = "http://www.w3.org/2000/svg";
590
+ switch (e.shape.type) {
591
+ case "circle": {
592
+ const s = document.createElementNS(i, "circle");
593
+ return s.setAttribute("r", String(e.shape.radius)), s.setAttribute("fill", "#6366f1"), s;
594
+ }
595
+ case "rect": {
596
+ const s = document.createElementNS(i, "rect");
597
+ return s.setAttribute("width", String(e.shape.width)), s.setAttribute("height", String(e.shape.height)), s.setAttribute("x", String(-e.shape.width / 2)), s.setAttribute("y", String(-e.shape.height / 2)), s.setAttribute("fill", "#6366f1"), s;
598
+ }
599
+ case "polygon": {
600
+ const s = document.createElementNS(i, "polygon"), r = e.shape.vertices.map((o) => `${o.x},${o.y}`).join(" ");
601
+ return s.setAttribute("points", r), s.setAttribute("fill", "#6366f1"), s;
602
+ }
603
+ }
604
+ }
605
+ // ---- Constraint Rendering ------------------------------------------------
606
+ renderConstraints(e, i) {
607
+ const s = new Map(i.map((o) => [o.id, o])), r = /* @__PURE__ */ new Set();
608
+ for (const o of e) {
609
+ const n = s.get(o.bodyA), a = s.get(o.bodyB);
610
+ if (!n || !a) continue;
611
+ r.add(o.id);
612
+ let c = this.constraintMap.get(o.id);
613
+ c || (c = document.createElementNS(
614
+ "http://www.w3.org/2000/svg",
615
+ "line"
616
+ ), c.setAttribute("stroke", "#94a3b8"), c.setAttribute("stroke-width", "1"), c.setAttribute("stroke-dasharray", "4 2"), this.constraintMap.set(o.id, c), this.svg.insertBefore(c, this.svg.firstChild));
617
+ const u = this.interpolate(n), l = this.interpolate(a), h = d(u, o.anchorA), p = d(l, o.anchorB);
618
+ c.setAttribute("x1", String(h.x)), c.setAttribute("y1", String(h.y)), c.setAttribute("x2", String(p.x)), c.setAttribute("y2", String(p.y));
619
+ }
620
+ for (const [o, n] of this.constraintMap)
621
+ r.has(o) || (n.remove(), this.constraintMap.delete(o));
622
+ }
623
+ }
624
+ export {
625
+ qt as P,
626
+ kt as S,
627
+ pt as a,
628
+ D as b,
629
+ ft as c,
630
+ k as d,
631
+ ht as e,
632
+ Ct as f,
633
+ Rt as g,
634
+ It as v,
635
+ M as w
636
+ };
@@ -0,0 +1 @@
1
+ "use strict";var V=Object.defineProperty;var X=(t,e,i)=>e in t?V(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i;var y=(t,e,i)=>X(t,typeof e!="symbol"?e+"":e,i);function j(t=0,e=0){return{x:t,y:e}}function Y(){return{x:0,y:0}}function d(t,e){return{x:t.x+e.x,y:t.y+e.y}}function S(t,e){return{x:t.x-e.x,y:t.y-e.y}}function g(t,e){return{x:t.x*e,y:t.y*e}}function _(t){return{x:-t.x,y:-t.y}}function U(t,e,i){return t.x=e.x+i.x,t.y=e.y+i.y,t}function $(t,e,i){return t.x=e.x-i.x,t.y=e.y-i.y,t}function H(t,e,i){return t.x=e.x*i,t.y=e.y*i,t}function k(t,e){return t.x+=e.x,t.y+=e.y,t}function z(t,e){return t.x-=e.x,t.y-=e.y,t}function W(t,e){return t.x*=e,t.y*=e,t}function A(t,e){return t.x*e.x+t.y*e.y}function G(t,e){return t.x*e.y-t.y*e.x}function Q(t,e){return{x:-t*e.y,y:t*e.x}}function Z(t,e){return{x:e*t.y,y:-e*t.x}}function F(t){return t.x*t.x+t.y*t.y}function m(t){return Math.sqrt(t.x*t.x+t.y*t.y)}function D(t,e){const i=e.x-t.x,s=e.y-t.y;return i*i+s*s}function J(t,e){return Math.sqrt(D(t,e))}function K(t){const e=m(t);return e<1e-10?{x:0,y:0}:{x:t.x/e,y:t.y/e}}function b(t){const e=m(t);return e<1e-10?(t.x=0,t.y=0):(t.x/=e,t.y/=e),t}function tt(t){return{x:-t.y,y:t.x}}function et(t){return{x:t.y,y:-t.x}}function P(t,e,i){return{x:t.x+(e.x-t.x)*i,y:t.y+(e.y-t.y)*i}}function it(t,e){const i=F(t);if(i>e*e){const s=Math.sqrt(i);return{x:t.x/s*e,y:t.y/s*e}}return{x:t.x,y:t.y}}function st(t,e){const i=A(e,e);if(i<1e-10)return{x:0,y:0};const s=A(t,e)/i;return{x:e.x*s,y:e.y*s}}function nt(t,e){const i=2*A(t,e);return{x:t.x-i*e.x,y:t.y-i*e.y}}function ot(t,e){return t.x=e.x,t.y=e.y,t}function rt(t){return{x:t.x,y:t.y}}function ct(t,e,i=1e-6){return Math.abs(t.x-e.x)<i&&Math.abs(t.y-e.y)<i}function at(t,e){const i=Math.cos(e),s=Math.sin(e);return{x:t.x*i-t.y*s,y:t.x*s+t.y*i}}const lt=Object.freeze(Object.defineProperty({__proto__:null,add:d,addMut:U,addTo:k,approxEqual:ct,clampLength:it,clone:rt,copy:ot,cross:G,crossSV:Q,crossVS:Z,distance:J,distanceSq:D,dot:A,length:m,lengthSq:F,lerp:P,negate:_,normalize:K,normalizeMut:b,perpL:tt,perpR:et,project:st,reflect:nt,rotate:at,scale:g,scaleBy:W,scaleMut:H,sub:S,subFrom:z,subMut:$,vec2:j,zero:Y},Symbol.toStringTag,{value:"Module"}));function ut(t,e){t.previousPosition.x=t.position.x,t.previousPosition.y=t.position.y,t.velocity.x+=t.acceleration.x*e,t.velocity.y+=t.acceleration.y*e,t.position.x+=t.velocity.x*e,t.position.y+=t.velocity.y*e,t.acceleration.x=0,t.acceleration.y=0}function ht(t,e,i=4){for(let s=0;s<i;s++)for(const r of t.values()){const o=e.get(r.bodyA),n=e.get(r.bodyB);if(!(!o||!n))switch(r.type){case"spring":pt(o,n,r);break;case"distance":ft(o,n,r);break;case"pin":yt(o,n,r);break}}}function pt(t,e,i){const s=d(t.position,i.anchorA),r=d(e.position,i.anchorB),o=S(r,s),n=m(o);if(n<1e-10)return;const a=g(o,1/n),c=i.length??n,u=n-c,l=S(e.velocity,t.velocity),h=A(l,a),p=i.stiffness*u+i.damping*h,f=g(a,p);t.isStatic||(t.acceleration.x+=f.x*t.invMass,t.acceleration.y+=f.y*t.invMass),e.isStatic||(e.acceleration.x-=f.x*e.invMass,e.acceleration.y-=f.y*e.invMass)}function ft(t,e,i){const s=d(t.position,i.anchorA),r=d(e.position,i.anchorB),o=S(r,s),n=m(o);if(n<1e-10)return;const a=i.length??0,c=n-a,u=g(o,1/n),l=t.invMass+e.invMass;if(l<1e-10)return;const h=i.stiffness;if(!t.isStatic){const p=c*t.invMass*h/l;t.position.x+=u.x*p,t.position.y+=u.y*p}if(!e.isStatic){const p=c*e.invMass*h/l;e.position.x-=u.x*p,e.position.y-=u.y*p}}function yt(t,e,i){const s=d(e.position,i.anchorB),r=d(t.position,i.anchorA),o=S(s,r),n=g(o,i.stiffness);t.isStatic||(k(t.position,n),t.velocity.x+=n.x*i.damping,t.velocity.y+=n.y*i.damping)}function C(t,e){t.acceleration.x+=e.x,t.acceleration.y+=e.y}function I(t,e){t.invMass<=0||(t.acceleration.x+=-e*t.velocity.x*t.invMass,t.acceleration.y+=-e*t.velocity.y*t.invMass)}function O(t,e,i){t.invMass<=0||(t.acceleration.x+=e.x*i*t.invMass,t.acceleration.y+=e.y*i*t.invMass)}function N(t,e,i,s="quadratic"){if(t.invMass<=0)return;const r=S(e,t.position),o=F(r),a=Math.max(o,100),c=Math.sqrt(a),u=g(r,1/c);let l;switch(s){case"none":l=i;break;case"linear":l=i/c;break;case"quadratic":l=i/a;break}t.acceleration.x+=u.x*l*t.invMass,t.acceleration.y+=u.y*l*t.invMass}function L(t,e,i){for(const s of e)switch(s.type){case"gravity":C(t,s.vector??i);break;case"drag":I(t,s.strength??.01);break;case"wind":s.vector&&O(t,s.vector,s.strength??1);break;case"attraction":s.vector&&N(t,s.vector,s.strength??100,s.falloff??"quadratic");break}}function xt(t){const e=[];for(let i=0;i<t.length;i++)for(let s=i+1;s<t.length;s++){const r=t[i],o=t[s];if(r.isStatic&&o.isStatic||r.isSleeping&&o.isSleeping)continue;const n=dt(r,o);n&&e.push(n)}return e}function dt(t,e){const i=t.shape.type,s=e.shape.type;if(i==="circle"&&s==="circle")return gt(t,e);if(i==="circle"&&s==="rect")return q(t,e);if(i==="rect"&&s==="circle"){const r=q(e,t);return r?{bodyA:t.id,bodyB:e.id,normal:_(r.normal),penetration:r.penetration,overlap:_(r.overlap)}:null}return i==="rect"&&s==="rect"?vt(t,e):null}function gt(t,e){if(t.shape.type!=="circle"||e.shape.type!=="circle")return null;const i=e.position.x-t.position.x,s=e.position.y-t.position.y,r=i*i+s*s,o=t.shape.radius+e.shape.radius;if(r>=o*o)return null;const n=Math.sqrt(r),a=n<1e-10?{x:0,y:1}:{x:i/n,y:s/n},c=o-n;return{bodyA:t.id,bodyB:e.id,normal:a,penetration:c,overlap:g(a,c)}}function q(t,e){if(t.shape.type!=="circle"||e.shape.type!=="rect")return null;const i=e.shape.width/2,s=e.shape.height/2,r=t.position.x-e.position.x,o=t.position.y-e.position.y,n=Math.max(-i,Math.min(i,r)),a=Math.max(-s,Math.min(s,o)),c=r-n,u=o-a,l=c*c+u*u,h=t.shape.radius;if(l>=h*h)return null;const p=Math.sqrt(l);let f,x;if(p<1e-10){const w=i-Math.abs(r),B=s-Math.abs(o);w<B?f={x:r>0?1:-1,y:0}:f={x:0,y:o>0?1:-1},x=h+Math.min(w,B)}else f={x:c/p,y:u/p},x=h-p;return{bodyA:t.id,bodyB:e.id,normal:f,penetration:x,overlap:g(f,x)}}function vt(t,e){if(t.shape.type!=="rect"||e.shape.type!=="rect")return null;const i=t.shape.width/2,s=t.shape.height/2,r=e.shape.width/2,o=e.shape.height/2,n=e.position.x-t.position.x,a=e.position.y-t.position.y,c=i+r-Math.abs(n);if(c<=0)return null;const u=s+o-Math.abs(a);if(u<=0)return null;let l,h;return c<u?(l={x:n>0?1:-1,y:0},h=c):(l={x:0,y:a>0?1:-1},h=u),{bodyA:t.id,bodyB:e.id,normal:l,penetration:h,overlap:g(l,h)}}const Mt=.5,St=.4,mt=.5;function wt(t,e,i){const{normal:s,penetration:r}=i,o=e.velocity.x-t.velocity.x,n=e.velocity.y-t.velocity.y,a=o*s.x+n*s.y;if(a>0)return;let c=Math.min(t.restitution,e.restitution);Math.abs(a)<mt&&(c=0);const u=t.invMass+e.invMass;if(u<1e-10)return;const l=-(1+c)*a/u;t.velocity.x-=l*t.invMass*s.x,t.velocity.y-=l*t.invMass*s.y,e.velocity.x+=l*e.invMass*s.x,e.velocity.y+=l*e.invMass*s.y;let h=o-a*s.x,p=n-a*s.y;const f=Math.sqrt(h*h+p*p);if(f>1e-10){h/=f,p/=f;const w=Math.sqrt(t.friction*e.friction);let M=-(o*h+n*p)/u;Math.abs(M)>Math.abs(l*w)&&(M=l*w*Math.sign(M)),t.velocity.x-=M*t.invMass*h,t.velocity.y-=M*t.invMass*p,e.velocity.x+=M*e.invMass*h,e.velocity.y+=M*e.invMass*p}const x=Math.max(r-Mt,0)*St/u;t.position.x-=x*t.invMass*s.x,t.position.y-=x*t.invMass*s.y,e.position.x+=x*e.invMass*s.x,e.position.y+=x*e.invMass*s.y}const At=.5,Et=30;function Bt(t){if(t.isStatic)return;m(t.velocity)<At?(t.sleepTimer++,t.sleepTimer>=Et&&(t.isSleeping=!0,t.velocity.x=0,t.velocity.y=0)):(t.sleepTimer=0,t.isSleeping=!1)}function v(t){t.isSleeping=!1,t.sleepTimer=0}function Tt(t,e){t.isSleeping&&!e.isSleeping&&!e.isStatic&&v(t),e.isSleeping&&!t.isSleeping&&!t.isStatic&&v(e)}class _t{constructor(e){y(this,"bodies",new Map);y(this,"constraints",new Map);y(this,"forces",[]);y(this,"config");this.config=e}step(e){const i=e/this.config.substeps;for(let s=0;s<this.config.substeps;s++){for(const n of this.constraints.values()){const a=this.bodies.get(n.bodyA),c=this.bodies.get(n.bodyB);a&&!a.isStatic&&a.isSleeping&&v(a),c&&!c.isStatic&&c.isSleeping&&v(c)}for(const n of this.bodies.values())n.isStatic||n.isSleeping||(C(n,this.config.gravity),I(n,.01),this.forces.length>0&&L(n,this.forces,this.config.gravity));for(const n of this.bodies.values())n.isStatic||n.isSleeping||ut(n,i);ht(this.constraints,this.bodies,this.config.velocityIterations);const r=Array.from(this.bodies.values()),o=xt(r);for(const n of o){const a=this.bodies.get(n.bodyA),c=this.bodies.get(n.bodyB);a&&c&&(Tt(a,c),wt(a,c,n))}this.config.bounds&&this.enforceBounds();for(const n of this.bodies.values())n.isStatic||Bt(n)}}enforceBounds(){const e=this.config.bounds;if(e)for(const i of this.bodies.values()){if(i.isStatic)continue;let s=0;i.shape.type==="circle"?s=i.shape.radius:i.shape.type==="rect"&&(s=Math.max(i.shape.width,i.shape.height)/2),i.position.x-s<e.min.x&&(i.position.x=e.min.x+s,i.velocity.x=Math.abs(i.velocity.x)*i.restitution),i.position.x+s>e.max.x&&(i.position.x=e.max.x-s,i.velocity.x=-Math.abs(i.velocity.x)*i.restitution),i.position.y-s<e.min.y&&(i.position.y=e.min.y+s,i.velocity.y=Math.abs(i.velocity.y)*i.restitution),i.position.y+s>e.max.y&&(i.position.y=e.max.y-s,i.velocity.y=-Math.abs(i.velocity.y)*i.restitution)}}addForceField(e){this.forces.push(e)}removeForceFields(e){for(let i=this.forces.length-1;i>=0;i--)this.forces[i].type===e&&this.forces.splice(i,1)}}const E=1/60,Ft=.25;class Pt{constructor(e){y(this,"world");y(this,"accumulator",0);y(this,"_alpha",0);this.world=new _t(e)}update(e){const i=Math.min(e,Ft);for(this.accumulator+=i;this.accumulator>=E;)this.world.step(E),this.accumulator-=E;this._alpha=this.accumulator/E}get alpha(){return this._alpha}getInterpolatedPosition(e){return P(e.previousPosition,e.position,this._alpha)}addBody(e){return this.world.bodies.set(e.id,e),e.id}removeBody(e){this.world.bodies.delete(e)}getBody(e){return this.world.bodies.get(e)}getBodies(){return Array.from(this.world.bodies.values())}applyImpulse(e,i){const s=this.world.bodies.get(e);!s||s.isStatic||(v(s),s.velocity.x+=i.x*s.invMass,s.velocity.y+=i.y*s.invMass)}setPosition(e,i){const s=this.world.bodies.get(e);s&&(v(s),s.position.x=i.x,s.position.y=i.y,s.previousPosition.x=i.x,s.previousPosition.y=i.y)}setVelocity(e,i){const s=this.world.bodies.get(e);!s||s.isStatic||(v(s),s.velocity.x=i.x,s.velocity.y=i.y)}addConstraint(e){return this.world.constraints.set(e.id,e),e.id}removeConstraint(e){this.world.constraints.delete(e)}getConstraints(){return Array.from(this.world.constraints.values())}addForceField(e){this.world.addForceField(e)}removeForceFields(e){this.world.removeForceFields(e)}getConfig(){return this.world.config}}const T={x:0,y:0},Ct={type:"circle",radius:10};function It(t={}){const e=t.isStatic??!1,i=e?0:t.mass??1,s=t.position??{...T};return{id:t.id??crypto.randomUUID(),position:{...s},previousPosition:t.previousPosition??{...s},velocity:t.velocity??{...T},acceleration:t.acceleration??{...T},mass:i,invMass:i>0?1/i:0,restitution:t.restitution??.5,friction:t.friction??.3,isStatic:e,isSleeping:t.isSleeping??!1,sleepTimer:t.sleepTimer??0,shape:t.shape??{...Ct},userData:t.userData}}const R={x:0,y:0};function qt(t){return{id:t.id??crypto.randomUUID(),type:t.type??"spring",bodyA:t.bodyA,bodyB:t.bodyB,anchorA:t.anchorA??{...R},anchorB:t.anchorB??{...R},stiffness:t.stiffness??.5,damping:t.damping??.1,length:t.length}}class Rt{constructor(){y(this,"svg",null);y(this,"elementMap",new Map);y(this,"constraintMap",new Map);y(this,"alpha",1)}init(e){this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.setAttribute("width","100%"),this.svg.setAttribute("height","100%"),this.svg.style.overflow="visible",e.appendChild(this.svg)}render(e,i){this.svg&&(this.renderConstraints(i,e),this.renderBodies(e))}destroy(){var e;(e=this.svg)==null||e.remove(),this.svg=null,this.elementMap.clear(),this.constraintMap.clear()}renderBodies(e){const i=new Set;for(const s of e){i.add(s.id);let r=this.elementMap.get(s.id);r||(r=this.createElement(s),this.elementMap.set(s.id,r),this.svg.appendChild(r));const o=this.interpolate(s);r.setAttribute("transform",`translate(${o.x}, ${o.y})`),r.setAttribute("opacity",s.isSleeping?"0.5":"1")}for(const[s,r]of this.elementMap)i.has(s)||(r.remove(),this.elementMap.delete(s))}interpolate(e){return this.alpha>=1?e.position:P(e.previousPosition,e.position,this.alpha)}createElement(e){const i="http://www.w3.org/2000/svg";switch(e.shape.type){case"circle":{const s=document.createElementNS(i,"circle");return s.setAttribute("r",String(e.shape.radius)),s.setAttribute("fill","#6366f1"),s}case"rect":{const s=document.createElementNS(i,"rect");return s.setAttribute("width",String(e.shape.width)),s.setAttribute("height",String(e.shape.height)),s.setAttribute("x",String(-e.shape.width/2)),s.setAttribute("y",String(-e.shape.height/2)),s.setAttribute("fill","#6366f1"),s}case"polygon":{const s=document.createElementNS(i,"polygon"),r=e.shape.vertices.map(o=>`${o.x},${o.y}`).join(" ");return s.setAttribute("points",r),s.setAttribute("fill","#6366f1"),s}}}renderConstraints(e,i){const s=new Map(i.map(o=>[o.id,o])),r=new Set;for(const o of e){const n=s.get(o.bodyA),a=s.get(o.bodyB);if(!n||!a)continue;r.add(o.id);let c=this.constraintMap.get(o.id);c||(c=document.createElementNS("http://www.w3.org/2000/svg","line"),c.setAttribute("stroke","#94a3b8"),c.setAttribute("stroke-width","1"),c.setAttribute("stroke-dasharray","4 2"),this.constraintMap.set(o.id,c),this.svg.insertBefore(c,this.svg.firstChild));const u=this.interpolate(n),l=this.interpolate(a),h=d(u,o.anchorA),p=d(l,o.anchorB);c.setAttribute("x1",String(h.x)),c.setAttribute("y1",String(h.y)),c.setAttribute("x2",String(p.x)),c.setAttribute("y2",String(p.y))}for(const[o,n]of this.constraintMap)r.has(o)||(n.remove(),this.constraintMap.delete(o))}}exports.PhysicsEngine=Pt;exports.SvgRenderer=Rt;exports.applyAttraction=N;exports.applyDrag=I;exports.applyForceFields=L;exports.applyGravity=C;exports.applyWind=O;exports.createBody=It;exports.createConstraint=qt;exports.vec2=lt;exports.wakeBody=v;
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@mcptoolshop/physics-svg",
3
+ "version": "0.1.0",
4
+ "description": "Deterministic 2D physics engine with SVG rendering for web games and simulations",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "MCP Tool Shop",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/mcp-tool-shop-org/siege-kit.git",
11
+ "directory": "packages/physics-svg"
12
+ },
13
+ "homepage": "https://github.com/mcp-tool-shop-org/siege-kit/tree/main/packages/physics-svg#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/mcp-tool-shop-org/siege-kit/issues"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.mjs",
25
+ "require": "./dist/index.cjs"
26
+ },
27
+ "./react": {
28
+ "types": "./dist/react/index.d.ts",
29
+ "import": "./dist/react/index.mjs",
30
+ "require": "./dist/react/index.cjs"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "peerDependencies": {
37
+ "react": ">=18.0.0",
38
+ "react-dom": ">=18.0.0",
39
+ "gsap": ">=3.0.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "react": {
43
+ "optional": true
44
+ },
45
+ "react-dom": {
46
+ "optional": true
47
+ },
48
+ "gsap": {
49
+ "optional": true
50
+ }
51
+ },
52
+ "devDependencies": {
53
+ "@types/react": "^19.0",
54
+ "@types/react-dom": "^19.0",
55
+ "@vitejs/plugin-react": "^4.4",
56
+ "react": "^19.0",
57
+ "react-dom": "^19.0",
58
+ "gsap": "^3.12",
59
+ "vite": "^6.2",
60
+ "vite-plugin-dts": "^4.5",
61
+ "vitest": "^3.0",
62
+ "typescript": "^5.7",
63
+ "@mcp-tool-shop/siege-types": "0.1.0",
64
+ "@mcp-tool-shop/tsconfig": "0.1.0"
65
+ },
66
+ "scripts": {
67
+ "dev": "vite build --watch",
68
+ "build": "vite build",
69
+ "typecheck": "tsc --noEmit",
70
+ "test": "vitest run",
71
+ "clean": "rm -rf dist"
72
+ }
73
+ }