@codefrydev/svg-engine 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.
@@ -0,0 +1,2794 @@
1
+ // src/core/geometry.ts
2
+ var GRID_SIZE = 20;
3
+ var snap = (val, gridSize = GRID_SIZE) => Math.round(val / gridSize) * gridSize;
4
+ var distance = (x1, y1, x2, y2) => Math.hypot(x2 - x1, y2 - y1);
5
+ var angleDeg = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
6
+ var getBounds = (x1, y1, x2, y2) => {
7
+ const minX = Math.min(x1, x2);
8
+ const minY = Math.min(y1, y2);
9
+ const maxX = Math.max(x1, x2);
10
+ const maxY = Math.max(y1, y2);
11
+ return {
12
+ minX,
13
+ minY,
14
+ maxX,
15
+ maxY,
16
+ width: Math.max(1, maxX - minX),
17
+ height: Math.max(1, maxY - minY)
18
+ };
19
+ };
20
+ var getMouseCoords = (svg, e) => {
21
+ const ctm = svg.getScreenCTM();
22
+ if (!ctm) return { x: 0, y: 0 };
23
+ return {
24
+ x: (e.clientX - ctm.e) / ctm.a,
25
+ y: (e.clientY - ctm.f) / ctm.d
26
+ };
27
+ };
28
+
29
+ // src/core/renderers/registry.ts
30
+ var rendererMap = /* @__PURE__ */ new Map();
31
+ var registerRenderer = (type, renderer) => {
32
+ rendererMap.set(type, renderer);
33
+ };
34
+ var getRenderer = (type) => rendererMap.get(type);
35
+ var hasRenderer = (type) => rendererMap.has(type);
36
+
37
+ // src/core/Renderer.tsx
38
+ import { useMemo } from "react";
39
+
40
+ // src/core/renderers/primitives.tsx
41
+ import { jsx, jsxs } from "react/jsx-runtime";
42
+ var colorOf = (el) => el.color || "#0f172a";
43
+ var strokeOf = (el) => el.strokeWidth || 2;
44
+ var fontOf = (el) => el.fontSize || 16;
45
+ registerRenderer("point", (el) => /* @__PURE__ */ jsxs("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
46
+ /* @__PURE__ */ jsx("circle", { cx: "0", cy: "0", r: 3, fill: colorOf(el) }),
47
+ el.label && /* @__PURE__ */ jsx("text", { x: "8", y: "-8", fontSize: fontOf(el), fill: colorOf(el), children: String(el.label) })
48
+ ] }));
49
+ registerRenderer("text", (el) => /* @__PURE__ */ jsx(
50
+ "text",
51
+ {
52
+ x: el.x1,
53
+ y: el.y1,
54
+ dominantBaseline: "central",
55
+ textAnchor: "middle",
56
+ fill: colorOf(el),
57
+ fontSize: fontOf(el),
58
+ fontFamily: el.fontFamily || "serif",
59
+ fontWeight: el.fontWeight || "normal",
60
+ children: String(el.label || el.value || "")
61
+ }
62
+ ));
63
+ var lineLike = (el, arrow = false) => {
64
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
65
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
66
+ const dashed = el.lineStyle === "dashed" || el.type === "dashed" || el.type === "dashed_line" ? "6 6" : el.lineStyle === "dotted" ? "2 4" : void 0;
67
+ return /* @__PURE__ */ jsxs("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
68
+ /* @__PURE__ */ jsx("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: colorOf(el), strokeWidth: strokeOf(el), strokeDasharray: dashed, strokeLinecap: "round" }),
69
+ arrow && /* @__PURE__ */ jsx("polygon", { points: `${d},0 ${d - 12},-6 ${d - 12},6`, fill: colorOf(el) }),
70
+ el.label && /* @__PURE__ */ jsx("text", { x: d / 2, y: -10, fontSize: fontOf(el), fill: colorOf(el), textAnchor: "middle", children: String(el.label) })
71
+ ] });
72
+ };
73
+ registerRenderer("line", (el) => lineLike(el));
74
+ registerRenderer("dashed", (el) => lineLike({ ...el, lineStyle: "dashed" }));
75
+ registerRenderer("dashed_line", (el) => lineLike({ ...el, lineStyle: "dashed" }));
76
+ registerRenderer("vector", (el) => lineLike(el, true));
77
+ registerRenderer("ray", (el) => lineLike(el, true));
78
+ registerRenderer("wire", (el) => lineLike(el));
79
+ registerRenderer("table_edge", (el) => {
80
+ const minX = Math.min(el.x1, el.x2);
81
+ const maxX = Math.max(el.x1, el.x2);
82
+ const minY = Math.min(el.y1, el.y2);
83
+ const maxY = Math.max(el.y1, el.y2);
84
+ const w = Math.max(1, maxX - minX);
85
+ const h = Math.max(1, maxY - minY);
86
+ const hashes = [];
87
+ const numH = Math.max(2, Math.floor(w / 12));
88
+ const numV = Math.max(2, Math.floor(h / 12));
89
+ for (let j = 0; j <= numH; j++) {
90
+ const x = minX + j / numH * w;
91
+ hashes.push(/* @__PURE__ */ jsx("line", { x1: x, y1: minY, x2: x - 8, y2: minY + 10, stroke: colorOf(el), strokeWidth: 1 }, `h-${j}`));
92
+ }
93
+ for (let j = 0; j <= numV; j++) {
94
+ const y = minY + j / numV * h;
95
+ hashes.push(/* @__PURE__ */ jsx("line", { x1: maxX, y1: y, x2: maxX - 10, y2: y + 8, stroke: colorOf(el), strokeWidth: 1 }, `v-${j}`));
96
+ }
97
+ return /* @__PURE__ */ jsxs("g", { children: [
98
+ /* @__PURE__ */ jsx("polyline", { points: `${minX},${minY} ${maxX},${minY} ${maxX},${maxY}`, fill: "none", stroke: colorOf(el), strokeWidth: strokeOf(el) }),
99
+ hashes,
100
+ el.label && /* @__PURE__ */ jsx("text", { x: minX + w / 2, y: minY - 10, fill: colorOf(el), textAnchor: "middle", fontSize: fontOf(el), children: String(el.label) })
101
+ ] });
102
+ });
103
+
104
+ // src/core/renderers/mechanics.tsx
105
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
106
+ var c = (el) => el.color || "#0f172a";
107
+ var sw = (el) => el.strokeWidth || 2;
108
+ var fo = (el) => el.fillOpacity ?? 0.2;
109
+ registerRenderer("slab", (el) => {
110
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
111
+ const depth = el.curveHeight ?? 20;
112
+ return /* @__PURE__ */ jsxs2("g", { children: [
113
+ /* @__PURE__ */ jsx2("path", { d: `M ${b.minX} ${b.minY} L ${b.maxX} ${b.minY} L ${b.maxX} ${b.maxY} L ${b.minX} ${b.maxY} Z`, fill: c(el), fillOpacity: fo(el), stroke: c(el), strokeWidth: sw(el) }),
114
+ /* @__PURE__ */ jsx2("path", { d: `M ${b.minX} ${b.minY} L ${b.minX + depth} ${b.minY - depth} L ${b.maxX + depth} ${b.minY - depth} L ${b.maxX} ${b.minY} Z`, fill: c(el), fillOpacity: Math.max(0, fo(el) - 0.1), stroke: c(el), strokeWidth: sw(el) }),
115
+ /* @__PURE__ */ jsx2("path", { d: `M ${b.maxX} ${b.minY} L ${b.maxX + depth} ${b.minY - depth} L ${b.maxX + depth} ${b.maxY - depth} L ${b.maxX} ${b.maxY} Z`, fill: c(el), fillOpacity: Math.min(1, fo(el) + 0.1), stroke: c(el), strokeWidth: sw(el) })
116
+ ] });
117
+ });
118
+ registerRenderer("sphere", (el) => {
119
+ const r = Math.max(4, distance(el.x1, el.y1, el.x2, el.y2));
120
+ return /* @__PURE__ */ jsx2("circle", { cx: el.x1, cy: el.y1, r, fill: c(el), fillOpacity: fo(el), stroke: c(el), strokeWidth: sw(el) });
121
+ });
122
+ registerRenderer("shell", (el) => {
123
+ const r = Math.max(10, distance(el.x1, el.y1, el.x2, el.y2));
124
+ const t = el.curveHeight ?? 10;
125
+ const innerR = Math.max(1, r - t);
126
+ return /* @__PURE__ */ jsx2(
127
+ "path",
128
+ {
129
+ d: `M ${el.x1 - r} ${el.y1} A ${r} ${r} 0 1 0 ${el.x1 + r} ${el.y1} A ${r} ${r} 0 1 0 ${el.x1 - r} ${el.y1} Z M ${el.x1 - innerR} ${el.y1} A ${innerR} ${innerR} 0 1 1 ${el.x1 + innerR} ${el.y1} A ${innerR} ${innerR} 0 1 1 ${el.x1 - innerR} ${el.y1} Z`,
130
+ fill: c(el),
131
+ fillOpacity: fo(el),
132
+ fillRule: "evenodd",
133
+ stroke: c(el),
134
+ strokeWidth: sw(el)
135
+ }
136
+ );
137
+ });
138
+ registerRenderer("cylinder", (el) => {
139
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
140
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
141
+ const r = el.curveHeight ?? 20;
142
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
143
+ /* @__PURE__ */ jsx2("path", { d: `M 0 ${-r} L ${d} ${-r} A 10 ${r} 0 0 1 ${d} ${r} L 0 ${r} Z`, fill: c(el), fillOpacity: fo(el) }),
144
+ /* @__PURE__ */ jsx2("path", { d: `M 0 ${-r} L ${d} ${-r} M 0 ${r} L ${d} ${r}`, fill: "none", stroke: c(el), strokeWidth: sw(el) }),
145
+ /* @__PURE__ */ jsx2("ellipse", { cx: d, cy: 0, rx: 10, ry: r, fill: c(el), fillOpacity: fo(el), stroke: c(el), strokeWidth: sw(el) }),
146
+ /* @__PURE__ */ jsx2("ellipse", { cx: 0, cy: 0, rx: 10, ry: r, fill: "none", stroke: c(el), strokeWidth: sw(el), strokeDasharray: "2 4" })
147
+ ] });
148
+ });
149
+ registerRenderer("ladder", (el) => {
150
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
151
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
152
+ const hw = el.curveHeight ?? 10;
153
+ const rungs = [];
154
+ for (let i = 15; i < d - 10; i += 15) {
155
+ rungs.push(/* @__PURE__ */ jsx2("line", { x1: i, y1: -hw, x2: i, y2: hw, stroke: c(el), strokeWidth: Math.max(1, sw(el) - 1) }, i));
156
+ }
157
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
158
+ /* @__PURE__ */ jsx2("line", { x1: 0, y1: -hw, x2: d, y2: -hw, stroke: c(el), strokeWidth: sw(el) }),
159
+ /* @__PURE__ */ jsx2("line", { x1: 0, y1: hw, x2: d, y2: hw, stroke: c(el), strokeWidth: sw(el) }),
160
+ rungs
161
+ ] });
162
+ });
163
+ registerRenderer("spring", (el) => {
164
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
165
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
166
+ const zigCount = Math.max(0, Math.floor(d / 12));
167
+ let path = "M 0 0";
168
+ for (let i = 0; i < zigCount; i++) {
169
+ path += ` L ${i * 12 + 3} 8 L ${i * 12 + 9} -8`;
170
+ }
171
+ path += ` L ${d} 0`;
172
+ return /* @__PURE__ */ jsx2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: /* @__PURE__ */ jsx2("path", { d: path, fill: "none", stroke: c(el), strokeWidth: sw(el), strokeLinejoin: "round" }) });
173
+ });
174
+ registerRenderer("rod", (el) => {
175
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
176
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
177
+ return /* @__PURE__ */ jsx2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: /* @__PURE__ */ jsx2("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c(el), strokeWidth: Math.max(4, sw(el)), strokeLinecap: "round" }) });
178
+ });
179
+ registerRenderer("arc_arrow", (el) => {
180
+ const r = Math.max(8, distance(el.x1, el.y1, el.x2, el.y2));
181
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
182
+ /* @__PURE__ */ jsx2("path", { d: `M ${r} 0 A ${r} ${r} 0 0 0 ${-r} 0`, fill: "none", stroke: c(el), strokeWidth: sw(el) }),
183
+ /* @__PURE__ */ jsx2("polygon", { points: `${-r},2 ${-r - 6},-10 ${-r + 6},-10`, fill: c(el) })
184
+ ] });
185
+ });
186
+ registerRenderer("lens_convex", (el) => {
187
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
188
+ const cx = b.minX + b.width / 2;
189
+ return /* @__PURE__ */ jsx2("ellipse", { cx, cy: b.minY + b.height / 2, rx: Math.max(6, b.width / 2), ry: b.height / 2, fill: c(el), fillOpacity: Math.max(0.15, fo(el)), stroke: c(el), strokeWidth: sw(el) });
190
+ });
191
+ registerRenderer("lens_concave", (el) => {
192
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
193
+ const cx = b.minX + b.width / 2;
194
+ const rx = Math.max(6, b.width / 2);
195
+ const ry = b.height / 2;
196
+ return /* @__PURE__ */ jsx2(
197
+ "path",
198
+ {
199
+ d: `M ${cx - rx} ${b.minY} Q ${cx - rx * 0.2} ${b.minY + ry} ${cx - rx} ${b.maxY} M ${cx + rx} ${b.minY} Q ${cx + rx * 0.2} ${b.minY + ry} ${cx + rx} ${b.maxY}`,
200
+ fill: "none",
201
+ stroke: c(el),
202
+ strokeWidth: sw(el)
203
+ }
204
+ );
205
+ });
206
+ registerRenderer("mirror_concave", (el) => {
207
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
208
+ const ch = el.curveHeight ?? 40;
209
+ return /* @__PURE__ */ jsx2("path", { d: `M ${b.minX} ${b.minY} Q ${b.maxX + ch} ${b.minY + b.height / 2} ${b.minX} ${b.maxY}`, fill: "none", stroke: c(el), strokeWidth: sw(el) });
210
+ });
211
+ registerRenderer("mirror_convex", (el) => {
212
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
213
+ const ch = el.curveHeight ?? 40;
214
+ const midY = b.minY + b.height / 2;
215
+ return /* @__PURE__ */ jsx2("path", { d: `M ${b.minX} ${b.minY} Q ${b.minX - ch} ${midY} ${b.minX} ${b.maxY}`, fill: "none", stroke: c(el), strokeWidth: sw(el) });
216
+ });
217
+ registerRenderer("prism", (el) => {
218
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
219
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
220
+ const py = -d * 0.866;
221
+ const fs = el.fontSize || 16;
222
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
223
+ /* @__PURE__ */ jsx2("polygon", { points: `0,0 ${d},0 ${d / 2},${py}`, fill: c(el), fillOpacity: Math.max(0.15, fo(el)), stroke: c(el), strokeWidth: sw(el), strokeLinejoin: "round" }),
224
+ el.label && /* @__PURE__ */ jsx2("text", { x: d / 2, y: py - 10, fontSize: fs, fill: c(el), textAnchor: "middle", children: String(el.label) })
225
+ ] });
226
+ });
227
+ registerRenderer("slit_single", (el) => {
228
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
229
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
230
+ const gap = 16;
231
+ const thick = Math.max(4, sw(el));
232
+ const fs = el.fontSize || 16;
233
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
234
+ /* @__PURE__ */ jsx2("line", { x1: 0, y1: 0, x2: d / 2 - gap / 2, y2: 0, stroke: c(el), strokeWidth: thick, strokeLinecap: "square" }),
235
+ /* @__PURE__ */ jsx2("line", { x1: d / 2 + gap / 2, y1: 0, x2: d, y2: 0, stroke: c(el), strokeWidth: thick, strokeLinecap: "square" }),
236
+ el.label && /* @__PURE__ */ jsx2("text", { x: d / 2, y: -14, fontSize: fs, fill: c(el), textAnchor: "middle", children: String(el.label) })
237
+ ] });
238
+ });
239
+ registerRenderer("slit_double", (el) => {
240
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
241
+ const cx = b.minX + b.width / 2;
242
+ return /* @__PURE__ */ jsxs2("g", { children: [
243
+ /* @__PURE__ */ jsx2("line", { x1: cx - 6, y1: b.minY, x2: cx - 6, y2: b.maxY, stroke: c(el), strokeWidth: sw(el) }),
244
+ /* @__PURE__ */ jsx2("line", { x1: cx + 6, y1: b.minY, x2: cx + 6, y2: b.maxY, stroke: c(el), strokeWidth: sw(el) })
245
+ ] });
246
+ });
247
+ registerRenderer("photon", (el) => {
248
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
249
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
250
+ const amp = 6;
251
+ const waves = Math.max(3, Math.floor(d / 24));
252
+ const step = d / (waves * 2);
253
+ let path = "M 0 0 ";
254
+ for (let i = 0; i < waves * 2; i++) {
255
+ const x = (i + 1) * step;
256
+ const y = i % 2 === 0 ? -amp : amp;
257
+ path += `L ${x} ${y} `;
258
+ }
259
+ path += `L ${d} 0`;
260
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
261
+ /* @__PURE__ */ jsx2("path", { d: path, fill: "none", stroke: c(el), strokeWidth: sw(el) }),
262
+ el.label && /* @__PURE__ */ jsx2("text", { x: d / 2, y: -12, textAnchor: "middle", fill: c(el), children: String(el.label) })
263
+ ] });
264
+ });
265
+ registerRenderer("glass_slab", (el) => {
266
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
267
+ return /* @__PURE__ */ jsx2("rect", { x: b.minX, y: b.minY, width: b.width, height: b.height, fill: c(el), fillOpacity: Math.max(0.1, fo(el)), stroke: c(el), strokeWidth: sw(el) });
268
+ });
269
+ registerRenderer("pipe", (el) => {
270
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
271
+ const neck = el.curveHeight ?? b.height * 0.35;
272
+ return /* @__PURE__ */ jsx2(
273
+ "path",
274
+ {
275
+ d: `M ${b.minX} ${b.minY} C ${b.minX + b.width * 0.3} ${b.minY}, ${b.minX + b.width * 0.3} ${b.minY + neck}, ${b.minX + b.width * 0.5} ${b.minY + neck} C ${b.minX + b.width * 0.7} ${b.minY + neck}, ${b.minX + b.width * 0.7} ${b.minY}, ${b.maxX} ${b.minY} L ${b.maxX} ${b.maxY} C ${b.minX + b.width * 0.7} ${b.maxY}, ${b.minX + b.width * 0.7} ${b.maxY - neck}, ${b.minX + b.width * 0.5} ${b.maxY - neck} C ${b.minX + b.width * 0.3} ${b.maxY - neck}, ${b.minX + b.width * 0.3} ${b.maxY}, ${b.minX} ${b.maxY} Z`,
276
+ fill: c(el),
277
+ fillOpacity: fo(el),
278
+ stroke: c(el),
279
+ strokeWidth: sw(el)
280
+ }
281
+ );
282
+ });
283
+ registerRenderer("liquid", (el) => {
284
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
285
+ return /* @__PURE__ */ jsxs2("g", { children: [
286
+ /* @__PURE__ */ jsx2("path", { d: `M ${b.minX} ${b.minY} Q ${b.minX + b.width / 2} ${b.minY + 10} ${b.maxX} ${b.minY} L ${b.maxX} ${b.maxY} L ${b.minX} ${b.maxY} Z`, fill: c(el), fillOpacity: Math.max(0.2, fo(el)) }),
287
+ /* @__PURE__ */ jsx2("path", { d: `M ${b.minX} ${b.minY} Q ${b.minX + b.width / 2} ${b.minY + 10} ${b.maxX} ${b.minY}`, fill: "none", stroke: c(el), strokeWidth: 2 })
288
+ ] });
289
+ });
290
+ registerRenderer("orbit", (el) => {
291
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
292
+ return /* @__PURE__ */ jsx2("ellipse", { cx: b.minX + b.width / 2, cy: b.minY + b.height / 2, rx: b.width / 2, ry: b.height / 2, fill: "none", stroke: c(el), strokeWidth: sw(el), strokeDasharray: "3 3" });
293
+ });
294
+ registerRenderer("pole_piece", (el) => {
295
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
296
+ const poleLabel = String(el.label || "N");
297
+ const isNorth = poleLabel.toUpperCase().includes("N");
298
+ const blockFill = isNorth ? "#ef4444" : "#3b82f6";
299
+ const labelFs = Math.min(b.width, b.height) * 0.5 + 10;
300
+ return /* @__PURE__ */ jsxs2("g", { children: [
301
+ /* @__PURE__ */ jsx2("rect", { x: b.minX, y: b.minY, width: b.width, height: b.height, fill: blockFill, fillOpacity: 0.2, stroke: c(el), strokeWidth: sw(el), rx: "4" }),
302
+ /* @__PURE__ */ jsx2("text", { x: b.minX + b.width / 2, y: b.minY + b.height / 2, textAnchor: "middle", dominantBaseline: "central", fill: c(el), fontWeight: "bold", fontSize: labelFs, children: poleLabel })
303
+ ] });
304
+ });
305
+ registerRenderer("b_field_line", (el) => {
306
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
307
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
308
+ const fs = el.fontSize || 18;
309
+ const mid = d / 2;
310
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
311
+ /* @__PURE__ */ jsx2("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c(el), strokeWidth: sw(el), strokeLinecap: "round" }),
312
+ /* @__PURE__ */ jsx2("polygon", { points: `${mid + 6},0 ${mid - 6},-5 ${mid - 6},5`, fill: c(el) }),
313
+ el.label ? /* @__PURE__ */ jsx2("text", { x: mid, y: -10, textAnchor: "middle", fill: c(el), fontSize: fs, children: String(el.label) }) : null
314
+ ] });
315
+ });
316
+ registerRenderer("b_field_curve", (el) => {
317
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
318
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
319
+ const curveHeight = el.curveHeight !== void 0 ? el.curveHeight : d * 0.4;
320
+ const fs = el.fontSize || 18;
321
+ const apexY = -curveHeight;
322
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
323
+ /* @__PURE__ */ jsx2(
324
+ "path",
325
+ {
326
+ d: `M 0 0 Q ${d / 2} ${-curveHeight * 2} ${d} 0`,
327
+ fill: "none",
328
+ stroke: c(el),
329
+ strokeWidth: sw(el),
330
+ strokeLinecap: "round"
331
+ }
332
+ ),
333
+ /* @__PURE__ */ jsx2("polygon", { points: `${d / 2 + 6},${apexY} ${d / 2 - 6},${apexY - 5} ${d / 2 - 6},${apexY + 5}`, fill: c(el) }),
334
+ el.label ? /* @__PURE__ */ jsx2("text", { x: d / 2, y: apexY - 15, textAnchor: "middle", fill: c(el), fontSize: fs, children: String(el.label) }) : null
335
+ ] });
336
+ });
337
+ registerRenderer("axes_3d", (el) => /* @__PURE__ */ jsxs2("g", { children: [
338
+ /* @__PURE__ */ jsx2("line", { x1: el.x1, y1: el.y1, x2: el.x1 + 100, y2: el.y1, stroke: c(el), strokeWidth: sw(el) }),
339
+ /* @__PURE__ */ jsx2("line", { x1: el.x1, y1: el.y1, x2: el.x1, y2: el.y1 - 100, stroke: c(el), strokeWidth: sw(el) }),
340
+ /* @__PURE__ */ jsx2("line", { x1: el.x1, y1: el.y1, x2: el.x1 + 70, y2: el.y1 + 50, stroke: c(el), strokeWidth: sw(el) })
341
+ ] }));
342
+ registerRenderer("wedge", (el) => {
343
+ const dx = el.x2 - el.x1;
344
+ const dy = el.y2 - el.y1;
345
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
346
+ /* @__PURE__ */ jsx2("polygon", { points: `0,0 ${dx},0 ${dx},${dy}`, fill: "#f1f5f9", stroke: c(el), strokeWidth: sw(el), strokeLinejoin: "round" }),
347
+ el.label ? /* @__PURE__ */ jsx2(
348
+ "text",
349
+ {
350
+ x: dx * 0.6,
351
+ y: dy * 0.3,
352
+ dominantBaseline: "central",
353
+ textAnchor: "middle",
354
+ fill: c(el),
355
+ fontSize: 20,
356
+ fontFamily: "serif",
357
+ fontWeight: "bold",
358
+ children: String(el.label)
359
+ }
360
+ ) : null
361
+ ] });
362
+ });
363
+ registerRenderer("dimension", (el) => {
364
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
365
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
366
+ const w = Math.max(1, sw(el) - 0.5);
367
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
368
+ /* @__PURE__ */ jsx2("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c(el), strokeWidth: w, strokeDasharray: "4 4" }),
369
+ /* @__PURE__ */ jsx2("polygon", { points: `0,0 10,-5 10,5`, fill: c(el) }),
370
+ /* @__PURE__ */ jsx2("polygon", { points: `${d},0 ${d - 10},-5 ${d - 10},5`, fill: c(el) }),
371
+ el.label ? /* @__PURE__ */ jsx2("text", { x: d / 2, y: -10, textAnchor: "middle", fill: c(el), fontSize: 18, fontFamily: "serif", fontStyle: "italic", fontWeight: "bold", children: String(el.label) }) : null
372
+ ] });
373
+ });
374
+ registerRenderer("arc", (el) => {
375
+ const dx = el.x2 - el.x1;
376
+ const dy = el.y2 - el.y1;
377
+ const d = Math.hypot(dx, dy);
378
+ const angleDegVal = Math.atan2(dy, dx) * 180 / Math.PI;
379
+ const R = Math.min(d, 40);
380
+ const sweepFlag = dy > 0 ? 1 : 0;
381
+ const startX = R;
382
+ const startY = 0;
383
+ const endX = R * Math.cos(angleDegVal * Math.PI / 180);
384
+ const endY = R * Math.sin(angleDegVal * Math.PI / 180);
385
+ const midAngle = angleDegVal / 2;
386
+ const textDist = R + 15;
387
+ const tx = textDist * Math.cos(midAngle * Math.PI / 180);
388
+ const ty = textDist * Math.sin(midAngle * Math.PI / 180);
389
+ const refLen = Math.max(d, 50);
390
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
391
+ /* @__PURE__ */ jsx2("line", { x1: 0, y1: 0, x2: refLen, y2: 0, stroke: c(el), strokeWidth: 1.5, strokeDasharray: "4 4" }),
392
+ /* @__PURE__ */ jsx2("path", { d: `M ${startX} ${startY} A ${R} ${R} 0 0 ${sweepFlag} ${endX} ${endY}`, fill: "none", stroke: c(el), strokeWidth: sw(el) }),
393
+ el.label ? /* @__PURE__ */ jsx2(
394
+ "text",
395
+ {
396
+ x: tx,
397
+ y: ty,
398
+ dominantBaseline: "central",
399
+ textAnchor: "middle",
400
+ fill: c(el),
401
+ fontSize: 16,
402
+ fontFamily: "serif",
403
+ fontStyle: "italic",
404
+ fontWeight: "bold",
405
+ children: String(el.label)
406
+ }
407
+ ) : null
408
+ ] });
409
+ });
410
+ registerRenderer("nucleus", (el) => {
411
+ const fs = el.fontSize || 18;
412
+ const stroke2 = c(el);
413
+ const w = sw(el);
414
+ return /* @__PURE__ */ jsxs2("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
415
+ /* @__PURE__ */ jsx2("ellipse", { cx: 0, cy: 0, rx: 24, ry: 8, fill: "none", stroke: stroke2, strokeWidth: w, transform: "rotate(30)" }),
416
+ /* @__PURE__ */ jsx2("ellipse", { cx: 0, cy: 0, rx: 24, ry: 8, fill: "none", stroke: stroke2, strokeWidth: w, transform: "rotate(-30)" }),
417
+ /* @__PURE__ */ jsx2("ellipse", { cx: 0, cy: 0, rx: 24, ry: 8, fill: "none", stroke: stroke2, strokeWidth: w, transform: "rotate(90)" }),
418
+ /* @__PURE__ */ jsx2("circle", { cx: 0, cy: 0, r: 6, fill: "#ef4444" }),
419
+ el.label && /* @__PURE__ */ jsx2("text", { x: 0, y: 36, fontSize: fs, fill: stroke2, textAnchor: "middle", children: String(el.label) })
420
+ ] });
421
+ });
422
+ ["cone", "curved_wedge", "incline", "container", "hinge"].forEach(
423
+ (t) => registerRenderer(t, (el) => {
424
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
425
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
426
+ return /* @__PURE__ */ jsx2("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: /* @__PURE__ */ jsx2("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c(el), strokeWidth: sw(el) }) });
427
+ })
428
+ );
429
+ ["semicircle", "quarter_circle", "axes"].forEach(
430
+ (t) => registerRenderer(t, (el) => {
431
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
432
+ return /* @__PURE__ */ jsx2("rect", { x: b.minX, y: b.minY, width: b.width, height: b.height, fill: "none", stroke: c(el), strokeWidth: sw(el) });
433
+ })
434
+ );
435
+
436
+ // src/core/renderers/magnetism.tsx
437
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
438
+ var c2 = (el) => el.color || "#0f172a";
439
+ var sw2 = (el) => el.strokeWidth || 2;
440
+ var fontSizeOf = (el) => el.fontSize || 18;
441
+ var dashOf = (el) => el.lineStyle === "dashed" || el.type === "dashed_line" ? "6 6" : el.lineStyle === "dotted" ? "2 4" : void 0;
442
+ registerRenderer("b_region_in", (el) => {
443
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
444
+ const minX = b.minX;
445
+ const maxX = b.maxX;
446
+ const minY = b.minY;
447
+ const maxY = b.maxY;
448
+ const midX = (minX + maxX) / 2;
449
+ const spacing = 40;
450
+ const markR = 6;
451
+ const marks = [];
452
+ for (let px = minX + spacing / 2; px <= maxX; px += spacing) {
453
+ for (let py = minY + spacing / 2; py <= maxY; py += spacing) {
454
+ marks.push(
455
+ /* @__PURE__ */ jsxs3("g", { transform: `translate(${px}, ${py})`, children: [
456
+ /* @__PURE__ */ jsx3("circle", { cx: 0, cy: 0, r: markR, fill: "none", stroke: c2(el), strokeWidth: sw2(el) * 0.75 }),
457
+ /* @__PURE__ */ jsx3("line", { x1: -markR * 0.7, y1: -markR * 0.7, x2: markR * 0.7, y2: markR * 0.7, stroke: c2(el), strokeWidth: sw2(el) * 0.75 }),
458
+ /* @__PURE__ */ jsx3("line", { x1: markR * 0.7, y1: -markR * 0.7, x2: -markR * 0.7, y2: markR * 0.7, stroke: c2(el), strokeWidth: sw2(el) * 0.75 })
459
+ ] }, `${px}-${py}`)
460
+ );
461
+ }
462
+ }
463
+ return /* @__PURE__ */ jsxs3("g", { children: [
464
+ /* @__PURE__ */ jsx3("rect", { x: minX, y: minY, width: b.width, height: b.height, fill: c2(el), stroke: c2(el), strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.1 }),
465
+ marks,
466
+ el.label ? /* @__PURE__ */ jsx3("text", { x: midX, y: minY - 10, fontSize: fontSizeOf(el), fill: c2(el), textAnchor: "middle", fontWeight: "bold", children: String(el.label) }) : null
467
+ ] });
468
+ });
469
+ registerRenderer("b_region_out", (el) => {
470
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
471
+ const minX = b.minX;
472
+ const maxX = b.maxX;
473
+ const minY = b.minY;
474
+ const maxY = b.maxY;
475
+ const midX = (minX + maxX) / 2;
476
+ const spacing = 40;
477
+ const markR = 6;
478
+ const marks = [];
479
+ for (let px = minX + spacing / 2; px <= maxX; px += spacing) {
480
+ for (let py = minY + spacing / 2; py <= maxY; py += spacing) {
481
+ marks.push(
482
+ /* @__PURE__ */ jsxs3("g", { transform: `translate(${px}, ${py})`, children: [
483
+ /* @__PURE__ */ jsx3("circle", { cx: 0, cy: 0, r: markR, fill: "none", stroke: c2(el), strokeWidth: sw2(el) * 0.75 }),
484
+ /* @__PURE__ */ jsx3("circle", { cx: 0, cy: 0, r: 2, fill: c2(el) })
485
+ ] }, `${px}-${py}`)
486
+ );
487
+ }
488
+ }
489
+ return /* @__PURE__ */ jsxs3("g", { children: [
490
+ /* @__PURE__ */ jsx3("rect", { x: minX, y: minY, width: b.width, height: b.height, fill: c2(el), stroke: c2(el), strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.1 }),
491
+ marks,
492
+ el.label ? /* @__PURE__ */ jsx3("text", { x: midX, y: minY - 10, fontSize: fontSizeOf(el), fill: c2(el), textAnchor: "middle", fontWeight: "bold", children: String(el.label) }) : null
493
+ ] });
494
+ });
495
+ registerRenderer("current_wire", (el) => {
496
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
497
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
498
+ const mid = d / 2;
499
+ const flip = angle > 90 || angle <= -90;
500
+ return /* @__PURE__ */ jsxs3("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
501
+ /* @__PURE__ */ jsx3("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c2(el), strokeWidth: sw2(el), strokeDasharray: dashOf(el), strokeLinecap: "round" }),
502
+ /* @__PURE__ */ jsx3("polygon", { points: `${mid + 8},0 ${mid - 6},-7 ${mid - 6},7`, fill: c2(el) }),
503
+ el.label ? /* @__PURE__ */ jsx3(
504
+ "text",
505
+ {
506
+ x: mid,
507
+ y: -15,
508
+ fontSize: fontSizeOf(el),
509
+ fill: c2(el),
510
+ textAnchor: "middle",
511
+ fontStyle: "italic",
512
+ transform: flip ? `rotate(180, ${mid}, -15)` : void 0,
513
+ children: String(el.label)
514
+ }
515
+ ) : null
516
+ ] });
517
+ });
518
+ registerRenderer("bar_magnet", (el) => {
519
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
520
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
521
+ const magW = Math.max(20, sw2(el) * 10);
522
+ const flipLabel = angle > 90 || angle <= -90;
523
+ return /* @__PURE__ */ jsxs3("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
524
+ /* @__PURE__ */ jsx3("rect", { x: 0, y: -magW / 2, width: d / 2, height: magW, fill: "#ef4444", stroke: c2(el), strokeWidth: 1 }),
525
+ /* @__PURE__ */ jsx3("rect", { x: d / 2, y: -magW / 2, width: d / 2, height: magW, fill: "#3b82f6", stroke: c2(el), strokeWidth: 1 }),
526
+ /* @__PURE__ */ jsx3(
527
+ "text",
528
+ {
529
+ x: d / 4,
530
+ y: 0,
531
+ fill: "white",
532
+ fontSize: magW * 0.6,
533
+ fontWeight: "bold",
534
+ textAnchor: "middle",
535
+ dominantBaseline: "central",
536
+ transform: flipLabel ? `rotate(180, ${d / 4}, 0)` : void 0,
537
+ children: "N"
538
+ }
539
+ ),
540
+ /* @__PURE__ */ jsx3(
541
+ "text",
542
+ {
543
+ x: d * 0.75,
544
+ y: 0,
545
+ fill: "white",
546
+ fontSize: magW * 0.6,
547
+ fontWeight: "bold",
548
+ textAnchor: "middle",
549
+ dominantBaseline: "central",
550
+ transform: flipLabel ? `rotate(180, ${d * 0.75}, 0)` : void 0,
551
+ children: "S"
552
+ }
553
+ ),
554
+ el.label ? /* @__PURE__ */ jsx3(
555
+ "text",
556
+ {
557
+ x: d / 2,
558
+ y: -magW / 2 - 10,
559
+ fill: c2(el),
560
+ fontSize: fontSizeOf(el),
561
+ textAnchor: "middle",
562
+ transform: flipLabel ? `rotate(180, ${d / 2}, ${-magW / 2 - 10})` : void 0,
563
+ children: String(el.label)
564
+ }
565
+ ) : null
566
+ ] });
567
+ });
568
+ registerRenderer("coil", (el) => {
569
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
570
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
571
+ const coils = Math.max(Math.floor(d / 15), 1);
572
+ let dPath = "M 0 0 ";
573
+ for (let i = 1; i <= coils; i++) {
574
+ dPath += `C ${i * (d / coils) - d / (coils * 2)} -15, ${i * (d / coils)} 20, ${i * (d / coils)} 0 `;
575
+ }
576
+ const flip = angle > 90 || angle <= -90;
577
+ return /* @__PURE__ */ jsxs3("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
578
+ /* @__PURE__ */ jsx3("path", { d: dPath, fill: "none", stroke: c2(el), strokeWidth: sw2(el), strokeLinejoin: "round" }),
579
+ el.label ? /* @__PURE__ */ jsx3(
580
+ "text",
581
+ {
582
+ x: d / 2,
583
+ y: -20,
584
+ fontSize: fontSizeOf(el),
585
+ fill: c2(el),
586
+ textAnchor: "middle",
587
+ transform: flip ? `rotate(180, ${d / 2}, -20)` : void 0,
588
+ children: String(el.label)
589
+ }
590
+ ) : null
591
+ ] });
592
+ });
593
+ registerRenderer("meter", (el) => {
594
+ const r = Math.max(16, sw2(el) * 5);
595
+ const label = String(el.label || "G");
596
+ return /* @__PURE__ */ jsxs3("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
597
+ /* @__PURE__ */ jsx3("circle", { cx: 0, cy: 0, r, fill: "white", stroke: c2(el), strokeWidth: sw2(el) }),
598
+ /* @__PURE__ */ jsx3("text", { x: 0, y: 0, fontSize: fontSizeOf(el), fill: c2(el), fontWeight: "bold", textAnchor: "middle", dominantBaseline: "central", children: label })
599
+ ] });
600
+ });
601
+ registerRenderer("ac_source", (el) => {
602
+ const r = Math.max(16, sw2(el) * 5);
603
+ return /* @__PURE__ */ jsxs3("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
604
+ /* @__PURE__ */ jsx3("circle", { cx: 0, cy: 0, r, fill: "white", stroke: c2(el), strokeWidth: sw2(el) }),
605
+ /* @__PURE__ */ jsx3(
606
+ "path",
607
+ {
608
+ d: `M ${-r * 0.6} 0 Q ${-r * 0.3} ${-r * 0.6} 0 0 T ${r * 0.6} 0`,
609
+ fill: "none",
610
+ stroke: c2(el),
611
+ strokeWidth: sw2(el) * 0.8
612
+ }
613
+ ),
614
+ el.label ? /* @__PURE__ */ jsx3("text", { x: 0, y: r + 18, fontSize: fontSizeOf(el), fill: c2(el), textAnchor: "middle", children: String(el.label) }) : null
615
+ ] });
616
+ });
617
+ registerRenderer("bezier", (el) => {
618
+ const { x1, y1, x2, y2 } = el;
619
+ const cps = el.cps?.length ? el.cps : [{ x: (x1 + x2) / 2, y: Math.min(y1, y2) - 50 }];
620
+ const cp0 = cps[0];
621
+ const dPath = `M ${x1} ${y1} Q ${cp0.x} ${cp0.y} ${x2} ${y2}`;
622
+ const labelX = 0.25 * x1 + 0.5 * cp0.x + 0.25 * x2;
623
+ const labelY = 0.25 * y1 + 0.5 * cp0.y + 0.25 * y2;
624
+ const angleRad = Math.atan2(y2 - y1, x2 - x1);
625
+ const showArrow = Boolean(el.showArrow);
626
+ return /* @__PURE__ */ jsxs3("g", { children: [
627
+ /* @__PURE__ */ jsx3("path", { d: dPath, fill: "none", stroke: "transparent", strokeWidth: 24, strokeLinecap: "round", strokeLinejoin: "round" }),
628
+ /* @__PURE__ */ jsx3("path", { d: dPath, fill: "none", stroke: c2(el), strokeWidth: sw2(el), strokeDasharray: dashOf(el), strokeLinecap: "round", strokeLinejoin: "round" }),
629
+ showArrow ? /* @__PURE__ */ jsx3("g", { transform: `translate(${labelX}, ${labelY}) rotate(${angleRad * 180 / Math.PI})`, children: /* @__PURE__ */ jsx3("polygon", { points: "6,0 -6,-5 -6,5", fill: c2(el) }) }) : null,
630
+ el.label ? /* @__PURE__ */ jsx3("text", { x: labelX, y: labelY - 14, fontSize: fontSizeOf(el), fill: c2(el), textAnchor: "middle", children: String(el.label) }) : null
631
+ ] });
632
+ });
633
+
634
+ // src/core/renderers/graph.tsx
635
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
636
+ var colorOf2 = (el) => el.color || "#0f172a";
637
+ var strokeOf2 = (el) => el.strokeWidth || 2;
638
+ var fontOf2 = (el) => el.fontSize || 16;
639
+ var dashOf2 = (el) => {
640
+ if (el.lineStyle === "dashed" || el.type === "dashed_line" || el.type === "dashed") return "6 6";
641
+ if (el.lineStyle === "dotted") return "2 4";
642
+ return void 0;
643
+ };
644
+ var op = (ctx) => ctx?.isGhost ? 0.5 : 1;
645
+ registerRenderer("axes", (el, ctx) => {
646
+ const minX = Math.min(el.x1, el.x2);
647
+ const maxX = Math.max(el.x1, el.x2);
648
+ const minY = Math.min(el.y1, el.y2);
649
+ const maxY = Math.max(el.y1, el.y2);
650
+ const midX = (minX + maxX) / 2;
651
+ const midY = (minY + maxY) / 2;
652
+ const w = Math.max(1, maxX - minX);
653
+ const h = Math.max(1, maxY - minY);
654
+ const c7 = colorOf2(el);
655
+ const sw7 = strokeOf2(el);
656
+ const dash = dashOf2(el);
657
+ if (maxX - minX <= 1 && maxY - minY <= 1) {
658
+ const cx = el.x1;
659
+ const cy = el.y1;
660
+ const arm = 40;
661
+ const fs = fontOf2(el);
662
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
663
+ /* @__PURE__ */ jsx4("line", { x1: cx, y1: cy, x2: cx + arm, y2: cy, stroke: c7, strokeWidth: sw7 }),
664
+ /* @__PURE__ */ jsx4("polygon", { points: `${cx + arm},${cy} ${cx + arm - 8},${cy - 5} ${cx + arm - 8},${cy + 5}`, fill: c7 }),
665
+ /* @__PURE__ */ jsx4(
666
+ "text",
667
+ {
668
+ x: cx + arm + 10,
669
+ y: cy,
670
+ dominantBaseline: "central",
671
+ textAnchor: "middle",
672
+ fill: c7,
673
+ fontSize: fs,
674
+ fontFamily: "serif",
675
+ fontStyle: "italic",
676
+ children: "x"
677
+ }
678
+ ),
679
+ /* @__PURE__ */ jsx4("line", { x1: cx, y1: cy, x2: cx, y2: cy - arm, stroke: c7, strokeWidth: sw7 }),
680
+ /* @__PURE__ */ jsx4("polygon", { points: `${cx},${cy - arm} ${cx - 5},${cy - arm + 8} ${cx + 5},${cy - arm + 8}`, fill: c7 }),
681
+ /* @__PURE__ */ jsx4(
682
+ "text",
683
+ {
684
+ x: cx,
685
+ y: cy - arm - 12,
686
+ dominantBaseline: "central",
687
+ textAnchor: "middle",
688
+ fill: c7,
689
+ fontSize: fs,
690
+ fontFamily: "serif",
691
+ fontStyle: "italic",
692
+ children: "y"
693
+ }
694
+ ),
695
+ /* @__PURE__ */ jsx4("circle", { cx, cy, r: 2, fill: c7 })
696
+ ] });
697
+ }
698
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
699
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
700
+ /* @__PURE__ */ jsxs4("g", { pointerEvents: "none", children: [
701
+ /* @__PURE__ */ jsx4("line", { x1: midX, y1: minY, x2: midX, y2: maxY, stroke: c7, strokeWidth: sw7, strokeDasharray: dash, opacity: 0.8 }),
702
+ /* @__PURE__ */ jsx4("line", { x1: minX, y1: midY, x2: maxX, y2: midY, stroke: c7, strokeWidth: sw7, strokeDasharray: dash, opacity: 0.8 }),
703
+ /* @__PURE__ */ jsx4("polygon", { points: `${maxX},${midY} ${maxX - 10},${midY - 5} ${maxX - 10},${midY + 5}`, fill: c7, opacity: 0.8 }),
704
+ /* @__PURE__ */ jsx4("polygon", { points: `${midX},${minY} ${midX - 5},${minY + 10} ${midX + 5},${minY + 10}`, fill: c7, opacity: 0.8 })
705
+ ] })
706
+ ] });
707
+ });
708
+ registerRenderer("circle", (el, ctx) => {
709
+ const r = distance(el.x1, el.y1, el.x2, el.y2);
710
+ const c7 = colorOf2(el);
711
+ const sw7 = strokeOf2(el);
712
+ const dash = dashOf2(el);
713
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
714
+ /* @__PURE__ */ jsx4("circle", { cx: el.x1, cy: el.y1, r, fill: "none", stroke: c7, strokeWidth: sw7, strokeDasharray: dash, pointerEvents: "none" }),
715
+ /* @__PURE__ */ jsx4("circle", { cx: el.x1, cy: el.y1, r, fill: "transparent", stroke: "transparent", strokeWidth: 20 })
716
+ ] });
717
+ });
718
+ registerRenderer("ellipse", (el, ctx) => {
719
+ const minX = Math.min(el.x1, el.x2);
720
+ const maxX = Math.max(el.x1, el.x2);
721
+ const minY = Math.min(el.y1, el.y2);
722
+ const maxY = Math.max(el.y1, el.y2);
723
+ const midX = (minX + maxX) / 2;
724
+ const midY = (minY + maxY) / 2;
725
+ const w = Math.max(1, maxX - minX);
726
+ const h = Math.max(1, maxY - minY);
727
+ const c7 = colorOf2(el);
728
+ const sw7 = strokeOf2(el);
729
+ const dash = dashOf2(el);
730
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
731
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
732
+ /* @__PURE__ */ jsx4("ellipse", { cx: midX, cy: midY, rx: w / 2, ry: h / 2, fill: "none", stroke: c7, strokeWidth: sw7, strokeDasharray: dash, pointerEvents: "none" })
733
+ ] });
734
+ });
735
+ registerRenderer("rectangle", (el, ctx) => {
736
+ const b = getBounds(el.x1, el.y1, el.x2, el.y2);
737
+ const c7 = colorOf2(el);
738
+ const sw7 = strokeOf2(el);
739
+ const dash = dashOf2(el);
740
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
741
+ /* @__PURE__ */ jsx4("rect", { x: b.minX, y: b.minY, width: b.width, height: b.height, fill: "transparent" }),
742
+ /* @__PURE__ */ jsx4(
743
+ "rect",
744
+ {
745
+ x: b.minX,
746
+ y: b.minY,
747
+ width: b.width,
748
+ height: b.height,
749
+ fill: "none",
750
+ stroke: c7,
751
+ strokeWidth: sw7,
752
+ strokeDasharray: dash,
753
+ strokeLinejoin: "round",
754
+ pointerEvents: "none"
755
+ }
756
+ )
757
+ ] });
758
+ });
759
+ registerRenderer("angle", (el, ctx) => {
760
+ const { x1, y1, x2, y2 } = el;
761
+ const dx = x2 - x1;
762
+ const dy = y2 - y1;
763
+ const dist = Math.hypot(dx, dy);
764
+ const minX = Math.min(x1, x2);
765
+ const maxX = Math.max(x1, x2);
766
+ const minY = Math.min(y1, y2);
767
+ const maxY = Math.max(y1, y2);
768
+ const w = Math.max(1, maxX - minX);
769
+ const h = Math.max(1, maxY - minY);
770
+ const c7 = colorOf2(el);
771
+ const sw7 = strokeOf2(el);
772
+ const dash = dashOf2(el);
773
+ const fs = fontOf2(el);
774
+ const angleRad = Math.atan2(dy, dx);
775
+ const r = dist;
776
+ const arcR = Math.min(r * 0.4, 40);
777
+ const hDir = dx >= 0 ? 1 : -1;
778
+ const baseA = hDir === 1 ? 0 : Math.PI;
779
+ let diff = angleRad - baseA;
780
+ diff = Math.atan2(Math.sin(diff), Math.cos(diff));
781
+ const midA = baseA + diff / 2;
782
+ const sweepFlag = diff > 0 ? 1 : 0;
783
+ const arcStartX = x1 + arcR * Math.cos(baseA);
784
+ const arcStartY = y1 + arcR * Math.sin(baseA);
785
+ const arcEndX = x1 + arcR * Math.cos(angleRad);
786
+ const arcEndY = y1 + arcR * Math.sin(angleRad);
787
+ const deg = angleRad * 180 / Math.PI;
788
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
789
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
790
+ /* @__PURE__ */ jsxs4("g", { pointerEvents: "none", children: [
791
+ /* @__PURE__ */ jsx4("line", { x1, y1, x2: x1 + dx, y2: y1, stroke: c7, strokeWidth: sw7, strokeDasharray: "4 4", opacity: 0.6 }),
792
+ /* @__PURE__ */ jsx4("line", { x1, y1, x2, y2, stroke: c7, strokeWidth: sw7, strokeLinecap: "round", strokeDasharray: dash }),
793
+ /* @__PURE__ */ jsx4("g", { transform: `translate(${x2}, ${y2}) rotate(${deg})`, children: /* @__PURE__ */ jsx4("polygon", { points: "0,0 -12,-6 -12,6", fill: c7 }) }),
794
+ dist > 20 && /* @__PURE__ */ jsx4(
795
+ "path",
796
+ {
797
+ d: `M ${arcStartX} ${arcStartY} A ${arcR} ${arcR} 0 0 ${sweepFlag} ${arcEndX} ${arcEndY}`,
798
+ fill: "none",
799
+ stroke: c7,
800
+ strokeWidth: sw7
801
+ }
802
+ ),
803
+ el.label && /* @__PURE__ */ jsx4(
804
+ "text",
805
+ {
806
+ x: x1 + (arcR + 16) * Math.cos(midA),
807
+ y: y1 + (arcR + 16) * Math.sin(midA),
808
+ fontSize: fs,
809
+ fill: c7,
810
+ fontFamily: "serif",
811
+ fontStyle: "italic",
812
+ dominantBaseline: "central",
813
+ textAnchor: "middle",
814
+ children: String(el.label)
815
+ }
816
+ )
817
+ ] })
818
+ ] });
819
+ });
820
+ registerRenderer("parabola_v", (el, ctx) => {
821
+ const minX = Math.min(el.x1, el.x2);
822
+ const maxX = Math.max(el.x1, el.x2);
823
+ const minY = Math.min(el.y1, el.y2);
824
+ const maxY = Math.max(el.y1, el.y2);
825
+ const midX = (minX + maxX) / 2;
826
+ const w = Math.max(1, maxX - minX);
827
+ const h = Math.max(1, maxY - minY);
828
+ const cpY = 2 * el.y1 - el.y2;
829
+ const c7 = colorOf2(el);
830
+ const sw7 = strokeOf2(el);
831
+ const dash = dashOf2(el);
832
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
833
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
834
+ /* @__PURE__ */ jsx4(
835
+ "path",
836
+ {
837
+ d: `M ${minX} ${el.y2} Q ${midX} ${cpY} ${maxX} ${el.y2}`,
838
+ fill: "none",
839
+ stroke: c7,
840
+ strokeWidth: sw7,
841
+ strokeDasharray: dash,
842
+ pointerEvents: "none"
843
+ }
844
+ )
845
+ ] });
846
+ });
847
+ registerRenderer("parabola_h", (el, ctx) => {
848
+ const minX = Math.min(el.x1, el.x2);
849
+ const maxX = Math.max(el.x1, el.x2);
850
+ const minY = Math.min(el.y1, el.y2);
851
+ const maxY = Math.max(el.y1, el.y2);
852
+ const midY = (minY + maxY) / 2;
853
+ const w = Math.max(1, maxX - minX);
854
+ const h = Math.max(1, maxY - minY);
855
+ const cpX = 2 * el.x1 - el.x2;
856
+ const c7 = colorOf2(el);
857
+ const sw7 = strokeOf2(el);
858
+ const dash = dashOf2(el);
859
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
860
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
861
+ /* @__PURE__ */ jsx4(
862
+ "path",
863
+ {
864
+ d: `M ${el.x2} ${minY} Q ${cpX} ${midY} ${el.x2} ${maxY}`,
865
+ fill: "none",
866
+ stroke: c7,
867
+ strokeWidth: sw7,
868
+ strokeDasharray: dash,
869
+ pointerEvents: "none"
870
+ }
871
+ )
872
+ ] });
873
+ });
874
+ registerRenderer("hyperbola", (el, ctx) => {
875
+ const minX = Math.min(el.x1, el.x2);
876
+ const maxX = Math.max(el.x1, el.x2);
877
+ const minY = Math.min(el.y1, el.y2);
878
+ const maxY = Math.max(el.y1, el.y2);
879
+ const midX = (minX + maxX) / 2;
880
+ const midY = (minY + maxY) / 2;
881
+ const w = Math.max(1, maxX - minX);
882
+ const h = Math.max(1, maxY - minY);
883
+ const c7 = colorOf2(el);
884
+ const sw7 = strokeOf2(el);
885
+ const dash = dashOf2(el);
886
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
887
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
888
+ /* @__PURE__ */ jsxs4("g", { pointerEvents: "none", children: [
889
+ /* @__PURE__ */ jsx4("path", { d: `M ${minX} ${minY} Q ${midX} ${midY} ${minX} ${maxY}`, fill: "none", stroke: c7, strokeWidth: sw7, strokeDasharray: dash }),
890
+ /* @__PURE__ */ jsx4("path", { d: `M ${maxX} ${minY} Q ${midX} ${midY} ${maxX} ${maxY}`, fill: "none", stroke: c7, strokeWidth: sw7, strokeDasharray: dash })
891
+ ] })
892
+ ] });
893
+ });
894
+ registerRenderer("modulus", (el, ctx) => {
895
+ const minX = Math.min(el.x1, el.x2);
896
+ const maxX = Math.max(el.x1, el.x2);
897
+ const minY = Math.min(el.y1, el.y2);
898
+ const maxY = Math.max(el.y1, el.y2);
899
+ const midX = (minX + maxX) / 2;
900
+ const w = Math.max(1, maxX - minX);
901
+ const h = Math.max(1, maxY - minY);
902
+ const c7 = colorOf2(el);
903
+ const sw7 = strokeOf2(el);
904
+ const dash = dashOf2(el);
905
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
906
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
907
+ /* @__PURE__ */ jsx4(
908
+ "polyline",
909
+ {
910
+ points: `${minX},${minY} ${midX},${maxY} ${maxX},${minY}`,
911
+ fill: "none",
912
+ stroke: c7,
913
+ strokeWidth: sw7,
914
+ strokeLinecap: "round",
915
+ strokeLinejoin: "round",
916
+ strokeDasharray: dash,
917
+ pointerEvents: "none"
918
+ }
919
+ )
920
+ ] });
921
+ });
922
+ registerRenderer("exponential", (el, ctx) => {
923
+ const minX = Math.min(el.x1, el.x2);
924
+ const maxX = Math.max(el.x1, el.x2);
925
+ const minY = Math.min(el.y1, el.y2);
926
+ const maxY = Math.max(el.y1, el.y2);
927
+ const midX = (minX + maxX) / 2;
928
+ const w = Math.max(1, maxX - minX);
929
+ const h = Math.max(1, maxY - minY);
930
+ const c7 = colorOf2(el);
931
+ const sw7 = strokeOf2(el);
932
+ const dash = dashOf2(el);
933
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
934
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
935
+ /* @__PURE__ */ jsx4(
936
+ "path",
937
+ {
938
+ d: `M ${minX} ${maxY} Q ${midX + w * 0.2} ${maxY} ${maxX} ${minY}`,
939
+ fill: "none",
940
+ stroke: c7,
941
+ strokeWidth: sw7,
942
+ strokeDasharray: dash,
943
+ pointerEvents: "none"
944
+ }
945
+ )
946
+ ] });
947
+ });
948
+ registerRenderer("logarithmic", (el, ctx) => {
949
+ const minX = Math.min(el.x1, el.x2);
950
+ const maxX = Math.max(el.x1, el.x2);
951
+ const minY = Math.min(el.y1, el.y2);
952
+ const maxY = Math.max(el.y1, el.y2);
953
+ const midY = (minY + maxY) / 2;
954
+ const w = Math.max(1, maxX - minX);
955
+ const h = Math.max(1, maxY - minY);
956
+ const c7 = colorOf2(el);
957
+ const sw7 = strokeOf2(el);
958
+ const dash = dashOf2(el);
959
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
960
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
961
+ /* @__PURE__ */ jsx4(
962
+ "path",
963
+ {
964
+ d: `M ${minX} ${maxY} Q ${minX} ${midY - h * 0.2} ${maxX} ${minY}`,
965
+ fill: "none",
966
+ stroke: c7,
967
+ strokeWidth: sw7,
968
+ strokeDasharray: dash,
969
+ pointerEvents: "none"
970
+ }
971
+ )
972
+ ] });
973
+ });
974
+ registerRenderer("sine_wave", (el, ctx) => {
975
+ const minX = Math.min(el.x1, el.x2);
976
+ const maxX = Math.max(el.x1, el.x2);
977
+ const minY = Math.min(el.y1, el.y2);
978
+ const maxY = Math.max(el.y1, el.y2);
979
+ const midX = (minX + maxX) / 2;
980
+ const midY = (minY + maxY) / 2;
981
+ const w = Math.max(1, maxX - minX);
982
+ const h = Math.max(1, maxY - minY);
983
+ const s = w / 4;
984
+ const c7 = colorOf2(el);
985
+ const sw7 = strokeOf2(el);
986
+ const dash = dashOf2(el);
987
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
988
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
989
+ /* @__PURE__ */ jsx4(
990
+ "path",
991
+ {
992
+ d: `M ${minX} ${midY} Q ${minX + s / 2} ${minY}, ${minX + s} ${midY} T ${minX + 2 * s} ${midY} T ${minX + 3 * s} ${midY} T ${maxX} ${midY}`,
993
+ fill: "none",
994
+ stroke: c7,
995
+ strokeWidth: sw7,
996
+ strokeLinecap: "round",
997
+ strokeLinejoin: "round",
998
+ strokeDasharray: dash,
999
+ pointerEvents: "none"
1000
+ }
1001
+ )
1002
+ ] });
1003
+ });
1004
+ registerRenderer("step_function", (el, ctx) => {
1005
+ const minX = Math.min(el.x1, el.x2);
1006
+ const maxX = Math.max(el.x1, el.x2);
1007
+ const minY = Math.min(el.y1, el.y2);
1008
+ const maxY = Math.max(el.y1, el.y2);
1009
+ const w = Math.max(1, maxX - minX);
1010
+ const h = Math.max(1, maxY - minY);
1011
+ const c7 = colorOf2(el);
1012
+ const sw7 = strokeOf2(el);
1013
+ const dash = dashOf2(el);
1014
+ const stepsCount = 4;
1015
+ const stepW = w / stepsCount;
1016
+ const stepH = h / stepsCount;
1017
+ const steps = [];
1018
+ for (let i = 0; i < stepsCount; i++) {
1019
+ const curX = minX + i * stepW;
1020
+ const curY = maxY - i * stepH;
1021
+ const nextX = curX + stepW;
1022
+ steps.push(
1023
+ /* @__PURE__ */ jsxs4("g", { children: [
1024
+ /* @__PURE__ */ jsx4("line", { x1: curX, y1: curY, x2: nextX, y2: curY, stroke: c7, strokeWidth: sw7, strokeDasharray: dash }),
1025
+ /* @__PURE__ */ jsx4("circle", { cx: curX, cy: curY, r: sw7 * 1.5, fill: c7 }),
1026
+ /* @__PURE__ */ jsx4("circle", { cx: nextX, cy: curY, r: sw7 * 1.5, fill: "white", stroke: c7, strokeWidth: sw7 * 0.75 })
1027
+ ] }, i)
1028
+ );
1029
+ }
1030
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
1031
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
1032
+ /* @__PURE__ */ jsx4("g", { pointerEvents: "none", children: steps })
1033
+ ] });
1034
+ });
1035
+ registerRenderer("shaded_area", (el, ctx) => {
1036
+ const minX = Math.min(el.x1, el.x2);
1037
+ const maxX = Math.max(el.x1, el.x2);
1038
+ const minY = Math.min(el.y1, el.y2);
1039
+ const maxY = Math.max(el.y1, el.y2);
1040
+ const midX = (minX + maxX) / 2;
1041
+ const w = Math.max(1, maxX - minX);
1042
+ const h = Math.max(1, maxY - minY);
1043
+ const c7 = colorOf2(el);
1044
+ const sw7 = strokeOf2(el);
1045
+ const dash = dashOf2(el);
1046
+ return /* @__PURE__ */ jsxs4("g", { opacity: op(ctx), children: [
1047
+ /* @__PURE__ */ jsx4("rect", { x: minX, y: minY, width: w, height: h, fill: "transparent" }),
1048
+ /* @__PURE__ */ jsxs4("g", { pointerEvents: "none", children: [
1049
+ /* @__PURE__ */ jsx4(
1050
+ "path",
1051
+ {
1052
+ d: `M ${minX} ${maxY} L ${minX} ${minY + h * 0.3} Q ${midX} ${minY} ${maxX} ${minY + h * 0.3} L ${maxX} ${maxY} Z`,
1053
+ fill: c7,
1054
+ opacity: 0.2
1055
+ }
1056
+ ),
1057
+ /* @__PURE__ */ jsx4("path", { d: `M ${minX} ${minY + h * 0.3} Q ${midX} ${minY} ${maxX} ${minY + h * 0.3}`, fill: "none", stroke: c7, strokeWidth: sw7, strokeDasharray: dash })
1058
+ ] })
1059
+ ] });
1060
+ });
1061
+
1062
+ // src/core/renderers/waveOscillation.tsx
1063
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1064
+ var c3 = (el) => el.color || "#0f172a";
1065
+ var sw3 = (el) => el.strokeWidth || 2;
1066
+ var font = (el) => el.fontSize || 18;
1067
+ registerRenderer("mass_box", (el) => {
1068
+ const size = el.size || 30;
1069
+ const color = c3(el);
1070
+ const strokeWidth = sw3(el);
1071
+ const fontSize = font(el);
1072
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1073
+ /* @__PURE__ */ jsx5(
1074
+ "rect",
1075
+ {
1076
+ x: -size / 2,
1077
+ y: -size / 2,
1078
+ width: size,
1079
+ height: size,
1080
+ fill: color,
1081
+ fillOpacity: 0.2,
1082
+ stroke: color,
1083
+ strokeWidth,
1084
+ rx: 4
1085
+ }
1086
+ ),
1087
+ el.label ? /* @__PURE__ */ jsx5("text", { x: 0, y: 0, dominantBaseline: "central", textAnchor: "middle", fontSize, fill: color, fontWeight: "bold", children: String(el.label) }) : null
1088
+ ] });
1089
+ });
1090
+ registerRenderer("tuning_fork", (el) => {
1091
+ const color = c3(el);
1092
+ const strokeWidth = sw3(el);
1093
+ const fontSize = font(el);
1094
+ const w = Math.max(3, strokeWidth);
1095
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1096
+ /* @__PURE__ */ jsx5(
1097
+ "path",
1098
+ {
1099
+ d: "M -10 -20 L -10 0 Q -10 10 0 10 Q 10 10 10 0 L 10 -20",
1100
+ fill: "none",
1101
+ stroke: color,
1102
+ strokeWidth: w,
1103
+ strokeLinecap: "round"
1104
+ }
1105
+ ),
1106
+ /* @__PURE__ */ jsx5("line", { x1: "0", y1: "10", x2: "0", y2: "30", stroke: color, strokeWidth: Math.max(4, strokeWidth), strokeLinecap: "round" }),
1107
+ el.label ? /* @__PURE__ */ jsx5("text", { x: 0, y: 45, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1108
+ ] });
1109
+ });
1110
+ registerRenderer("speaker", (el) => {
1111
+ const color = c3(el);
1112
+ const fontSize = font(el);
1113
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1114
+ /* @__PURE__ */ jsx5("polygon", { points: "-10,-15 5,-25 5,25 -10,15", fill: color }),
1115
+ /* @__PURE__ */ jsx5("rect", { x: "-20", y: "-15", width: "10", height: "30", fill: color }),
1116
+ /* @__PURE__ */ jsx5("path", { d: "M 12 -10 Q 18 0 12 10 M 18 -20 Q 28 0 18 20", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round" }),
1117
+ el.label ? /* @__PURE__ */ jsx5("text", { x: 0, y: 40, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1118
+ ] });
1119
+ });
1120
+ registerRenderer("wavefronts", (el) => {
1121
+ const rings = el.rings || 5;
1122
+ const vRatio = el.velocityRatio ?? 0;
1123
+ const color = c3(el);
1124
+ const strokeWidth = sw3(el);
1125
+ const fontSize = font(el);
1126
+ const circles = [];
1127
+ for (let i = 1; i <= rings; i++) {
1128
+ const r = i * 20;
1129
+ const cx = vRatio * r;
1130
+ circles.push(
1131
+ /* @__PURE__ */ jsx5(
1132
+ "circle",
1133
+ {
1134
+ cx,
1135
+ cy: 0,
1136
+ r,
1137
+ fill: "none",
1138
+ stroke: color,
1139
+ strokeWidth,
1140
+ opacity: 1 - i / rings * 0.5
1141
+ },
1142
+ i
1143
+ )
1144
+ );
1145
+ }
1146
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1147
+ /* @__PURE__ */ jsx5("circle", { cx: 0, cy: 0, r: 4, fill: color }),
1148
+ circles,
1149
+ el.label ? /* @__PURE__ */ jsx5("text", { x: 0, y: rings * 20 + 20, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1150
+ ] });
1151
+ });
1152
+ registerRenderer("pendulum", (el) => {
1153
+ const size = el.size || 15;
1154
+ const color = c3(el);
1155
+ const strokeWidth = sw3(el);
1156
+ const fontSize = font(el);
1157
+ const theta = Math.atan2(el.x2 - el.x1, el.y2 - el.y1);
1158
+ const thetaDeg = theta * (180 / Math.PI);
1159
+ const l = Math.hypot(el.x2 - el.x1, el.y2 - el.y1);
1160
+ const arcR = Math.min(40, l * 0.5);
1161
+ const arcX = Math.sin(theta) * arcR;
1162
+ const arcY = Math.cos(theta) * arcR;
1163
+ const arcFlag = theta > 0 ? 0 : 1;
1164
+ const showF = el.showForces;
1165
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1166
+ /* @__PURE__ */ jsx5("line", { x1: -20, y1: 0, x2: 20, y2: 0, stroke: color, strokeWidth: 2 }),
1167
+ /* @__PURE__ */ jsx5("line", { x1: -15, y1: 0, x2: -10, y2: -5, stroke: color }),
1168
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 5, y2: -5, stroke: color }),
1169
+ /* @__PURE__ */ jsx5("line", { x1: 15, y1: 0, x2: 20, y2: -5, stroke: color }),
1170
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 0, y2: l + 20, stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.5 }),
1171
+ Math.abs(theta) > 0.05 ? /* @__PURE__ */ jsx5(
1172
+ "path",
1173
+ {
1174
+ d: `M 0 ${arcR} A ${arcR} ${arcR} 0 0 ${arcFlag} ${arcX} ${arcY}`,
1175
+ fill: "none",
1176
+ stroke: color,
1177
+ strokeWidth: 1.5
1178
+ }
1179
+ ) : null,
1180
+ /* @__PURE__ */ jsxs5("g", { transform: `rotate(${-thetaDeg})`, children: [
1181
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 0, y2: l, stroke: color, strokeWidth }),
1182
+ /* @__PURE__ */ jsx5("circle", { cx: 0, cy: l, r: size, fill: color, stroke: "#fff", strokeWidth: 2 }),
1183
+ showF ? /* @__PURE__ */ jsxs5("g", { transform: `translate(0, ${l})`, children: [
1184
+ /* @__PURE__ */ jsxs5("g", { transform: `rotate(${thetaDeg})`, children: [
1185
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 0, y2: 40, stroke: "#ef4444", strokeWidth: 2 }),
1186
+ /* @__PURE__ */ jsx5("polygon", { points: "0,45 -4,37 4,37", fill: "#ef4444" }),
1187
+ /* @__PURE__ */ jsx5("text", { x: 10, y: 40, fontSize: 12, fill: "#ef4444", children: "F_g" })
1188
+ ] }),
1189
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 0, y2: -40, stroke: "#3b82f6", strokeWidth: 2 }),
1190
+ /* @__PURE__ */ jsx5("polygon", { points: "0,-45 -4,-37 4,-37", fill: "#3b82f6" }),
1191
+ /* @__PURE__ */ jsx5("text", { x: 10, y: -35, fontSize: 12, fill: "#3b82f6", children: "T" }),
1192
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: -35 * Math.sin(theta), y2: 0, stroke: "#10b981", strokeWidth: 2 }),
1193
+ /* @__PURE__ */ jsx5(
1194
+ "polygon",
1195
+ {
1196
+ points: `${-40 * Math.sin(theta)},0 ${-32 * Math.sin(theta)},-4 ${-32 * Math.sin(theta)},4`,
1197
+ fill: "#10b981"
1198
+ }
1199
+ ),
1200
+ /* @__PURE__ */ jsx5("text", { x: -45 * Math.sin(theta), y: -10, fontSize: 12, fill: "#10b981", children: "F_g sin(\u03B8)" })
1201
+ ] }) : null,
1202
+ el.label ? /* @__PURE__ */ jsx5("text", { x: 0, y: l + size + 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1203
+ ] })
1204
+ ] });
1205
+ });
1206
+ registerRenderer("phasor", (el) => {
1207
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1208
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1209
+ const dx = el.x2 - el.x1;
1210
+ const dy = el.y2 - el.y1;
1211
+ const color = c3(el);
1212
+ const strokeWidth = sw3(el);
1213
+ const fontSize = font(el);
1214
+ const showProj = el.showProjection;
1215
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1216
+ /* @__PURE__ */ jsx5("circle", { cx: 0, cy: 0, r: dist, fill: "none", stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.5 }),
1217
+ /* @__PURE__ */ jsx5("line", { x1: -dist - 10, y1: 0, x2: dist + 10, y2: 0, stroke: color, strokeWidth: 1, opacity: 0.3 }),
1218
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: -dist - 10, x2: 0, y2: dist + 10, stroke: color, strokeWidth: 1, opacity: 0.3 }),
1219
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth }),
1220
+ /* @__PURE__ */ jsx5("polygon", { points: `${dist},0 ${dist - 12},-6 ${dist - 12},6`, fill: color }),
1221
+ showProj ? /* @__PURE__ */ jsxs5("g", { transform: `rotate(${-angle})`, children: [
1222
+ /* @__PURE__ */ jsx5("line", { x1: dx, y1: dy, x2: dx, y2: 0, stroke: "#ef4444", strokeWidth: 1, strokeDasharray: "4 4" }),
1223
+ /* @__PURE__ */ jsx5("line", { x1: dx, y1: dy, x2: 0, y2: dy, stroke: "#3b82f6", strokeWidth: 1, strokeDasharray: "4 4" }),
1224
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dx, y2: 0, stroke: "#ef4444", strokeWidth: 2 }),
1225
+ /* @__PURE__ */ jsx5("polygon", { points: `${dx},0 ${dx > 0 ? dx - 8 : dx + 8},-4 ${dx > 0 ? dx - 8 : dx + 8},4`, fill: "#ef4444" }),
1226
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 0, y2: dy, stroke: "#3b82f6", strokeWidth: 2 }),
1227
+ /* @__PURE__ */ jsx5("polygon", { points: `0,${dy} -4,${dy > 0 ? dy - 8 : dy + 8} 4,${dy > 0 ? dy - 8 : dy + 8}`, fill: "#3b82f6" })
1228
+ ] }) : null,
1229
+ /* @__PURE__ */ jsx5(
1230
+ "path",
1231
+ {
1232
+ d: `M ${dist * 0.3} 0 A ${dist * 0.3} ${dist * 0.3} 0 0 0 ${dist * 0.3 * Math.cos(-angle * Math.PI / 180)} ${dist * 0.3 * Math.sin(-angle * Math.PI / 180)}`,
1233
+ fill: "none",
1234
+ stroke: color,
1235
+ strokeWidth: 1.5,
1236
+ transform: `rotate(${-angle})`
1237
+ }
1238
+ ),
1239
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1240
+ ] });
1241
+ });
1242
+ registerRenderer("sine_wave", (el) => {
1243
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1244
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1245
+ const amp = el.amplitude || 40;
1246
+ const loops = el.loops || 2;
1247
+ const wl = dist / (loops / 2);
1248
+ const color = c3(el);
1249
+ const strokeWidth = sw3(el);
1250
+ const fontSize = font(el);
1251
+ let d = "M 0 0";
1252
+ const step = Math.max(1, dist / 100);
1253
+ for (let i = 0; i <= dist; i += step) {
1254
+ d += ` L ${i} ${-amp * Math.sin(i / wl * 2 * Math.PI)}`;
1255
+ }
1256
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1257
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.5 }),
1258
+ /* @__PURE__ */ jsx5("path", { d, fill: "none", stroke: color, strokeWidth, strokeLinejoin: "round" }),
1259
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -amp - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1260
+ ] });
1261
+ });
1262
+ registerRenderer("standing_wave", (el) => {
1263
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1264
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1265
+ const amp = el.amplitude || 40;
1266
+ const loops = el.loops || 3;
1267
+ const wl = dist / (loops / 2);
1268
+ const color = c3(el);
1269
+ const strokeWidth = sw3(el);
1270
+ const fontSize = font(el);
1271
+ let d1 = "M 0 0";
1272
+ let d2 = "M 0 0";
1273
+ const step = Math.max(1, dist / 100);
1274
+ for (let i = 0; i <= dist; i += step) {
1275
+ const y = amp * Math.sin(i / wl * 2 * Math.PI);
1276
+ d1 += ` L ${i} ${-y}`;
1277
+ d2 += ` L ${i} ${y}`;
1278
+ }
1279
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1280
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth: 1, opacity: 0.5 }),
1281
+ /* @__PURE__ */ jsx5("path", { d: d1, fill: color, fillOpacity: 0.1, stroke: color, strokeWidth, strokeLinejoin: "round" }),
1282
+ /* @__PURE__ */ jsx5("path", { d: d2, fill: "none", stroke: color, strokeWidth, strokeDasharray: "4 4", strokeLinejoin: "round" }),
1283
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -amp - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1284
+ ] });
1285
+ });
1286
+ registerRenderer("shm_graph", (el) => {
1287
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1288
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1289
+ const amp = el.amplitude || 40;
1290
+ const loops = el.loops || 1;
1291
+ const wl = dist / loops;
1292
+ const gType = el.graphType || "x";
1293
+ const color = c3(el);
1294
+ const strokeWidth = sw3(el);
1295
+ const fontSize = font(el);
1296
+ let dX = `M 0 ${-amp}`;
1297
+ let dV = "M 0 0";
1298
+ let dA = `M 0 ${amp}`;
1299
+ const step = Math.max(1, dist / 100);
1300
+ for (let i = 0; i <= dist; i += step) {
1301
+ const phase = i / wl * 2 * Math.PI;
1302
+ dX += ` L ${i} ${-amp * Math.cos(phase)}`;
1303
+ dV += ` L ${i} ${-amp * 0.8 * -Math.sin(phase)}`;
1304
+ dA += ` L ${i} ${-amp * 0.6 * -Math.cos(phase)}`;
1305
+ }
1306
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1307
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth: 1, opacity: 0.5 }),
1308
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: -amp * 1.2, x2: 0, y2: amp * 1.2, stroke: color, strokeWidth: 1, opacity: 0.5 }),
1309
+ (gType === "x" || gType === "all") && /* @__PURE__ */ jsx5("path", { d: dX, fill: "none", stroke: "#3b82f6", strokeWidth, strokeLinejoin: "round" }),
1310
+ (gType === "v" || gType === "all") && /* @__PURE__ */ jsx5("path", { d: dV, fill: "none", stroke: "#ef4444", strokeWidth, strokeLinejoin: "round" }),
1311
+ (gType === "a" || gType === "all") && /* @__PURE__ */ jsx5("path", { d: dA, fill: "none", stroke: "#10b981", strokeWidth, strokeLinejoin: "round" }),
1312
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -amp - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1313
+ ] });
1314
+ });
1315
+ registerRenderer("energy_graph", (el) => {
1316
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1317
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1318
+ const amp = el.amplitude || 50;
1319
+ const loops = el.loops || 1;
1320
+ const wl = dist / loops;
1321
+ const dom = el.domain || "time";
1322
+ const color = c3(el);
1323
+ const strokeWidth = sw3(el);
1324
+ const fontSize = font(el);
1325
+ let dU = "M 0 0";
1326
+ let dK = `M 0 ${-amp}`;
1327
+ const step = Math.max(1, dist / 100);
1328
+ if (dom === "time") {
1329
+ dU = `M 0 ${-amp}`;
1330
+ dK = "M 0 0";
1331
+ for (let i = 0; i <= dist; i += step) {
1332
+ const phase = i / wl * 2 * Math.PI;
1333
+ dU += ` L ${i} ${-amp * Math.pow(Math.cos(phase), 2)}`;
1334
+ dK += ` L ${i} ${-amp * Math.pow(Math.sin(phase), 2)}`;
1335
+ }
1336
+ } else {
1337
+ for (let i = 0; i <= dist; i += step) {
1338
+ const xNorm = 2 * (i / dist) - 1;
1339
+ const uVal = amp * xNorm * xNorm;
1340
+ dU += ` L ${i} ${-uVal}`;
1341
+ dK += ` L ${i} ${-(amp - uVal)}`;
1342
+ }
1343
+ }
1344
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1345
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth: 1, opacity: 0.5 }),
1346
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: -amp, x2: dist, y2: -amp, stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.5 }),
1347
+ /* @__PURE__ */ jsx5("path", { d: dU, fill: "none", stroke: "#10b981", strokeWidth, strokeLinejoin: "round" }),
1348
+ /* @__PURE__ */ jsx5("path", { d: dK, fill: "none", stroke: "#ef4444", strokeWidth, strokeLinejoin: "round" }),
1349
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -amp - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1350
+ ] });
1351
+ });
1352
+ registerRenderer("strobe_shm", (el) => {
1353
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1354
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1355
+ const amp = el.amplitude || 40;
1356
+ const loops = el.loops || 1;
1357
+ const color = c3(el);
1358
+ const strokeWidth = sw3(el);
1359
+ const fontSize = font(el);
1360
+ const rows = 10;
1361
+ const pts = [];
1362
+ const circles = [];
1363
+ const lines = [];
1364
+ for (let i = 0; i <= rows; i++) {
1365
+ const t = i / rows;
1366
+ const cx = amp * Math.cos(t * 2 * Math.PI * loops);
1367
+ const cy = t * dist;
1368
+ pts.push(`${cx},${cy}`);
1369
+ circles.push(/* @__PURE__ */ jsx5("circle", { cx, cy, r: strokeWidth * 2, fill: color }, `c${i}`));
1370
+ lines.push(
1371
+ /* @__PURE__ */ jsx5("line", { x1: -amp - 20, y1: cy, x2: amp + 20, y2: cy, stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.3 }, `l${i}`)
1372
+ );
1373
+ }
1374
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1375
+ lines,
1376
+ /* @__PURE__ */ jsx5("polyline", { points: pts.join(" "), fill: "none", stroke: color, strokeWidth: 1, opacity: 0.4 }),
1377
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: 0, y2: dist, stroke: color, strokeWidth: 1, opacity: 0.5 }),
1378
+ circles,
1379
+ el.label ? /* @__PURE__ */ jsx5("text", { x: 0, y: -15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1380
+ ] });
1381
+ });
1382
+ registerRenderer("torsion_pendulum", (el) => {
1383
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1384
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1385
+ const color = c3(el);
1386
+ const strokeWidth = sw3(el);
1387
+ const fontSize = font(el);
1388
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1389
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth }),
1390
+ /* @__PURE__ */ jsx5("ellipse", { cx: dist, cy: 0, rx: 40, ry: 15, fill: color, fillOpacity: 0.2, stroke: color, strokeWidth }),
1391
+ /* @__PURE__ */ jsx5("line", { x1: dist, y1: 0, x2: dist + 40, y2: 0, stroke: color, strokeWidth, strokeDasharray: "2 2" }),
1392
+ /* @__PURE__ */ jsx5("line", { x1: dist, y1: 0, x2: dist + 30, y2: 20, stroke: "#ef4444", strokeWidth }),
1393
+ /* @__PURE__ */ jsx5("path", { d: `M ${dist + 20} 0 A 20 7.5 0 0 1 ${dist + 15} 10`, fill: "none", stroke: "#ef4444", strokeWidth: 1.5 }),
1394
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1395
+ ] });
1396
+ });
1397
+ registerRenderer("vane_liquid", (el) => {
1398
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1399
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1400
+ const color = c3(el);
1401
+ const strokeWidth = sw3(el);
1402
+ const fontSize = font(el);
1403
+ const beakerW = Math.max(40, dist * 0.4);
1404
+ const beakerH = Math.max(40, dist * 0.5);
1405
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1406
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth }),
1407
+ /* @__PURE__ */ jsx5("line", { x1: dist, y1: -beakerW * 0.3, x2: dist, y2: beakerW * 0.3, stroke: color, strokeWidth: strokeWidth * 1.5, strokeLinecap: "round" }),
1408
+ /* @__PURE__ */ jsx5(
1409
+ "path",
1410
+ {
1411
+ d: `M ${dist - beakerH} ${-beakerW / 2} L ${dist + 10} ${-beakerW / 2} L ${dist + 10} ${beakerW / 2} L ${dist - beakerH} ${beakerW / 2}`,
1412
+ fill: "none",
1413
+ stroke: color,
1414
+ strokeWidth: 2,
1415
+ strokeLinecap: "round",
1416
+ strokeLinejoin: "round"
1417
+ }
1418
+ ),
1419
+ /* @__PURE__ */ jsx5(
1420
+ "rect",
1421
+ {
1422
+ x: dist - beakerH + 2,
1423
+ y: -beakerW / 2 + 2,
1424
+ width: beakerH + 8,
1425
+ height: beakerW - 4,
1426
+ fill: "#38bdf8",
1427
+ fillOpacity: 0.3
1428
+ }
1429
+ ),
1430
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -beakerW / 2 - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1431
+ ] });
1432
+ });
1433
+ registerRenderer("wave_pulse", (el) => {
1434
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1435
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1436
+ const amp = el.amplitude || 50;
1437
+ const color = c3(el);
1438
+ const strokeWidth = sw3(el);
1439
+ const fontSize = font(el);
1440
+ const mid = dist / 2;
1441
+ const spread = dist / 6;
1442
+ let d = "M 0 0";
1443
+ const step = Math.max(1, dist / 50);
1444
+ for (let i = 0; i <= dist; i += step) {
1445
+ const y = amp * Math.exp(-Math.pow(i - mid, 2) / (2 * spread * spread));
1446
+ d += ` L ${i} ${-y}`;
1447
+ }
1448
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1449
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth, strokeLinecap: "round" }),
1450
+ /* @__PURE__ */ jsx5("path", { d, fill: color, fillOpacity: 0.1, stroke: color, strokeWidth, strokeLinejoin: "round" }),
1451
+ el.label ? /* @__PURE__ */ jsx5("text", { x: mid, y: -amp - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1452
+ ] });
1453
+ });
1454
+ registerRenderer("damped_wave", (el) => {
1455
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1456
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1457
+ const amp = el.amplitude || 50;
1458
+ const damp = el.damping || 0.015;
1459
+ const freq = el.frequency || 10;
1460
+ const color = c3(el);
1461
+ const strokeWidth = sw3(el);
1462
+ const fontSize = font(el);
1463
+ let d = `M 0 ${-amp}`;
1464
+ let env1 = `M 0 ${-amp}`;
1465
+ let env2 = `M 0 ${amp}`;
1466
+ const step = Math.max(1, dist / 200);
1467
+ for (let i = 0; i <= dist; i += step) {
1468
+ const envY = amp * Math.exp(-damp * i);
1469
+ const y = envY * Math.cos(i / dist * freq * 2 * Math.PI);
1470
+ d += ` L ${i} ${-y}`;
1471
+ env1 += ` L ${i} ${-envY}`;
1472
+ env2 += ` L ${i} ${envY}`;
1473
+ }
1474
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1475
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth: 1, opacity: 0.3 }),
1476
+ /* @__PURE__ */ jsx5("path", { d: env1, fill: "none", stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.5 }),
1477
+ /* @__PURE__ */ jsx5("path", { d: env2, fill: "none", stroke: color, strokeWidth: 1, strokeDasharray: "4 4", opacity: 0.5 }),
1478
+ /* @__PURE__ */ jsx5("path", { d, fill: "none", stroke: color, strokeWidth, strokeLinejoin: "round" }),
1479
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -amp - 15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1480
+ ] });
1481
+ });
1482
+ registerRenderer("beats_graph", (el) => {
1483
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1484
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1485
+ const amp = el.amplitude || 30;
1486
+ const freq = el.frequency || 20;
1487
+ const beatF = el.beatFreq || 2;
1488
+ const color = c3(el);
1489
+ const strokeWidth = sw3(el);
1490
+ const fontSize = font(el);
1491
+ let d = "M 0 0";
1492
+ let env1 = "M 0 0";
1493
+ let env2 = "M 0 0";
1494
+ const step = Math.max(1, dist / 200);
1495
+ for (let i = 0; i <= dist; i += step) {
1496
+ const env = amp * Math.cos(i / dist * beatF * Math.PI);
1497
+ const y = env * Math.sin(i / dist * freq * 2 * Math.PI);
1498
+ d += ` L ${i} ${-y}`;
1499
+ env1 += ` L ${i} ${-Math.abs(env)}`;
1500
+ env2 += ` L ${i} ${Math.abs(env)}`;
1501
+ }
1502
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1503
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth: 1, opacity: 0.3 }),
1504
+ /* @__PURE__ */ jsx5("path", { d: env1, fill: "none", stroke: color, strokeWidth: 1, strokeDasharray: "2 4", opacity: 0.5 }),
1505
+ /* @__PURE__ */ jsx5("path", { d: env2, fill: "none", stroke: color, strokeWidth: 1, strokeDasharray: "2 4", opacity: 0.5 }),
1506
+ /* @__PURE__ */ jsx5("path", { d, fill: "none", stroke: color, strokeWidth, strokeLinejoin: "round" }),
1507
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: -amp - 20, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1508
+ ] });
1509
+ });
1510
+ registerRenderer("mach_cone", (el) => {
1511
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1512
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1513
+ const M = el.machNumber || 2;
1514
+ const coneAngle = Math.asin(1 / Math.max(1.01, M));
1515
+ const h = dist;
1516
+ const r = h * Math.tan(coneAngle);
1517
+ const color = c3(el);
1518
+ const strokeWidth = sw3(el);
1519
+ const fontSize = font(el);
1520
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1521
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: h, y2: 0, stroke: color, strokeWidth: 1, strokeDasharray: "4 4" }),
1522
+ /* @__PURE__ */ jsx5("line", { x1: h, y1: 0, x2: 0, y2: -r, stroke: color, strokeWidth }),
1523
+ /* @__PURE__ */ jsx5("line", { x1: h, y1: 0, x2: 0, y2: r, stroke: color, strokeWidth }),
1524
+ /* @__PURE__ */ jsx5("circle", { cx: h, cy: 0, r: 4, fill: color }),
1525
+ [0.2, 0.5, 0.8].map((t) => /* @__PURE__ */ jsx5("circle", { cx: h * t, cy: 0, r: (1 - t) * r, fill: "none", stroke: color, strokeWidth: 1, opacity: 0.6 }, t)),
1526
+ el.label ? /* @__PURE__ */ jsx5("text", { x: h / 2, y: r + 20, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1527
+ ] });
1528
+ });
1529
+ registerRenderer("wall", (el) => {
1530
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1531
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1532
+ const color = c3(el);
1533
+ const strokeWidth = sw3(el);
1534
+ const fontSize = font(el);
1535
+ const hashes = [];
1536
+ const numHashes = Math.max(2, Math.floor(dist / 10));
1537
+ for (let j = 0; j <= numHashes; j++) {
1538
+ const i = j / numHashes * dist;
1539
+ hashes.push(/* @__PURE__ */ jsx5("line", { x1: i, y1: 0, x2: i - 8, y2: -12, stroke: color, strokeWidth: 1 }, j));
1540
+ }
1541
+ return /* @__PURE__ */ jsxs5("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1542
+ /* @__PURE__ */ jsx5("line", { x1: 0, y1: 0, x2: dist, y2: 0, stroke: color, strokeWidth }),
1543
+ hashes,
1544
+ el.label ? /* @__PURE__ */ jsx5("text", { x: dist / 2, y: 20, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
1545
+ ] });
1546
+ });
1547
+
1548
+ // src/core/renderers/mechanical.tsx
1549
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1550
+ var c4 = (el) => el.color || "#0f172a";
1551
+ var sw4 = (el) => el.strokeWidth || 2;
1552
+ var font2 = (el) => el.fontSize || 18;
1553
+ registerRenderer("string", (el) => {
1554
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1555
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1556
+ return /* @__PURE__ */ jsx6("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: /* @__PURE__ */ jsx6("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c4(el), strokeWidth: sw4(el), strokeLinecap: "round" }) });
1557
+ });
1558
+ registerRenderer("surface", (el) => {
1559
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1560
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1561
+ const hatchCount = Math.max(0, Math.floor(d / 12));
1562
+ const hatches = [];
1563
+ for (let i = 0; i <= hatchCount; i++) {
1564
+ hatches.push(/* @__PURE__ */ jsx6("line", { x1: i * 12, y1: 0, x2: i * 12 - 8, y2: 12, stroke: c4(el), strokeWidth: 1.5 }, i));
1565
+ }
1566
+ return /* @__PURE__ */ jsxs6("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1567
+ /* @__PURE__ */ jsx6("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c4(el), strokeWidth: sw4(el) + 0.5, strokeLinecap: "round" }),
1568
+ hatches
1569
+ ] });
1570
+ });
1571
+ var rotOf = (el) => el.rotation || 0;
1572
+ registerRenderer("block", (el) => {
1573
+ const w = Math.abs(el.x2 - el.x1);
1574
+ const h = Math.abs(el.y2 - el.y1);
1575
+ const cx = (el.x1 + el.x2) / 2;
1576
+ const cy = (el.y1 + el.y2) / 2;
1577
+ const rot = rotOf(el);
1578
+ return /* @__PURE__ */ jsxs6("g", { transform: `translate(${cx}, ${cy}) rotate(${rot})`, children: [
1579
+ /* @__PURE__ */ jsx6("rect", { x: -w / 2, y: -h / 2, width: w, height: h, fill: "#f1f5f9", stroke: c4(el), strokeWidth: sw4(el) }),
1580
+ el.label ? /* @__PURE__ */ jsx6(
1581
+ "text",
1582
+ {
1583
+ x: 0,
1584
+ y: el.value ? -6 : 0,
1585
+ dominantBaseline: "central",
1586
+ textAnchor: "middle",
1587
+ fill: c4(el),
1588
+ fontSize: 18,
1589
+ fontFamily: "serif",
1590
+ fontWeight: "bold",
1591
+ children: String(el.label)
1592
+ }
1593
+ ) : null,
1594
+ el.value ? /* @__PURE__ */ jsx6(
1595
+ "text",
1596
+ {
1597
+ x: 0,
1598
+ y: el.label ? 10 : 0,
1599
+ dominantBaseline: "central",
1600
+ textAnchor: "middle",
1601
+ fill: "#4b5563",
1602
+ fontSize: 14,
1603
+ fontFamily: "sans-serif",
1604
+ children: String(el.value)
1605
+ }
1606
+ ) : null
1607
+ ] });
1608
+ });
1609
+ registerRenderer("cart", (el) => {
1610
+ const w = Math.abs(el.x2 - el.x1);
1611
+ const h = Math.abs(el.y2 - el.y1);
1612
+ const cx = (el.x1 + el.x2) / 2;
1613
+ const cy = (el.y1 + el.y2) / 2;
1614
+ const rot = rotOf(el);
1615
+ const wheelR = Math.min(w * 0.15, h * 0.25, 12);
1616
+ return /* @__PURE__ */ jsxs6("g", { transform: `translate(${cx}, ${cy}) rotate(${rot})`, children: [
1617
+ /* @__PURE__ */ jsx6("rect", { x: -w / 2, y: -h / 2, width: w, height: h - wheelR, fill: "#f1f5f9", stroke: c4(el), strokeWidth: sw4(el) }),
1618
+ /* @__PURE__ */ jsx6("circle", { cx: -w / 2 + wheelR * 1.5, cy: h / 2 - wheelR, r: wheelR, fill: "#cbd5e1", stroke: c4(el), strokeWidth: sw4(el) }),
1619
+ /* @__PURE__ */ jsx6("circle", { cx: w / 2 - wheelR * 1.5, cy: h / 2 - wheelR, r: wheelR, fill: "#cbd5e1", stroke: c4(el), strokeWidth: sw4(el) }),
1620
+ el.label ? /* @__PURE__ */ jsx6(
1621
+ "text",
1622
+ {
1623
+ x: 0,
1624
+ y: el.value ? -8 : -2,
1625
+ dominantBaseline: "central",
1626
+ textAnchor: "middle",
1627
+ fill: c4(el),
1628
+ fontSize: 18,
1629
+ fontFamily: "serif",
1630
+ fontWeight: "bold",
1631
+ children: String(el.label)
1632
+ }
1633
+ ) : null,
1634
+ el.value ? /* @__PURE__ */ jsx6(
1635
+ "text",
1636
+ {
1637
+ x: 0,
1638
+ y: el.label ? 8 : -2,
1639
+ dominantBaseline: "central",
1640
+ textAnchor: "middle",
1641
+ fill: "#4b5563",
1642
+ fontSize: 14,
1643
+ fontFamily: "sans-serif",
1644
+ children: String(el.value)
1645
+ }
1646
+ ) : null
1647
+ ] });
1648
+ });
1649
+ registerRenderer("particle", (el) => {
1650
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1651
+ const r = Math.max(5, d);
1652
+ return /* @__PURE__ */ jsxs6("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1653
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r, fill: c4(el) }),
1654
+ el.label ? /* @__PURE__ */ jsx6("text", { x: 0, y: -r - 12, dominantBaseline: "central", textAnchor: "middle", fill: c4(el), fontSize: font2(el), fontFamily: "serif", fontWeight: "bold", children: String(el.label) }) : null,
1655
+ el.value ? /* @__PURE__ */ jsx6("text", { x: 0, y: r + 12, dominantBaseline: "central", textAnchor: "middle", fill: "#4b5563", fontSize: 14, fontFamily: "sans-serif", children: String(el.value) }) : null
1656
+ ] });
1657
+ });
1658
+ registerRenderer("disk", (el) => {
1659
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1660
+ const r = Math.max(10, d);
1661
+ return /* @__PURE__ */ jsxs6("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1662
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r, fill: "#e2e8f0", stroke: c4(el), strokeWidth: sw4(el) }),
1663
+ /* @__PURE__ */ jsx6("line", { x1: 0, y1: 0, x2: r, y2: 0, stroke: c4(el), strokeWidth: sw4(el) }),
1664
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r: 3, fill: c4(el) }),
1665
+ el.label ? /* @__PURE__ */ jsx6("text", { x: 0, y: -r - 12, dominantBaseline: "central", textAnchor: "middle", fill: c4(el), fontSize: font2(el), fontFamily: "serif", fontWeight: "bold", children: String(el.label) }) : null,
1666
+ el.value ? /* @__PURE__ */ jsx6("text", { x: 0, y: r + 12, dominantBaseline: "central", textAnchor: "middle", fill: "#4b5563", fontSize: 14, fontFamily: "sans-serif", children: String(el.value) }) : null
1667
+ ] });
1668
+ });
1669
+ registerRenderer("com", (el) => /* @__PURE__ */ jsxs6("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1670
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r: 10, fill: "none", stroke: c4(el), strokeWidth: sw4(el) }),
1671
+ /* @__PURE__ */ jsx6("path", { d: "M 0 -10 A 10 10 0 0 1 10 0 L 0 0 Z", fill: c4(el) }),
1672
+ /* @__PURE__ */ jsx6("path", { d: "M 0 10 A 10 10 0 0 1 -10 0 L 0 0 Z", fill: c4(el) })
1673
+ ] }));
1674
+ registerRenderer("pivot", (el) => /* @__PURE__ */ jsxs6("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1675
+ /* @__PURE__ */ jsx6("polygon", { points: "0,0 -12,20 12,20", fill: "#f8fafc", stroke: c4(el), strokeWidth: sw4(el), strokeLinejoin: "round" }),
1676
+ /* @__PURE__ */ jsx6("line", { x1: -20, y1: 20, x2: 20, y2: 20, stroke: c4(el), strokeWidth: sw4(el), strokeLinecap: "round" }),
1677
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r: 3, fill: c4(el) })
1678
+ ] }));
1679
+ registerRenderer("pulley", (el) => {
1680
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1681
+ const r = Math.max(10, d);
1682
+ return /* @__PURE__ */ jsxs6("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1683
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r, fill: "#f8fafc", stroke: c4(el), strokeWidth: sw4(el) }),
1684
+ /* @__PURE__ */ jsx6("circle", { cx: 0, cy: 0, r: 4, fill: c4(el) }),
1685
+ el.label ? /* @__PURE__ */ jsx6("text", { x: 0, y: -r - 12, dominantBaseline: "central", textAnchor: "middle", fill: c4(el), fontSize: font2(el), fontFamily: "serif", fontWeight: "bold", children: String(el.label) }) : null
1686
+ ] });
1687
+ });
1688
+
1689
+ // src/core/renderers/rotation.tsx
1690
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1691
+ var c5 = (el) => el.color || "#0f172a";
1692
+ var sw5 = (el) => el.strokeWidth || 2;
1693
+ var font3 = (el) => el.fontSize || 18;
1694
+ function generateSpringPath(dist, coils, width2 = 20) {
1695
+ const ccount = Math.max(3, coils ?? Math.floor(dist / 20));
1696
+ const step = dist / ccount;
1697
+ let d = `M 0 0 L ${step * 0.2} 0 `;
1698
+ for (let i = 0; i < ccount; i++) {
1699
+ const startX = i * step;
1700
+ if (i === ccount - 1) {
1701
+ d += `L ${startX + step * 0.25} ${-width2 / 2} L ${startX + step * 0.75} ${width2 / 2} L ${dist} 0 `;
1702
+ } else {
1703
+ d += `L ${startX + step * 0.25} ${-width2 / 2} L ${startX + step * 0.75} ${width2 / 2} L ${startX + step} 0 `;
1704
+ }
1705
+ }
1706
+ return d;
1707
+ }
1708
+ registerRenderer("point_mass", (el) => {
1709
+ const size = el.size ?? 15;
1710
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1711
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: size, fill: c5(el), fillOpacity: 0.8, stroke: c5(el), strokeWidth: 2 }),
1712
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: size * 0.3, fill: "#fff", fillOpacity: 0.5 }),
1713
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: size + 15, fontSize: font3(el), fill: c5(el), textAnchor: "middle", fontWeight: "bold", children: String(el.label) }) : null
1714
+ ] });
1715
+ });
1716
+ registerRenderer("com_indicator", (el) => {
1717
+ const size = el.size ?? 15;
1718
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1719
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: size, fill: "none", stroke: c5(el), strokeWidth: sw5(el) }),
1720
+ /* @__PURE__ */ jsx7("line", { x1: -size * 1.3, y1: 0, x2: size * 1.3, y2: 0, stroke: c5(el), strokeWidth: sw5(el) }),
1721
+ /* @__PURE__ */ jsx7("line", { x1: 0, y1: -size * 1.3, x2: 0, y2: size * 1.3, stroke: c5(el), strokeWidth: sw5(el) }),
1722
+ /* @__PURE__ */ jsx7("path", { d: `M 0 0 L ${size} 0 A ${size} ${size} 0 0 0 0 ${-size} Z`, fill: c5(el), fillOpacity: 0.5 }),
1723
+ /* @__PURE__ */ jsx7("path", { d: `M 0 0 L ${-size} 0 A ${size} ${size} 0 0 0 0 ${size} Z`, fill: c5(el), fillOpacity: 0.5 }),
1724
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: size + 15, fontSize: font3(el), fill: c5(el), textAnchor: "middle", fontWeight: "bold", children: String(el.label) }) : null
1725
+ ] });
1726
+ });
1727
+ registerRenderer("pivot", (el) => {
1728
+ const size = el.size ?? 20;
1729
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1730
+ /* @__PURE__ */ jsx7(
1731
+ "polygon",
1732
+ {
1733
+ points: `0,0 ${-size},${size * 1.5} ${size},${size * 1.5}`,
1734
+ fill: "none",
1735
+ stroke: c5(el),
1736
+ strokeWidth: sw5(el)
1737
+ }
1738
+ ),
1739
+ /* @__PURE__ */ jsx7(
1740
+ "line",
1741
+ {
1742
+ x1: -size * 1.5,
1743
+ y1: size * 1.5,
1744
+ x2: size * 1.5,
1745
+ y2: size * 1.5,
1746
+ stroke: c5(el),
1747
+ strokeWidth: sw5(el) + 1,
1748
+ strokeLinecap: "round"
1749
+ }
1750
+ ),
1751
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: sw5(el) * 1.5, fill: c5(el) }),
1752
+ Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx7(
1753
+ "line",
1754
+ {
1755
+ x1: -size + i * size * 0.5,
1756
+ y1: size * 1.5,
1757
+ x2: -size + i * size * 0.5 - 5,
1758
+ y2: size * 1.5 + 8,
1759
+ stroke: c5(el),
1760
+ strokeWidth: 1
1761
+ },
1762
+ i
1763
+ )),
1764
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: size * 1.5 + 20, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1765
+ ] });
1766
+ });
1767
+ registerRenderer("block_mass", (el) => {
1768
+ const minX = Math.min(el.x1, el.x2);
1769
+ const minY = Math.min(el.y1, el.y2);
1770
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
1771
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
1772
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${minX}, ${minY})`, children: [
1773
+ /* @__PURE__ */ jsx7("rect", { x: 0, y: 0, width: w, height: h, fill: c5(el), fillOpacity: 0.2, stroke: c5(el), strokeWidth: sw5(el), rx: 2 }),
1774
+ el.label ? /* @__PURE__ */ jsx7("text", { x: w / 2, y: h / 2, dominantBaseline: "central", textAnchor: "middle", fontSize: font3(el), fill: c5(el), fontWeight: "bold", children: String(el.label) }) : null
1775
+ ] });
1776
+ });
1777
+ registerRenderer("system_boundary", (el) => {
1778
+ const minX = Math.min(el.x1, el.x2);
1779
+ const minY = Math.min(el.y1, el.y2);
1780
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
1781
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
1782
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${minX}, ${minY})`, children: [
1783
+ /* @__PURE__ */ jsx7("rect", { x: 0, y: 0, width: w, height: h, fill: "none", stroke: c5(el), strokeWidth: sw5(el), strokeDasharray: "8 6", rx: 15 }),
1784
+ el.label ? /* @__PURE__ */ jsx7("text", { x: w / 2, y: -10, fontSize: font3(el), fill: c5(el), textAnchor: "middle", fontStyle: "italic", children: String(el.label) }) : null
1785
+ ] });
1786
+ });
1787
+ registerRenderer("rocket", (el) => {
1788
+ const dx = el.x2 - el.x1;
1789
+ const dy = el.y2 - el.y1;
1790
+ const dist = Math.hypot(dx, dy);
1791
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1792
+ const minX = Math.min(el.x1, el.x2);
1793
+ const maxX = Math.max(el.x1, el.x2);
1794
+ const minY = Math.min(el.y1, el.y2);
1795
+ const maxY = Math.max(el.y1, el.y2);
1796
+ const w = Math.max(1, maxX - minX);
1797
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1798
+ /* @__PURE__ */ jsx7(
1799
+ "path",
1800
+ {
1801
+ d: `M 0 ${-w / 4} L ${dist * 0.7} ${-w / 4} L ${dist} 0 L ${dist * 0.7} ${w / 4} L 0 ${w / 4} Z`,
1802
+ fill: "none",
1803
+ stroke: c5(el),
1804
+ strokeWidth: sw5(el)
1805
+ }
1806
+ ),
1807
+ /* @__PURE__ */ jsx7("polygon", { points: `0,${-w / 4} ${dist * 0.2},${-w / 4} 0,${-w / 2}`, fill: c5(el), fillOpacity: 0.8 }),
1808
+ /* @__PURE__ */ jsx7("polygon", { points: `0,${w / 4} ${dist * 0.2},${w / 4} 0,${w / 2}`, fill: c5(el), fillOpacity: 0.8 }),
1809
+ /* @__PURE__ */ jsx7("path", { d: `M 0 ${-w / 6} Q ${-dist * 0.3} 0 0 ${w / 6}`, fill: "#f97316", fillOpacity: 0.8 }),
1810
+ /* @__PURE__ */ jsx7("path", { d: `M 0 ${-w / 8} Q ${-dist * 0.5} 0 0 ${w / 8}`, fill: "#ef4444", fillOpacity: 0.6 }),
1811
+ el.label ? /* @__PURE__ */ jsx7("text", { x: dist / 2, y: -w / 2 - 10, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1812
+ ] });
1813
+ });
1814
+ registerRenderer("dashed_path", (el) => {
1815
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1816
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1817
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1818
+ /* @__PURE__ */ jsx7("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c5(el), strokeWidth: sw5(el), strokeLinecap: "round", strokeDasharray: "8 6" }),
1819
+ el.label ? /* @__PURE__ */ jsx7("text", { x: d / 2, y: -10, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1820
+ ] });
1821
+ });
1822
+ registerRenderer("uniform_rod", (el) => {
1823
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1824
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1825
+ const strokeWidth = sw5(el);
1826
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1827
+ /* @__PURE__ */ jsx7("rect", { x: 0, y: -strokeWidth / 2, width: dist, height: strokeWidth, fill: c5(el), rx: strokeWidth / 4 }),
1828
+ /* @__PURE__ */ jsx7("circle", { cx: dist / 2, cy: 0, r: Math.max(2, strokeWidth / 4), fill: "#fff" }),
1829
+ el.label ? /* @__PURE__ */ jsx7("text", { x: dist / 2, y: -strokeWidth / 2 - 10, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1830
+ ] });
1831
+ });
1832
+ registerRenderer("solid_disk", (el) => {
1833
+ const dx = el.x2 - el.x1;
1834
+ const dy = el.y2 - el.y1;
1835
+ const radius = Math.hypot(dx, dy);
1836
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1837
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: radius, fill: c5(el), fillOpacity: 0.4, stroke: c5(el), strokeWidth: sw5(el) }),
1838
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: radius + 20, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1839
+ ] });
1840
+ });
1841
+ registerRenderer("hoop_ring", (el) => {
1842
+ const dx = el.x2 - el.x1;
1843
+ const dy = el.y2 - el.y1;
1844
+ const radius = Math.hypot(dx, dy);
1845
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1846
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: radius, fill: "none", stroke: c5(el), strokeWidth: Math.max(4, sw5(el) * 2) }),
1847
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: radius + 20, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1848
+ ] });
1849
+ });
1850
+ registerRenderer("rolling_body", (el) => {
1851
+ const dx = el.x2 - el.x1;
1852
+ const dy = el.y2 - el.y1;
1853
+ const radius = Math.hypot(dx, dy);
1854
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1855
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: radius, fill: c5(el), fillOpacity: 0.1, stroke: c5(el), strokeWidth: sw5(el) }),
1856
+ /* @__PURE__ */ jsx7("line", { x1: -radius, y1: 0, x2: radius, y2: 0, stroke: c5(el), strokeWidth: 1, strokeDasharray: "4 4" }),
1857
+ /* @__PURE__ */ jsx7("line", { x1: 0, y1: -radius, x2: 0, y2: radius, stroke: c5(el), strokeWidth: 1, strokeDasharray: "4 4" }),
1858
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: 3, fill: c5(el) }),
1859
+ el.showVelocity ? /* @__PURE__ */ jsxs7("g", { children: [
1860
+ /* @__PURE__ */ jsx7("line", { x1: 0, y1: 0, x2: radius * 1.5, y2: 0, stroke: "#ef4444", strokeWidth: 2 }),
1861
+ /* @__PURE__ */ jsx7("polygon", { points: `${radius * 1.5},0 ${radius * 1.5 - 8},-4 ${radius * 1.5 - 8},4`, fill: "#ef4444" }),
1862
+ /* @__PURE__ */ jsx7("text", { x: radius * 1.5 + 10, y: 5, fill: "#ef4444", fontSize: 14, fontStyle: "italic", children: "v" })
1863
+ ] }) : null,
1864
+ el.showOmega ? /* @__PURE__ */ jsxs7("g", { transform: `translate(0, ${-radius * 1.2})`, children: [
1865
+ /* @__PURE__ */ jsx7("path", { d: `M ${-radius * 0.4} 0 A ${radius * 0.4} ${radius * 0.4} 0 0 1 ${radius * 0.4} 0`, fill: "none", stroke: "#10b981", strokeWidth: 2 }),
1866
+ /* @__PURE__ */ jsx7("polygon", { points: `${radius * 0.4},0 ${radius * 0.4 - 4},-6 ${radius * 0.4 + 4},-6`, fill: "#10b981" }),
1867
+ /* @__PURE__ */ jsx7("text", { x: 0, y: -10, fill: "#10b981", fontSize: 14, fontStyle: "italic", textAnchor: "middle", children: "\u03C9" })
1868
+ ] }) : null,
1869
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: radius + 20, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1870
+ ] });
1871
+ });
1872
+ registerRenderer("inclined_wedge", (el) => {
1873
+ const { x1, y1, x2, y2 } = el;
1874
+ const dx = x2 - x1;
1875
+ const dy = y2 - y1;
1876
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
1877
+ return /* @__PURE__ */ jsxs7("g", { children: [
1878
+ /* @__PURE__ */ jsx7(
1879
+ "polygon",
1880
+ {
1881
+ points: `${x1},${y1} ${x1},${y2} ${x2},${y2}`,
1882
+ fill: c5(el),
1883
+ fillOpacity: 0.1,
1884
+ stroke: c5(el),
1885
+ strokeWidth: sw5(el),
1886
+ strokeLinejoin: "round"
1887
+ }
1888
+ ),
1889
+ el.label ? /* @__PURE__ */ jsx7("text", { x: (x1 + x2) / 2, y: y2 - 10, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null,
1890
+ Math.abs(x2 - x1) > 20 && Math.abs(y2 - y1) > 20 ? /* @__PURE__ */ jsx7(
1891
+ "path",
1892
+ {
1893
+ d: `M ${x2 > x1 ? x2 - 20 : x2 + 20} ${y2} A 20 20 0 0 ${x2 > x1 ? 0 : 1} ${x2 > x1 ? x2 - 20 * Math.cos(angle * Math.PI / 180) : x2 + 20 * Math.cos(angle * Math.PI / 180)} ${y2 - 20 * Math.sin(Math.abs(angle) * Math.PI / 180)}`,
1894
+ fill: "none",
1895
+ stroke: c5(el),
1896
+ strokeWidth: 1
1897
+ }
1898
+ ) : null
1899
+ ] });
1900
+ });
1901
+ registerRenderer("pulley", (el) => {
1902
+ const dx = el.x2 - el.x1;
1903
+ const dy = el.y2 - el.y1;
1904
+ const radius = Math.hypot(dx, dy);
1905
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
1906
+ /* @__PURE__ */ jsx7("path", { d: `M 0 0 L 0 ${-radius * 1.5}`, fill: "none", stroke: c5(el), strokeWidth: sw5(el) }),
1907
+ /* @__PURE__ */ jsx7("line", { x1: -radius * 0.8, y1: -radius * 1.5, x2: radius * 0.8, y2: -radius * 1.5, stroke: c5(el), strokeWidth: sw5(el) }),
1908
+ Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx7(
1909
+ "line",
1910
+ {
1911
+ x1: -radius * 0.8 + i * radius * 0.4,
1912
+ y1: -radius * 1.5,
1913
+ x2: -radius * 0.8 + i * radius * 0.4 + 5,
1914
+ y2: -radius * 1.5 - 5,
1915
+ stroke: c5(el),
1916
+ strokeWidth: 1
1917
+ },
1918
+ i
1919
+ )),
1920
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: radius, fill: "#fff", stroke: c5(el), strokeWidth: sw5(el) }),
1921
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: radius * 0.8, fill: "none", stroke: c5(el), strokeWidth: 1, opacity: 0.3 }),
1922
+ /* @__PURE__ */ jsx7("circle", { cx: 0, cy: 0, r: 3, fill: c5(el) }),
1923
+ el.label ? /* @__PURE__ */ jsx7("text", { x: 0, y: -radius * 1.5 - 15, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1924
+ ] });
1925
+ });
1926
+ registerRenderer("curve_arrow", (el) => {
1927
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1928
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1929
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1930
+ /* @__PURE__ */ jsx7("path", { d: `M 0 0 Q ${dist / 2} ${-dist * 0.5} ${dist} 0`, fill: "none", stroke: c5(el), strokeWidth: sw5(el), strokeLinecap: "round" }),
1931
+ /* @__PURE__ */ jsx7("polygon", { points: `${dist},0 ${dist - 8},-6 ${dist - 4},-1`, fill: c5(el), transform: `rotate(20 ${dist} 0)` }),
1932
+ el.label ? /* @__PURE__ */ jsx7("text", { x: dist / 2, y: -dist * 0.3, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1933
+ ] });
1934
+ });
1935
+ registerRenderer("spring", (el) => {
1936
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
1937
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
1938
+ return /* @__PURE__ */ jsxs7("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
1939
+ /* @__PURE__ */ jsx7(
1940
+ "path",
1941
+ {
1942
+ d: generateSpringPath(dist, el.coils),
1943
+ fill: "none",
1944
+ stroke: c5(el),
1945
+ strokeWidth: sw5(el),
1946
+ strokeLinecap: "round",
1947
+ strokeLinejoin: "round"
1948
+ }
1949
+ ),
1950
+ el.label ? /* @__PURE__ */ jsx7("text", { x: dist / 2, y: -20, fontSize: font3(el), fill: c5(el), textAnchor: "middle", children: String(el.label) }) : null
1951
+ ] });
1952
+ });
1953
+
1954
+ // src/core/renderers/circuit.tsx
1955
+ import { Fragment, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1956
+ var drawColor = (el, ctx) => ctx?.isSelected ? "#2563eb" : el.color || "#111827";
1957
+ var drawStroke = (el, ctx) => ctx?.isSelected ? 2.5 : el.strokeWidth || 2;
1958
+ registerRenderer("wire", (el, ctx) => /* @__PURE__ */ jsxs8("g", { opacity: ctx?.isGhost ? 0.5 : 1, children: [
1959
+ /* @__PURE__ */ jsx8(
1960
+ "line",
1961
+ {
1962
+ x1: el.x1,
1963
+ y1: el.y1,
1964
+ x2: el.x2,
1965
+ y2: el.y2,
1966
+ stroke: "transparent",
1967
+ strokeWidth: 20,
1968
+ strokeLinecap: "round"
1969
+ }
1970
+ ),
1971
+ /* @__PURE__ */ jsx8(
1972
+ "line",
1973
+ {
1974
+ x1: el.x1,
1975
+ y1: el.y1,
1976
+ x2: el.x2,
1977
+ y2: el.y2,
1978
+ stroke: drawColor(el, ctx),
1979
+ strokeWidth: drawStroke(el, ctx),
1980
+ strokeLinecap: "round",
1981
+ pointerEvents: "none"
1982
+ }
1983
+ )
1984
+ ] }));
1985
+ var rotated = (el, inner, ctx) => {
1986
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
1987
+ const a = angleDeg(el.x1, el.y1, el.x2, el.y2);
1988
+ const dx = el.x2 - el.x1;
1989
+ const dy = el.y2 - el.y1;
1990
+ const mx = (el.x1 + el.x2) / 2;
1991
+ const my = (el.y1 + el.y2) / 2;
1992
+ let nx = -dy / (d || 1);
1993
+ let ny = dx / (d || 1);
1994
+ if (ny > 0) {
1995
+ nx = -nx;
1996
+ ny = -ny;
1997
+ }
1998
+ const labelDist = 20;
1999
+ return /* @__PURE__ */ jsxs8("g", { opacity: ctx?.isGhost ? 0.5 : 1, children: [
2000
+ /* @__PURE__ */ jsx8("line", { x1: el.x1, y1: el.y1, x2: el.x2, y2: el.y2, stroke: "transparent", strokeWidth: 20 }),
2001
+ /* @__PURE__ */ jsx8("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${a})`, children: /* @__PURE__ */ jsx8("g", { children: inner }) }),
2002
+ el.label && /* @__PURE__ */ jsx8("text", { x: mx + nx * labelDist, y: my + ny * labelDist, dominantBaseline: "central", textAnchor: "middle", fill: drawColor(el, ctx), fontSize: "16", fontFamily: "serif", fontWeight: "bold", children: String(el.label) }),
2003
+ el.value && /* @__PURE__ */ jsx8("text", { x: mx - nx * labelDist, y: my - ny * labelDist, dominantBaseline: "central", textAnchor: "middle", fill: "#4b5563", fontSize: "14", fontFamily: "sans-serif", children: String(el.value) })
2004
+ ] });
2005
+ };
2006
+ registerRenderer("resistor", (el, ctx) => {
2007
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2008
+ const start = d / 2 - 15;
2009
+ return rotated(el, /* @__PURE__ */ jsx8("path", { d: `M 0 0 L ${start} 0 l 2.5 -8 l 5 16 l 5 -16 l 5 16 l 5 -16 l 5 16 l 2.5 -8 L ${d} 0`, fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx), strokeLinejoin: "bevel" }), ctx);
2010
+ });
2011
+ registerRenderer("capacitor", (el, ctx) => {
2012
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2013
+ const cx = d / 2;
2014
+ return rotated(el, /* @__PURE__ */ jsx8("path", { d: `M 0 0 L ${cx - 4} 0 M ${cx - 4} -12 L ${cx - 4} 12 M ${cx + 4} -12 L ${cx + 4} 12 M ${cx + 4} 0 L ${d} 0`, fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }), ctx);
2015
+ });
2016
+ registerRenderer("inductor", (el, ctx) => {
2017
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2018
+ const s = d / 2 - 15;
2019
+ return rotated(el, /* @__PURE__ */ jsx8("path", { d: `M 0 0 L ${s} 0 A 5 5 0 0 0 ${s + 10} 0 A 5 5 0 0 0 ${s + 20} 0 A 5 5 0 0 0 ${s + 30} 0 L ${d} 0`, fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }), ctx);
2020
+ });
2021
+ registerRenderer("diode", (el, ctx) => {
2022
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2023
+ const cx = d / 2;
2024
+ return rotated(el, /* @__PURE__ */ jsx8("path", { d: `M 0 0 L ${cx - 8} 0 M ${cx - 8} -8 L ${cx - 8} 8 L ${cx + 8} 0 Z M ${cx + 8} -8 L ${cx + 8} 8 M ${cx + 8} 0 L ${d} 0`, fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }), ctx);
2025
+ });
2026
+ registerRenderer("battery", (el, ctx) => {
2027
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2028
+ const cx = d / 2;
2029
+ return rotated(el, /* @__PURE__ */ jsxs8(Fragment, { children: [
2030
+ /* @__PURE__ */ jsx8("path", { d: `M 0 0 L ${cx - 4} 0 M ${cx - 4} -16 L ${cx - 4} 16 M ${cx + 4} -8 L ${cx + 4} 8 M ${cx + 4} 0 L ${d} 0`, fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }),
2031
+ /* @__PURE__ */ jsx8("line", { x1: cx + 4, y1: -8, x2: cx + 4, y2: 8, stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) + 2 }),
2032
+ /* @__PURE__ */ jsx8("text", { x: cx - 12, y: -12, fontSize: "12", fill: drawColor(el, ctx), textAnchor: "middle", children: "+" })
2033
+ ] }), ctx);
2034
+ });
2035
+ ["meter_v", "meter_a"].forEach(
2036
+ (t) => registerRenderer(t, (el, ctx) => {
2037
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2038
+ const cx = d / 2;
2039
+ const letter = t === "meter_v" ? "V" : "A";
2040
+ return rotated(el, /* @__PURE__ */ jsxs8(Fragment, { children: [
2041
+ /* @__PURE__ */ jsx8("path", { d: `M 0 0 L ${cx - 14} 0 M ${cx + 14} 0 L ${d} 0`, fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }),
2042
+ /* @__PURE__ */ jsx8("circle", { cx, cy: 0, r: 14, fill: "#f8f9fa", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }),
2043
+ /* @__PURE__ */ jsx8("text", { x: cx, y: 0, textAnchor: "middle", dominantBaseline: "central", fill: drawColor(el, ctx), fontSize: "14", fontWeight: "bold", children: letter })
2044
+ ] }), ctx);
2045
+ })
2046
+ );
2047
+ registerRenderer("ground", (el, ctx) => /* @__PURE__ */ jsx8("g", { transform: `translate(${el.x1}, ${el.y1})`, opacity: ctx?.isGhost ? 0.5 : 1, children: /* @__PURE__ */ jsx8("path", { d: "M 0 0 L 0 15 M -12 15 L 12 15 M -8 20 L 8 20 M -4 25 L 4 25", fill: "none", stroke: drawColor(el, ctx), strokeWidth: drawStroke(el, ctx) }) }));
2048
+
2049
+ // src/core/renderers/circuitAutoNodes.ts
2050
+ var getCircuitAutoNodes = (elements) => {
2051
+ const pointMap = {};
2052
+ elements.forEach((el) => {
2053
+ if (el.type !== "wire") return;
2054
+ const p1 = `${el.x1},${el.y1}`;
2055
+ const p2 = `${el.x2},${el.y2}`;
2056
+ pointMap[p1] = (pointMap[p1] || 0) + 1;
2057
+ pointMap[p2] = (pointMap[p2] || 0) + 1;
2058
+ });
2059
+ return Object.entries(pointMap).filter(([, count]) => count > 2).map(([pt]) => pt.split(",").map(Number));
2060
+ };
2061
+
2062
+ // src/core/renderers/thermo.tsx
2063
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2064
+ var c6 = (el) => el.color || "#0f172a";
2065
+ var sw6 = (el) => el.strokeWidth || 2;
2066
+ var font4 = (el) => el.fontSize || 18;
2067
+ var seededRandom = (seed) => {
2068
+ const x = Math.sin(seed) * 1e4;
2069
+ return x - Math.floor(x);
2070
+ };
2071
+ var strokeDashFromLineStyle = (el) => {
2072
+ if (el.lineStyle === "dashed") return "6 6";
2073
+ if (el.lineStyle === "dotted") return "2 4";
2074
+ return void 0;
2075
+ };
2076
+ registerRenderer("pv_axes", (el) => {
2077
+ const minX = Math.min(el.x1, el.x2);
2078
+ const minY = Math.min(el.y1, el.y2);
2079
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
2080
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
2081
+ const yLabel = String(el.yLabel ?? "P");
2082
+ const xLabel = String(el.xLabel ?? "V");
2083
+ const color = c6(el);
2084
+ const strokeWidth = sw6(el);
2085
+ const fontSize = font4(el);
2086
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${minX}, ${minY})`, children: [
2087
+ /* @__PURE__ */ jsx9("line", { x1: 0, y1: 0, x2: 0, y2: h, stroke: color, strokeWidth }),
2088
+ /* @__PURE__ */ jsx9("polygon", { points: "0,0 -5,10 5,10", fill: color }),
2089
+ /* @__PURE__ */ jsx9("text", { x: -15, y: 10, fontSize, fill: color, fontWeight: "bold", children: yLabel }),
2090
+ /* @__PURE__ */ jsx9("line", { x1: 0, y1: h, x2: w, y2: h, stroke: color, strokeWidth }),
2091
+ /* @__PURE__ */ jsx9("polygon", { points: `${w},${h} ${w - 10},${h - 5} ${w - 10},${h + 5}`, fill: color }),
2092
+ /* @__PURE__ */ jsx9("text", { x: w - 10, y: h + 20, fontSize, fill: color, fontWeight: "bold", children: xLabel }),
2093
+ /* @__PURE__ */ jsx9("text", { x: -10, y: h + 15, fontSize: 12, fill: color, children: "0" }),
2094
+ el.label ? /* @__PURE__ */ jsx9("text", { x: w / 2, y: -10, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
2095
+ ] });
2096
+ });
2097
+ registerRenderer("piston_cylinder", (el) => {
2098
+ const minX = Math.min(el.x1, el.x2);
2099
+ const minY = Math.min(el.y1, el.y2);
2100
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
2101
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
2102
+ const compression = el.compression ?? 0.5;
2103
+ const pistonY = h * compression;
2104
+ const color = c6(el);
2105
+ const strokeWidth = sw6(el);
2106
+ const particles = [];
2107
+ const numParticles = 40;
2108
+ for (let i = 0; i < numParticles; i++) {
2109
+ const px = seededRandom(Number(el.id) + i) * (w - 10) + 5;
2110
+ const py = pistonY + 10 + seededRandom(Number(el.id) + i * 100) * (h - pistonY - 15);
2111
+ particles.push(/* @__PURE__ */ jsx9("circle", { cx: px, cy: py, r: "2", fill: "#94a3b8" }, i));
2112
+ }
2113
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${minX}, ${minY})`, children: [
2114
+ /* @__PURE__ */ jsx9(
2115
+ "polyline",
2116
+ {
2117
+ points: `0,0 0,${h} ${w},${h} ${w},0`,
2118
+ fill: "#f8fafc",
2119
+ stroke: color,
2120
+ strokeWidth,
2121
+ strokeLinecap: "square",
2122
+ strokeLinejoin: "miter"
2123
+ }
2124
+ ),
2125
+ particles,
2126
+ /* @__PURE__ */ jsxs9("g", { transform: `translate(0, ${pistonY})`, children: [
2127
+ /* @__PURE__ */ jsx9("rect", { x: "2", y: "0", width: w - 4, height: "12", fill: "#64748b", rx: "2" }),
2128
+ /* @__PURE__ */ jsx9("line", { x1: w / 2, y1: "0", x2: w / 2, y2: "-40", stroke: "#64748b", strokeWidth: "4" }),
2129
+ /* @__PURE__ */ jsx9("line", { x1: w / 2 - 15, y1: "-40", x2: w / 2 + 15, y2: "-40", stroke: "#64748b", strokeWidth: "6", strokeLinecap: "round" }),
2130
+ /* @__PURE__ */ jsx9("line", { x1: w / 2, y1: "-50", x2: w / 2, y2: "-42", stroke: "#ef4444", strokeWidth: "2" }),
2131
+ /* @__PURE__ */ jsx9("polygon", { points: `${w / 2},-42 ${w / 2 - 4},-46 ${w / 2 + 4},-46`, fill: "#ef4444" })
2132
+ ] }),
2133
+ el.showHeat ? /* @__PURE__ */ jsxs9("g", { transform: `translate(${w / 2}, ${h + 15})`, children: [
2134
+ /* @__PURE__ */ jsx9("path", { d: "M-10,0 Q-15,-10 -5,-20 Q0,-10 10,-15 Q5,-5 10,0 Z", fill: "#ef4444", opacity: "0.8" }),
2135
+ /* @__PURE__ */ jsx9("path", { d: "M-5,0 Q-8,-6 0,-12 Q2,-5 5,0 Z", fill: "#f59e0b" }),
2136
+ /* @__PURE__ */ jsx9("text", { x: "25", y: "-5", fontSize: "14", fill: "#ef4444", fontWeight: "bold", children: "Q" })
2137
+ ] }) : null,
2138
+ el.label ? /* @__PURE__ */ jsx9("text", { x: w / 2, y: h + (el.showHeat ? 35 : 20), textAnchor: "middle", fill: color, fontSize: font4(el), children: String(el.label) }) : null
2139
+ ] });
2140
+ });
2141
+ registerRenderer("heat_engine", (el) => {
2142
+ const minX = Math.min(el.x1, el.x2);
2143
+ const minY = Math.min(el.y1, el.y2);
2144
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
2145
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
2146
+ const isEngine = el.engineType !== "refrigerator";
2147
+ const r = Math.min(w * 0.3, h * 0.2);
2148
+ const color = c6(el);
2149
+ const strokeWidth = sw6(el);
2150
+ const fontSize = font4(el);
2151
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${minX}, ${minY})`, children: [
2152
+ /* @__PURE__ */ jsx9("rect", { x: 0, y: 0, width: w, height: h * 0.2, fill: "#ef4444", rx: "4" }),
2153
+ /* @__PURE__ */ jsx9("text", { x: w / 2, y: h * 0.1, fontSize, fill: "#fff", textAnchor: "middle", dominantBaseline: "central", children: "T_H" }),
2154
+ /* @__PURE__ */ jsx9("rect", { x: 0, y: h * 0.8, width: w, height: h * 0.2, fill: "#3b82f6", rx: "4" }),
2155
+ /* @__PURE__ */ jsx9("text", { x: w / 2, y: h * 0.9, fontSize, fill: "#fff", textAnchor: "middle", dominantBaseline: "central", children: "T_C" }),
2156
+ /* @__PURE__ */ jsx9("circle", { cx: w / 2, cy: h / 2, r, fill: "#fff", stroke: color, strokeWidth }),
2157
+ /* @__PURE__ */ jsx9(
2158
+ "text",
2159
+ {
2160
+ x: w / 2,
2161
+ y: h / 2,
2162
+ fontSize: fontSize * 1.2,
2163
+ fill: color,
2164
+ textAnchor: "middle",
2165
+ dominantBaseline: "central",
2166
+ fontWeight: "bold",
2167
+ children: isEngine ? "E" : "R"
2168
+ }
2169
+ ),
2170
+ /* @__PURE__ */ jsxs9("g", { strokeWidth: 2, stroke: color, children: [
2171
+ /* @__PURE__ */ jsx9("line", { x1: w / 2, y1: h * 0.2, x2: w / 2, y2: h * 0.5 - r - 5 }),
2172
+ /* @__PURE__ */ jsx9(
2173
+ "polygon",
2174
+ {
2175
+ points: isEngine ? `${w / 2},${h * 0.5 - r - 2} ${w / 2 - 5},${h * 0.5 - r - 10} ${w / 2 + 5},${h * 0.5 - r - 10}` : `${w / 2},${h * 0.2 + 2} ${w / 2 - 5},${h * 0.2 + 10} ${w / 2 + 5},${h * 0.2 + 10}`,
2176
+ fill: color
2177
+ }
2178
+ ),
2179
+ /* @__PURE__ */ jsx9("text", { x: w / 2 + 10, y: h * 0.35, fontSize: 14, fill: color, dominantBaseline: "central", children: "Q_H" }),
2180
+ /* @__PURE__ */ jsx9("line", { x1: w / 2, y1: h * 0.5 + r + 5, x2: w / 2, y2: h * 0.8 }),
2181
+ /* @__PURE__ */ jsx9(
2182
+ "polygon",
2183
+ {
2184
+ points: isEngine ? `${w / 2},${h * 0.8 - 2} ${w / 2 - 5},${h * 0.8 - 10} ${w / 2 + 5},${h * 0.8 - 10}` : `${w / 2},${h * 0.5 + r + 2} ${w / 2 - 5},${h * 0.5 + r + 10} ${w / 2 + 5},${h * 0.5 + r + 10}`,
2185
+ fill: color
2186
+ }
2187
+ ),
2188
+ /* @__PURE__ */ jsx9("text", { x: w / 2 + 10, y: h * 0.65, fontSize: 14, fill: color, dominantBaseline: "central", children: "Q_C" }),
2189
+ /* @__PURE__ */ jsx9(
2190
+ "line",
2191
+ {
2192
+ x1: isEngine ? w / 2 + r + 5 : w,
2193
+ y1: h / 2,
2194
+ x2: isEngine ? w : w / 2 + r + 5,
2195
+ y2: h / 2
2196
+ }
2197
+ ),
2198
+ /* @__PURE__ */ jsx9(
2199
+ "polygon",
2200
+ {
2201
+ points: isEngine ? `${w},${h / 2} ${w - 8},${h / 2 - 5} ${w - 8},${h / 2 + 5}` : `${w / 2 + r + 5},${h / 2} ${w / 2 + r + 13},${h / 2 - 5} ${w / 2 + r + 13},${h / 2 + 5}`,
2202
+ fill: color
2203
+ }
2204
+ ),
2205
+ /* @__PURE__ */ jsx9("text", { x: w * 0.8, y: h / 2 - 15, fontSize: 14, fill: color, textAnchor: "middle", children: "W" })
2206
+ ] }),
2207
+ el.label ? /* @__PURE__ */ jsx9("text", { x: w / 2, y: h + 20, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
2208
+ ] });
2209
+ });
2210
+ registerRenderer("conduction_rod", (el) => {
2211
+ const dist = distance(el.x1, el.y1, el.x2, el.y2);
2212
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
2213
+ const gradId = `grad-rod-${el.id}`;
2214
+ const color = c6(el);
2215
+ const strokeWidth = sw6(el);
2216
+ const fontSize = font4(el);
2217
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
2218
+ /* @__PURE__ */ jsx9("defs", { children: /* @__PURE__ */ jsxs9("linearGradient", { id: gradId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: [
2219
+ /* @__PURE__ */ jsx9("stop", { offset: "0%", stopColor: "#ef4444" }),
2220
+ /* @__PURE__ */ jsx9("stop", { offset: "100%", stopColor: "#3b82f6" })
2221
+ ] }) }),
2222
+ /* @__PURE__ */ jsx9("rect", { x: 0, y: -20, width: dist, height: 40, fill: `url(#${gradId})`, stroke: color, strokeWidth, rx: "4" }),
2223
+ /* @__PURE__ */ jsxs9("g", { stroke: "#fff", strokeWidth: "2", opacity: 0.6, children: [
2224
+ /* @__PURE__ */ jsx9("line", { x1: dist * 0.2, y1: 0, x2: dist * 0.4, y2: 0 }),
2225
+ /* @__PURE__ */ jsx9("polygon", { points: `${dist * 0.4},0 ${dist * 0.4 - 6},-4 ${dist * 0.4 - 6},4`, fill: "#fff" }),
2226
+ /* @__PURE__ */ jsx9("line", { x1: dist * 0.6, y1: 0, x2: dist * 0.8, y2: 0 }),
2227
+ /* @__PURE__ */ jsx9("polygon", { points: `${dist * 0.8},0 ${dist * 0.8 - 6},-4 ${dist * 0.8 - 6},4`, fill: "#fff" })
2228
+ ] }),
2229
+ /* @__PURE__ */ jsx9("text", { x: 0, y: -30, fontSize, fill: "#ef4444", textAnchor: "middle", fontWeight: "bold", children: "T_H" }),
2230
+ /* @__PURE__ */ jsx9("text", { x: dist, y: -30, fontSize, fill: "#3b82f6", textAnchor: "middle", fontWeight: "bold", children: "T_C" }),
2231
+ el.label ? /* @__PURE__ */ jsx9("text", { x: dist / 2, y: 35, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
2232
+ ] });
2233
+ });
2234
+ registerRenderer("thermo_process", (el) => {
2235
+ const pType = el.processType || "isotherm";
2236
+ const dx = el.x2 - el.x1;
2237
+ const dy = el.y2 - el.y1;
2238
+ let pathD = "";
2239
+ if (pType === "isobaric") pathD = `M 0 0 L ${dx} 0`;
2240
+ else if (pType === "isochoric") pathD = `M 0 0 L 0 ${dy}`;
2241
+ else if (pType === "adiabatic") pathD = `M 0 0 Q ${dx * 0.1} ${dy * 0.9} ${dx} ${dy}`;
2242
+ else pathD = `M 0 0 Q ${dx * 0.2} ${dy * 0.8} ${dx} ${dy}`;
2243
+ let midX = dx / 2;
2244
+ let midY = dy / 2;
2245
+ if (pType === "isotherm" || pType === "adiabatic") {
2246
+ const cx = dx * (pType === "adiabatic" ? 0.1 : 0.2);
2247
+ const cy = dy * (pType === "adiabatic" ? 0.9 : 0.8);
2248
+ midX = 0.25 * 0 + 0.5 * cx + 0.25 * dx;
2249
+ midY = 0.25 * 0 + 0.5 * cy + 0.25 * dy;
2250
+ }
2251
+ const arrowAngle = Math.atan2(dy, dx) * 180 / Math.PI;
2252
+ const dash = strokeDashFromLineStyle(el);
2253
+ const color = c6(el);
2254
+ const strokeWidth = sw6(el);
2255
+ const fontSize = font4(el);
2256
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2257
+ /* @__PURE__ */ jsx9("path", { d: pathD, fill: "none", stroke: color, strokeWidth, strokeDasharray: dash }),
2258
+ /* @__PURE__ */ jsx9("g", { transform: `translate(${midX}, ${midY}) rotate(${arrowAngle})`, children: /* @__PURE__ */ jsx9("polygon", { points: "0,0 -8,-5 -8,5", fill: color }) }),
2259
+ el.label ? /* @__PURE__ */ jsx9("text", { x: midX + 15, y: midY - 10, fontSize, fill: color, children: String(el.label) }) : null
2260
+ ] });
2261
+ });
2262
+ registerRenderer("carnot_cycle", (el) => {
2263
+ const minX = Math.min(el.x1, el.x2);
2264
+ const minY = Math.min(el.y1, el.y2);
2265
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
2266
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
2267
+ const p1 = { x: w * 0.1, y: h * 0.1 };
2268
+ const p2 = { x: w * 0.6, y: h * 0.3 };
2269
+ const p3 = { x: w * 0.9, y: h * 0.9 };
2270
+ const p4 = { x: w * 0.4, y: h * 0.7 };
2271
+ const iso1 = `M ${p1.x} ${p1.y} Q ${w * 0.3} ${h * 0.15} ${p2.x} ${p2.y}`;
2272
+ const ad1 = `Q ${w * 0.7} ${h * 0.6} ${p3.x} ${p3.y}`;
2273
+ const iso2 = `Q ${w * 0.6} ${h * 0.85} ${p4.x} ${p4.y}`;
2274
+ const ad2 = `Q ${w * 0.2} ${h * 0.4} ${p1.x} ${p1.y}`;
2275
+ const color = c6(el);
2276
+ const strokeWidth = sw6(el);
2277
+ const fontSize = font4(el);
2278
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${minX}, ${minY})`, children: [
2279
+ /* @__PURE__ */ jsx9("path", { d: `${iso1} ${ad1} ${iso2} ${ad2} Z`, fill: color, fillOpacity: 0.1 }),
2280
+ /* @__PURE__ */ jsx9("path", { d: iso1, fill: "none", stroke: "#ef4444", strokeWidth }),
2281
+ /* @__PURE__ */ jsx9("path", { d: `M ${p2.x} ${p2.y} ${ad1}`, fill: "none", stroke: "#64748b", strokeWidth, strokeDasharray: "4 4" }),
2282
+ /* @__PURE__ */ jsx9("path", { d: `M ${p3.x} ${p3.y} ${iso2}`, fill: "none", stroke: "#3b82f6", strokeWidth }),
2283
+ /* @__PURE__ */ jsx9("path", { d: `M ${p4.x} ${p4.y} ${ad2}`, fill: "none", stroke: "#64748b", strokeWidth, strokeDasharray: "4 4" }),
2284
+ /* @__PURE__ */ jsx9("circle", { cx: p1.x, cy: p1.y, r: "3", fill: "#1e293b" }),
2285
+ /* @__PURE__ */ jsx9("circle", { cx: p2.x, cy: p2.y, r: "3", fill: "#1e293b" }),
2286
+ /* @__PURE__ */ jsx9("circle", { cx: p3.x, cy: p3.y, r: "3", fill: "#1e293b" }),
2287
+ /* @__PURE__ */ jsx9("circle", { cx: p4.x, cy: p4.y, r: "3", fill: "#1e293b" }),
2288
+ /* @__PURE__ */ jsx9("text", { x: w * 0.4, y: h * 0.15, fontSize: "14", fill: "#ef4444", fontWeight: "bold", children: "T_H" }),
2289
+ /* @__PURE__ */ jsx9("text", { x: w * 0.6, y: h * 0.95, fontSize: "14", fill: "#3b82f6", fontWeight: "bold", children: "T_C" }),
2290
+ /* @__PURE__ */ jsx9("text", { x: w / 2, y: h / 2 + 5, fontSize: 16, fill: color, textAnchor: "middle", fontWeight: "bold", children: "W" }),
2291
+ el.label ? /* @__PURE__ */ jsx9("text", { x: w / 2, y: -15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
2292
+ ] });
2293
+ });
2294
+ registerRenderer("maxwell_boltzmann", (el) => {
2295
+ const minX = Math.min(el.x1, el.x2);
2296
+ const minY = Math.min(el.y1, el.y2);
2297
+ const w = Math.max(1, Math.abs(el.x2 - el.x1));
2298
+ const h = Math.max(1, Math.abs(el.y2 - el.y1));
2299
+ const t1 = el.t1 || 300;
2300
+ const t2 = el.t2 || 600;
2301
+ const strokeWidth = sw6(el);
2302
+ const fontSize = font4(el);
2303
+ const color = c6(el);
2304
+ const buildCurve = (temp, peakHeight, strokeCol, dash) => {
2305
+ let d = `M 0 ${h}`;
2306
+ const k = 1 / temp;
2307
+ const vmp = Math.sqrt(2 / k);
2308
+ const xMax = vmp * 3.5;
2309
+ for (let x = 0; x <= w; x += 2) {
2310
+ const v = x / w * xMax;
2311
+ const rawVal = v * v * Math.exp(-k * v * v);
2312
+ const maxRawVal = vmp * vmp * Math.exp(-1);
2313
+ const y = h - rawVal / maxRawVal * peakHeight;
2314
+ d += ` L ${x} ${y}`;
2315
+ }
2316
+ return /* @__PURE__ */ jsx9("path", { d, fill: "none", stroke: strokeCol, strokeWidth, strokeDasharray: dash, strokeLinejoin: "round" });
2317
+ };
2318
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${minX}, ${minY})`, children: [
2319
+ /* @__PURE__ */ jsx9("line", { x1: 0, y1: 0, x2: 0, y2: h, stroke: "#1e293b", strokeWidth: "2" }),
2320
+ /* @__PURE__ */ jsx9("line", { x1: 0, y1: h, x2: w, y2: h, stroke: "#1e293b", strokeWidth: "2" }),
2321
+ /* @__PURE__ */ jsx9("text", { x: -25, y: h / 2, fontSize: 14, fill: "#1e293b", transform: `rotate(-90, -25, ${h / 2})`, textAnchor: "middle", children: "N(v)" }),
2322
+ /* @__PURE__ */ jsx9("text", { x: w / 2, y: h + 20, fontSize: 14, fill: "#1e293b", textAnchor: "middle", children: "Speed (v)" }),
2323
+ buildCurve(t1, h * 0.8, "#ef4444"),
2324
+ buildCurve(t2, h * 0.5, "#3b82f6", "4 4"),
2325
+ /* @__PURE__ */ jsx9("rect", { x: w - 70, y: 10, width: 10, height: 10, fill: "#ef4444" }),
2326
+ /* @__PURE__ */ jsxs9("text", { x: w - 55, y: 20, fontSize: 12, fill: "#1e293b", children: [
2327
+ "T\u2081 = ",
2328
+ t1,
2329
+ "K"
2330
+ ] }),
2331
+ /* @__PURE__ */ jsx9("rect", { x: w - 70, y: 30, width: 10, height: 10, fill: "#3b82f6" }),
2332
+ /* @__PURE__ */ jsxs9("text", { x: w - 55, y: 40, fontSize: 12, fill: "#1e293b", children: [
2333
+ "T\u2082 = ",
2334
+ t2,
2335
+ "K"
2336
+ ] }),
2337
+ el.label ? /* @__PURE__ */ jsx9("text", { x: w / 2, y: -15, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
2338
+ ] });
2339
+ });
2340
+ registerRenderer("diatomic_gas", (el) => {
2341
+ const color = c6(el);
2342
+ const strokeWidth = sw6(el);
2343
+ const fontSize = font4(el);
2344
+ const showRot = el.showRotations !== false;
2345
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2346
+ /* @__PURE__ */ jsx9("circle", { cx: -15, cy: 0, r: 8, fill: color, stroke: "#fff", strokeWidth: 2 }),
2347
+ /* @__PURE__ */ jsx9("circle", { cx: 15, cy: 0, r: 8, fill: color, stroke: "#fff", strokeWidth: 2 }),
2348
+ /* @__PURE__ */ jsx9("line", { x1: -10, y1: 0, x2: 10, y2: 0, stroke: color, strokeWidth: 4 }),
2349
+ showRot ? /* @__PURE__ */ jsxs9("g", { stroke: "#94a3b8", strokeWidth: 1.5, fill: "none", children: [
2350
+ /* @__PURE__ */ jsx9("path", { d: "M -10 -15 A 15 15 0 0 1 10 -15", strokeDasharray: "2 2" }),
2351
+ /* @__PURE__ */ jsx9("polygon", { points: "10,-15 6,-18 6,-12", fill: "#94a3b8" }),
2352
+ /* @__PURE__ */ jsx9("path", { d: "M -25 0 A 25 10 0 0 1 0 10 A 25 10 0 0 1 25 0", strokeDasharray: "2 2" })
2353
+ ] }) : null,
2354
+ el.label ? /* @__PURE__ */ jsx9("text", { x: 0, y: 25, fontSize, fill: color, textAnchor: "middle", children: String(el.label) }) : null
2355
+ ] });
2356
+ });
2357
+ registerRenderer("random_walk", (el) => {
2358
+ const steps = el.steps || 5;
2359
+ const dist = Math.hypot(el.x2 - el.x1, el.y2 - el.y1);
2360
+ let d = "M 0 0";
2361
+ let curX = 0;
2362
+ let curY = 0;
2363
+ const points = [/* @__PURE__ */ jsx9("circle", { cx: "0", cy: "0", r: "4", fill: "#22c55e" }, "start")];
2364
+ for (let i = 1; i <= steps; i++) {
2365
+ const angle = seededRandom(Number(el.id) + i * 7) * Math.PI * 2;
2366
+ const stepDist = dist / steps * (0.5 + seededRandom(Number(el.id) + i * 13));
2367
+ curX += Math.cos(angle) * stepDist;
2368
+ curY += Math.sin(angle) * stepDist;
2369
+ d += ` L ${curX} ${curY}`;
2370
+ points.push(/* @__PURE__ */ jsx9("circle", { cx: curX, cy: curY, r: i === steps ? 4 : 2, fill: i === steps ? "#ef4444" : c6(el) }, i));
2371
+ }
2372
+ return /* @__PURE__ */ jsxs9("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2373
+ /* @__PURE__ */ jsx9("path", { d, fill: "none", stroke: c6(el), strokeWidth: sw6(el), strokeLinejoin: "round" }),
2374
+ points,
2375
+ el.label ? /* @__PURE__ */ jsx9("text", { x: dist / 2, y: dist / 2, fontSize: font4(el), fill: c6(el), textAnchor: "middle", children: String(el.label) }) : null
2376
+ ] });
2377
+ });
2378
+
2379
+ // src/core/renderers/chemistry.tsx
2380
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2381
+ var colorOf3 = (el, isSelected) => {
2382
+ if (isSelected) return "#0d9488";
2383
+ return el.color || "#111827";
2384
+ };
2385
+ var strokeOf3 = (el, isSelected) => {
2386
+ const base = el.strokeWidth || 2;
2387
+ return isSelected ? Math.max(3, base) : base;
2388
+ };
2389
+ var fontOf3 = (el) => el.fontSize || 16;
2390
+ var ringPolygonPoints = (sides, radius, startDeg) => Array.from({ length: sides }).map((_, i) => {
2391
+ const angle = (i * 360 / sides + startDeg) * (Math.PI / 180);
2392
+ return `${radius * Math.cos(angle)},${radius * Math.sin(angle)}`;
2393
+ }).join(" ");
2394
+ registerRenderer("atom", (el, ctx) => /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2395
+ /* @__PURE__ */ jsx10("rect", { x: "-20", y: "-15", width: "40", height: "30", fill: "white", rx: "6" }),
2396
+ /* @__PURE__ */ jsx10(
2397
+ "text",
2398
+ {
2399
+ x: "0",
2400
+ y: "0",
2401
+ dominantBaseline: "central",
2402
+ textAnchor: "middle",
2403
+ fill: colorOf3(el, ctx.isSelected),
2404
+ fontSize: Math.max(18, fontOf3(el)),
2405
+ fontFamily: "sans-serif",
2406
+ fontWeight: "bold",
2407
+ children: String(el.label || "C")
2408
+ }
2409
+ )
2410
+ ] }));
2411
+ registerRenderer("charge_plus", (el, ctx) => {
2412
+ const stroke2 = colorOf3(el, ctx.isSelected);
2413
+ const sw7 = strokeOf3(el, ctx.isSelected);
2414
+ const baseSw = el.strokeWidth || 2;
2415
+ const r = Math.max(12, baseSw * 4);
2416
+ return /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2417
+ /* @__PURE__ */ jsx10("circle", { cx: "0", cy: "0", r, fill: "white", stroke: stroke2, strokeWidth: sw7 }),
2418
+ /* @__PURE__ */ jsx10("line", { x1: -r / 2, y1: "0", x2: r / 2, y2: "0", stroke: stroke2, strokeWidth: sw7 }),
2419
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: -r / 2, x2: "0", y2: r / 2, stroke: stroke2, strokeWidth: sw7 }),
2420
+ el.label && /* @__PURE__ */ jsx10(
2421
+ "text",
2422
+ {
2423
+ x: "0",
2424
+ y: r + 18,
2425
+ fontSize: fontOf3(el),
2426
+ fill: stroke2,
2427
+ fontFamily: "sans-serif",
2428
+ fontWeight: "bold",
2429
+ textAnchor: "middle",
2430
+ children: String(el.label)
2431
+ }
2432
+ )
2433
+ ] });
2434
+ });
2435
+ registerRenderer("charge_minus", (el, ctx) => {
2436
+ const stroke2 = colorOf3(el, ctx.isSelected);
2437
+ const sw7 = strokeOf3(el, ctx.isSelected);
2438
+ const baseSw = el.strokeWidth || 2;
2439
+ const r = Math.max(12, baseSw * 4);
2440
+ return /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2441
+ /* @__PURE__ */ jsx10("circle", { cx: "0", cy: "0", r, fill: "white", stroke: stroke2, strokeWidth: sw7 }),
2442
+ /* @__PURE__ */ jsx10("line", { x1: -r / 2, y1: "0", x2: r / 2, y2: "0", stroke: stroke2, strokeWidth: sw7 }),
2443
+ el.label && /* @__PURE__ */ jsx10(
2444
+ "text",
2445
+ {
2446
+ x: "0",
2447
+ y: r + 18,
2448
+ fontSize: fontOf3(el),
2449
+ fill: stroke2,
2450
+ fontFamily: "sans-serif",
2451
+ fontWeight: "bold",
2452
+ textAnchor: "middle",
2453
+ children: String(el.label)
2454
+ }
2455
+ )
2456
+ ] });
2457
+ });
2458
+ registerRenderer("radical", (el, ctx) => /* @__PURE__ */ jsx10("circle", { cx: el.x1, cy: el.y1, r: "3.5", fill: colorOf3(el, ctx.isSelected) }));
2459
+ registerRenderer("lone_pair", (el, ctx) => /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2460
+ /* @__PURE__ */ jsx10("circle", { cx: "-4", cy: "0", r: "2.5", fill: colorOf3(el, ctx.isSelected) }),
2461
+ /* @__PURE__ */ jsx10("circle", { cx: "4", cy: "0", r: "2.5", fill: colorOf3(el, ctx.isSelected) })
2462
+ ] }));
2463
+ registerRenderer("benzene", (el, ctx) => {
2464
+ const r = 30;
2465
+ const stroke2 = colorOf3(el, ctx.isSelected);
2466
+ const sw7 = strokeOf3(el, ctx.isSelected);
2467
+ return /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: [
2468
+ /* @__PURE__ */ jsx10("polygon", { points: ringPolygonPoints(6, r, -30), fill: "white", stroke: stroke2, strokeWidth: sw7, strokeLinejoin: "round" }),
2469
+ /* @__PURE__ */ jsx10("circle", { cx: "0", cy: "0", r: r - 10, fill: "none", stroke: stroke2, strokeWidth: sw7 })
2470
+ ] });
2471
+ });
2472
+ registerRenderer("cyclohexane", (el, ctx) => /* @__PURE__ */ jsx10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: /* @__PURE__ */ jsx10(
2473
+ "polygon",
2474
+ {
2475
+ points: ringPolygonPoints(6, 30, -30),
2476
+ fill: "white",
2477
+ stroke: colorOf3(el, ctx.isSelected),
2478
+ strokeWidth: strokeOf3(el, ctx.isSelected),
2479
+ strokeLinejoin: "round"
2480
+ }
2481
+ ) }));
2482
+ registerRenderer("cyclopentane", (el, ctx) => /* @__PURE__ */ jsx10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: /* @__PURE__ */ jsx10(
2483
+ "polygon",
2484
+ {
2485
+ points: ringPolygonPoints(5, 30, -90),
2486
+ fill: "white",
2487
+ stroke: colorOf3(el, ctx.isSelected),
2488
+ strokeWidth: strokeOf3(el, ctx.isSelected),
2489
+ strokeLinejoin: "round"
2490
+ }
2491
+ ) }));
2492
+ registerRenderer("cyclobutane", (el, ctx) => /* @__PURE__ */ jsx10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: /* @__PURE__ */ jsx10(
2493
+ "polygon",
2494
+ {
2495
+ points: ringPolygonPoints(4, 30, -45),
2496
+ fill: "white",
2497
+ stroke: colorOf3(el, ctx.isSelected),
2498
+ strokeWidth: strokeOf3(el, ctx.isSelected),
2499
+ strokeLinejoin: "round"
2500
+ }
2501
+ ) }));
2502
+ registerRenderer("cyclopropane", (el, ctx) => /* @__PURE__ */ jsx10("g", { transform: `translate(${el.x1}, ${el.y1})`, children: /* @__PURE__ */ jsx10(
2503
+ "polygon",
2504
+ {
2505
+ points: ringPolygonPoints(3, 30, -90),
2506
+ fill: "white",
2507
+ stroke: colorOf3(el, ctx.isSelected),
2508
+ strokeWidth: strokeOf3(el, ctx.isSelected),
2509
+ strokeLinejoin: "round"
2510
+ }
2511
+ ) }));
2512
+ var drawBond = (el, style, isSelected) => {
2513
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2514
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
2515
+ const stroke2 = colorOf3(el, isSelected);
2516
+ const sw7 = strokeOf3(el, isSelected);
2517
+ return /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
2518
+ style === "single" && /* @__PURE__ */ jsx10("line", { x1: "0", y1: "0", x2: d, y2: "0", stroke: stroke2, strokeWidth: sw7, strokeLinecap: "round" }),
2519
+ style === "double" && /* @__PURE__ */ jsxs10(Fragment2, { children: [
2520
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "-3.5", x2: d, y2: "-3.5", stroke: stroke2, strokeWidth: sw7, strokeLinecap: "round" }),
2521
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "3.5", x2: d, y2: "3.5", stroke: stroke2, strokeWidth: sw7, strokeLinecap: "round" })
2522
+ ] }),
2523
+ style === "triple" && /* @__PURE__ */ jsxs10(Fragment2, { children: [
2524
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "-6", x2: d, y2: "-6", stroke: stroke2, strokeWidth: sw7, strokeLinecap: "round" }),
2525
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "0", x2: d, y2: "0", stroke: stroke2, strokeWidth: sw7, strokeLinecap: "round" }),
2526
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "6", x2: d, y2: "6", stroke: stroke2, strokeWidth: sw7, strokeLinecap: "round" })
2527
+ ] }),
2528
+ style === "wedge" && /* @__PURE__ */ jsx10("polygon", { points: `0,0 ${d},-5 ${d},5`, fill: stroke2 }),
2529
+ style === "dash" && /* @__PURE__ */ jsx10("line", { x1: "0", y1: "0", x2: d, y2: "0", stroke: stroke2, strokeWidth: sw7 + 1, strokeDasharray: "5 5", strokeLinecap: "square" })
2530
+ ] });
2531
+ };
2532
+ registerRenderer("single_bond", (el, ctx) => drawBond(el, "single", ctx.isSelected));
2533
+ registerRenderer("double_bond", (el, ctx) => drawBond(el, "double", ctx.isSelected));
2534
+ registerRenderer("triple_bond", (el, ctx) => drawBond(el, "triple", ctx.isSelected));
2535
+ registerRenderer("wedge_bond", (el, ctx) => drawBond(el, "wedge", ctx.isSelected));
2536
+ registerRenderer("dash_bond", (el, ctx) => drawBond(el, "dash", ctx.isSelected));
2537
+ var lineMid = (el) => ({ x: (el.x1 + el.x2) / 2, y: (el.y1 + el.y2) / 2 });
2538
+ registerRenderer("reaction_arrow", (el, ctx) => {
2539
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2540
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
2541
+ const stroke2 = colorOf3(el, ctx.isSelected);
2542
+ const sw7 = strokeOf3(el, ctx.isSelected);
2543
+ const mid = lineMid(el);
2544
+ return /* @__PURE__ */ jsxs10("g", { children: [
2545
+ /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
2546
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "0", x2: d, y2: "0", stroke: stroke2, strokeWidth: sw7 }),
2547
+ /* @__PURE__ */ jsx10("polygon", { points: `${d},0 ${d - 12},-6 ${d - 12},6`, fill: stroke2 })
2548
+ ] }),
2549
+ el.label && /* @__PURE__ */ jsx10("text", { x: mid.x, y: mid.y - 18, textAnchor: "middle", fill: "#0f766e", fontSize: "14", fontFamily: "sans-serif", fontWeight: "bold", children: String(el.label) }),
2550
+ el.value && /* @__PURE__ */ jsx10("text", { x: mid.x, y: mid.y + 18, textAnchor: "middle", fill: "#4b5563", fontSize: "13", fontFamily: "sans-serif", children: String(el.value) })
2551
+ ] });
2552
+ });
2553
+ registerRenderer("equilibrium_arrow", (el, ctx) => {
2554
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2555
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
2556
+ const stroke2 = colorOf3(el, ctx.isSelected);
2557
+ const sw7 = strokeOf3(el, ctx.isSelected);
2558
+ const mid = lineMid(el);
2559
+ return /* @__PURE__ */ jsxs10("g", { children: [
2560
+ /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
2561
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "-4", x2: d, y2: "-4", stroke: stroke2, strokeWidth: sw7 }),
2562
+ /* @__PURE__ */ jsx10("polygon", { points: `${d},-4 ${d - 10},-10 ${d - 10},-4`, fill: stroke2 }),
2563
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "4", x2: d, y2: "4", stroke: stroke2, strokeWidth: sw7 }),
2564
+ /* @__PURE__ */ jsx10("polygon", { points: `0,4 10,4 10,10`, fill: stroke2 })
2565
+ ] }),
2566
+ el.label && /* @__PURE__ */ jsx10("text", { x: mid.x, y: mid.y - 18, textAnchor: "middle", fill: "#0f766e", fontSize: "14", fontFamily: "sans-serif", fontWeight: "bold", children: String(el.label) }),
2567
+ el.value && /* @__PURE__ */ jsx10("text", { x: mid.x, y: mid.y + 18, textAnchor: "middle", fill: "#4b5563", fontSize: "13", fontFamily: "sans-serif", children: String(el.value) })
2568
+ ] });
2569
+ });
2570
+ registerRenderer("resonance_arrow", (el, ctx) => {
2571
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2572
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
2573
+ const stroke2 = colorOf3(el, ctx.isSelected);
2574
+ const sw7 = strokeOf3(el, ctx.isSelected);
2575
+ return /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
2576
+ /* @__PURE__ */ jsx10("line", { x1: "0", y1: "0", x2: d, y2: "0", stroke: stroke2, strokeWidth: sw7 }),
2577
+ /* @__PURE__ */ jsx10("polygon", { points: `0,0 12,-6 12,6`, fill: stroke2 }),
2578
+ /* @__PURE__ */ jsx10("polygon", { points: `${d},0 ${d - 12},-6 ${d - 12},6`, fill: stroke2 })
2579
+ ] });
2580
+ });
2581
+ registerRenderer("curved_arrow", (el, ctx) => {
2582
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2583
+ const angle = angleDeg(el.x1, el.y1, el.x2, el.y2);
2584
+ const h = d / 3;
2585
+ const arrowAngle = Math.atan2(h, d / 2) * (180 / Math.PI);
2586
+ const stroke2 = colorOf3(el, ctx.isSelected);
2587
+ const sw7 = strokeOf3(el, ctx.isSelected);
2588
+ return /* @__PURE__ */ jsxs10("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${angle})`, children: [
2589
+ /* @__PURE__ */ jsx10("path", { d: `M 0 0 Q ${d / 2} ${-h} ${d} 0`, fill: "none", stroke: stroke2, strokeWidth: sw7 }),
2590
+ /* @__PURE__ */ jsx10("g", { transform: `translate(${d}, 0) rotate(${arrowAngle})`, children: /* @__PURE__ */ jsx10("polygon", { points: "0,0 -12,-6 -12,6", fill: stroke2 }) })
2591
+ ] });
2592
+ });
2593
+
2594
+ // src/core/renderers/electrostatics.tsx
2595
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2596
+ var stroke = (el, selected) => selected ? "#2563eb" : el.color || "#0f172a";
2597
+ var width = (el, selected) => selected ? 2.5 : el.strokeWidth || 2;
2598
+ var rotated2 = (el, content, selected) => {
2599
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2600
+ const a = angleDeg(el.x1, el.y1, el.x2, el.y2);
2601
+ const dx = el.x2 - el.x1;
2602
+ const dy = el.y2 - el.y1;
2603
+ const mx = (el.x1 + el.x2) / 2;
2604
+ const my = (el.y1 + el.y2) / 2;
2605
+ let nx = -dy / (d || 1);
2606
+ let ny = dx / (d || 1);
2607
+ if (ny > 0) {
2608
+ nx = -nx;
2609
+ ny = -ny;
2610
+ }
2611
+ const labelDist = 18;
2612
+ const c7 = stroke(el, selected);
2613
+ return /* @__PURE__ */ jsxs11("g", { children: [
2614
+ /* @__PURE__ */ jsx11("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${a})`, children: content }),
2615
+ el.label && /* @__PURE__ */ jsx11("text", { x: mx + nx * labelDist, y: my + ny * labelDist, dominantBaseline: "central", textAnchor: "middle", fill: c7, fontSize: 14, fontFamily: "sans-serif", children: String(el.label) })
2616
+ ] });
2617
+ };
2618
+ registerRenderer("charge_pos", (el, ctx) => {
2619
+ const c7 = ctx.isSelected ? "#2563eb" : "#ef4444";
2620
+ return /* @__PURE__ */ jsxs11("g", { transform: `translate(${el.x1}, ${el.y1})`, opacity: ctx?.isGhost ? 0.5 : 1, children: [
2621
+ /* @__PURE__ */ jsx11("circle", { cx: "0", cy: "0", r: "10", fill: "#fecaca", stroke: c7, strokeWidth: width(el, ctx.isSelected) }),
2622
+ /* @__PURE__ */ jsx11("line", { x1: "0", y1: "-4", x2: "0", y2: "4", stroke: c7, strokeWidth: 2 }),
2623
+ /* @__PURE__ */ jsx11("line", { x1: "-4", y1: "0", x2: "4", y2: "0", stroke: c7, strokeWidth: 2 }),
2624
+ el.label && /* @__PURE__ */ jsx11("text", { x: 0, y: -16, textAnchor: "middle", fill: c7, fontSize: el.fontSize || 14, children: String(el.label) })
2625
+ ] });
2626
+ });
2627
+ registerRenderer("charge_neg", (el, ctx) => {
2628
+ const c7 = ctx.isSelected ? "#2563eb" : "#3b82f6";
2629
+ return /* @__PURE__ */ jsxs11("g", { transform: `translate(${el.x1}, ${el.y1})`, opacity: ctx?.isGhost ? 0.5 : 1, children: [
2630
+ /* @__PURE__ */ jsx11("circle", { cx: "0", cy: "0", r: "10", fill: "#bfdbfe", stroke: c7, strokeWidth: width(el, ctx.isSelected) }),
2631
+ /* @__PURE__ */ jsx11("line", { x1: "-4", y1: "0", x2: "4", y2: "0", stroke: c7, strokeWidth: 2 }),
2632
+ el.label && /* @__PURE__ */ jsx11("text", { x: 0, y: -16, textAnchor: "middle", fill: c7, fontSize: el.fontSize || 14, children: String(el.label) })
2633
+ ] });
2634
+ });
2635
+ registerRenderer("dipole", (el, ctx) => {
2636
+ const w = width(el, ctx.isSelected);
2637
+ return /* @__PURE__ */ jsxs11("g", { opacity: ctx?.isGhost ? 0.5 : 1, children: [
2638
+ /* @__PURE__ */ jsx11("line", { x1: el.x1, y1: el.y1, x2: el.x2, y2: el.y2, stroke: "#64748b", strokeWidth: w, strokeDasharray: "4 4" }),
2639
+ /* @__PURE__ */ jsx11("circle", { cx: el.x1, cy: el.y1, r: "8", fill: "#fecaca", stroke: ctx.isSelected ? "#2563eb" : "#ef4444", strokeWidth: w }),
2640
+ /* @__PURE__ */ jsx11("circle", { cx: el.x2, cy: el.y2, r: "8", fill: "#bfdbfe", stroke: ctx.isSelected ? "#2563eb" : "#3b82f6", strokeWidth: w }),
2641
+ el.label && /* @__PURE__ */ jsx11("text", { x: (el.x1 + el.x2) / 2, y: el.y1 - 16, textAnchor: "middle", fill: "#475569", fontSize: 14, children: String(el.label) })
2642
+ ] });
2643
+ });
2644
+ var plateGlyphs = (d, isPos) => {
2645
+ const n = Math.max(2, Math.floor(d / 25));
2646
+ const glyphs = [];
2647
+ for (let i = 0; i <= n; i++) {
2648
+ const pos = i / n * d;
2649
+ glyphs.push(
2650
+ /* @__PURE__ */ jsx11("g", { transform: `translate(${pos}, 0)`, children: isPos ? /* @__PURE__ */ jsx11(Fragment3, { children: /* @__PURE__ */ jsx11("path", { d: "M-4 0 h8 M0 -4 v8", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round" }) }) : /* @__PURE__ */ jsx11("path", { d: "M-4 0 h8", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round" }) }, i)
2651
+ );
2652
+ }
2653
+ return glyphs;
2654
+ };
2655
+ registerRenderer("charged_plate_pos", (el, ctx) => {
2656
+ const c7 = ctx.isSelected ? "#2563eb" : "#ef4444";
2657
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2658
+ const a = angleDeg(el.x1, el.y1, el.x2, el.y2);
2659
+ const sw7 = Math.max(12, el.strokeWidth * 4 || 8);
2660
+ return /* @__PURE__ */ jsxs11("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${a})`, opacity: ctx?.isGhost ? 0.5 : 1, children: [
2661
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c7, strokeWidth: sw7, strokeLinecap: "round" }),
2662
+ plateGlyphs(d, true)
2663
+ ] });
2664
+ });
2665
+ registerRenderer("charged_plate_neg", (el, ctx) => {
2666
+ const c7 = ctx.isSelected ? "#2563eb" : "#3b82f6";
2667
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2668
+ const a = angleDeg(el.x1, el.y1, el.x2, el.y2);
2669
+ const sw7 = Math.max(12, el.strokeWidth * 4 || 8);
2670
+ return /* @__PURE__ */ jsxs11("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${a})`, opacity: ctx?.isGhost ? 0.5 : 1, children: [
2671
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: 0, x2: d, y2: 0, stroke: c7, strokeWidth: sw7, strokeLinecap: "round" }),
2672
+ plateGlyphs(d, false)
2673
+ ] });
2674
+ });
2675
+ registerRenderer("gaussian_sphere", (el, ctx) => {
2676
+ const r = Math.max(10, distance(el.x1, el.y1, el.x2, el.y2));
2677
+ const c7 = ctx.isSelected ? "#2563eb" : "#10b981";
2678
+ return /* @__PURE__ */ jsxs11("g", { opacity: ctx?.isGhost ? 0.5 : 1, children: [
2679
+ /* @__PURE__ */ jsx11("circle", { cx: el.x1, cy: el.y1, r, fill: "#d1fae5", fillOpacity: 0.35, stroke: c7, strokeWidth: width(el, ctx.isSelected), strokeDasharray: "5 5" }),
2680
+ el.label && /* @__PURE__ */ jsx11("text", { x: el.x1, y: el.y1 - r - 12, textAnchor: "middle", fill: c7, fontSize: 13, children: String(el.label) })
2681
+ ] });
2682
+ });
2683
+ registerRenderer("gaussian_cylinder", (el, ctx) => {
2684
+ const d = distance(el.x1, el.y1, el.x2, el.y2);
2685
+ const a = angleDeg(el.x1, el.y1, el.x2, el.y2);
2686
+ const r = el.curveHeight ?? 40;
2687
+ const capRx = 15;
2688
+ const c7 = ctx.isSelected ? "#2563eb" : "#10b981";
2689
+ const sw7 = width(el, ctx.isSelected);
2690
+ const dash = "6 6";
2691
+ return /* @__PURE__ */ jsxs11("g", { opacity: ctx?.isGhost ? 0.5 : 1, children: [
2692
+ /* @__PURE__ */ jsx11("line", { x1: el.x1, y1: el.y1, x2: el.x2, y2: el.y2, stroke: "transparent", strokeWidth: Math.max(24, r * 2), strokeLinecap: "round" }),
2693
+ /* @__PURE__ */ jsxs11("g", { transform: `translate(${el.x1}, ${el.y1}) rotate(${a})`, children: [
2694
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: -r, x2: d, y2: -r, stroke: c7, strokeWidth: sw7, strokeDasharray: dash }),
2695
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: r, x2: d, y2: r, stroke: c7, strokeWidth: sw7, strokeDasharray: dash }),
2696
+ /* @__PURE__ */ jsx11("ellipse", { cx: 0, cy: 0, rx: capRx, ry: r, fill: c7, fillOpacity: 0.05, stroke: c7, strokeWidth: sw7, strokeDasharray: dash }),
2697
+ /* @__PURE__ */ jsx11("ellipse", { cx: d, cy: 0, rx: capRx, ry: r, fill: c7, fillOpacity: 0.05, stroke: c7, strokeWidth: sw7, strokeDasharray: dash }),
2698
+ el.label && /* @__PURE__ */ jsx11("text", { x: d / 2, y: -r - 10, textAnchor: "middle", fill: c7, fontSize: el.fontSize || 14, children: String(el.label) })
2699
+ ] })
2700
+ ] });
2701
+ });
2702
+ registerRenderer(
2703
+ "mirror_plane",
2704
+ (el, ctx) => rotated2(
2705
+ el,
2706
+ /* @__PURE__ */ jsxs11(Fragment3, { children: [
2707
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: -24, x2: 0, y2: 24, stroke: stroke(el, ctx.isSelected), strokeWidth: width(el, ctx.isSelected) }),
2708
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: -18, x2: -8, y2: -12, stroke: stroke(el, ctx.isSelected), strokeWidth: 1.5 }),
2709
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: -6, x2: -8, y2: 0, stroke: stroke(el, ctx.isSelected), strokeWidth: 1.5 }),
2710
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: 6, x2: -8, y2: 12, stroke: stroke(el, ctx.isSelected), strokeWidth: 1.5 }),
2711
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: 18, x2: -8, y2: 24, stroke: stroke(el, ctx.isSelected), strokeWidth: 1.5 })
2712
+ ] }),
2713
+ ctx.isSelected
2714
+ )
2715
+ );
2716
+ registerRenderer("energy_level", (el, ctx) => {
2717
+ const d = Math.max(24, distance(el.x1, el.y1, el.x2, el.y2));
2718
+ const c7 = stroke(el, ctx.isSelected);
2719
+ const energyText = el.energy != null ? String(el.energy) : "";
2720
+ return rotated2(
2721
+ el,
2722
+ /* @__PURE__ */ jsxs11(Fragment3, { children: [
2723
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: -8, x2: d, y2: -8, stroke: c7, strokeWidth: width(el, ctx.isSelected) }),
2724
+ /* @__PURE__ */ jsx11("line", { x1: 0, y1: 8, x2: d, y2: 8, stroke: c7, strokeWidth: width(el, ctx.isSelected) }),
2725
+ energyText && /* @__PURE__ */ jsx11("text", { x: d / 2, y: 22, textAnchor: "middle", fontSize: 10, fill: "#4b5563", children: energyText })
2726
+ ] }),
2727
+ ctx.isSelected
2728
+ );
2729
+ });
2730
+
2731
+ // src/core/Renderer.tsx
2732
+ import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2733
+ var UnknownElement = ({ x, y, type }) => /* @__PURE__ */ jsxs12("g", { children: [
2734
+ /* @__PURE__ */ jsx12("rect", { x: x - 20, y: y - 12, width: 40, height: 24, fill: "#fee2e2", stroke: "#ef4444" }),
2735
+ /* @__PURE__ */ jsx12("text", { x, y, textAnchor: "middle", dominantBaseline: "central", fontSize: 10, fill: "#991b1b", children: type })
2736
+ ] });
2737
+ var Renderer = ({
2738
+ elements,
2739
+ selectedId,
2740
+ drawing,
2741
+ viewMode = false,
2742
+ showGrid = true,
2743
+ gridSize = GRID_SIZE,
2744
+ className,
2745
+ svgRef,
2746
+ onBackgroundMouseDown,
2747
+ onBackgroundMouseMove,
2748
+ onBackgroundMouseUp,
2749
+ onBackgroundMouseLeave,
2750
+ onElementMouseDown
2751
+ }) => {
2752
+ const autoNodes = useMemo(() => getCircuitAutoNodes(elements), [elements]);
2753
+ return /* @__PURE__ */ jsxs12(
2754
+ "svg",
2755
+ {
2756
+ ref: svgRef,
2757
+ className,
2758
+ onMouseDown: onBackgroundMouseDown,
2759
+ onMouseMove: onBackgroundMouseMove,
2760
+ onMouseUp: onBackgroundMouseUp,
2761
+ onMouseLeave: onBackgroundMouseLeave,
2762
+ children: [
2763
+ !viewMode && showGrid && /* @__PURE__ */ jsxs12(Fragment4, { children: [
2764
+ /* @__PURE__ */ jsx12("defs", { children: /* @__PURE__ */ jsx12("pattern", { id: "svg-engine-grid", width: gridSize, height: gridSize, patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx12("path", { d: `M ${gridSize} 0 L 0 0 0 ${gridSize}`, fill: "none", stroke: "#e2e8f0", strokeWidth: "1" }) }) }),
2765
+ /* @__PURE__ */ jsx12("rect", { width: "100%", height: "100%", fill: "url(#svg-engine-grid)", pointerEvents: "none" })
2766
+ ] }),
2767
+ elements.map((el) => {
2768
+ const renderer = getRenderer(String(el.type));
2769
+ const content = renderer ? renderer(el, { isSelected: selectedId === el.id, viewMode }) : /* @__PURE__ */ jsx12(UnknownElement, { x: el.x1, y: el.y1, type: String(el.type) });
2770
+ return /* @__PURE__ */ jsx12("g", { onMouseDown: (e) => onElementMouseDown?.(e, el), cursor: viewMode ? "default" : "move", children: content }, String(el.id));
2771
+ }),
2772
+ autoNodes.map(([nx, ny], idx) => /* @__PURE__ */ jsx12("circle", { cx: nx, cy: ny, r: 4, fill: "#111827", pointerEvents: "none" }, `junction-${idx}`)),
2773
+ drawing && (() => {
2774
+ const renderer = getRenderer(String(drawing.type));
2775
+ if (!renderer) return null;
2776
+ return /* @__PURE__ */ jsx12("g", { opacity: 0.5, children: renderer(drawing, { isGhost: true, viewMode }) });
2777
+ })()
2778
+ ]
2779
+ }
2780
+ );
2781
+ };
2782
+
2783
+ export {
2784
+ GRID_SIZE,
2785
+ snap,
2786
+ distance,
2787
+ angleDeg,
2788
+ getBounds,
2789
+ getMouseCoords,
2790
+ registerRenderer,
2791
+ getRenderer,
2792
+ hasRenderer,
2793
+ Renderer
2794
+ };