@xenolithengine/graph-theme-daylight 0.7.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 strelok2012
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # @xenolithengine/graph-theme-daylight
2
+
3
+ [![BETA](https://img.shields.io/badge/status-BETA-FCB400?style=flat-square)](https://github.com/XenolithEngine/xenolith-graph#status)
4
+ [![MIT](https://img.shields.io/badge/license-MIT-FCB400?style=flat-square)](https://github.com/XenolithEngine/xenolith-graph/blob/main/LICENSE)
5
+
6
+ Daylight theme for XenolithGraph — an original light-mode design language. Soft light-grey canvas (`#E2E2E2`), node bodies sharing the canvas fill and separated purely by drop-shadow, pin halos that protrude from the body while wires pass underneath, connected pins reading as a concentric "bullseye" target, Helvetica Neue typography with an Inter fallback.
7
+
8
+ > **Beta** — public API in `STABLE-API.md` is the surface we plan to freeze, but it is **NOT frozen yet** — breaking changes can land at any point before v1.0. If you adopt now, pin an exact version.
9
+
10
+ Part of [XenolithGraph](https://github.com/XenolithEngine/xenolith-graph) — an AI-native, embeddable node-graph editor for the web.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add @xenolithengine/graph-theme-daylight pixi.js
16
+ ```
17
+
18
+ Peer dependency: `pixi.js@^8.6.0`.
19
+
20
+ ## Usage
21
+
22
+ ```ts
23
+ import { XenolithEditor } from '@xenolithengine/graph-editor'
24
+ import { daylightTheme } from '@xenolithengine/graph-theme-daylight'
25
+
26
+ const editor = await XenolithEditor.init('#graph', { theme: daylightTheme })
27
+
28
+ // or swap at runtime
29
+ editor.setTheme(daylightTheme)
30
+ ```
31
+
32
+ ## What's exported
33
+
34
+ - `daylightTheme` — drop-in `XenolithTheme`
35
+ - `daylightTokens` — token map for further overrides via `mergeTheme`
36
+
37
+ ## Docs
38
+
39
+ - [Theming guide](https://graph.xenolith.studio/guides/api/)
40
+ - [GitHub](https://github.com/XenolithEngine/xenolith-graph)
41
+
42
+ MIT © XenolithEngine
@@ -0,0 +1,14 @@
1
+ import type { XenolithTheme } from '@xenolithengine/graph-render-pixi';
2
+ /**
3
+ * Daylight — original light-mode design language. Soft grey canvas, drop-shadowed nodes,
4
+ * protruding pin halos with wires that pass underneath, Helvetica typography. Pin
5
+ * connected/disconnected state shows as filled disc vs ring.
6
+ *
7
+ * The custom `renderNode` (pin halos + category dot in header) lands in render-node.ts.
8
+ * Until then this theme uses the default Xen node renderer — tokens already give it the
9
+ * right colours but without the halo protrusion.
10
+ */
11
+ export declare const daylightTheme: XenolithTheme;
12
+ export { daylightTokens } from './tokens.js';
13
+ export declare const VERSION = "0.7.0-beta.5";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAA;AAItE;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,EAAE,aAsB3B,CAAA;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,eAAO,MAAM,OAAO,iBAAiB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ import { daylightTokens } from './tokens.js';
2
+ import { renderNodeDaylight } from './render-node.js';
3
+ /**
4
+ * Daylight — original light-mode design language. Soft grey canvas, drop-shadowed nodes,
5
+ * protruding pin halos with wires that pass underneath, Helvetica typography. Pin
6
+ * connected/disconnected state shows as filled disc vs ring.
7
+ *
8
+ * The custom `renderNode` (pin halos + category dot in header) lands in render-node.ts.
9
+ * Until then this theme uses the default Xen node renderer — tokens already give it the
10
+ * right colours but without the halo protrusion.
11
+ */
12
+ export const daylightTheme = {
13
+ id: 'daylight',
14
+ // Helvetica Neue is installed by default on macOS/iOS; Inter is the CDN fallback the editor
15
+ // already loads for Xen so the family resolution is two-step: Helvetica Neue → Inter → sans.
16
+ fonts: [{ family: 'Inter', weights: [400, 500, 700] }],
17
+ tokens: daylightTokens,
18
+ needsBackdrop: false,
19
+ freezeOnNavigate: false,
20
+ commentHeaderStyle: 'tint',
21
+ paletteStyle: {
22
+ panelBackground: 'rgba(255, 255, 255, 0.92)',
23
+ panelBorder: 'rgba(0, 0, 0, 0.08)',
24
+ panelShadow: '0 4px 14px rgba(174, 174, 174, 0.23)',
25
+ panelRadius: '12px',
26
+ textColor: '#181717',
27
+ mutedColor: '#515151',
28
+ accent: '#2769FF',
29
+ rowSelectedBackground: 'rgba(39, 105, 255, 0.1)',
30
+ inputBackground: 'rgba(255, 255, 255, 0.6)',
31
+ inputBorder: 'rgba(0, 0, 0, 0.12)',
32
+ },
33
+ renderNode: (node, opts) => renderNodeDaylight(node, daylightTokens, opts),
34
+ };
35
+ export { daylightTokens } from './tokens.js';
36
+ export const VERSION = '0.7.0-beta.5';
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,EAAE,EAAE,UAAU;IACd,4FAA4F;IAC5F,6FAA6F;IAC7F,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IACtD,MAAM,EAAE,cAAc;IACtB,aAAa,EAAE,KAAK;IACpB,gBAAgB,EAAE,KAAK;IACvB,kBAAkB,EAAE,MAAM;IAC1B,YAAY,EAAE;QACZ,eAAe,EAAQ,2BAA2B;QAClD,WAAW,EAAY,qBAAqB;QAC5C,WAAW,EAAY,sCAAsC;QAC7D,WAAW,EAAY,MAAM;QAC7B,SAAS,EAAc,SAAS;QAChC,UAAU,EAAa,SAAS;QAChC,MAAM,EAAiB,SAAS;QAChC,qBAAqB,EAAE,yBAAyB;QAChD,eAAe,EAAQ,0BAA0B;QACjD,WAAW,EAAY,qBAAqB;KAC7C;IACD,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC;CAC3E,CAAA;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,CAAC,MAAM,OAAO,GAAG,cAAc,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { Node } from '@xenolithengine/graph-core';
2
+ import { type NodeView, type RenderNodeOptions } from '@xenolithengine/graph-render-pixi';
3
+ import type { XenTokens } from '@xenolithengine/graph-theme-xen';
4
+ export declare function renderNodeDaylight(node: Node, tokens: XenTokens, opts?: RenderNodeOptions): NodeView;
5
+ //# sourceMappingURL=render-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-node.d.ts","sourceRoot":"","sources":["../src/render-node.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAEL,KAAK,QAAQ,EAAwB,KAAK,iBAAiB,EAC5D,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAsChE,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,iBAAsB,GAC3B,QAAQ,CAkYV"}
@@ -0,0 +1,422 @@
1
+ import { Container, Graphics, BitmapText } from 'pixi.js';
2
+ import { computeNodeLayout, renderWidgets, markPinInteractive, } from '@xenolithengine/graph-render-pixi';
3
+ // Daylight renderNode — drawn from scratch, not as a wrap around the base Xen renderer.
4
+ // Full control over draw order is what the two Daylight-specific affordances need:
5
+ //
6
+ // 1. Pin halos that PROTRUDE from the body (~10 px disc of body-colour grey at each pin
7
+ // position). They draw AFTER the body (so they mask the body's curved corner where the pin
8
+ // sits) and BEFORE the pin disc (so the disc stays on top). The wire underneath terminates
9
+ // under the halo because the editor renders #edgesLayer below #nodesLayer.
10
+ //
11
+ // 2. Pin disc swaps between a SOLID disc (connected) and a RING (disconnected) so the halo
12
+ // grey shows through the centre — matches the Figma source exactly. Driven by
13
+ // `opts.connectedPinIds`.
14
+ //
15
+ // Also: a small accent dot in the header marks the node's category (image / data / utility /
16
+ // macro in our token map; falls back to brand-blue if the category is unknown).
17
+ // Figma spec (Frame 2131333001 "Node Draft" — width 233, generic node):
18
+ // - node body: 12px corner radius, box-shadow: 0 4px 14px rgba(174,174,174,0.23)
19
+ // - header: title text at top:12 (12px padding from node top), font 12/500 line-height 12 → text
20
+ // bottom at y=24; title area occupies y=12..28 (icon+text+chevron+dot row, height 16)
21
+ // - first pin halo top at y=37 → gap between header bottom (28) and pin halo (37) is 9px
22
+ // - pin halo: 20x20 (frame background = node fill; drop-shadow hides the seam), border-radius 12
23
+ // - pin colored disc: 12x12 (r=6), inner dot: 5.33x5.33 (r=2.67, ratio 0.44 of the outer)
24
+ // - vertical gap between stacked pins: 9px (frame 2131333008 auto-layout gap)
25
+ // - category dot in header: 4x4
26
+ const TITLE_TOP_PAD = 12; // Figma: title text `top: 12` inside node
27
+ const TITLE_FONT_SIZE = 12; // Figma: font-size 12, line-height 12
28
+ const HEADER_HEIGHT = TITLE_TOP_PAD + 16; // = 28 (title text + row content)
29
+ const HEADER_TO_PIN_GAP = 9; // Figma: gap between header bottom and first pin halo TOP
30
+ const HALO_RADIUS = 10; // 20x20 halo frame → r=10
31
+ const PIN_RADIUS = 6; // 12x12 colored disc → r=6
32
+ const PIN_INNER_RATIO = 0.444; // 5.33 / 12 (Figma inner-dot ratio)
33
+ const PIN_GREY_GAP_RATIO = 0.60; // width of the middle grey "gap" that separates outer ring from inner dot
34
+ const PIN_ROW_GAP = 9; // vertical gap between stacked pin halos
35
+ const CATEGORY_DOT = 4; // 4x4
36
+ const DISCONNECTED_RING_WIDTH = 2.5;
37
+ export function renderNodeDaylight(node, tokens, opts = {}) {
38
+ const isPinConnected = (pinKey) => {
39
+ const set = opts.connectedPinIds;
40
+ if (!set)
41
+ return false;
42
+ const pin = node.pins.find((p) => p.label === pinKey || String(p.id) === pinKey);
43
+ return pin ? set.has(String(pin.id)) : false;
44
+ };
45
+ // All Y-driving tokens flipped to Daylight's Figma spec: HEADER_HEIGHT + HEADER_TO_PIN_GAP for
46
+ // the top band, per-row height sized to the HALO diameter (else 20px halos overlap on tight
47
+ // Xen row spacing), and PIN_ROW_GAP for the vertical gap between neighbouring pin halos.
48
+ // pin_center_Y = HEADER_HEIGHT + HEADER_TO_PIN_GAP + halo_r = 28 + 9 + 10 = 47
49
+ // halo_top_Y = pin_center_Y - halo_r = 37 (Figma "first pin at 37")
50
+ const layout = computeNodeLayout(node, {
51
+ node: { ...tokens.geometry.node, headerHeight: HEADER_HEIGHT },
52
+ pin: {
53
+ diameter: tokens.geometry.pin.diameter,
54
+ rowSpacing: PIN_ROW_GAP,
55
+ rowHeight: HALO_RADIUS * 2,
56
+ },
57
+ header: { toPinsGap: HEADER_TO_PIN_GAP },
58
+ widget: { rowHeight: tokens.geometry.widget.rowHeight, gap: tokens.geometry.widget.gap, controlMinWidth: tokens.geometry.widget.controlMinWidth },
59
+ }, isPinConnected);
60
+ const W = layout.body.width;
61
+ const FULL_H = layout.body.height;
62
+ // Collapsed form: pill height is INVARIANT (same as the no-pin pill). When more pins need to
63
+ // fit on the cap perimeter, we SHRINK the halo / disc radius instead of growing the pill. Each
64
+ // node still reads at the same vertical footprint when collapsed.
65
+ const inputsCount = node.pins.filter((p) => p.direction === 'in').length;
66
+ const outputsCount = node.pins.filter((p) => p.direction === 'out').length;
67
+ const maxPerSide = Math.max(inputsCount, outputsCount);
68
+ const COLLAPSED_R = tokens.geometry.node.pillRadius ?? 20;
69
+ const COLLAPSED_H = tokens.geometry.node.pillHeight ?? (2 * COLLAPSED_R);
70
+ const COLLAPSED_CY = COLLAPSED_H / 2;
71
+ // Tight-pack halos on the cap perimeter: adjacent halos should nearly touch (~2px gap).
72
+ // chord between neighbours = 2 * COLLAPSED_R * sin(step/2)
73
+ // gap = chord - 2 * haloR → for gap=2px and haloR=HALO_RADIUS: step = 2·asin((haloR+1)/R)
74
+ // If that step × (N-1) fits in the semicircle we keep haloR at its full value and REDUCE the
75
+ // fan spread; otherwise we spread across the full semicircle and shrink haloR to fit.
76
+ // Floor haloR at 3 so the disc stays visible even with a comically pin-heavy node.
77
+ const HALO_GAP = 2;
78
+ const tightStep = 2 * Math.asin(Math.min(1, (HALO_RADIUS + HALO_GAP / 2) / COLLAPSED_R));
79
+ const spreadFits = maxPerSide <= 1 || (maxPerSide - 1) * tightStep <= Math.PI;
80
+ const collapsedStep = maxPerSide <= 1
81
+ ? 0
82
+ : spreadFits ? tightStep : Math.PI / (maxPerSide - 1);
83
+ const collapsedHaloR = spreadFits
84
+ ? HALO_RADIUS
85
+ : Math.max(3, COLLAPSED_R * Math.sin(collapsedStep / 2) - HALO_GAP / 2);
86
+ const collapsedPinR = Math.max(2, collapsedHaloR * 0.6);
87
+ const r = tokens.geometry.node.radius;
88
+ const container = new Container({ label: `daylight:${node.id}` });
89
+ container.position.set(node.position.x, node.position.y);
90
+ container.eventMode = 'static';
91
+ // shell — body, shadow, header, title, category dot (always present)
92
+ // halos — pin halos (drawn between shell and pins so they mask body corners but stay under discs)
93
+ // pins — pin discs + labels + widgets (expanded only)
94
+ // glow — hover/selected outline (attached on demand)
95
+ const shell = new Container({ label: 'shell' });
96
+ const halos = new Container({ label: 'halos' });
97
+ const pins = new Container({ label: 'pins' });
98
+ container.addChild(shell, halos, pins);
99
+ let collapsed = !!opts.collapsed;
100
+ let currentState = opts.state ?? 'default';
101
+ let glow = null;
102
+ let widgetsView = null;
103
+ // Per-halo descriptors captured during buildPinsAndHalos so setGlow can stroke each halo's
104
+ // outward arc — the selection outline must follow the node silhouette including pin bumps,
105
+ // not just the body rect (image #42).
106
+ let haloRefs = [];
107
+ function buildShell() {
108
+ while (shell.children.length > 0)
109
+ shell.removeChildAt(0).destroy({ children: true });
110
+ const h = collapsed ? COLLAPSED_H : FULL_H;
111
+ // Soft drop shadow — Daylight's body shares its fill with the canvas, so the shadow IS the
112
+ // visual separator. Faked as a stack of offset rounded rects (no DropShadowFilter dependency).
113
+ // The Figma value is `0 4px 14px rgba(174,174,174,0.23)`; we approximate the blur fall-off
114
+ // with 5 rings.
115
+ const SHADOW_RINGS = 5;
116
+ const shadowRadius = collapsed ? COLLAPSED_R : r;
117
+ for (let i = SHADOW_RINGS; i >= 1; i--) {
118
+ const pad = (i / SHADOW_RINGS) * 7;
119
+ const alpha = 0.07 * (1 - i / (SHADOW_RINGS + 1));
120
+ const shadow = new Graphics()
121
+ .roundRect(-pad, 4 - pad, W + pad * 2, h + pad * 2, shadowRadius + pad)
122
+ .fill({ color: 0xAEAEAE, alpha });
123
+ shadow.eventMode = 'none';
124
+ shell.addChild(shadow);
125
+ }
126
+ // Body — flat grey rounded rect (pill when collapsed, big radius). Same colour as canvas;
127
+ // shadow above provides the rim.
128
+ const bodyRadius = collapsed ? COLLAPSED_R : r;
129
+ const body = new Graphics()
130
+ .roundRect(0, 0, W, h, bodyRadius)
131
+ .fill(tokens.color.surface.node)
132
+ .stroke({ color: tokens.color.surface.outline, width: 0.5 });
133
+ body.eventMode = 'static';
134
+ shell.addChild(body);
135
+ // Title — Helvetica Neue with Inter / system fallback (the editor preloads Inter from CDN).
136
+ // For the expanded form: title anchored at Figma's fixed 12px top-padding (NOT centred in the
137
+ // header band — Figma places the whole title row at `top: 12` inside the node). For the
138
+ // collapsed pill: centre in the pill.
139
+ const titleText = new BitmapText({
140
+ text: opts.title ?? node.type,
141
+ style: {
142
+ fontFamily: '"Helvetica Neue", Inter, system-ui, sans-serif',
143
+ fontSize: TITLE_FONT_SIZE,
144
+ fontWeight: '500',
145
+ fill: tokens.color.text.primary,
146
+ },
147
+ });
148
+ const titleY = collapsed ? (h - titleText.height) / 2 : TITLE_TOP_PAD;
149
+ titleText.position.set(12, titleY);
150
+ titleText.eventMode = 'none';
151
+ shell.addChild(titleText);
152
+ // Category dot (Figma: 4x4, ellipse in the header auto-layout, 6px gap right of the title).
153
+ if (opts.category) {
154
+ const accent = tokens.category[opts.category]?.accent
155
+ ?? tokens.color.brand['primary'];
156
+ const dot = new Graphics().circle(0, 0, CATEGORY_DOT / 2).fill(accent);
157
+ dot.__categoryDot = true;
158
+ dot.position.set(12 + titleText.width + 6, titleY + titleText.height / 2);
159
+ shell.addChild(dot);
160
+ }
161
+ // Chevron — collapse/expand toggle. Sits on the same baseline as the title (Figma: last child
162
+ // of the header auto-layout row).
163
+ const chev = new Graphics();
164
+ if (collapsed) {
165
+ chev.moveTo(0, 0).lineTo(5, 4).lineTo(0, 8).stroke({ color: tokens.color.text.secondary, width: 1.4 });
166
+ }
167
+ else {
168
+ chev.moveTo(0, 0).lineTo(4, 5).lineTo(8, 0).stroke({ color: tokens.color.text.secondary, width: 1.4 });
169
+ }
170
+ const chevY = collapsed ? (h - 8) / 2 : titleY + (titleText.height - 8) / 2;
171
+ chev.position.set(W - 22, chevY);
172
+ chev.eventMode = 'static';
173
+ chev.cursor = 'pointer';
174
+ chev.hitArea = { contains: (px, py) => px >= -8 && px <= 16 && py >= -8 && py <= 16 };
175
+ chev.on('pointerdown', (e) => {
176
+ e.stopPropagation();
177
+ collapsed = !collapsed;
178
+ buildShell();
179
+ buildPinsAndHalos();
180
+ setGlow(currentState === 'hover' ? 'hover' : currentState === 'selected' ? 'selected' : 'none');
181
+ });
182
+ shell.addChild(chev);
183
+ }
184
+ function buildPinsAndHalos() {
185
+ while (halos.children.length > 0)
186
+ halos.removeChildAt(0).destroy({ children: true });
187
+ while (pins.children.length > 0)
188
+ pins.removeChildAt(0).destroy({ children: true });
189
+ haloRefs = [];
190
+ // Widgets first (under pins for hit-test order — pins must win clicks on shared rows).
191
+ // MUST use the SAME layout tokens as `computeNodeLayout` above — the widget renderer's
192
+ // `pinRowCenterY` reads pin.rowSpacing / pin.rowHeight / node.headerHeight / header.toPinsGap
193
+ // to compute a widget row's Y, so any drift here shifts a bound widget off its pin.
194
+ if (!collapsed && node.widgets && node.widgets.length > 0) {
195
+ const layoutTokens = {
196
+ node: { headerHeight: HEADER_HEIGHT },
197
+ pin: {
198
+ rowSpacing: PIN_ROW_GAP,
199
+ rowHeight: HALO_RADIUS * 2,
200
+ diameter: tokens.geometry.pin.diameter,
201
+ labelGap: tokens.geometry.pin.labelGap,
202
+ },
203
+ header: { toPinsGap: HEADER_TO_PIN_GAP },
204
+ widget: {
205
+ rowHeight: tokens.geometry.widget.rowHeight,
206
+ gap: tokens.geometry.widget.gap,
207
+ paddingX: tokens.geometry.widget.paddingX,
208
+ },
209
+ };
210
+ widgetsView = renderWidgets(node, W, tokens, layoutTokens, opts.customWidgets, { isPinConnected });
211
+ pins.addChild(widgetsView.container);
212
+ }
213
+ else {
214
+ widgetsView = null;
215
+ }
216
+ // Pin halos + discs.
217
+ // For COLLAPSED form, pins sit on the rounded end-cap perimeter — fanned over the FULL
218
+ // semicircle (180° spread). The cap radius was pre-sized (COLLAPSED_R) so neighbouring
219
+ // halos don't overlap, so we can just walk the angle from -π/2 (top) to π/2 (bottom).
220
+ const collapsedInputs = node.pins.filter((p) => p.direction === 'in');
221
+ const collapsedOutputs = node.pins.filter((p) => p.direction === 'out');
222
+ // Center a fan of `count` pins around the horizontal axis (angle 0), using the pre-computed
223
+ // step so neighbours pack tight with a small gap between halos. Fan spread = (count-1)*step.
224
+ const fanAngle = (count, idx) => {
225
+ if (count <= 1)
226
+ return 0;
227
+ return -((count - 1) * collapsedStep) / 2 + idx * collapsedStep;
228
+ };
229
+ for (const p of layout.pins) {
230
+ const pin = node.pins.find((x) => String(x.id) === String(p.id));
231
+ const colour = resolvePinColor(pin.type, tokens);
232
+ let localX, localY;
233
+ if (collapsed) {
234
+ // Pin sits on the cap circle perimeter at angle θ (from "due-left" axis for inputs,
235
+ // "due-right" for outputs). Halo center == pin center == on the pill boundary; the halo
236
+ // disc protrudes radially outward.
237
+ if (pin.direction === 'in') {
238
+ const idx = collapsedInputs.indexOf(pin);
239
+ const a = fanAngle(collapsedInputs.length, idx);
240
+ localX = COLLAPSED_R - COLLAPSED_R * Math.cos(a);
241
+ localY = COLLAPSED_CY + COLLAPSED_R * Math.sin(a);
242
+ }
243
+ else {
244
+ const idx = collapsedOutputs.indexOf(pin);
245
+ const a = fanAngle(collapsedOutputs.length, idx);
246
+ localX = W - COLLAPSED_R + COLLAPSED_R * Math.cos(a);
247
+ localY = COLLAPSED_CY + COLLAPSED_R * Math.sin(a);
248
+ }
249
+ }
250
+ else {
251
+ localX = p.x - layout.body.x;
252
+ localY = p.y - layout.body.y;
253
+ }
254
+ // Halo + half-disc shadow on the PROTRUDING (outward-radial) side.
255
+ // - Expanded: pins ride the left/right body edges → "outward" is just left or right.
256
+ // - Collapsed: pins sit on a cap-circle perimeter → "outward" is the vector from cap
257
+ // centre through pin. Compute outward angle from cap centre.
258
+ // Shadow drawn as a half-disc (arc + closePath) on the outward side so its inner half
259
+ // (which would sit inside the body) doesn't bleed in as a dark blob (image #31).
260
+ let outwardAngle;
261
+ if (collapsed) {
262
+ const capCx = pin.direction === 'in' ? COLLAPSED_R : W - COLLAPSED_R;
263
+ outwardAngle = Math.atan2(localY - COLLAPSED_CY, localX - capCx);
264
+ }
265
+ else {
266
+ outwardAngle = p.side === 'left' ? Math.PI : 0;
267
+ }
268
+ const SHADOW_RINGS = 4;
269
+ for (let i = SHADOW_RINGS; i >= 1; i--) {
270
+ const pad = (i / SHADOW_RINGS) * 4;
271
+ const alpha = 0.07 * (1 - i / (SHADOW_RINGS + 1));
272
+ const sr = (collapsed ? collapsedHaloR : HALO_RADIUS) + pad;
273
+ const g = new Graphics();
274
+ // Half-disc spanning ±π/2 around `outwardAngle`. arc(cx, cy, r, a0, a1, ccw=false) draws
275
+ // the short way from a0 → a1 when ccw=false; with start=outwardAngle-π/2, end=+π/2, it
276
+ // sweeps through outwardAngle — i.e. the outward half-disc.
277
+ g.arc(localX, localY + 2, sr, outwardAngle - Math.PI / 2, outwardAngle + Math.PI / 2, false)
278
+ .closePath()
279
+ .fill({ color: 0xAEAEAE, alpha });
280
+ g.eventMode = 'none';
281
+ halos.addChild(g);
282
+ }
283
+ const haloR = collapsed ? collapsedHaloR : HALO_RADIUS;
284
+ const halo = new Graphics()
285
+ .circle(localX, localY, haloR)
286
+ .fill(tokens.color.surface.node);
287
+ halo.eventMode = 'none';
288
+ halos.addChild(halo);
289
+ haloRefs.push({ x: localX, y: localY, outwardAngle, radius: haloR });
290
+ // Pin disc — solid when connected, ring when not. The disconnected ring lets the halo grey
291
+ // show through, matching the Figma source.
292
+ const disc = new Graphics();
293
+ const connected = isPinConnected(String(pin.id));
294
+ const pinR = collapsed ? collapsedPinR : PIN_RADIUS;
295
+ if (connected) {
296
+ // Bullseye "target" symbol — outer ring, grey gap, inner dot. Ratios from Figma spec:
297
+ // outer disc diameter = 12 (r=PIN_RADIUS)
298
+ // inner dot diameter = 5.33 (r = PIN_RADIUS * PIN_INNER_RATIO ≈ 2.67)
299
+ // grey gap punched between them at PIN_RADIUS * PIN_GREY_GAP_RATIO to visually separate.
300
+ disc.circle(localX, localY, pinR).fill(colour);
301
+ disc.circle(localX, localY, pinR * PIN_GREY_GAP_RATIO).fill(tokens.color.surface.node);
302
+ disc.circle(localX, localY, pinR * PIN_INNER_RATIO).fill(colour);
303
+ }
304
+ else {
305
+ // Disconnected pin: paint an annulus (outer disc − inner disc filled with the halo grey)
306
+ // so its OUTER diameter is exactly `2·pinR`, matching the connected bullseye. A stroke at
307
+ // `pinR` extends to `pinR + width/2` outward, reading as a visibly larger pin — hence the
308
+ // two-fill approach here.
309
+ const ringW = Math.max(1.2, DISCONNECTED_RING_WIDTH * (pinR / PIN_RADIUS));
310
+ disc.circle(localX, localY, pinR).fill(colour);
311
+ disc.circle(localX, localY, Math.max(0, pinR - ringW)).fill(tokens.color.surface.node);
312
+ }
313
+ markPinInteractive(disc, pin, String(node.id), localX, localY, pinR);
314
+ pins.addChild(disc);
315
+ if (!collapsed && pin.label) {
316
+ const label = new BitmapText({
317
+ text: pin.label,
318
+ style: {
319
+ fontFamily: '"Helvetica Neue", Inter, system-ui, sans-serif',
320
+ fontSize: 11,
321
+ fill: tokens.color.text.secondary,
322
+ },
323
+ });
324
+ label.eventMode = 'none';
325
+ const ly = localY - label.height / 2;
326
+ if (p.side === 'left') {
327
+ label.position.set(localX + PIN_RADIUS + 8, ly);
328
+ }
329
+ else {
330
+ label.anchor.set(1, 0);
331
+ label.position.set(localX - PIN_RADIUS - 8, ly);
332
+ }
333
+ pins.addChild(label);
334
+ }
335
+ }
336
+ }
337
+ function setGlow(intensity) {
338
+ if (glow) {
339
+ const g = glow;
340
+ glow = null;
341
+ g.destroy({ children: true });
342
+ }
343
+ if (intensity === 'none')
344
+ return;
345
+ const h = collapsed ? COLLAPSED_H : FULL_H;
346
+ const bodyR = collapsed ? COLLAPSED_R : r;
347
+ const strokeColor = tokens.color.brand['primary'];
348
+ const RIM = 2;
349
+ // Trick: instead of computing the body+halo path union ourselves (the union has gaps where
350
+ // halo arcs meet body corners, image #44), draw a SOLID silhouette padded by RIM in all
351
+ // directions. Body + halos are rendered on top in their normal colours — the only visible
352
+ // pixels of this silhouette are the RIM-wide ring around the union outline. No gaps, no
353
+ // tangent artifacts, no manual path stitching.
354
+ // Build silhouette as ONE compound path filled in a single .fill() — PIXI v8 closes &
355
+ // discards the current path after fill, so each shape needs to be queued BEFORE the fill
356
+ // call. Earlier per-halo `.arc().closePath().fill()` had only the first halo render and the
357
+ // body outline distort (images #46/#47).
358
+ const sel = new Graphics();
359
+ sel.roundRect(-RIM, -RIM, W + 2 * RIM, h + 2 * RIM, bodyR + RIM);
360
+ for (const halo of haloRefs) {
361
+ sel.circle(halo.x, halo.y, halo.radius + RIM);
362
+ }
363
+ sel.fill(strokeColor);
364
+ sel.eventMode = 'none';
365
+ container.addChildAt(sel, 0);
366
+ glow = sel;
367
+ }
368
+ buildShell();
369
+ buildPinsAndHalos();
370
+ if (currentState === 'hover')
371
+ setGlow('hover');
372
+ if (currentState === 'selected')
373
+ setGlow('selected');
374
+ const view = {
375
+ get container() { return container; },
376
+ setVisualState: (s) => {
377
+ if (s === currentState)
378
+ return;
379
+ currentState = s;
380
+ setGlow(s === 'hover' ? 'hover' : s === 'selected' ? 'selected' : 'none');
381
+ },
382
+ setCollapsed: (c) => {
383
+ if (c === collapsed)
384
+ return;
385
+ collapsed = c;
386
+ buildShell();
387
+ buildPinsAndHalos();
388
+ setGlow(currentState === 'hover' ? 'hover' : currentState === 'selected' ? 'selected' : 'none');
389
+ },
390
+ isCollapsed: () => collapsed,
391
+ pinLocalPosition: (id) => {
392
+ const lp = layout.pins.find((p) => String(p.id) === id);
393
+ if (!lp)
394
+ return null;
395
+ if (collapsed) {
396
+ // Recompute the fan position so wires land on the visible pin disc, not the pill centre.
397
+ const pin = node.pins.find((p) => String(p.id) === id);
398
+ if (!pin)
399
+ return { x: lp.side === 'left' ? 0 : W, y: COLLAPSED_CY };
400
+ const siblings = node.pins.filter((p) => p.direction === pin.direction);
401
+ const idx = siblings.indexOf(pin);
402
+ const count = siblings.length;
403
+ const a = count <= 1 ? 0 : -Math.PI / 2 + idx * (Math.PI / (count - 1));
404
+ return pin.direction === 'in'
405
+ ? { x: COLLAPSED_R - COLLAPSED_R * Math.cos(a), y: COLLAPSED_CY + COLLAPSED_R * Math.sin(a) }
406
+ : { x: W - COLLAPSED_R + COLLAPSED_R * Math.cos(a), y: COLLAPSED_CY + COLLAPSED_R * Math.sin(a) };
407
+ }
408
+ return { x: lp.x - layout.body.x, y: lp.y - layout.body.y };
409
+ },
410
+ // Forward widgetHit AND updateWidget — `updateWidget` is what the editor calls during live
411
+ // slider / number / xypad drags to refresh the widget visual without rebuilding the node.
412
+ // Without it the value updates in the model but the canvas stays frozen at the start value.
413
+ widgetHit: (lx, ly) => widgetsView?.widgetHit(lx, ly) ?? null,
414
+ updateWidget: (id, value) => { widgetsView?.update(id, value); },
415
+ };
416
+ return view;
417
+ }
418
+ function resolvePinColor(type, tokens) {
419
+ const tok = tokens.pinType[type];
420
+ return tok?.color ?? tokens.color.brand['primary'];
421
+ }
422
+ //# sourceMappingURL=render-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-node.js","sourceRoot":"","sources":["../src/render-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type XenTokens } from '@xenolithengine/graph-theme-xen';
2
+ export declare const daylightTokens: XenTokens;
3
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,SAAS,EAAoB,MAAM,iCAAiC,CAAA;AA6HzG,eAAO,MAAM,cAAc,EAAE,SAAmD,CAAA"}
package/dist/tokens.js ADDED
@@ -0,0 +1,125 @@
1
+ import { xenTokens, mergeTheme } from '@xenolithengine/graph-theme-xen';
2
+ /**
3
+ * Daylight — original light-mode design language for XenolithGraph. Soft light-grey canvas
4
+ * (`#E2E2E2`) where node bodies share the SAME fill as the canvas; separation comes purely
5
+ * from a soft drop-shadow. Pin halos protrude from the body in a matching grey, with the
6
+ * wire passing UNDER the halo. Typography is Helvetica Neue with an Inter fallback.
7
+ *
8
+ * Source: Figma "Node Draft" file, P3 colours flattened to sRGB hex.
9
+ */
10
+ const daylightOverride = {
11
+ color: {
12
+ surface: {
13
+ canvas: '#E2E2E2',
14
+ node: '#E2E2E2',
15
+ panel: '#EDEDED',
16
+ elevated: '#FFFFFF',
17
+ muted: '#D6D6D6',
18
+ subtle: '#CFCFCF',
19
+ outline: 'rgba(255, 255, 255, 0.31)',
20
+ divider: 'rgba(0, 0, 0, 0.08)',
21
+ headerEnd: '#E2E2E2',
22
+ },
23
+ text: {
24
+ primary: '#181717',
25
+ secondary: '#515151',
26
+ muted: 'rgba(24, 23, 23, 0.5)',
27
+ disabled: 'rgba(24, 23, 23, 0.3)',
28
+ },
29
+ alpha: {
30
+ white10: 'rgba(255, 255, 255, 0.1)',
31
+ white20: 'rgba(255, 255, 255, 0.2)',
32
+ white30: 'rgba(255, 255, 255, 0.31)',
33
+ white50: 'rgba(255, 255, 255, 0.5)',
34
+ dark50: 'rgba(0, 0, 0, 0.06)',
35
+ },
36
+ minimap: {
37
+ background: 'rgba(255, 255, 255, 0.85)',
38
+ border: 'rgba(0, 0, 0, 0.12)',
39
+ node: 'rgba(24, 23, 23, 0.32)',
40
+ frame: 'rgba(39, 105, 255, 0.14)',
41
+ frameBorder: '#2769FF',
42
+ },
43
+ widget: {
44
+ bg: 'rgba(255, 255, 255, 0.39)',
45
+ bgHover: 'rgba(255, 255, 255, 0.55)',
46
+ bgFocused: '#FFFFFF',
47
+ track: 'rgba(0, 0, 0, 0.08)',
48
+ fill: '#2769FF',
49
+ fillAlpha: 0.6,
50
+ text: '#181717',
51
+ label: '#515151',
52
+ placeholder: '#515151',
53
+ border: 'rgba(0, 0, 0, 0.12)',
54
+ borderFocused: '#2769FF',
55
+ selection: 'rgba(39, 105, 255, 0.25)',
56
+ knob: '#FFFFFF',
57
+ },
58
+ brand: {
59
+ primary: '#2769FF',
60
+ primaryDark: '#1B4FCC',
61
+ primaryDeep: '#0F306B',
62
+ primaryLight: '#6E9BFF',
63
+ primaryPale: '#C8D9FF',
64
+ primaryAlpha20: 'rgba(39, 105, 255, 0.2)',
65
+ primaryAlpha30: 'rgba(39, 105, 255, 0.3)',
66
+ primaryAlpha50: 'rgba(39, 105, 255, 0.5)',
67
+ primaryAlpha60: 'rgba(39, 105, 255, 0.6)',
68
+ },
69
+ },
70
+ category: {
71
+ logic: { accent: '#1AA63D' },
72
+ data: { accent: '#2769FF' },
73
+ macro: { accent: '#8A78D2' },
74
+ utility: { accent: '#515151' },
75
+ },
76
+ state: {
77
+ hover: { border: '#2769FF', borderWidth: 1, glow: 'rgba(39, 105, 255, 0.35)', glowBlur: 4 },
78
+ selected: { border: '#181717', borderWidth: 1, glow: 'rgba(0, 0, 0, 0.15)', glowBlur: 5 },
79
+ active: { border: '#2769FF', borderWidth: 1, glow: 'rgba(39, 105, 255, 0.45)', glowBlur: 6 },
80
+ },
81
+ geometry: {
82
+ node: {
83
+ radius: 12,
84
+ // Header band matches the Figma "Node Draft" spec: title at top:12 + height:16 = 28.
85
+ headerHeight: 28,
86
+ },
87
+ header: {
88
+ // Gap between header bottom (y=28) and first pin's halo top (y=37) — 9px per Figma.
89
+ toPinsGap: 9,
90
+ },
91
+ pin: {
92
+ // Row cell height MUST equal the halo diameter (20px) so 20px halos don't overlap when the
93
+ // row layout computes centers from rowHeight — same size the render-node.ts custom renderer
94
+ // uses (`HALO_RADIUS * 2`). rowSpacing = Figma inter-halo gap (9px, matches its auto-layout).
95
+ rowHeight: 20,
96
+ rowSpacing: 9,
97
+ },
98
+ // Wider wires than Xen — Daylight reads on a light grey canvas with low-contrast pin colours,
99
+ // so a 2px wire (Xen default) looks anemic. 3px matches the Figma source.
100
+ edge: {
101
+ width: 3,
102
+ execWidth: 3,
103
+ },
104
+ },
105
+ pinType: {
106
+ exec: { color: '#2769FF', edgeColor: '#2769FF', edgeWidth: 3 },
107
+ float: { color: '#1AA63D', edgeColor: '#1AA63D', edgeWidth: 3 },
108
+ string: { color: '#8A78D2', edgeColor: '#8A78D2', edgeWidth: 3 },
109
+ object: { color: '#2769FF', edgeColor: '#2769FF', edgeWidth: 3 },
110
+ wildcard: { color: '#515151', edgeColor: '#515151', edgeWidth: 3 },
111
+ any: { color: '#515151', edgeColor: '#515151', edgeWidth: 3 },
112
+ },
113
+ background: {
114
+ color: '#E2E2E2',
115
+ grid: {
116
+ kind: 'dots',
117
+ spacing: 24,
118
+ size: 1,
119
+ // Dark dots on a light canvas — Xen's `rgba(255,255,255,0.3)` was invisible on Daylight grey.
120
+ color: 'rgba(0, 0, 0, 0.18)',
121
+ },
122
+ },
123
+ };
124
+ export const daylightTokens = mergeTheme(xenTokens, daylightOverride);
125
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAoC,MAAM,iCAAiC,CAAA;AAEzG;;;;;;;GAOG;AACH,MAAM,gBAAgB,GAA2B;IAC/C,KAAK,EAAE;QACL,OAAO,EAAE;YACP,MAAM,EAAK,SAAS;YACpB,IAAI,EAAO,SAAS;YACpB,KAAK,EAAM,SAAS;YACpB,QAAQ,EAAG,SAAS;YACpB,KAAK,EAAM,SAAS;YACpB,MAAM,EAAK,SAAS;YACpB,OAAO,EAAI,2BAA2B;YACtC,OAAO,EAAI,qBAAqB;YAChC,SAAS,EAAE,SAAS;SACrB;QACD,IAAI,EAAE;YACJ,OAAO,EAAI,SAAS;YACpB,SAAS,EAAE,SAAS;YACpB,KAAK,EAAM,uBAAuB;YAClC,QAAQ,EAAG,uBAAuB;SACnC;QACD,KAAK,EAAE;YACL,OAAO,EAAE,0BAA0B;YACnC,OAAO,EAAE,0BAA0B;YACnC,OAAO,EAAE,2BAA2B;YACpC,OAAO,EAAE,0BAA0B;YACnC,MAAM,EAAG,qBAAqB;SAC/B;QACD,OAAO,EAAE;YACP,UAAU,EAAG,2BAA2B;YACxC,MAAM,EAAO,qBAAqB;YAClC,IAAI,EAAS,wBAAwB;YACrC,KAAK,EAAQ,0BAA0B;YACvC,WAAW,EAAE,SAAS;SACvB;QACD,MAAM,EAAE;YACN,EAAE,EAAa,2BAA2B;YAC1C,OAAO,EAAQ,2BAA2B;YAC1C,SAAS,EAAM,SAAS;YACxB,KAAK,EAAU,qBAAqB;YACpC,IAAI,EAAW,SAAS;YACxB,SAAS,EAAM,GAAG;YAClB,IAAI,EAAW,SAAS;YACxB,KAAK,EAAU,SAAS;YACxB,WAAW,EAAI,SAAS;YACxB,MAAM,EAAS,qBAAqB;YACpC,aAAa,EAAE,SAAS;YACxB,SAAS,EAAM,0BAA0B;YACzC,IAAI,EAAW,SAAS;SACzB;QACD,KAAK,EAAE;YACL,OAAO,EAAQ,SAAS;YACxB,WAAW,EAAI,SAAS;YACxB,WAAW,EAAI,SAAS;YACxB,YAAY,EAAG,SAAS;YACxB,WAAW,EAAI,SAAS;YACxB,cAAc,EAAE,yBAAyB;YACzC,cAAc,EAAE,yBAAyB;YACzC,cAAc,EAAE,yBAAyB;YACzC,cAAc,EAAE,yBAAyB;SAC1C;KACF;IACD,QAAQ,EAAE;QACR,KAAK,EAAI,EAAE,MAAM,EAAE,SAAS,EAAE;QAC9B,IAAI,EAAK,EAAE,MAAM,EAAE,SAAS,EAAE;QAC9B,KAAK,EAAI,EAAE,MAAM,EAAE,SAAS,EAAE;QAC9B,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;KAC/B;IACD,KAAK,EAAE;QACL,KAAK,EAAK,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC9F,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,CAAC,EAAE;QACzF,MAAM,EAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,QAAQ,EAAE,CAAC,EAAE;KAC/F;IACD,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,MAAM,EAAQ,EAAE;YAChB,qFAAqF;YACrF,YAAY,EAAE,EAAE;SACjB;QACD,MAAM,EAAE;YACN,oFAAoF;YACpF,SAAS,EAAE,CAAC;SACb;QACD,GAAG,EAAE;YACH,2FAA2F;YAC3F,4FAA4F;YAC5F,8FAA8F;YAC9F,SAAS,EAAG,EAAE;YACd,UAAU,EAAE,CAAC;SACd;QACD,8FAA8F;QAC9F,0EAA0E;QAC1E,IAAI,EAAE;YACJ,KAAK,EAAM,CAAC;YACZ,SAAS,EAAE,CAAC;SACb;KACF;IACD,OAAO,EAAE;QACP,IAAI,EAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAClE,KAAK,EAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAClE,MAAM,EAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAClE,MAAM,EAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAClE,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAClE,GAAG,EAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;KACnE;IACD,UAAU,EAAE;QACV,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE;YACJ,IAAI,EAAK,MAAM;YACf,OAAO,EAAE,EAAE;YACX,IAAI,EAAK,CAAC;YACV,8FAA8F;YAC9F,KAAK,EAAI,qBAAqB;SAC/B;KACF;CACF,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAc,UAAU,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@xenolithengine/graph-theme-daylight",
3
+ "version": "0.7.0-beta.5",
4
+ "description": "Daylight — original light-mode design language for XenolithGraph. Soft grey canvas, protruding pin halos, Helvetica typography.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "sideEffects": false,
21
+ "dependencies": {
22
+ "@xenolithengine/graph-core": "0.7.0-beta.5",
23
+ "@xenolithengine/graph-render-pixi": "0.7.0-beta.5",
24
+ "@xenolithengine/graph-theme-xen": "0.7.0-beta.5"
25
+ },
26
+ "peerDependencies": {
27
+ "pixi.js": "^8.6.0"
28
+ },
29
+ "devDependencies": {
30
+ "pixi.js": "^8.6.0",
31
+ "typescript": "^5.7.0",
32
+ "vitest": "^3.0.0"
33
+ },
34
+ "keywords": [
35
+ "theme",
36
+ "daylight",
37
+ "light-mode",
38
+ "node-editor"
39
+ ],
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/XenolithEngine/xenolith-graph.git",
46
+ "directory": "packages/theme-daylight"
47
+ },
48
+ "homepage": "https://graph.xenolith.studio/",
49
+ "bugs": {
50
+ "url": "https://github.com/XenolithEngine/xenolith-graph/issues"
51
+ },
52
+ "author": "XenolithEngine",
53
+ "scripts": {
54
+ "build": "tsc -b",
55
+ "dev": "tsc -b --watch",
56
+ "test": "vitest run --passWithNoTests",
57
+ "lint": "eslint src",
58
+ "typecheck": "tsc --noEmit"
59
+ }
60
+ }