@three-flatland/devtools 0.1.0-alpha.3
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 +21 -0
- package/README.md +82 -0
- package/dist/buffers-modal.cjs +491 -0
- package/dist/buffers-modal.cjs.map +1 -0
- package/dist/buffers-modal.d.cts +62 -0
- package/dist/buffers-modal.d.ts +62 -0
- package/dist/buffers-modal.js +467 -0
- package/dist/buffers-modal.js.map +1 -0
- package/dist/buffers-view.cjs +269 -0
- package/dist/buffers-view.cjs.map +1 -0
- package/dist/buffers-view.d.cts +39 -0
- package/dist/buffers-view.d.ts +39 -0
- package/dist/buffers-view.js +245 -0
- package/dist/buffers-view.js.map +1 -0
- package/dist/create-pane.cjs +203 -0
- package/dist/create-pane.cjs.map +1 -0
- package/dist/create-pane.d.cts +66 -0
- package/dist/create-pane.d.ts +66 -0
- package/dist/create-pane.js +178 -0
- package/dist/create-pane.js.map +1 -0
- package/dist/dashboard/app.tsx +42 -0
- package/dist/dashboard/client.ts +21 -0
- package/dist/dashboard/export.ts +84 -0
- package/dist/dashboard/hooks.ts +75 -0
- package/dist/dashboard/index.html +1149 -0
- package/dist/dashboard/index.tsx +18 -0
- package/dist/dashboard/panels/batches.tsx +282 -0
- package/dist/dashboard/panels/buffers.tsx +425 -0
- package/dist/dashboard/panels/env.tsx +85 -0
- package/dist/dashboard/panels/header-stats.tsx +30 -0
- package/dist/dashboard/panels/producer-select.tsx +81 -0
- package/dist/dashboard/panels/protocol-log.tsx +743 -0
- package/dist/dashboard/panels/registry.tsx +642 -0
- package/dist/dashboard/panels/stats.tsx +431 -0
- package/dist/dashboard/protocol-store.ts +312 -0
- package/dist/dashboard/tsconfig.json +19 -0
- package/dist/dashboard/vendor/hooks.module.js +1 -0
- package/dist/dashboard/vendor/jsx-runtime.js +22 -0
- package/dist/dashboard/vendor/preact.module.js +12 -0
- package/dist/devtools-client.cjs +870 -0
- package/dist/devtools-client.cjs.map +1 -0
- package/dist/devtools-client.d.cts +362 -0
- package/dist/devtools-client.d.ts +362 -0
- package/dist/devtools-client.js +852 -0
- package/dist/devtools-client.js.map +1 -0
- package/dist/index.cjs +42 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/perf-trace.cjs +103 -0
- package/dist/perf-trace.cjs.map +1 -0
- package/dist/perf-trace.d.cts +27 -0
- package/dist/perf-trace.d.ts +27 -0
- package/dist/perf-trace.js +79 -0
- package/dist/perf-trace.js.map +1 -0
- package/dist/plugins.cjs +44 -0
- package/dist/plugins.cjs.map +1 -0
- package/dist/plugins.d.cts +7 -0
- package/dist/plugins.d.ts +7 -0
- package/dist/plugins.js +9 -0
- package/dist/plugins.js.map +1 -0
- package/dist/provider-switcher.cjs +95 -0
- package/dist/provider-switcher.cjs.map +1 -0
- package/dist/provider-switcher.d.cts +18 -0
- package/dist/provider-switcher.d.ts +18 -0
- package/dist/provider-switcher.js +71 -0
- package/dist/provider-switcher.js.map +1 -0
- package/dist/react/devtools-provider.cjs +59 -0
- package/dist/react/devtools-provider.cjs.map +1 -0
- package/dist/react/devtools-provider.d.cts +39 -0
- package/dist/react/devtools-provider.d.ts +39 -0
- package/dist/react/devtools-provider.js +38 -0
- package/dist/react/devtools-provider.js.map +1 -0
- package/dist/react/use-fps-graph.cjs +49 -0
- package/dist/react/use-fps-graph.cjs.map +1 -0
- package/dist/react/use-fps-graph.d.cts +15 -0
- package/dist/react/use-fps-graph.d.ts +15 -0
- package/dist/react/use-fps-graph.js +25 -0
- package/dist/react/use-fps-graph.js.map +1 -0
- package/dist/react/use-pane-button.cjs +58 -0
- package/dist/react/use-pane-button.cjs.map +1 -0
- package/dist/react/use-pane-button.d.cts +10 -0
- package/dist/react/use-pane-button.d.ts +10 -0
- package/dist/react/use-pane-button.js +34 -0
- package/dist/react/use-pane-button.js.map +1 -0
- package/dist/react/use-pane-folder.cjs +48 -0
- package/dist/react/use-pane-folder.cjs.map +1 -0
- package/dist/react/use-pane-folder.d.cts +15 -0
- package/dist/react/use-pane-folder.d.ts +15 -0
- package/dist/react/use-pane-folder.js +24 -0
- package/dist/react/use-pane-folder.js.map +1 -0
- package/dist/react/use-pane-input.cjs +70 -0
- package/dist/react/use-pane-input.cjs.map +1 -0
- package/dist/react/use-pane-input.d.cts +44 -0
- package/dist/react/use-pane-input.d.ts +44 -0
- package/dist/react/use-pane-input.js +46 -0
- package/dist/react/use-pane-input.js.map +1 -0
- package/dist/react/use-pane-radio-grid.cjs +78 -0
- package/dist/react/use-pane-radio-grid.cjs.map +1 -0
- package/dist/react/use-pane-radio-grid.d.cts +35 -0
- package/dist/react/use-pane-radio-grid.d.ts +35 -0
- package/dist/react/use-pane-radio-grid.js +54 -0
- package/dist/react/use-pane-radio-grid.js.map +1 -0
- package/dist/react/use-pane.cjs +45 -0
- package/dist/react/use-pane.cjs.map +1 -0
- package/dist/react/use-pane.d.cts +40 -0
- package/dist/react/use-pane.d.ts +40 -0
- package/dist/react/use-pane.js +21 -0
- package/dist/react/use-pane.js.map +1 -0
- package/dist/react.cjs +50 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +12 -0
- package/dist/react.d.ts +12 -0
- package/dist/react.js +19 -0
- package/dist/react.js.map +1 -0
- package/dist/registry-view.cjs +371 -0
- package/dist/registry-view.cjs.map +1 -0
- package/dist/registry-view.d.cts +24 -0
- package/dist/registry-view.d.ts +24 -0
- package/dist/registry-view.js +347 -0
- package/dist/registry-view.js.map +1 -0
- package/dist/stats-graph.cjs +297 -0
- package/dist/stats-graph.cjs.map +1 -0
- package/dist/stats-graph.d.cts +40 -0
- package/dist/stats-graph.d.ts +40 -0
- package/dist/stats-graph.js +273 -0
- package/dist/stats-graph.js.map +1 -0
- package/dist/stats-row.cjs +153 -0
- package/dist/stats-row.cjs.map +1 -0
- package/dist/stats-row.d.cts +24 -0
- package/dist/stats-row.d.ts +24 -0
- package/dist/stats-row.js +129 -0
- package/dist/stats-row.js.map +1 -0
- package/dist/theme.cjs +260 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.cts +10 -0
- package/dist/theme.d.ts +10 -0
- package/dist/theme.js +235 -0
- package/dist/theme.js.map +1 -0
- package/dist/vite-plugin.cjs +113 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.cts +9 -0
- package/dist/vite-plugin.d.ts +9 -0
- package/dist/vite-plugin.js +88 -0
- package/dist/vite-plugin.js.map +1 -0
- package/package.json +124 -0
package/dist/theme.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
const FLATLAND_THEME = {
|
|
2
|
+
// Backgrounds — retro darks
|
|
3
|
+
"--tp-base-background-color": "#00021c",
|
|
4
|
+
// retro-midnight
|
|
5
|
+
"--tp-container-background-color": "rgba(28, 40, 77, 0.4)",
|
|
6
|
+
// retro-deep-purple @ 40%
|
|
7
|
+
"--tp-input-background-color": "rgba(0, 2, 28, 0.6)",
|
|
8
|
+
// retro-black @ 60%
|
|
9
|
+
"--tp-monitor-background-color": "rgba(0, 2, 28, 0.4)",
|
|
10
|
+
// retro-black @ 40%
|
|
11
|
+
// Text — retro whites and greys
|
|
12
|
+
"--tp-container-foreground-color": "#f0edd8",
|
|
13
|
+
// retro-white
|
|
14
|
+
"--tp-button-foreground-color": "#f0edd8",
|
|
15
|
+
// retro-white
|
|
16
|
+
"--tp-input-foreground-color": "#c8c5b4",
|
|
17
|
+
// muted retro-white
|
|
18
|
+
"--tp-label-foreground-color": "rgba(240, 237, 216, 0.55)",
|
|
19
|
+
// retro-white @ 55%
|
|
20
|
+
"--tp-monitor-foreground-color": "#c8c5b4",
|
|
21
|
+
// muted retro-white
|
|
22
|
+
// Buttons — retro-deep-purple
|
|
23
|
+
"--tp-button-background-color": "#1c284d",
|
|
24
|
+
// retro-deep-purple
|
|
25
|
+
// Accent — slider grooves & separators
|
|
26
|
+
"--tp-groove-foreground-color": "rgba(240, 237, 216, 0.12)",
|
|
27
|
+
// muted separator/groove
|
|
28
|
+
// Typography
|
|
29
|
+
"--tp-base-font-family": "monospace"
|
|
30
|
+
};
|
|
31
|
+
const ACCENT_CSS = `
|
|
32
|
+
/* Slider thumb */
|
|
33
|
+
.tp-sldv_k::after { background-color: #d94c87 !important; }
|
|
34
|
+
.tp-sldv_t:hover .tp-sldv_k::after { background-color: #e0609a !important; }
|
|
35
|
+
.tp-sldv_t:active .tp-sldv_k::after { background-color: #a6216e !important; }
|
|
36
|
+
/* Slider track (filled portion) */
|
|
37
|
+
.tp-sldv_k::before { background-color: rgba(240, 237, 216, 0.25) !important; }
|
|
38
|
+
/* Number spinner drag handle */
|
|
39
|
+
.tp-txtv_k::before { background-color: #d94c87 !important; }
|
|
40
|
+
/* Select/dropdown */
|
|
41
|
+
.tp-lstv_s { background-color: rgba(28, 40, 77, 0.6) !important; color: rgba(240, 237, 216, 0.5) !important; }
|
|
42
|
+
.tp-lstv_s:hover { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }
|
|
43
|
+
.tp-lstv_s:focus { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }
|
|
44
|
+
.tp-lstv_s:active { background-color: #343473 !important; color: #d94c87 !important; }
|
|
45
|
+
.tp-lstv_m { color: rgba(240, 237, 216, 0.5) !important; }
|
|
46
|
+
/* Buttons */
|
|
47
|
+
.tp-btnv_b { background-color: rgba(28, 40, 77, 0.6) !important; color: rgba(240, 237, 216, 0.5) !important; }
|
|
48
|
+
.tp-btnv_b:hover { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }
|
|
49
|
+
.tp-btnv_b:active { background-color: #343473 !important; color: #d94c87 !important; }
|
|
50
|
+
/* Radio grid buttons */
|
|
51
|
+
.tp-radv_b { background-color: rgba(28, 40, 77, 0.6) !important; color: rgba(240, 237, 216, 0.5) !important; }
|
|
52
|
+
.tp-radv_i:hover + .tp-radv_b { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }
|
|
53
|
+
.tp-radv_i:checked + .tp-radv_b { background-color: #1c284d !important; color: #d94c87 !important; }
|
|
54
|
+
.tp-radv_i:active + .tp-radv_b { background-color: #343473 !important; color: #f0edd8 !important; }
|
|
55
|
+
/* Checkbox \u2014 default background blends with the container, so bump to
|
|
56
|
+
the same surface as the select/button controls for a visible hit
|
|
57
|
+
target, and accent the check stroke on :checked. Markup:
|
|
58
|
+
<input.tp-ckbv_i> + <div.tp-ckbv_w><svg><path/></svg></div>
|
|
59
|
+
|
|
60
|
+
Tweakpane's hidden input ships at browser-default size (~13\xD713) at
|
|
61
|
+
top-left of the label, relying on <label>\u2192<input> click forwarding
|
|
62
|
+
to toggle from clicks on the visible box. That forwarding is flaky
|
|
63
|
+
under some pointer-events + z-index combinations (reports: clicks
|
|
64
|
+
sometimes register, sometimes don't). Stretching the input to cover
|
|
65
|
+
the entire visible box puts the hit target directly on the pointer,
|
|
66
|
+
no label forwarding required. */
|
|
67
|
+
.tp-ckbv_i {
|
|
68
|
+
/* Absolute positioning + zero opacity is Tweakpane's default; we
|
|
69
|
+
just add explicit size + cursor so the click area matches the
|
|
70
|
+
visible affordance exactly. */
|
|
71
|
+
width: var(--cnt-usz) !important;
|
|
72
|
+
height: var(--cnt-usz) !important;
|
|
73
|
+
margin: 0 !important;
|
|
74
|
+
cursor: pointer !important;
|
|
75
|
+
}
|
|
76
|
+
.tp-ckbv_w { background-color: rgba(28, 40, 77, 0.6) !important; }
|
|
77
|
+
.tp-ckbv_i:hover + .tp-ckbv_w { background-color: rgba(28, 40, 77, 0.9) !important; }
|
|
78
|
+
.tp-ckbv_i:focus + .tp-ckbv_w { background-color: rgba(28, 40, 77, 0.9) !important; }
|
|
79
|
+
.tp-ckbv_i:active + .tp-ckbv_w { background-color: #343473 !important; }
|
|
80
|
+
.tp-ckbv_i:checked + .tp-ckbv_w svg path { stroke: #d94c87 !important; }
|
|
81
|
+
|
|
82
|
+
/* Dimmable pane \u2014 slightly translucent when idle, opaque on hover or when pinned.
|
|
83
|
+
Hover-promotion is gated on devices that actually have a pointer (desktop),
|
|
84
|
+
so on touch devices the pin toggle is the only way to flip opacity. */
|
|
85
|
+
.tp-flatland-dimmable { opacity: 0.8; transition: opacity 750ms ease; }
|
|
86
|
+
.tp-flatland-dimmable.tp-flatland-pinned { opacity: 1; }
|
|
87
|
+
@media (hover: hover) {
|
|
88
|
+
.tp-flatland-dimmable:hover { opacity: 1; }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Pin in the pane header (left side, mirrors the collapse caret on the right) */
|
|
92
|
+
.tp-flatland-pin {
|
|
93
|
+
position: absolute;
|
|
94
|
+
left: var(--cnt-hp, 4px);
|
|
95
|
+
top: 0;
|
|
96
|
+
bottom: 0;
|
|
97
|
+
margin: auto;
|
|
98
|
+
width: var(--cnt-usz, 20px);
|
|
99
|
+
height: var(--cnt-usz, 20px);
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
color: rgba(240, 237, 216, 0.45);
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
border-radius: 2px;
|
|
106
|
+
transition: color 150ms, background-color 150ms;
|
|
107
|
+
}
|
|
108
|
+
.tp-flatland-pin:hover { color: #d94c87; background: transparent; }
|
|
109
|
+
.tp-flatland-pin svg { display: block; }
|
|
110
|
+
.tp-flatland-pin svg circle { fill: none; stroke: currentColor; stroke-width: 1.6; }
|
|
111
|
+
.tp-flatland-pinned .tp-flatland-pin svg circle { fill: currentColor; }
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* Three-mode cycle toggle in the header (replaces Tweakpane's built-in
|
|
115
|
+
* fold caret). We hide the native caret via the .tp-rotv_m marker
|
|
116
|
+
* class and render our own button that cycles full - minimal -
|
|
117
|
+
* collapsed - full. The data-mode attribute drives icon styling.
|
|
118
|
+
*/
|
|
119
|
+
.tp-rotv_m { display: none !important; }
|
|
120
|
+
.tp-flatland-mode {
|
|
121
|
+
position: absolute;
|
|
122
|
+
right: var(--cnt-hp, 4px);
|
|
123
|
+
top: 0;
|
|
124
|
+
bottom: 0;
|
|
125
|
+
margin: auto;
|
|
126
|
+
min-width: var(--cnt-usz, 20px);
|
|
127
|
+
height: var(--cnt-usz, 20px);
|
|
128
|
+
padding: 0 4px;
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
justify-content: center;
|
|
132
|
+
/* Match the original tweakpane fold caret and folder-header glyphs \u2014
|
|
133
|
+
* the muted foreground token pane headers use throughout. */
|
|
134
|
+
color: var(--tp-label-foreground-color);
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
font-size: 11px;
|
|
137
|
+
line-height: 1;
|
|
138
|
+
user-select: none;
|
|
139
|
+
}
|
|
140
|
+
/*
|
|
141
|
+
* Glyph exactly replicates tweakpane's native fold marker \u2014 a 6\xD76
|
|
142
|
+
* square with a horizontal linear-gradient that draws two vertical
|
|
143
|
+
* stripes (screw-head look). Rotating gives the three states:
|
|
144
|
+
* full \u2192 0\xB0 (vertical stripes, ||) \u2014 matches tweakpane's expanded
|
|
145
|
+
* minimal \u2192 45\xB0 (diagonal, like a flat-head screw)
|
|
146
|
+
* collapsed \u2192 90\xB0 (horizontal stripes, =) \u2014 matches tweakpane's collapsed
|
|
147
|
+
*/
|
|
148
|
+
.tp-flatland-mode-glyph {
|
|
149
|
+
display: block;
|
|
150
|
+
width: 6px;
|
|
151
|
+
height: 6px;
|
|
152
|
+
border-radius: 2px;
|
|
153
|
+
background: linear-gradient(
|
|
154
|
+
to left,
|
|
155
|
+
var(--cnt-fg, currentColor),
|
|
156
|
+
var(--cnt-fg, currentColor) 2px,
|
|
157
|
+
transparent 2px,
|
|
158
|
+
transparent 4px,
|
|
159
|
+
var(--cnt-fg, currentColor) 4px
|
|
160
|
+
);
|
|
161
|
+
opacity: 0.5;
|
|
162
|
+
/* 0.2s ease-in-out \u2014 the exact transition tweakpane applies to its
|
|
163
|
+
* own fold marker. */
|
|
164
|
+
transition: transform 0.2s ease-in-out;
|
|
165
|
+
}
|
|
166
|
+
.tp-flatland-mode[data-mode="full"] .tp-flatland-mode-glyph { transform: rotate(0deg); }
|
|
167
|
+
.tp-flatland-mode[data-mode="minimal"] .tp-flatland-mode-glyph { transform: rotate(45deg); }
|
|
168
|
+
.tp-flatland-mode[data-mode="collapsed"] .tp-flatland-mode-glyph { transform: rotate(90deg); }
|
|
169
|
+
|
|
170
|
+
/*
|
|
171
|
+
* Minimal mode: keep only blades tagged with .tp-flatland-minimal-keep
|
|
172
|
+
* (stats graph + stats row). Non-keep blades animate max-height to 0
|
|
173
|
+
* and fade out so the whole pane visibly shrinks, matching tweakpane
|
|
174
|
+
* native fold feel. Values and bindings stay intact \u2014 DOM is just
|
|
175
|
+
* clipped.
|
|
176
|
+
*
|
|
177
|
+
* max-height uses a generous ceiling instead of a measured value so we
|
|
178
|
+
* can stay declarative; the transition duration matches the native
|
|
179
|
+
* pane fold for continuity.
|
|
180
|
+
*/
|
|
181
|
+
/*
|
|
182
|
+
* Animation timings + easings mirror tweakpane's own fold exactly:
|
|
183
|
+
* .tp-rotv_c / .tp-fldv_c use
|
|
184
|
+
* height .2s ease-in-out, opacity .2s linear, padding .2s ease-in-out
|
|
185
|
+
* and on expand, opacity has a 0.2s delay so height finishes first
|
|
186
|
+
* then opacity fades in. The collapse direction has no delay \u2014 both
|
|
187
|
+
* animate together.
|
|
188
|
+
*
|
|
189
|
+
* We use max-height in place of height because content height isn't
|
|
190
|
+
* known at author time; with a generous ceiling the visual is
|
|
191
|
+
* indistinguishable from native height tweens.
|
|
192
|
+
*/
|
|
193
|
+
.tp-rotv_c > *:not(.tp-flatland-minimal-keep) {
|
|
194
|
+
max-height: 1200px;
|
|
195
|
+
opacity: 1;
|
|
196
|
+
overflow: hidden;
|
|
197
|
+
transition:
|
|
198
|
+
max-height 0.2s ease-in-out,
|
|
199
|
+
opacity 0.2s linear 0.2s,
|
|
200
|
+
margin 0.2s ease-in-out,
|
|
201
|
+
padding 0.2s ease-in-out;
|
|
202
|
+
}
|
|
203
|
+
.tp-flatland-minimal .tp-rotv_c > *:not(.tp-flatland-minimal-keep) {
|
|
204
|
+
max-height: 0;
|
|
205
|
+
opacity: 0;
|
|
206
|
+
margin-top: 0 !important;
|
|
207
|
+
margin-bottom: 0 !important;
|
|
208
|
+
padding-top: 0 !important;
|
|
209
|
+
padding-bottom: 0 !important;
|
|
210
|
+
pointer-events: none;
|
|
211
|
+
/* On collapse: no delay on opacity \u2014 both animate together,
|
|
212
|
+
* matching tweakpane's non-expanded transition shape. */
|
|
213
|
+
transition:
|
|
214
|
+
max-height 0.2s ease-in-out,
|
|
215
|
+
opacity 0.2s linear,
|
|
216
|
+
margin 0.2s ease-in-out,
|
|
217
|
+
padding 0.2s ease-in-out;
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
220
|
+
function applyTheme(element, theme = FLATLAND_THEME) {
|
|
221
|
+
for (const [key, value] of Object.entries(theme)) {
|
|
222
|
+
element.style.setProperty(key, value);
|
|
223
|
+
}
|
|
224
|
+
if (!element.querySelector("style[data-flatland]")) {
|
|
225
|
+
const style = document.createElement("style");
|
|
226
|
+
style.setAttribute("data-flatland", "");
|
|
227
|
+
style.textContent = ACCENT_CSS;
|
|
228
|
+
element.appendChild(style);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
export {
|
|
232
|
+
FLATLAND_THEME,
|
|
233
|
+
applyTheme
|
|
234
|
+
};
|
|
235
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme.ts"],"sourcesContent":["/**\n * Flatland theme — based on the Jehkoba32 retro palette.\n *\n * Uses project dark/neutral colors for backgrounds, retro-white/grey for text,\n * and accent color only on control thumbs and slider grooves.\n */\nexport const FLATLAND_THEME: Record<string, string> = {\n // Backgrounds — retro darks\n '--tp-base-background-color': '#00021c', // retro-midnight\n '--tp-container-background-color': 'rgba(28, 40, 77, 0.4)', // retro-deep-purple @ 40%\n '--tp-input-background-color': 'rgba(0, 2, 28, 0.6)', // retro-black @ 60%\n '--tp-monitor-background-color': 'rgba(0, 2, 28, 0.4)', // retro-black @ 40%\n\n // Text — retro whites and greys\n '--tp-container-foreground-color': '#f0edd8', // retro-white\n '--tp-button-foreground-color': '#f0edd8', // retro-white\n '--tp-input-foreground-color': '#c8c5b4', // muted retro-white\n '--tp-label-foreground-color': 'rgba(240, 237, 216, 0.55)', // retro-white @ 55%\n '--tp-monitor-foreground-color': '#c8c5b4', // muted retro-white\n\n // Buttons — retro-deep-purple\n '--tp-button-background-color': '#1c284d', // retro-deep-purple\n\n // Accent — slider grooves & separators\n '--tp-groove-foreground-color': 'rgba(240, 237, 216, 0.12)', // muted separator/groove\n\n // Typography\n '--tp-base-font-family': 'monospace',\n}\n\n/** Accent CSS — colorizes slider thumb and number spinner drag handle */\nconst ACCENT_CSS = `\n/* Slider thumb */\n.tp-sldv_k::after { background-color: #d94c87 !important; }\n.tp-sldv_t:hover .tp-sldv_k::after { background-color: #e0609a !important; }\n.tp-sldv_t:active .tp-sldv_k::after { background-color: #a6216e !important; }\n/* Slider track (filled portion) */\n.tp-sldv_k::before { background-color: rgba(240, 237, 216, 0.25) !important; }\n/* Number spinner drag handle */\n.tp-txtv_k::before { background-color: #d94c87 !important; }\n/* Select/dropdown */\n.tp-lstv_s { background-color: rgba(28, 40, 77, 0.6) !important; color: rgba(240, 237, 216, 0.5) !important; }\n.tp-lstv_s:hover { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }\n.tp-lstv_s:focus { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }\n.tp-lstv_s:active { background-color: #343473 !important; color: #d94c87 !important; }\n.tp-lstv_m { color: rgba(240, 237, 216, 0.5) !important; }\n/* Buttons */\n.tp-btnv_b { background-color: rgba(28, 40, 77, 0.6) !important; color: rgba(240, 237, 216, 0.5) !important; }\n.tp-btnv_b:hover { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }\n.tp-btnv_b:active { background-color: #343473 !important; color: #d94c87 !important; }\n/* Radio grid buttons */\n.tp-radv_b { background-color: rgba(28, 40, 77, 0.6) !important; color: rgba(240, 237, 216, 0.5) !important; }\n.tp-radv_i:hover + .tp-radv_b { background-color: rgba(28, 40, 77, 0.9) !important; color: #f0edd8 !important; }\n.tp-radv_i:checked + .tp-radv_b { background-color: #1c284d !important; color: #d94c87 !important; }\n.tp-radv_i:active + .tp-radv_b { background-color: #343473 !important; color: #f0edd8 !important; }\n/* Checkbox — default background blends with the container, so bump to\n the same surface as the select/button controls for a visible hit\n target, and accent the check stroke on :checked. Markup:\n <input.tp-ckbv_i> + <div.tp-ckbv_w><svg><path/></svg></div>\n\n Tweakpane's hidden input ships at browser-default size (~13×13) at\n top-left of the label, relying on <label>→<input> click forwarding\n to toggle from clicks on the visible box. That forwarding is flaky\n under some pointer-events + z-index combinations (reports: clicks\n sometimes register, sometimes don't). Stretching the input to cover\n the entire visible box puts the hit target directly on the pointer,\n no label forwarding required. */\n.tp-ckbv_i {\n /* Absolute positioning + zero opacity is Tweakpane's default; we\n just add explicit size + cursor so the click area matches the\n visible affordance exactly. */\n width: var(--cnt-usz) !important;\n height: var(--cnt-usz) !important;\n margin: 0 !important;\n cursor: pointer !important;\n}\n.tp-ckbv_w { background-color: rgba(28, 40, 77, 0.6) !important; }\n.tp-ckbv_i:hover + .tp-ckbv_w { background-color: rgba(28, 40, 77, 0.9) !important; }\n.tp-ckbv_i:focus + .tp-ckbv_w { background-color: rgba(28, 40, 77, 0.9) !important; }\n.tp-ckbv_i:active + .tp-ckbv_w { background-color: #343473 !important; }\n.tp-ckbv_i:checked + .tp-ckbv_w svg path { stroke: #d94c87 !important; }\n\n/* Dimmable pane — slightly translucent when idle, opaque on hover or when pinned.\n Hover-promotion is gated on devices that actually have a pointer (desktop),\n so on touch devices the pin toggle is the only way to flip opacity. */\n.tp-flatland-dimmable { opacity: 0.8; transition: opacity 750ms ease; }\n.tp-flatland-dimmable.tp-flatland-pinned { opacity: 1; }\n@media (hover: hover) {\n .tp-flatland-dimmable:hover { opacity: 1; }\n}\n\n/* Pin in the pane header (left side, mirrors the collapse caret on the right) */\n.tp-flatland-pin {\n position: absolute;\n left: var(--cnt-hp, 4px);\n top: 0;\n bottom: 0;\n margin: auto;\n width: var(--cnt-usz, 20px);\n height: var(--cnt-usz, 20px);\n display: flex;\n align-items: center;\n justify-content: center;\n color: rgba(240, 237, 216, 0.45);\n cursor: pointer;\n border-radius: 2px;\n transition: color 150ms, background-color 150ms;\n}\n.tp-flatland-pin:hover { color: #d94c87; background: transparent; }\n.tp-flatland-pin svg { display: block; }\n.tp-flatland-pin svg circle { fill: none; stroke: currentColor; stroke-width: 1.6; }\n.tp-flatland-pinned .tp-flatland-pin svg circle { fill: currentColor; }\n\n/*\n * Three-mode cycle toggle in the header (replaces Tweakpane's built-in\n * fold caret). We hide the native caret via the .tp-rotv_m marker\n * class and render our own button that cycles full - minimal -\n * collapsed - full. The data-mode attribute drives icon styling.\n */\n.tp-rotv_m { display: none !important; }\n.tp-flatland-mode {\n position: absolute;\n right: var(--cnt-hp, 4px);\n top: 0;\n bottom: 0;\n margin: auto;\n min-width: var(--cnt-usz, 20px);\n height: var(--cnt-usz, 20px);\n padding: 0 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n /* Match the original tweakpane fold caret and folder-header glyphs —\n * the muted foreground token pane headers use throughout. */\n color: var(--tp-label-foreground-color);\n cursor: pointer;\n font-size: 11px;\n line-height: 1;\n user-select: none;\n}\n/*\n * Glyph exactly replicates tweakpane's native fold marker — a 6×6\n * square with a horizontal linear-gradient that draws two vertical\n * stripes (screw-head look). Rotating gives the three states:\n * full → 0° (vertical stripes, ||) — matches tweakpane's expanded\n * minimal → 45° (diagonal, like a flat-head screw)\n * collapsed → 90° (horizontal stripes, =) — matches tweakpane's collapsed\n */\n.tp-flatland-mode-glyph {\n display: block;\n width: 6px;\n height: 6px;\n border-radius: 2px;\n background: linear-gradient(\n to left,\n var(--cnt-fg, currentColor),\n var(--cnt-fg, currentColor) 2px,\n transparent 2px,\n transparent 4px,\n var(--cnt-fg, currentColor) 4px\n );\n opacity: 0.5;\n /* 0.2s ease-in-out — the exact transition tweakpane applies to its\n * own fold marker. */\n transition: transform 0.2s ease-in-out;\n}\n.tp-flatland-mode[data-mode=\"full\"] .tp-flatland-mode-glyph { transform: rotate(0deg); }\n.tp-flatland-mode[data-mode=\"minimal\"] .tp-flatland-mode-glyph { transform: rotate(45deg); }\n.tp-flatland-mode[data-mode=\"collapsed\"] .tp-flatland-mode-glyph { transform: rotate(90deg); }\n\n/*\n * Minimal mode: keep only blades tagged with .tp-flatland-minimal-keep\n * (stats graph + stats row). Non-keep blades animate max-height to 0\n * and fade out so the whole pane visibly shrinks, matching tweakpane\n * native fold feel. Values and bindings stay intact — DOM is just\n * clipped.\n *\n * max-height uses a generous ceiling instead of a measured value so we\n * can stay declarative; the transition duration matches the native\n * pane fold for continuity.\n */\n/*\n * Animation timings + easings mirror tweakpane's own fold exactly:\n * .tp-rotv_c / .tp-fldv_c use\n * height .2s ease-in-out, opacity .2s linear, padding .2s ease-in-out\n * and on expand, opacity has a 0.2s delay so height finishes first\n * then opacity fades in. The collapse direction has no delay — both\n * animate together.\n *\n * We use max-height in place of height because content height isn't\n * known at author time; with a generous ceiling the visual is\n * indistinguishable from native height tweens.\n */\n.tp-rotv_c > *:not(.tp-flatland-minimal-keep) {\n max-height: 1200px;\n opacity: 1;\n overflow: hidden;\n transition:\n max-height 0.2s ease-in-out,\n opacity 0.2s linear 0.2s,\n margin 0.2s ease-in-out,\n padding 0.2s ease-in-out;\n}\n.tp-flatland-minimal .tp-rotv_c > *:not(.tp-flatland-minimal-keep) {\n max-height: 0;\n opacity: 0;\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n pointer-events: none;\n /* On collapse: no delay on opacity — both animate together,\n * matching tweakpane's non-expanded transition shape. */\n transition:\n max-height 0.2s ease-in-out,\n opacity 0.2s linear,\n margin 0.2s ease-in-out,\n padding 0.2s ease-in-out;\n}\n`\n\nexport function applyTheme(\n element: HTMLElement,\n theme: Record<string, string> = FLATLAND_THEME,\n): void {\n for (const [key, value] of Object.entries(theme)) {\n element.style.setProperty(key, value)\n }\n\n // Inject accent styles once\n if (!element.querySelector('style[data-flatland]')) {\n const style = document.createElement('style')\n style.setAttribute('data-flatland', '')\n style.textContent = ACCENT_CSS\n element.appendChild(style)\n }\n}\n"],"mappings":"AAMO,MAAM,iBAAyC;AAAA;AAAA,EAEpD,8BAA8B;AAAA;AAAA,EAC9B,mCAAmC;AAAA;AAAA,EACnC,+BAA+B;AAAA;AAAA,EAC/B,iCAAiC;AAAA;AAAA;AAAA,EAGjC,mCAAmC;AAAA;AAAA,EACnC,gCAAgC;AAAA;AAAA,EAChC,+BAA+B;AAAA;AAAA,EAC/B,+BAA+B;AAAA;AAAA,EAC/B,iCAAiC;AAAA;AAAA;AAAA,EAGjC,gCAAgC;AAAA;AAAA;AAAA,EAGhC,gCAAgC;AAAA;AAAA;AAAA,EAGhC,yBAAyB;AAC3B;AAGA,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8LZ,SAAS,WACd,SACA,QAAgC,gBAC1B;AACN,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAQ,MAAM,YAAY,KAAK,KAAK;AAAA,EACtC;AAGA,MAAI,CAAC,QAAQ,cAAc,sBAAsB,GAAG;AAClD,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,aAAa,iBAAiB,EAAE;AACtC,UAAM,cAAc;AACpB,YAAQ,YAAY,KAAK;AAAA,EAC3B;AACF;","names":[]}
|
|
@@ -0,0 +1,113 @@
|
|
|
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
|
+
var vite_plugin_exports = {};
|
|
20
|
+
__export(vite_plugin_exports, {
|
|
21
|
+
default: () => vite_plugin_default,
|
|
22
|
+
threeFlatlandDevtools: () => threeFlatlandDevtools
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(vite_plugin_exports);
|
|
25
|
+
var import_node_fs = require("node:fs");
|
|
26
|
+
var import_promises = require("node:fs/promises");
|
|
27
|
+
var import_node_url = require("node:url");
|
|
28
|
+
var import_node_path = require("node:path");
|
|
29
|
+
const import_meta = {};
|
|
30
|
+
const DEFAULT_PATH = "/.devtools";
|
|
31
|
+
function resolveDashboardRoot() {
|
|
32
|
+
const here = (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
33
|
+
const siblingSrc = (0, import_node_path.resolve)(here, "../src/dashboard");
|
|
34
|
+
if ((0, import_node_fs.existsSync)(siblingSrc)) return siblingSrc;
|
|
35
|
+
return (0, import_node_path.resolve)(here, "dashboard");
|
|
36
|
+
}
|
|
37
|
+
function threeFlatlandDevtools(options = {}) {
|
|
38
|
+
const mountPath = options.path ?? DEFAULT_PATH;
|
|
39
|
+
const dashboardRoot = resolveDashboardRoot();
|
|
40
|
+
const vendorRoot = (0, import_node_path.resolve)(dashboardRoot, "vendor");
|
|
41
|
+
return {
|
|
42
|
+
name: "three-flatland-devtools",
|
|
43
|
+
apply: "serve",
|
|
44
|
+
config() {
|
|
45
|
+
return {
|
|
46
|
+
resolve: {
|
|
47
|
+
// Order matters — Vite/rollup-plugin-alias matches left-to-right
|
|
48
|
+
// by string prefix, so the broad `preact` entry must come last
|
|
49
|
+
// or it swallows `preact/jsx-*` and `preact/hooks`.
|
|
50
|
+
alias: [
|
|
51
|
+
{
|
|
52
|
+
find: "preact/jsx-runtime",
|
|
53
|
+
replacement: (0, import_node_path.resolve)(vendorRoot, "jsx-runtime.js")
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
// esbuild dev mode emits `import { jsxDEV } from 'preact/jsx-dev-runtime'`;
|
|
57
|
+
// the same shim exports `jsxDEV`.
|
|
58
|
+
find: "preact/jsx-dev-runtime",
|
|
59
|
+
replacement: (0, import_node_path.resolve)(vendorRoot, "jsx-runtime.js")
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
find: "preact/hooks",
|
|
63
|
+
replacement: (0, import_node_path.resolve)(vendorRoot, "hooks.module.js")
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
find: /^preact$/,
|
|
67
|
+
replacement: (0, import_node_path.resolve)(vendorRoot, "preact.module.js")
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
configResolved(config) {
|
|
74
|
+
if (!config.server.fs.allow.includes(dashboardRoot)) {
|
|
75
|
+
config.server.fs.allow.push(dashboardRoot);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
configureServer(server) {
|
|
79
|
+
server.middlewares.use((req, res, next) => {
|
|
80
|
+
void (async () => {
|
|
81
|
+
if (req.url === void 0) return next();
|
|
82
|
+
const url = req.url.split("?")[0] ?? "";
|
|
83
|
+
if (url !== mountPath && url !== `${mountPath}/`) return next();
|
|
84
|
+
try {
|
|
85
|
+
const indexPath = (0, import_node_path.resolve)(dashboardRoot, "index.html");
|
|
86
|
+
let html = await (0, import_promises.readFile)(indexPath, "utf-8");
|
|
87
|
+
const entryAbs = (0, import_node_path.resolve)(dashboardRoot, "index.tsx");
|
|
88
|
+
html = html.replace("./index.tsx", `/@fs${entryAbs}`);
|
|
89
|
+
html = await server.transformIndexHtml(req.url, html, req.originalUrl);
|
|
90
|
+
res.statusCode = 200;
|
|
91
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
92
|
+
res.end(html);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
next(err);
|
|
95
|
+
}
|
|
96
|
+
})();
|
|
97
|
+
});
|
|
98
|
+
const logger = server.config.logger;
|
|
99
|
+
const port = server.config.server.port ?? 5173;
|
|
100
|
+
logger.info(
|
|
101
|
+
`
|
|
102
|
+
\x1B[32m\u279C\x1B[0m three-flatland devtools: \x1B[36mhttp://localhost:${port}${mountPath}\x1B[0m
|
|
103
|
+
`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
var vite_plugin_default = threeFlatlandDevtools;
|
|
109
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
110
|
+
0 && (module.exports = {
|
|
111
|
+
threeFlatlandDevtools
|
|
112
|
+
});
|
|
113
|
+
//# sourceMappingURL=vite-plugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vite-plugin.ts"],"sourcesContent":["/**\n * Vite plugin that serves the standalone devtools dashboard alongside the\n * user's app. Mounts a dev-only middleware at a configurable path (default\n * `/.devtools`).\n *\n * The dashboard source lives inside this package\n * (`packages/devtools/src/dashboard/`), not inside the consumer's project.\n * The plugin:\n * 1. Whitelists the dashboard directory via `server.fs.allow` so Vite\n * is willing to read its files across the workspace boundary.\n * 2. Serves `index.html` at the mount path, rewritten so the entry\n * script loads via `/@fs/<abs>` — Vite then transforms it with full\n * HMR.\n * 3. Aliases the vendored Preact files so `import from 'preact'`\n * resolves locally — no runtime dep on Preact leaks into the\n * consumer's `node_modules`.\n *\n * Access the dashboard at the Vite dev server's origin directly, e.g.\n * `http://localhost:5174/.devtools`. If the host project sits behind a\n * microfrontend proxy, point the browser at the Vite port — the\n * dashboard's transitive requests (`/@fs/`, `/@vite/client`, pre-bundled\n * `node_modules/.vite/`) are not namespaced and expect to land on the\n * same origin that served the HTML.\n *\n * Dev-only; the plugin is inert in production builds.\n */\nimport { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, resolve } from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nexport interface ThreeFlatlandDevtoolsOptions {\n /** URL path the dashboard is served under. Default: `/.devtools`. */\n path?: string\n}\n\nconst DEFAULT_PATH = '/.devtools'\n\nfunction resolveDashboardRoot(): string {\n // Three possible layouts for this file at runtime:\n // 1. `packages/devtools/src/vite-plugin.ts` (source condition)\n // 2. `packages/devtools/dist/vite-plugin.js` (workspace, Node import condition)\n // 3. `node_modules/@three-flatland/devtools/dist/vite-plugin.js` (published)\n //\n // For (2) — the dev workflow where Node loads the built plugin but we\n // want HMR over the unbuilt sources — prefer the sibling `../src/dashboard/`\n // if it exists. Otherwise resolve `./dashboard` relative to this file.\n const here = dirname(fileURLToPath(import.meta.url))\n const siblingSrc = resolve(here, '../src/dashboard')\n if (existsSync(siblingSrc)) return siblingSrc\n return resolve(here, 'dashboard')\n}\n\nexport function threeFlatlandDevtools(\n options: ThreeFlatlandDevtoolsOptions = {},\n): Plugin {\n const mountPath = options.path ?? DEFAULT_PATH\n const dashboardRoot = resolveDashboardRoot()\n const vendorRoot = resolve(dashboardRoot, 'vendor')\n\n return {\n name: 'three-flatland-devtools',\n apply: 'serve',\n\n config() {\n return {\n resolve: {\n // Order matters — Vite/rollup-plugin-alias matches left-to-right\n // by string prefix, so the broad `preact` entry must come last\n // or it swallows `preact/jsx-*` and `preact/hooks`.\n alias: [\n {\n find: 'preact/jsx-runtime',\n replacement: resolve(vendorRoot, 'jsx-runtime.js'),\n },\n {\n // esbuild dev mode emits `import { jsxDEV } from 'preact/jsx-dev-runtime'`;\n // the same shim exports `jsxDEV`.\n find: 'preact/jsx-dev-runtime',\n replacement: resolve(vendorRoot, 'jsx-runtime.js'),\n },\n {\n find: 'preact/hooks',\n replacement: resolve(vendorRoot, 'hooks.module.js'),\n },\n {\n find: /^preact$/,\n replacement: resolve(vendorRoot, 'preact.module.js'),\n },\n ],\n },\n }\n },\n\n configResolved(config) {\n // Append, don't replace. Returning an array from `config` would\n // overwrite Vite's default allow-list (project + workspace root),\n // locking the host app out of its own files.\n if (!config.server.fs.allow.includes(dashboardRoot)) {\n config.server.fs.allow.push(dashboardRoot)\n }\n },\n\n configureServer(server: ViteDevServer) {\n server.middlewares.use((req, res, next) => {\n void (async () => {\n if (req.url === undefined) return next()\n const url = req.url.split('?')[0] ?? ''\n if (url !== mountPath && url !== `${mountPath}/`) return next()\n\n try {\n const indexPath = resolve(dashboardRoot, 'index.html')\n let html = await readFile(indexPath, 'utf-8')\n const entryAbs = resolve(dashboardRoot, 'index.tsx')\n html = html.replace('./index.tsx', `/@fs${entryAbs}`)\n html = await server.transformIndexHtml(req.url, html, req.originalUrl)\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n res.end(html)\n } catch (err) {\n next(err)\n }\n })()\n })\n\n const logger = server.config.logger\n const port = server.config.server.port ?? 5173\n logger.info(\n `\\n \\u001b[32m\\u279c\\u001b[0m three-flatland devtools: \\u001b[36mhttp://localhost:${port}${mountPath}\\u001b[0m\\n`,\n )\n },\n }\n}\n\nexport default threeFlatlandDevtools\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BA,qBAA2B;AAC3B,sBAAyB;AACzB,sBAA8B;AAC9B,uBAAiC;AA7BjC;AAsCA,MAAM,eAAe;AAErB,SAAS,uBAA+B;AAStC,QAAM,WAAO,8BAAQ,+BAAc,YAAY,GAAG,CAAC;AACnD,QAAM,iBAAa,0BAAQ,MAAM,kBAAkB;AACnD,UAAI,2BAAW,UAAU,EAAG,QAAO;AACnC,aAAO,0BAAQ,MAAM,WAAW;AAClC;AAEO,SAAS,sBACd,UAAwC,CAAC,GACjC;AACR,QAAM,YAAY,QAAQ,QAAQ;AAClC,QAAM,gBAAgB,qBAAqB;AAC3C,QAAM,iBAAa,0BAAQ,eAAe,QAAQ;AAElD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IAEP,SAAS;AACP,aAAO;AAAA,QACL,SAAS;AAAA;AAAA;AAAA;AAAA,UAIP,OAAO;AAAA,YACL;AAAA,cACE,MAAM;AAAA,cACN,iBAAa,0BAAQ,YAAY,gBAAgB;AAAA,YACnD;AAAA,YACA;AAAA;AAAA;AAAA,cAGE,MAAM;AAAA,cACN,iBAAa,0BAAQ,YAAY,gBAAgB;AAAA,YACnD;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,iBAAa,0BAAQ,YAAY,iBAAiB;AAAA,YACpD;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,iBAAa,0BAAQ,YAAY,kBAAkB;AAAA,YACrD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,eAAe,QAAQ;AAIrB,UAAI,CAAC,OAAO,OAAO,GAAG,MAAM,SAAS,aAAa,GAAG;AACnD,eAAO,OAAO,GAAG,MAAM,KAAK,aAAa;AAAA,MAC3C;AAAA,IACF;AAAA,IAEA,gBAAgB,QAAuB;AACrC,aAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AACzC,cAAM,YAAY;AAChB,cAAI,IAAI,QAAQ,OAAW,QAAO,KAAK;AACvC,gBAAM,MAAM,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK;AACrC,cAAI,QAAQ,aAAa,QAAQ,GAAG,SAAS,IAAK,QAAO,KAAK;AAE9D,cAAI;AACF,kBAAM,gBAAY,0BAAQ,eAAe,YAAY;AACrD,gBAAI,OAAO,UAAM,0BAAS,WAAW,OAAO;AAC5C,kBAAM,eAAW,0BAAQ,eAAe,WAAW;AACnD,mBAAO,KAAK,QAAQ,eAAe,OAAO,QAAQ,EAAE;AACpD,mBAAO,MAAM,OAAO,mBAAmB,IAAI,KAAK,MAAM,IAAI,WAAW;AACrE,gBAAI,aAAa;AACjB,gBAAI,UAAU,gBAAgB,0BAA0B;AACxD,gBAAI,IAAI,IAAI;AAAA,UACd,SAAS,KAAK;AACZ,iBAAK,GAAG;AAAA,UACV;AAAA,QACF,GAAG;AAAA,MACL,CAAC;AAED,YAAM,SAAS,OAAO,OAAO;AAC7B,YAAM,OAAO,OAAO,OAAO,OAAO,QAAQ;AAC1C,aAAO;AAAA,QACL;AAAA,6EAAsF,IAAI,GAAG,SAAS;AAAA;AAAA,MACxG;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,sBAAQ;","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface ThreeFlatlandDevtoolsOptions {
|
|
4
|
+
/** URL path the dashboard is served under. Default: `/.devtools`. */
|
|
5
|
+
path?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function threeFlatlandDevtools(options?: ThreeFlatlandDevtoolsOptions): Plugin;
|
|
8
|
+
|
|
9
|
+
export { type ThreeFlatlandDevtoolsOptions, threeFlatlandDevtools as default, threeFlatlandDevtools };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface ThreeFlatlandDevtoolsOptions {
|
|
4
|
+
/** URL path the dashboard is served under. Default: `/.devtools`. */
|
|
5
|
+
path?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function threeFlatlandDevtools(options?: ThreeFlatlandDevtoolsOptions): Plugin;
|
|
8
|
+
|
|
9
|
+
export { type ThreeFlatlandDevtoolsOptions, threeFlatlandDevtools as default, threeFlatlandDevtools };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
const DEFAULT_PATH = "/.devtools";
|
|
6
|
+
function resolveDashboardRoot() {
|
|
7
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const siblingSrc = resolve(here, "../src/dashboard");
|
|
9
|
+
if (existsSync(siblingSrc)) return siblingSrc;
|
|
10
|
+
return resolve(here, "dashboard");
|
|
11
|
+
}
|
|
12
|
+
function threeFlatlandDevtools(options = {}) {
|
|
13
|
+
const mountPath = options.path ?? DEFAULT_PATH;
|
|
14
|
+
const dashboardRoot = resolveDashboardRoot();
|
|
15
|
+
const vendorRoot = resolve(dashboardRoot, "vendor");
|
|
16
|
+
return {
|
|
17
|
+
name: "three-flatland-devtools",
|
|
18
|
+
apply: "serve",
|
|
19
|
+
config() {
|
|
20
|
+
return {
|
|
21
|
+
resolve: {
|
|
22
|
+
// Order matters — Vite/rollup-plugin-alias matches left-to-right
|
|
23
|
+
// by string prefix, so the broad `preact` entry must come last
|
|
24
|
+
// or it swallows `preact/jsx-*` and `preact/hooks`.
|
|
25
|
+
alias: [
|
|
26
|
+
{
|
|
27
|
+
find: "preact/jsx-runtime",
|
|
28
|
+
replacement: resolve(vendorRoot, "jsx-runtime.js")
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
// esbuild dev mode emits `import { jsxDEV } from 'preact/jsx-dev-runtime'`;
|
|
32
|
+
// the same shim exports `jsxDEV`.
|
|
33
|
+
find: "preact/jsx-dev-runtime",
|
|
34
|
+
replacement: resolve(vendorRoot, "jsx-runtime.js")
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
find: "preact/hooks",
|
|
38
|
+
replacement: resolve(vendorRoot, "hooks.module.js")
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
find: /^preact$/,
|
|
42
|
+
replacement: resolve(vendorRoot, "preact.module.js")
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
configResolved(config) {
|
|
49
|
+
if (!config.server.fs.allow.includes(dashboardRoot)) {
|
|
50
|
+
config.server.fs.allow.push(dashboardRoot);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
configureServer(server) {
|
|
54
|
+
server.middlewares.use((req, res, next) => {
|
|
55
|
+
void (async () => {
|
|
56
|
+
if (req.url === void 0) return next();
|
|
57
|
+
const url = req.url.split("?")[0] ?? "";
|
|
58
|
+
if (url !== mountPath && url !== `${mountPath}/`) return next();
|
|
59
|
+
try {
|
|
60
|
+
const indexPath = resolve(dashboardRoot, "index.html");
|
|
61
|
+
let html = await readFile(indexPath, "utf-8");
|
|
62
|
+
const entryAbs = resolve(dashboardRoot, "index.tsx");
|
|
63
|
+
html = html.replace("./index.tsx", `/@fs${entryAbs}`);
|
|
64
|
+
html = await server.transformIndexHtml(req.url, html, req.originalUrl);
|
|
65
|
+
res.statusCode = 200;
|
|
66
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
67
|
+
res.end(html);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
next(err);
|
|
70
|
+
}
|
|
71
|
+
})();
|
|
72
|
+
});
|
|
73
|
+
const logger = server.config.logger;
|
|
74
|
+
const port = server.config.server.port ?? 5173;
|
|
75
|
+
logger.info(
|
|
76
|
+
`
|
|
77
|
+
\x1B[32m\u279C\x1B[0m three-flatland devtools: \x1B[36mhttp://localhost:${port}${mountPath}\x1B[0m
|
|
78
|
+
`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
var vite_plugin_default = threeFlatlandDevtools;
|
|
84
|
+
export {
|
|
85
|
+
vite_plugin_default as default,
|
|
86
|
+
threeFlatlandDevtools
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=vite-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vite-plugin.ts"],"sourcesContent":["/**\n * Vite plugin that serves the standalone devtools dashboard alongside the\n * user's app. Mounts a dev-only middleware at a configurable path (default\n * `/.devtools`).\n *\n * The dashboard source lives inside this package\n * (`packages/devtools/src/dashboard/`), not inside the consumer's project.\n * The plugin:\n * 1. Whitelists the dashboard directory via `server.fs.allow` so Vite\n * is willing to read its files across the workspace boundary.\n * 2. Serves `index.html` at the mount path, rewritten so the entry\n * script loads via `/@fs/<abs>` — Vite then transforms it with full\n * HMR.\n * 3. Aliases the vendored Preact files so `import from 'preact'`\n * resolves locally — no runtime dep on Preact leaks into the\n * consumer's `node_modules`.\n *\n * Access the dashboard at the Vite dev server's origin directly, e.g.\n * `http://localhost:5174/.devtools`. If the host project sits behind a\n * microfrontend proxy, point the browser at the Vite port — the\n * dashboard's transitive requests (`/@fs/`, `/@vite/client`, pre-bundled\n * `node_modules/.vite/`) are not namespaced and expect to land on the\n * same origin that served the HTML.\n *\n * Dev-only; the plugin is inert in production builds.\n */\nimport { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, resolve } from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nexport interface ThreeFlatlandDevtoolsOptions {\n /** URL path the dashboard is served under. Default: `/.devtools`. */\n path?: string\n}\n\nconst DEFAULT_PATH = '/.devtools'\n\nfunction resolveDashboardRoot(): string {\n // Three possible layouts for this file at runtime:\n // 1. `packages/devtools/src/vite-plugin.ts` (source condition)\n // 2. `packages/devtools/dist/vite-plugin.js` (workspace, Node import condition)\n // 3. `node_modules/@three-flatland/devtools/dist/vite-plugin.js` (published)\n //\n // For (2) — the dev workflow where Node loads the built plugin but we\n // want HMR over the unbuilt sources — prefer the sibling `../src/dashboard/`\n // if it exists. Otherwise resolve `./dashboard` relative to this file.\n const here = dirname(fileURLToPath(import.meta.url))\n const siblingSrc = resolve(here, '../src/dashboard')\n if (existsSync(siblingSrc)) return siblingSrc\n return resolve(here, 'dashboard')\n}\n\nexport function threeFlatlandDevtools(\n options: ThreeFlatlandDevtoolsOptions = {},\n): Plugin {\n const mountPath = options.path ?? DEFAULT_PATH\n const dashboardRoot = resolveDashboardRoot()\n const vendorRoot = resolve(dashboardRoot, 'vendor')\n\n return {\n name: 'three-flatland-devtools',\n apply: 'serve',\n\n config() {\n return {\n resolve: {\n // Order matters — Vite/rollup-plugin-alias matches left-to-right\n // by string prefix, so the broad `preact` entry must come last\n // or it swallows `preact/jsx-*` and `preact/hooks`.\n alias: [\n {\n find: 'preact/jsx-runtime',\n replacement: resolve(vendorRoot, 'jsx-runtime.js'),\n },\n {\n // esbuild dev mode emits `import { jsxDEV } from 'preact/jsx-dev-runtime'`;\n // the same shim exports `jsxDEV`.\n find: 'preact/jsx-dev-runtime',\n replacement: resolve(vendorRoot, 'jsx-runtime.js'),\n },\n {\n find: 'preact/hooks',\n replacement: resolve(vendorRoot, 'hooks.module.js'),\n },\n {\n find: /^preact$/,\n replacement: resolve(vendorRoot, 'preact.module.js'),\n },\n ],\n },\n }\n },\n\n configResolved(config) {\n // Append, don't replace. Returning an array from `config` would\n // overwrite Vite's default allow-list (project + workspace root),\n // locking the host app out of its own files.\n if (!config.server.fs.allow.includes(dashboardRoot)) {\n config.server.fs.allow.push(dashboardRoot)\n }\n },\n\n configureServer(server: ViteDevServer) {\n server.middlewares.use((req, res, next) => {\n void (async () => {\n if (req.url === undefined) return next()\n const url = req.url.split('?')[0] ?? ''\n if (url !== mountPath && url !== `${mountPath}/`) return next()\n\n try {\n const indexPath = resolve(dashboardRoot, 'index.html')\n let html = await readFile(indexPath, 'utf-8')\n const entryAbs = resolve(dashboardRoot, 'index.tsx')\n html = html.replace('./index.tsx', `/@fs${entryAbs}`)\n html = await server.transformIndexHtml(req.url, html, req.originalUrl)\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n res.end(html)\n } catch (err) {\n next(err)\n }\n })()\n })\n\n const logger = server.config.logger\n const port = server.config.server.port ?? 5173\n logger.info(\n `\\n \\u001b[32m\\u279c\\u001b[0m three-flatland devtools: \\u001b[36mhttp://localhost:${port}${mountPath}\\u001b[0m\\n`,\n )\n },\n }\n}\n\nexport default threeFlatlandDevtools\n"],"mappings":"AA0BA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,SAAS,eAAe;AASjC,MAAM,eAAe;AAErB,SAAS,uBAA+B;AAStC,QAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;AACnD,QAAM,aAAa,QAAQ,MAAM,kBAAkB;AACnD,MAAI,WAAW,UAAU,EAAG,QAAO;AACnC,SAAO,QAAQ,MAAM,WAAW;AAClC;AAEO,SAAS,sBACd,UAAwC,CAAC,GACjC;AACR,QAAM,YAAY,QAAQ,QAAQ;AAClC,QAAM,gBAAgB,qBAAqB;AAC3C,QAAM,aAAa,QAAQ,eAAe,QAAQ;AAElD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IAEP,SAAS;AACP,aAAO;AAAA,QACL,SAAS;AAAA;AAAA;AAAA;AAAA,UAIP,OAAO;AAAA,YACL;AAAA,cACE,MAAM;AAAA,cACN,aAAa,QAAQ,YAAY,gBAAgB;AAAA,YACnD;AAAA,YACA;AAAA;AAAA;AAAA,cAGE,MAAM;AAAA,cACN,aAAa,QAAQ,YAAY,gBAAgB;AAAA,YACnD;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa,QAAQ,YAAY,iBAAiB;AAAA,YACpD;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa,QAAQ,YAAY,kBAAkB;AAAA,YACrD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,eAAe,QAAQ;AAIrB,UAAI,CAAC,OAAO,OAAO,GAAG,MAAM,SAAS,aAAa,GAAG;AACnD,eAAO,OAAO,GAAG,MAAM,KAAK,aAAa;AAAA,MAC3C;AAAA,IACF;AAAA,IAEA,gBAAgB,QAAuB;AACrC,aAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AACzC,cAAM,YAAY;AAChB,cAAI,IAAI,QAAQ,OAAW,QAAO,KAAK;AACvC,gBAAM,MAAM,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK;AACrC,cAAI,QAAQ,aAAa,QAAQ,GAAG,SAAS,IAAK,QAAO,KAAK;AAE9D,cAAI;AACF,kBAAM,YAAY,QAAQ,eAAe,YAAY;AACrD,gBAAI,OAAO,MAAM,SAAS,WAAW,OAAO;AAC5C,kBAAM,WAAW,QAAQ,eAAe,WAAW;AACnD,mBAAO,KAAK,QAAQ,eAAe,OAAO,QAAQ,EAAE;AACpD,mBAAO,MAAM,OAAO,mBAAmB,IAAI,KAAK,MAAM,IAAI,WAAW;AACrE,gBAAI,aAAa;AACjB,gBAAI,UAAU,gBAAgB,0BAA0B;AACxD,gBAAI,IAAI,IAAI;AAAA,UACd,SAAS,KAAK;AACZ,iBAAK,GAAG;AAAA,UACV;AAAA,QACF,GAAG;AAAA,MACL,CAAC;AAED,YAAM,SAAS,OAAO,OAAO;AAC7B,YAAM,OAAO,OAAO,OAAO,OAAO,QAAQ;AAC1C,aAAO;AAAA,QACL;AAAA,6EAAsF,IAAI,GAAG,SAAS;AAAA;AAAA,MACxG;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,sBAAQ;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@three-flatland/devtools",
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
|
+
"description": "Dev-time introspection toolkit for three-flatland — Tweakpane v4 UI plugin, stats monitor, and buffer inspection",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"source": "./src/index.ts",
|
|
9
|
+
"import": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"require": {
|
|
14
|
+
"types": "./dist/index.d.cts",
|
|
15
|
+
"default": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"./react": {
|
|
19
|
+
"source": "./src/react.ts",
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/react.d.ts",
|
|
22
|
+
"default": "./dist/react.js"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/react.d.cts",
|
|
26
|
+
"default": "./dist/react.cjs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"./react/*": {
|
|
30
|
+
"source": "./src/react/*.ts",
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/react/*.d.ts",
|
|
33
|
+
"default": "./dist/react/*.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/react/*.d.cts",
|
|
37
|
+
"default": "./dist/react/*.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./vite": {
|
|
41
|
+
"source": "./src/vite-plugin.ts",
|
|
42
|
+
"import": {
|
|
43
|
+
"types": "./dist/vite-plugin.d.ts",
|
|
44
|
+
"default": "./dist/vite-plugin.js"
|
|
45
|
+
},
|
|
46
|
+
"require": {
|
|
47
|
+
"types": "./dist/vite-plugin.d.cts",
|
|
48
|
+
"default": "./dist/vite-plugin.cjs"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"main": "./dist/index.cjs",
|
|
53
|
+
"module": "./dist/index.js",
|
|
54
|
+
"types": "./dist/index.d.ts",
|
|
55
|
+
"files": [
|
|
56
|
+
"dist"
|
|
57
|
+
],
|
|
58
|
+
"sideEffects": false,
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@react-three/fiber": "^10.0.0-alpha.2",
|
|
61
|
+
"@tweakpane/plugin-essentials": "^0.2.1",
|
|
62
|
+
"react": "^19.2.0",
|
|
63
|
+
"three": "^0.183.0",
|
|
64
|
+
"three-flatland": "^0.1.0-alpha.4",
|
|
65
|
+
"tweakpane": "^4.0.5",
|
|
66
|
+
"vite": "^5.0.0 || ^6.0.0"
|
|
67
|
+
},
|
|
68
|
+
"peerDependenciesMeta": {
|
|
69
|
+
"react": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"@react-three/fiber": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"three": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"three-flatland": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"vite": {
|
|
82
|
+
"optional": true
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"devDependencies": {
|
|
86
|
+
"@react-three/fiber": "10.0.0-alpha.2",
|
|
87
|
+
"@testing-library/react": "^16.1.0",
|
|
88
|
+
"@tweakpane/core": "^2.0.5",
|
|
89
|
+
"@tweakpane/plugin-essentials": "^0.2.1",
|
|
90
|
+
"@types/react": "^19.0.2",
|
|
91
|
+
"@types/react-dom": "^19.0.2",
|
|
92
|
+
"@types/three": "^0.183.1",
|
|
93
|
+
"happy-dom": "^15.11.7",
|
|
94
|
+
"react": "^19.2.0",
|
|
95
|
+
"react-dom": "^19.2.0",
|
|
96
|
+
"three": "^0.183.1",
|
|
97
|
+
"tweakpane": "^4.0.5",
|
|
98
|
+
"typescript": "^5.7.3",
|
|
99
|
+
"vite": "^6.4.1",
|
|
100
|
+
"three-flatland": "0.1.0-alpha.6"
|
|
101
|
+
},
|
|
102
|
+
"keywords": [
|
|
103
|
+
"three.js",
|
|
104
|
+
"tweakpane",
|
|
105
|
+
"debug",
|
|
106
|
+
"controls",
|
|
107
|
+
"webgpu"
|
|
108
|
+
],
|
|
109
|
+
"license": "MIT",
|
|
110
|
+
"repository": {
|
|
111
|
+
"type": "git",
|
|
112
|
+
"url": "https://github.com/thejustinwalsh/three-flatland.git",
|
|
113
|
+
"directory": "packages/devtools"
|
|
114
|
+
},
|
|
115
|
+
"scripts": {
|
|
116
|
+
"build": "tsup",
|
|
117
|
+
"build:bundle": "vite build --config vite.config.bundle.ts",
|
|
118
|
+
"dev": "tsup --watch",
|
|
119
|
+
"test": "vitest run",
|
|
120
|
+
"test:watch": "vitest",
|
|
121
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p src/dashboard/tsconfig.json",
|
|
122
|
+
"clean": "rm -rf dist bundle"
|
|
123
|
+
}
|
|
124
|
+
}
|