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