@ultrst-armada/floks 0.0.0-stage → 1.0.1

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.
Files changed (93) hide show
  1. package/README.md +2 -3
  2. package/index.d.ts +2 -0
  3. package/index.js +2 -0
  4. package/package.json +69 -4
  5. package/packages/canvas-ui/dist/canvas/index.d.ts +54 -0
  6. package/packages/canvas-ui/dist/canvas/index.js +12 -0
  7. package/packages/canvas-ui/dist/chunk-34YRDZPJ.js +189 -0
  8. package/packages/canvas-ui/dist/chunk-6VB74RCH.js +147 -0
  9. package/packages/canvas-ui/dist/chunk-OOTTFWXA.js +508 -0
  10. package/packages/canvas-ui/dist/chunk-QTTWWBNN.js +114 -0
  11. package/packages/canvas-ui/dist/chunk-SA3JADUG.js +160 -0
  12. package/packages/canvas-ui/dist/chunk-U2SC3RMJ.js +391 -0
  13. package/packages/canvas-ui/dist/chunk-XVAHT5WE.js +718 -0
  14. package/packages/canvas-ui/dist/dock/index.d.ts +37 -0
  15. package/packages/canvas-ui/dist/dock/index.js +10 -0
  16. package/packages/canvas-ui/dist/editor/index.d.ts +44 -0
  17. package/packages/canvas-ui/dist/editor/index.js +10 -0
  18. package/packages/canvas-ui/dist/graph-2d/index.d.ts +270 -0
  19. package/packages/canvas-ui/dist/graph-2d/index.js +50 -0
  20. package/packages/canvas-ui/dist/index.d.ts +176 -0
  21. package/packages/canvas-ui/dist/index.js +1171 -0
  22. package/packages/canvas-ui/dist/predictive/index.d.ts +75 -0
  23. package/packages/canvas-ui/dist/predictive/index.js +13 -0
  24. package/packages/canvas-ui/dist/tile-menu/index.d.ts +45 -0
  25. package/packages/canvas-ui/dist/tile-menu/index.js +12 -0
  26. package/packages/canvas-ui/dist/types-D3RRfQUo.d.ts +46 -0
  27. package/packages/canvas-ui/floks.manifest.json +35 -0
  28. package/packages/canvas-ui/package.json +82 -0
  29. package/packages/ui/dist/BottomStrip-DYhAUQR4.d.ts +12 -0
  30. package/packages/ui/dist/chunk-5ZMXFCD4.js +0 -0
  31. package/packages/ui/dist/chunk-62ITRDJX.js +141 -0
  32. package/packages/ui/dist/chunk-A2CDQISJ.js +32 -0
  33. package/packages/ui/dist/chunk-ATQPZLJX.js +238 -0
  34. package/packages/ui/dist/chunk-C32CB5WO.js +1161 -0
  35. package/packages/ui/dist/chunk-C3L53YN4.js +372 -0
  36. package/packages/ui/dist/chunk-DZJ3NSCX.js +665 -0
  37. package/packages/ui/dist/chunk-ELZOBTWX.js +562 -0
  38. package/packages/ui/dist/chunk-GKP6KHTI.js +75 -0
  39. package/packages/ui/dist/chunk-GWW3BGOB.js +238 -0
  40. package/packages/ui/dist/chunk-KIFQA7L6.js +167 -0
  41. package/packages/ui/dist/chunk-KYFSUQVT.js +769 -0
  42. package/packages/ui/dist/chunk-OR5ZNJI4.js +62 -0
  43. package/packages/ui/dist/chunk-RLQ2ALJG.js +182 -0
  44. package/packages/ui/dist/chunk-S227WJ5E.js +152 -0
  45. package/packages/ui/dist/chunk-SLJBDDSN.js +0 -0
  46. package/packages/ui/dist/chunk-TXKLROFC.js +370 -0
  47. package/packages/ui/dist/chunk-UOR4P6PO.js +32 -0
  48. package/packages/ui/dist/chunk-VEWPTZGO.js +351 -0
  49. package/packages/ui/dist/chunk-W42SJGOJ.js +19 -0
  50. package/packages/ui/dist/chunk-XXIH2HWI.js +297 -0
  51. package/packages/ui/dist/chunk-ZQK5I5ZL.js +277 -0
  52. package/packages/ui/dist/components/auth/index.css +183 -0
  53. package/packages/ui/dist/components/auth/index.d.ts +10 -0
  54. package/packages/ui/dist/components/auth/index.js +8 -0
  55. package/packages/ui/dist/components/base/index.css +183 -0
  56. package/packages/ui/dist/components/base/index.d.ts +74 -0
  57. package/packages/ui/dist/components/base/index.js +33 -0
  58. package/packages/ui/dist/components/bottom-strip/index.css +183 -0
  59. package/packages/ui/dist/components/bottom-strip/index.d.ts +67 -0
  60. package/packages/ui/dist/components/bottom-strip/index.js +22 -0
  61. package/packages/ui/dist/components/composite/index.css +273 -0
  62. package/packages/ui/dist/components/composite/index.d.ts +104 -0
  63. package/packages/ui/dist/components/composite/index.js +33 -0
  64. package/packages/ui/dist/components/containers/index.css +404 -0
  65. package/packages/ui/dist/components/containers/index.d.ts +93 -0
  66. package/packages/ui/dist/components/containers/index.js +35 -0
  67. package/packages/ui/dist/components/layout/index.css +246 -0
  68. package/packages/ui/dist/components/layout/index.d.ts +53 -0
  69. package/packages/ui/dist/components/layout/index.js +16 -0
  70. package/packages/ui/dist/components/settings/index.css +183 -0
  71. package/packages/ui/dist/components/settings/index.d.ts +14 -0
  72. package/packages/ui/dist/components/settings/index.js +12 -0
  73. package/packages/ui/dist/components/workspace/index.d.ts +101 -0
  74. package/packages/ui/dist/components/workspace/index.js +16 -0
  75. package/packages/ui/dist/hierarchy/index.css +183 -0
  76. package/packages/ui/dist/hierarchy/index.d.ts +233 -0
  77. package/packages/ui/dist/hierarchy/index.js +74 -0
  78. package/packages/ui/dist/index.css +467 -0
  79. package/packages/ui/dist/index.d.ts +16 -0
  80. package/packages/ui/dist/index.js +320 -0
  81. package/packages/ui/dist/palette/index.d.ts +29 -0
  82. package/packages/ui/dist/palette/index.js +27 -0
  83. package/packages/ui/dist/palettes-De5u5iID.d.ts +394 -0
  84. package/packages/ui/dist/theme/index.d.ts +12063 -0
  85. package/packages/ui/dist/theme/index.js +96 -0
  86. package/packages/ui/floks.manifest.json +119 -0
  87. package/packages/ui/package.json +92 -0
  88. package/packages/ui/src/styles/base.css +130 -0
  89. package/packages/ui/src/styles/composite.css +6 -0
  90. package/packages/ui/src/styles/containers.css +10 -0
  91. package/packages/ui/src/styles/details-panel.css +147 -0
  92. package/packages/ui/src/styles/layout.css +58 -0
  93. package/packages/ui/src/theme/tokens.css +93 -0
@@ -0,0 +1,160 @@
1
+ // src/tile-menu/Tile.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function Tile({ tile, onClick, onContextMenu, dragHandleProps, isDragging }) {
4
+ return /* @__PURE__ */ jsxs(
5
+ "div",
6
+ {
7
+ style: {
8
+ backgroundColor: "rgba(30, 30, 30, 0.7)",
9
+ backdropFilter: "blur(12px)",
10
+ border: "1px solid rgba(255, 255, 255, 0.1)",
11
+ borderRadius: "12px",
12
+ padding: "16px",
13
+ display: "flex",
14
+ flexDirection: "column",
15
+ gap: "8px",
16
+ cursor: "pointer",
17
+ opacity: isDragging ? 0.5 : 1,
18
+ boxShadow: isDragging ? "0 8px 16px rgba(0,0,0,0.5)" : "0 2px 4px rgba(0,0,0,0.2)",
19
+ transition: "transform 0.2s, box-shadow 0.2s"
20
+ },
21
+ onClick: () => onClick?.(tile.id),
22
+ onContextMenu: (e) => onContextMenu?.(e, tile.id),
23
+ children: [
24
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
25
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
26
+ tile.icon && /* @__PURE__ */ jsx("span", { style: { fontSize: "24px" }, children: tile.icon }),
27
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
28
+ /* @__PURE__ */ jsx("span", { style: { color: "#fff", fontWeight: 600, fontSize: "14px" }, children: tile.title }),
29
+ tile.subtitle && /* @__PURE__ */ jsx("span", { style: { color: "#aaa", fontSize: "12px" }, children: tile.subtitle })
30
+ ] })
31
+ ] }),
32
+ /* @__PURE__ */ jsx("div", { ...dragHandleProps, style: { cursor: "grab", padding: "4px", color: "#666" }, children: "\u283F" })
33
+ ] }),
34
+ tile.badges && tile.badges.length > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "4px", flexWrap: "wrap", marginTop: "8px" }, children: tile.badges.map((badge) => /* @__PURE__ */ jsx("span", { style: {
35
+ fontSize: "10px",
36
+ backgroundColor: "rgba(255,255,255,0.1)",
37
+ padding: "2px 6px",
38
+ borderRadius: "12px",
39
+ color: "#ccc"
40
+ }, children: badge }, badge)) })
41
+ ]
42
+ }
43
+ );
44
+ }
45
+
46
+ // src/tile-menu/TileGrid.tsx
47
+ import { useState, useRef, useEffect } from "react";
48
+ import { jsx as jsx2 } from "react/jsx-runtime";
49
+ function TileGrid({
50
+ tiles,
51
+ onReorder: _onReorder,
52
+ onTileClick
53
+ }) {
54
+ const containerRef = useRef(null);
55
+ const [columns, setColumns] = useState(3);
56
+ const [tileMinHeight, setTileMinHeight] = useState(110);
57
+ useEffect(() => {
58
+ if (!containerRef.current) return;
59
+ const observer = new ResizeObserver((entries) => {
60
+ for (const entry of entries) {
61
+ const { width, height } = entry.contentRect;
62
+ if (width <= 0) return;
63
+ let cols = 1;
64
+ if (width >= 1200) cols = 4;
65
+ else if (width >= 860) cols = 3;
66
+ else if (width >= 540) cols = 2;
67
+ else cols = 1;
68
+ const estimatedRows = Math.ceil(tiles.length / cols);
69
+ let dynamicHeight = 110;
70
+ if (height > 0 && estimatedRows > 0) {
71
+ const availableRowHeight = (height - (estimatedRows + 1) * 16) / estimatedRows;
72
+ dynamicHeight = Math.max(90, Math.min(180, Math.floor(availableRowHeight)));
73
+ }
74
+ setColumns(cols);
75
+ setTileMinHeight(dynamicHeight);
76
+ }
77
+ });
78
+ observer.observe(containerRef.current);
79
+ return () => observer.disconnect();
80
+ }, [tiles.length]);
81
+ return /* @__PURE__ */ jsx2(
82
+ "div",
83
+ {
84
+ ref: containerRef,
85
+ className: "skipo-tile-grid-container",
86
+ style: {
87
+ display: "grid",
88
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
89
+ gridAutoRows: `minmax(${tileMinHeight}px, auto)`,
90
+ gap: "14px",
91
+ padding: "14px",
92
+ width: "100%",
93
+ height: "100%",
94
+ boxSizing: "border-box",
95
+ overflowY: "auto"
96
+ },
97
+ children: tiles.map((tile) => /* @__PURE__ */ jsx2(Tile, { tile, onClick: onTileClick }, tile.id))
98
+ }
99
+ );
100
+ }
101
+
102
+ // src/tile-menu/TileCreateButton.tsx
103
+ import { jsx as jsx3 } from "react/jsx-runtime";
104
+ function TileCreateButton({ onClick }) {
105
+ return /* @__PURE__ */ jsx3(
106
+ "div",
107
+ {
108
+ onClick,
109
+ style: {
110
+ border: "2px dashed rgba(255, 255, 255, 0.2)",
111
+ borderRadius: "12px",
112
+ padding: "16px",
113
+ display: "flex",
114
+ justifyContent: "center",
115
+ alignItems: "center",
116
+ cursor: "pointer",
117
+ minHeight: "100px",
118
+ color: "rgba(255, 255, 255, 0.5)",
119
+ transition: "all 0.2s"
120
+ },
121
+ onMouseEnter: (e) => {
122
+ e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.5)";
123
+ e.currentTarget.style.color = "#fff";
124
+ },
125
+ onMouseLeave: (e) => {
126
+ e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.2)";
127
+ e.currentTarget.style.color = "rgba(255, 255, 255, 0.5)";
128
+ },
129
+ children: /* @__PURE__ */ jsx3("span", { style: { fontSize: "32px" }, children: "+" })
130
+ }
131
+ );
132
+ }
133
+
134
+ // src/tile-menu/useTileMenu.ts
135
+ import { useState as useState2, useCallback } from "react";
136
+ function useTileMenu(initialTiles = []) {
137
+ const [tiles, setTiles] = useState2(initialTiles);
138
+ const addTile = useCallback((tile) => {
139
+ setTiles((prev) => [...prev, tile]);
140
+ }, []);
141
+ const removeTile = useCallback((id) => {
142
+ setTiles((prev) => prev.filter((t) => t.id !== id));
143
+ }, []);
144
+ const reorderTiles = useCallback((newOrder) => {
145
+ setTiles(newOrder);
146
+ }, []);
147
+ return {
148
+ tiles,
149
+ addTile,
150
+ removeTile,
151
+ reorderTiles
152
+ };
153
+ }
154
+
155
+ export {
156
+ Tile,
157
+ TileGrid,
158
+ TileCreateButton,
159
+ useTileMenu
160
+ };
@@ -0,0 +1,391 @@
1
+ // src/graph-2d/socketCoordinates.ts
2
+ import { getNodeSockets } from "@ultrst-armada/kloks/state-graph";
3
+ import { GraphNodeParent } from "@ultrst-armada/kloks/state-graph";
4
+ function getSocketLocalOffset(node, socketId, isOutput, index, totalSockets) {
5
+ const isCustomBox = node.type === "arrangement" || node.type === "code";
6
+ const clearance = isCustomBox ? 16 : 14;
7
+ return GraphNodeParent.calculateConstrainedSocketOffset(
8
+ node,
9
+ socketId,
10
+ isOutput,
11
+ index,
12
+ totalSockets,
13
+ clearance
14
+ );
15
+ }
16
+ function getSocketScreenPosition(node, socketId, isOutput, worldToScreen, camera) {
17
+ const center = worldToScreen(node.position[0], node.position[2]);
18
+ const { inputs, outputs } = getNodeSockets(node);
19
+ const sockets = isOutput ? outputs : inputs;
20
+ if (sockets.length === 0) {
21
+ return center;
22
+ }
23
+ let idx = -1;
24
+ if (socketId) {
25
+ idx = sockets.findIndex((s) => s.socketId === socketId);
26
+ }
27
+ const validIdx = idx >= 0 ? idx : 0;
28
+ const targetSocket = sockets[validIdx];
29
+ const localOffset = getSocketLocalOffset(
30
+ node,
31
+ targetSocket.socketId,
32
+ isOutput,
33
+ validIdx,
34
+ sockets.length
35
+ );
36
+ return {
37
+ x: center.x + localOffset.x * camera.zoom,
38
+ y: center.y + localOffset.y * camera.zoom
39
+ };
40
+ }
41
+
42
+ // src/graph-2d/Socket2D.tsx
43
+ import { SIGNAL_TYPES } from "@ultrst-armada/kloks/state-graph";
44
+ import { jsx, jsxs } from "react/jsx-runtime";
45
+ var Socket2D = ({
46
+ nodeId,
47
+ socket,
48
+ direction,
49
+ isConnected = false,
50
+ onSocketHover,
51
+ onSocketMouseDown,
52
+ onSocketMouseUp,
53
+ onHover,
54
+ onMouseDown,
55
+ onMouseUp
56
+ }) => {
57
+ const sigDef = SIGNAL_TYPES[socket.signalType] || SIGNAL_TYPES.trigger;
58
+ const colorStr = sigDef.colorStr;
59
+ const resolvedDirection = direction || (socket.polarity === "input" ? "in" : "out");
60
+ const isInput = resolvedDirection === "in";
61
+ const portKey = socket.portId || socket.socketId;
62
+ const hoverCb = onSocketHover || onHover;
63
+ const downCb = onSocketMouseDown || onMouseDown;
64
+ const upCb = onSocketMouseUp || onMouseUp;
65
+ return /* @__PURE__ */ jsxs(
66
+ "div",
67
+ {
68
+ id: `socket-2d-${nodeId}-${resolvedDirection}-${portKey}`,
69
+ className: `flex items-center gap-1.5 cursor-pointer group/sock select-none ${isInput ? "justify-start" : "justify-end ml-auto"}`,
70
+ onMouseEnter: (e) => {
71
+ const rect = e.currentTarget.getBoundingClientRect();
72
+ hoverCb?.({
73
+ nodeId,
74
+ socket,
75
+ screenX: isInput ? rect.left : rect.right,
76
+ screenY: rect.top
77
+ });
78
+ },
79
+ onMouseLeave: () => hoverCb?.(null),
80
+ onMouseDown: (e) => {
81
+ e.stopPropagation();
82
+ downCb?.(nodeId, socket, e);
83
+ },
84
+ onMouseUp: (e) => {
85
+ e.stopPropagation();
86
+ upCb?.(nodeId, socket, e);
87
+ },
88
+ children: [
89
+ isInput && /* @__PURE__ */ jsx(
90
+ "div",
91
+ {
92
+ style: { backgroundColor: colorStr },
93
+ className: `w-2.5 h-2.5 rounded-full border border-black group-hover/sock:scale-130 transition-transform ${isConnected ? "ring-1 ring-white/60" : "opacity-85"}`
94
+ }
95
+ ),
96
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-bold text-[9px] text-neutral-300 group-hover/sock:text-amber-300 tracking-tight", children: socket.label }),
97
+ !isInput && /* @__PURE__ */ jsx(
98
+ "div",
99
+ {
100
+ style: { backgroundColor: colorStr },
101
+ className: `w-2.5 h-2.5 rotate-45 border border-black group-hover/sock:scale-130 transition-transform ${isConnected ? "ring-1 ring-white/60" : "opacity-85"}`
102
+ }
103
+ )
104
+ ]
105
+ }
106
+ );
107
+ };
108
+
109
+ // src/graph-2d/RecorderWaveformDisplay.tsx
110
+ import { useState, useEffect, useRef } from "react";
111
+ import { retrospectiveBufferEngine } from "@ultrst-armada/kloks/audio-midi";
112
+ import { sequencerEngine } from "@ultrst-armada/kloks/audio-midi";
113
+ import { synthEngine } from "@ultrst-armada/kloks/audio-midi";
114
+ import * as GraphConcepts from "@ultrst-armada/kloks/state-graph";
115
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
116
+ function buildWaveformPath(peaks, width, height) {
117
+ if (!peaks || peaks.length === 0) return `M 0 ${height / 2} L ${width} ${height / 2}`;
118
+ const step = width / Math.max(1, peaks.length - 1);
119
+ const midY = height / 2;
120
+ let topPoints = "";
121
+ let bottomPoints = "";
122
+ for (let i = 0; i < peaks.length; i++) {
123
+ const x = Math.round(i * step * 10) / 10;
124
+ const amp = Math.max(0.08, Math.min(1, peaks[i] || 0.08)) * (midY - 2);
125
+ topPoints += `${i === 0 ? "M" : "L"} ${x} ${midY - amp} `;
126
+ bottomPoints = `L ${x} ${midY + amp} ` + bottomPoints;
127
+ }
128
+ return `${topPoints} ${bottomPoints} Z`;
129
+ }
130
+ var RecorderWaveformDisplay = ({
131
+ node,
132
+ connections = [],
133
+ allNodes = [],
134
+ width = 150
135
+ }) => {
136
+ const [currentBeat, setCurrentBeat] = useState(0);
137
+ const [capturedFlash, setCapturedFlash] = useState(false);
138
+ const [livePeaksL, setLivePeaksL] = useState([]);
139
+ const [livePeaksR, setLivePeaksR] = useState([]);
140
+ const lastBeatRef = useRef(0);
141
+ const isArmed = !!node.isArmed;
142
+ const isRetrospective = node.recordingMode === "retrospective";
143
+ const isRecording = !isRetrospective && !!node.isRecording;
144
+ const isStereo = node.recorderType !== "audio_mono";
145
+ useEffect(() => {
146
+ return retrospectiveBufferEngine.onSnapshotCaptured((recId) => {
147
+ if (recId === node.id) {
148
+ setCapturedFlash(true);
149
+ setTimeout(() => setCapturedFlash(false), 1200);
150
+ }
151
+ });
152
+ }, [node.id]);
153
+ useEffect(() => {
154
+ if (!isArmed) return;
155
+ let animId;
156
+ let lastSampleTime = 0;
157
+ const sourceNode = GraphConcepts.findSourceNode?.(node.id, "stream_in", connections, allNodes);
158
+ const incomingWire = connections.find(
159
+ (c) => c.toNodeId === node.id && (c.toPort === "stream_in" || c.toSocketIndex === 0 || !c.toPort)
160
+ );
161
+ const tick = (time) => {
162
+ const beat = sequencerEngine.currentBeat;
163
+ setCurrentBeat(beat);
164
+ if (time - lastSampleTime >= 40) {
165
+ lastSampleTime = time;
166
+ const gainVal = node.gain ?? 1;
167
+ const levels = sourceNode ? synthEngine.getWireSignalLevel(sourceNode, incomingWire?.fromPort) : { left: 0, right: 0 };
168
+ const pL = Math.min(1, levels.left * gainVal);
169
+ const pR = Math.min(1, levels.right * gainVal);
170
+ if (isRecording) {
171
+ setLivePeaksL((prev) => [...prev.slice(-63), pL]);
172
+ setLivePeaksR((prev) => [...prev.slice(-63), pR]);
173
+ } else if (isRetrospective) {
174
+ setLivePeaksL((prev) => [...prev.slice(-39), pL]);
175
+ setLivePeaksR((prev) => [...prev.slice(-39), pR]);
176
+ }
177
+ }
178
+ animId = requestAnimationFrame(tick);
179
+ };
180
+ const currentBeatVal = sequencerEngine.currentBeat;
181
+ if (isRecording && Math.abs(currentBeatVal - lastBeatRef.current) > 0.5) {
182
+ setLivePeaksL([]);
183
+ setLivePeaksR([]);
184
+ }
185
+ lastBeatRef.current = currentBeatVal;
186
+ animId = requestAnimationFrame(tick);
187
+ return () => cancelAnimationFrame(animId);
188
+ }, [isArmed, isRecording, isRetrospective, node.id, node.gain, connections, allNodes]);
189
+ if (!isArmed) return null;
190
+ const elapsedBeats = isRecording ? Math.max(0, currentBeat - (node.recordingStartBeat || 0)) : 0;
191
+ const bars = Math.floor(elapsedBeats / 4);
192
+ const beatsInBar = (elapsedBeats % 4).toFixed(1);
193
+ const timeText = isRecording ? `${bars} BAR${bars === 1 ? "" : "S"} ${beatsInBar} BEATS` : isRetrospective ? `${node.bufferLengthBars ?? 4} BARS BUFFER` : "1 BAR PREVIEW";
194
+ const isRedState = isRecording || isRetrospective && capturedFlash;
195
+ const colorStroke = isRedState ? "#f43f5e" : "#94a3b8";
196
+ const colorFill = isRedState ? "rgba(244, 63, 94, 0.25)" : "rgba(148, 163, 184, 0.15)";
197
+ const glowShadow = isRedState ? "0 0 8px rgba(244, 63, 94, 0.6)" : "none";
198
+ const renderPeaksL = isRecording || isRetrospective ? livePeaksL.length > 0 ? livePeaksL : [0.15, 0.3, 0.2, 0.4, 0.2, 0.15] : [0.15, 0.3, 0.25, 0.5, 0.3, 0.4, 0.2, 0.15];
199
+ const renderPeaksR = isRecording || isRetrospective ? livePeaksR.length > 0 ? livePeaksR : [0.12, 0.28, 0.18, 0.38, 0.22, 0.14] : [0.12, 0.28, 0.22, 0.45, 0.28, 0.35, 0.18, 0.12];
200
+ const trackHeight = isStereo ? 18 : 36;
201
+ return /* @__PURE__ */ jsxs2(
202
+ "div",
203
+ {
204
+ className: "flex flex-col items-center justify-center w-full px-1 py-1 rounded bg-black/60 border border-slate-800 select-none overflow-hidden",
205
+ style: { boxShadow: glowShadow },
206
+ children: [
207
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between w-full px-1 mb-0.5 text-[8px] font-mono font-bold tracking-tight", children: [
208
+ /* @__PURE__ */ jsx2("span", { className: isRedState ? "text-rose-400 animate-pulse" : "text-slate-400", children: isRedState ? "\u25CF REC" : isRetrospective ? "\u25CF BUFFER" : "ARMED" }),
209
+ /* @__PURE__ */ jsx2("span", { className: isRedState ? "text-rose-300 font-extrabold" : "text-slate-400", children: timeText })
210
+ ] }),
211
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-0.5 w-full", children: [
212
+ /* @__PURE__ */ jsxs2("div", { className: `relative w-full ${isStereo ? "h-[18px]" : "h-[36px]"} bg-slate-950/80 rounded border border-slate-800/80 overflow-hidden`, children: [
213
+ isStereo && /* @__PURE__ */ jsx2("span", { className: "absolute top-0.5 left-1 text-[7px] font-mono font-bold text-slate-500 z-10", children: "L" }),
214
+ /* @__PURE__ */ jsx2("svg", { className: "w-full h-full", viewBox: `0 0 ${width} ${trackHeight}`, preserveAspectRatio: "none", children: /* @__PURE__ */ jsx2("path", { d: buildWaveformPath(renderPeaksL, width, trackHeight), fill: colorFill, stroke: colorStroke, strokeWidth: "1.2" }) })
215
+ ] }),
216
+ isStereo && /* @__PURE__ */ jsxs2("div", { className: "relative w-full h-[18px] bg-slate-950/80 rounded border border-slate-800/80 overflow-hidden", children: [
217
+ /* @__PURE__ */ jsx2("span", { className: "absolute top-0.5 left-1 text-[7px] font-mono font-bold text-slate-500 z-10", children: "R" }),
218
+ /* @__PURE__ */ jsx2("svg", { className: "w-full h-full", viewBox: `0 0 ${width} ${trackHeight}`, preserveAspectRatio: "none", children: /* @__PURE__ */ jsx2("path", { d: buildWaveformPath(renderPeaksR, width, trackHeight), fill: colorFill, stroke: colorStroke, strokeWidth: "1.2" }) })
219
+ ] })
220
+ ] })
221
+ ]
222
+ }
223
+ );
224
+ };
225
+
226
+ // src/graph-2d/Node2DBase.tsx
227
+ import {
228
+ Castle,
229
+ Sparkles,
230
+ Flame,
231
+ FileAudio,
232
+ Activity,
233
+ Layers,
234
+ Music,
235
+ Clock,
236
+ RotateCw,
237
+ Volume2,
238
+ Zap,
239
+ Radio,
240
+ LogIn,
241
+ LogOut,
242
+ GitMerge,
243
+ Split,
244
+ Cpu,
245
+ Repeat,
246
+ Type,
247
+ Hash,
248
+ ToggleLeft,
249
+ Braces,
250
+ Folder,
251
+ FileText
252
+ } from "lucide-react";
253
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
254
+ var NODE_CARD_WIDTH = 210;
255
+ var SOCKET_ROW_HEIGHT = 24;
256
+ var renderSpriteIcon = (iconName, color, className = "w-4 h-4 shrink-0") => {
257
+ const props = { className, style: { color } };
258
+ switch (iconName) {
259
+ case "Castle":
260
+ return /* @__PURE__ */ jsx3(Castle, { ...props });
261
+ case "Sparkles":
262
+ return /* @__PURE__ */ jsx3(Sparkles, { ...props });
263
+ case "Flame":
264
+ return /* @__PURE__ */ jsx3(Flame, { ...props });
265
+ case "FileAudio":
266
+ return /* @__PURE__ */ jsx3(FileAudio, { ...props });
267
+ case "Activity":
268
+ return /* @__PURE__ */ jsx3(Activity, { ...props });
269
+ case "Layers":
270
+ return /* @__PURE__ */ jsx3(Layers, { ...props });
271
+ case "Music":
272
+ return /* @__PURE__ */ jsx3(Music, { ...props });
273
+ case "Clock":
274
+ return /* @__PURE__ */ jsx3(Clock, { ...props });
275
+ case "RotateCw":
276
+ return /* @__PURE__ */ jsx3(RotateCw, { ...props });
277
+ case "Volume2":
278
+ return /* @__PURE__ */ jsx3(Volume2, { ...props });
279
+ case "Zap":
280
+ return /* @__PURE__ */ jsx3(Zap, { ...props });
281
+ case "Radio":
282
+ return /* @__PURE__ */ jsx3(Radio, { ...props });
283
+ case "LogIn":
284
+ return /* @__PURE__ */ jsx3(LogIn, { ...props });
285
+ case "LogOut":
286
+ return /* @__PURE__ */ jsx3(LogOut, { ...props });
287
+ case "GitMerge":
288
+ return /* @__PURE__ */ jsx3(GitMerge, { ...props });
289
+ case "Split":
290
+ return /* @__PURE__ */ jsx3(Split, { ...props });
291
+ case "Cpu":
292
+ return /* @__PURE__ */ jsx3(Cpu, { ...props });
293
+ case "Repeat":
294
+ return /* @__PURE__ */ jsx3(Repeat, { ...props });
295
+ case "Type":
296
+ return /* @__PURE__ */ jsx3(Type, { ...props });
297
+ case "Hash":
298
+ return /* @__PURE__ */ jsx3(Hash, { ...props });
299
+ case "ToggleLeft":
300
+ return /* @__PURE__ */ jsx3(ToggleLeft, { ...props });
301
+ case "Braces":
302
+ return /* @__PURE__ */ jsx3(Braces, { ...props });
303
+ case "Folder":
304
+ return /* @__PURE__ */ jsx3(Folder, { ...props });
305
+ case "FileText":
306
+ return /* @__PURE__ */ jsx3(FileText, { ...props });
307
+ default:
308
+ return /* @__PURE__ */ jsx3(Castle, { ...props });
309
+ }
310
+ };
311
+ var Node2DBase = ({
312
+ node,
313
+ sprite,
314
+ sockets,
315
+ screenPos,
316
+ zoom,
317
+ isSelected,
318
+ isHovered,
319
+ children,
320
+ onNodeMouseDown,
321
+ onNodeDoubleClick,
322
+ onNodeMouseEnter,
323
+ onNodeMouseLeave,
324
+ onSocketHover,
325
+ onSocketMouseDown,
326
+ onSocketMouseUp
327
+ }) => {
328
+ const totalRows = Math.max(sockets.inputs.length, sockets.outputs.length, 1);
329
+ const cardHeight = Math.max(70, 36 + totalRows * SOCKET_ROW_HEIGHT);
330
+ const nodeInspectionText = `NODE: ${node.name || sprite.spriteName || node.type} (${(node.type || "NODE").toUpperCase()})`;
331
+ return /* @__PURE__ */ jsxs3(
332
+ "div",
333
+ {
334
+ id: `floks-node-2d-${node.id}`,
335
+ "data-skipo-tip": nodeInspectionText,
336
+ title: nodeInspectionText,
337
+ onMouseEnter: onNodeMouseEnter,
338
+ onMouseLeave: onNodeMouseLeave,
339
+ onMouseDown: onNodeMouseDown,
340
+ onDoubleClick: onNodeDoubleClick,
341
+ style: {
342
+ transform: `translate(${screenPos.x}px, ${screenPos.y}px) translate(-50%, -50%) scale(${zoom})`,
343
+ width: NODE_CARD_WIDTH,
344
+ minHeight: cardHeight,
345
+ boxShadow: isSelected ? `0 0 0 2px #38bdf8, 4px 4px 0px #000000, 0 0 16px ${sprite.glowColor}` : `4px 4px 0px #000000, 0 0 10px ${isHovered ? sprite.glowColor : "rgba(0,0,0,0.5)"}`
346
+ },
347
+ className: `absolute flex flex-col bg-[#0b0e17]/95 border-2 rounded-none transition-transform select-none cursor-move z-20 ${isSelected ? "border-sky-400 bg-[#0f172a]" : isHovered ? "border-amber-400" : "border-[#334155]"}`,
348
+ children: [
349
+ node.type === "recorder" && node.isArmed ? /* @__PURE__ */ jsx3("div", { className: "w-full px-2 py-1 my-auto", children: /* @__PURE__ */ jsx3(RecorderWaveformDisplay, { node, width: 180 }) }) : /* @__PURE__ */ jsx3("div", { className: "flex items-center justify-center p-3 flex-1 my-auto", children: renderSpriteIcon(sprite.iconName, sprite.accentColor, "w-7 h-7 shrink-0") }),
350
+ children,
351
+ /* @__PURE__ */ jsx3("div", { className: "flex flex-col gap-1 px-1.5 py-1.5 mt-auto border-t border-[#1e293b] bg-black/40", children: Array.from({ length: totalRows }).map((_, rowIdx) => {
352
+ const inSock = sockets.inputs[rowIdx];
353
+ const outSock = sockets.outputs[rowIdx];
354
+ return /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-1 text-[9px] h-5", children: [
355
+ inSock ? /* @__PURE__ */ jsx3(
356
+ Socket2D,
357
+ {
358
+ nodeId: node.id,
359
+ socket: inSock,
360
+ onHover: (info) => onSocketHover?.(info),
361
+ onMouseDown: (nodeId, sock, e) => onSocketMouseDown?.(nodeId, sock, e),
362
+ onMouseUp: (nodeId, sock, e) => onSocketMouseUp?.(nodeId, sock, e)
363
+ }
364
+ ) : /* @__PURE__ */ jsx3("div", {}),
365
+ outSock ? /* @__PURE__ */ jsx3(
366
+ Socket2D,
367
+ {
368
+ nodeId: node.id,
369
+ socket: outSock,
370
+ onHover: (info) => onSocketHover?.(info),
371
+ onMouseDown: (nodeId, sock, e) => onSocketMouseDown?.(nodeId, sock, e),
372
+ onMouseUp: (nodeId, sock, e) => onSocketMouseUp?.(nodeId, sock, e)
373
+ }
374
+ ) : /* @__PURE__ */ jsx3("div", {})
375
+ ] }, `socket-row-${rowIdx}`);
376
+ }) })
377
+ ]
378
+ }
379
+ );
380
+ };
381
+
382
+ export {
383
+ getSocketLocalOffset,
384
+ getSocketScreenPosition,
385
+ Socket2D,
386
+ RecorderWaveformDisplay,
387
+ NODE_CARD_WIDTH,
388
+ SOCKET_ROW_HEIGHT,
389
+ renderSpriteIcon,
390
+ Node2DBase
391
+ };