@vibecook/ice 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -5
- package/dist/{chunk-ZTY2VRIS.js → chunk-6W2FPXR7.js} +13 -7
- package/dist/chunk-6W2FPXR7.js.map +1 -0
- package/dist/{chunk-Y7K6CHSF.js → chunk-LAZIY3J7.js} +286 -189
- package/dist/chunk-LAZIY3J7.js.map +1 -0
- package/dist/{chunk-REJTEK3V.js → chunk-M2HUDENL.js} +288 -318
- package/dist/chunk-M2HUDENL.js.map +1 -0
- package/dist/{chunk-BH5AFWJX.js → chunk-VZEZ7CYW.js} +9 -13
- package/dist/chunk-VZEZ7CYW.js.map +1 -0
- package/dist/desk-kit.js +2 -2
- package/dist/desk-objects.js +45 -14
- package/dist/desk-objects.js.map +1 -1
- package/dist/desk.js +3 -3
- package/dist/devtools.js +1 -1
- package/dist/dom.js +2 -2
- package/dist/index.js +7 -1
- package/dist/react.js +2 -2
- package/dist/types/packages/core/src/canvas/engine-catalog.d.ts +6 -0
- package/dist/types/packages/core/src/catalog/desk.d.ts +6 -6
- package/dist/types/packages/core/src/catalog/gesture.d.ts +2 -0
- package/dist/types/packages/core/src/catalog/selection-presence.d.ts +2 -0
- package/dist/types/packages/core/src/catalog/settings-resources.d.ts +8 -4
- package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +11 -5
- package/dist/types/packages/core/src/index.d.ts +1 -1
- package/dist/types/packages/core/src/ops/selection-drag.d.ts +8 -0
- package/dist/types/packages/core/src/settings/defaults.d.ts +2 -0
- package/dist/types/packages/core/src/systems/camera-sim.d.ts +13 -0
- package/dist/types/packages/core/src/systems/tray.d.ts +5 -4
- package/dist/types/packages/core/src/tools/define-tool.d.ts +2 -2
- package/dist/types/packages/core/src/widget/define-widget.d.ts +2 -1
- package/dist/types/packages/desk/src/ground.d.ts +4 -3
- package/dist/types/packages/desk/src/host/layer.d.ts +1 -3
- package/dist/types/packages/desk/src/mat/layout.d.ts +45 -5
- package/dist/types/packages/desk/src/mat/mat-pass.d.ts +7 -0
- package/dist/types/packages/desk/src/mat/ruler-regions.d.ts +17 -0
- package/dist/types/packages/desk/src/shaders.gen.d.ts +4 -4
- package/dist/types/packages/desk/src/theme.d.ts +0 -15
- package/dist/types/packages/desk/src/tray/drawer.d.ts +10 -8
- package/dist/types/packages/desk/src/tray/flux.d.ts +2 -3
- package/dist/types/packages/desk/src/tray/layout.d.ts +1 -6
- package/dist/types/packages/desk/src/tray/look.d.ts +0 -9
- package/dist/types/packages/desk/src/tray/pass.d.ts +7 -18
- package/dist/types/packages/desk/src/tray/specimens.d.ts +2 -19
- package/dist/types/packages/dom/src/pointer-adapter.d.ts +1 -1
- package/dist/types/packages/objects/src/minimat/layout.d.ts +1 -1
- package/dist/types/packages/objects/src/photo/photo.d.ts +2 -2
- package/dist/types/packages/objects/src/preset.d.ts +5 -3
- package/package.json +15 -16
- package/dist/chunk-BH5AFWJX.js.map +0 -1
- package/dist/chunk-REJTEK3V.js.map +0 -1
- package/dist/chunk-Y7K6CHSF.js.map +0 -1
- package/dist/chunk-ZTY2VRIS.js.map +0 -1
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
spring,
|
|
83
83
|
themeFrom,
|
|
84
84
|
tilted
|
|
85
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-VZEZ7CYW.js";
|
|
86
86
|
import {
|
|
87
87
|
BLEND_OVER,
|
|
88
88
|
bindGroup,
|
|
@@ -169,7 +169,7 @@ import {
|
|
|
169
169
|
trayTakeProps,
|
|
170
170
|
widgetSpawnInits,
|
|
171
171
|
widgetTypeFor
|
|
172
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-LAZIY3J7.js";
|
|
173
173
|
import {
|
|
174
174
|
clientToScreen,
|
|
175
175
|
cubicBezierEase,
|
|
@@ -626,13 +626,13 @@ var DRAWER = {
|
|
|
626
626
|
/**
|
|
627
627
|
* The HEADER (design-018 R4 — James, 2026-09-28: "make the fade stronger and more gap, and design the filters nicely at that empty
|
|
628
628
|
* safe top space instead"): a CLEAR band this high under the face's top edge (inside the arris) where what hangs on the board — the
|
|
629
|
-
* specimens, their shadows
|
|
629
|
+
* specimens, their shadows and their tags — and the holes are wholly gone: the plain face, on which the bar lays
|
|
630
630
|
* its category chips as label tape (`<TrayBar>`, @ice/react — the handle's `anchor().drawer.header`). The face's portal clip starts
|
|
631
631
|
* this far down, so nothing of the content is even drawn above it.
|
|
632
632
|
*/
|
|
633
633
|
header: 48,
|
|
634
634
|
/**
|
|
635
|
-
* The CONTENT's fade under the header (design-018 §4, R4): the specimens, their shadows, their
|
|
635
|
+
* The CONTENT's fade under the header (design-018 §4, R4): the specimens, their shadows, their tags and the holes
|
|
636
636
|
* fade in over this band (CSS px, 0.8 pitch) — `smoothstep(top + header, top + header + fade, y)`, `top` the face's top edge — the
|
|
637
637
|
* feather on the face's portal clip (R1's 28 px band at the edge itself, stretched and moved down: D-R4.1). The board does not fade.
|
|
638
638
|
*/
|
|
@@ -783,22 +783,8 @@ var TrayUniforms = defineStruct("TrayUniforms", [
|
|
|
783
783
|
// …its 210 (bump) · 42 · 105 (flecks)…
|
|
784
784
|
["keepEdge", "vec4f"],
|
|
785
785
|
// …and the punched fibre's 9 · 18 · 36
|
|
786
|
-
["accessory", "vec4f"],
|
|
787
|
-
// K5a: the accessories' powder coat, linear, and their shadows' strength on the board
|
|
788
786
|
["fade", "vec4f"]
|
|
789
|
-
// the content's fade under the header (design-018 §4, R4): its band F, the clear header H above it, CSS px; a host's foot inset (I21; 0 none);
|
|
790
|
-
]);
|
|
791
|
-
var TrayAccessoryStruct = defineStruct("TrayAccessory", [
|
|
792
|
-
["box", "vec4f"],
|
|
793
|
-
// the quad: x0, y0, x1, y1
|
|
794
|
-
["kind", "vec4f"],
|
|
795
|
-
// the accessory (0 hook · 1 shelf · 2 clip · 3 rail), its pegs, how far it stands off the board (px), —
|
|
796
|
-
["rect", "vec4f"],
|
|
797
|
-
// the specimen: x0, y0, x1, y1
|
|
798
|
-
["pegs0", "vec4f"],
|
|
799
|
-
// pegs 0 and 1: x, y
|
|
800
|
-
["pegs1", "vec4f"]
|
|
801
|
-
// pegs 2 and 3
|
|
787
|
+
// the content's fade under the header (design-018 §4, R4): its band F, the clear header H above it, CSS px; a host's foot inset (I21; 0 none); its fade band, CSS px
|
|
802
788
|
]);
|
|
803
789
|
|
|
804
790
|
// ../desk/src/tray/shaders.ts
|
|
@@ -806,7 +792,7 @@ var TRAY_SHADER_FILES = { tray: "tray/tray.wgsl", trayPass: "tray/tray-pass.wgsl
|
|
|
806
792
|
function trayShaders(text2) {
|
|
807
793
|
const t = text2(TRAY_SHADER_FILES);
|
|
808
794
|
return kitWgsl(["view", "sdf", "light"], {
|
|
809
|
-
structs: [TrayUniforms
|
|
795
|
+
structs: [TrayUniforms],
|
|
810
796
|
modules: [{ label: "tray/tray.wgsl", text: t.tray }],
|
|
811
797
|
entry: { label: "tray/tray-pass.wgsl", text: t.trayPass }
|
|
812
798
|
}, text2);
|
|
@@ -1386,6 +1372,40 @@ var HoldPass = class _HoldPass {
|
|
|
1386
1372
|
}
|
|
1387
1373
|
};
|
|
1388
1374
|
|
|
1375
|
+
// ../desk/src/mat/ruler-regions.ts
|
|
1376
|
+
function rulerRegions(view, ruler2, previous) {
|
|
1377
|
+
const { width, height, dpr } = view;
|
|
1378
|
+
const { margin, band: band2, line } = ruler2;
|
|
1379
|
+
if (previous && previous.width === width && previous.height === height && previous.dpr === dpr && previous.margin === margin && previous.band === band2 && previous.line === line) return previous;
|
|
1380
|
+
const w = Math.max(1, Math.round(width * dpr));
|
|
1381
|
+
const h = Math.max(1, Math.round(height * dpr));
|
|
1382
|
+
const pad = line * dpr / 2 + 0.5;
|
|
1383
|
+
const clamp2 = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
|
|
1384
|
+
const left = clamp2(Math.floor(margin * dpr - pad), 0, w);
|
|
1385
|
+
const top = clamp2(Math.floor(margin * dpr - pad), 0, h);
|
|
1386
|
+
const right = clamp2(Math.ceil((width - margin) * dpr + pad), left, w);
|
|
1387
|
+
const bottom = clamp2(Math.ceil((height - margin) * dpr + pad), top, h);
|
|
1388
|
+
const innerLeft = clamp2(Math.ceil((margin + band2) * dpr + pad), left, right);
|
|
1389
|
+
const innerTop = clamp2(Math.ceil((margin + band2) * dpr + pad), top, bottom);
|
|
1390
|
+
const innerRight = clamp2(Math.floor((width - margin) * dpr - pad), innerLeft, right);
|
|
1391
|
+
const innerBottom = clamp2(Math.floor((height - margin) * dpr - pad), innerTop, bottom);
|
|
1392
|
+
const surface2 = [
|
|
1393
|
+
[0, 0, w, top],
|
|
1394
|
+
[0, bottom, w, h - bottom],
|
|
1395
|
+
[0, top, left, bottom - top],
|
|
1396
|
+
[right, top, w - right, bottom - top],
|
|
1397
|
+
[innerLeft, innerTop, innerRight - innerLeft, innerBottom - innerTop]
|
|
1398
|
+
];
|
|
1399
|
+
const edges = [
|
|
1400
|
+
[left, top, right - left, innerTop - top],
|
|
1401
|
+
[left, innerTop, innerLeft - left, innerBottom - innerTop],
|
|
1402
|
+
[innerRight, innerTop, right - innerRight, innerBottom - innerTop],
|
|
1403
|
+
[left, innerBottom, right - left, bottom - innerBottom]
|
|
1404
|
+
];
|
|
1405
|
+
const nonempty = (r) => r[2] > 0 && r[3] > 0;
|
|
1406
|
+
return { width, height, dpr, margin, band: band2, line, surface: surface2.filter(nonempty), edges: edges.filter(nonempty) };
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1389
1409
|
// ../desk/src/mat/mat-pass.ts
|
|
1390
1410
|
var PLATE_NAMES = ["c", "b"];
|
|
1391
1411
|
var CuttingMat = class _CuttingMat {
|
|
@@ -1406,6 +1426,7 @@ var CuttingMat = class _CuttingMat {
|
|
|
1406
1426
|
/** The view block as last uploaded (K7a: uploaded only when its bytes moved; a layered kind compares a layer's view by it). */
|
|
1407
1427
|
sentView = new Uint8Array(MatUniforms.size);
|
|
1408
1428
|
viewSent = false;
|
|
1429
|
+
ruler = null;
|
|
1409
1430
|
device;
|
|
1410
1431
|
shared;
|
|
1411
1432
|
constructor(device, shared) {
|
|
@@ -1585,6 +1606,7 @@ var CuttingMat = class _CuttingMat {
|
|
|
1585
1606
|
* wind pass if the silhouette it holds is stale. Returns whether it ran.
|
|
1586
1607
|
*/
|
|
1587
1608
|
prepare(encoder, view, fadeIn, cfg, frame, present, light = DAY_LIGHT, lit) {
|
|
1609
|
+
this.ruler = cfg.ruler.on ? rulerRegions(view, cfg.ruler, this.ruler) : null;
|
|
1588
1610
|
const plate = PLATE_NAMES.includes(cfg.gobo.plate) ? cfg.gobo.plate : "c";
|
|
1589
1611
|
const strength = MAT_GRID.gobo.plates[plate].strength;
|
|
1590
1612
|
this.uniforms.set(matUniformValues(view, fadeIn, { ...cfg, gobo: { ...cfg.gobo, plate } }, frame, strength, present, light, this.shared.glyphMeta, lit));
|
|
@@ -1625,6 +1647,37 @@ var CuttingMat = class _CuttingMat {
|
|
|
1625
1647
|
pass.setBindGroup(0, this.matGroup);
|
|
1626
1648
|
pass.draw(3);
|
|
1627
1649
|
}
|
|
1650
|
+
/** The mat beneath objects; enabled ruler strips are reserved for the foreground. */
|
|
1651
|
+
drawSurface(pass, clip) {
|
|
1652
|
+
if (!this.ruler) {
|
|
1653
|
+
this.draw(pass);
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
this.drawRegions(pass, this.ruler.surface, clip);
|
|
1657
|
+
}
|
|
1658
|
+
/** The edge bands and frame above every object in this slot, within its portal. */
|
|
1659
|
+
drawRulers(pass, clip) {
|
|
1660
|
+
if (this.ruler) this.drawRegions(pass, this.ruler.edges, clip);
|
|
1661
|
+
}
|
|
1662
|
+
drawRegions(pass, regions, clip) {
|
|
1663
|
+
const [cx, cy, cw, ch] = clip;
|
|
1664
|
+
let bound = false;
|
|
1665
|
+
for (const [rx, ry, rw, rh] of regions) {
|
|
1666
|
+
const x = Math.max(cx, rx);
|
|
1667
|
+
const y = Math.max(cy, ry);
|
|
1668
|
+
const right = Math.min(cx + cw, rx + rw);
|
|
1669
|
+
const bottom = Math.min(cy + ch, ry + rh);
|
|
1670
|
+
if (right <= x || bottom <= y) continue;
|
|
1671
|
+
if (!bound) {
|
|
1672
|
+
pass.setPipeline(this.shared.matPipeline);
|
|
1673
|
+
pass.setBindGroup(0, this.matGroup);
|
|
1674
|
+
bound = true;
|
|
1675
|
+
}
|
|
1676
|
+
pass.setScissorRect(x, y, right - x, bottom - y);
|
|
1677
|
+
pass.draw(3);
|
|
1678
|
+
}
|
|
1679
|
+
if (bound) pass.setScissorRect(cx, cy, cw, ch);
|
|
1680
|
+
}
|
|
1628
1681
|
/** This slot's buffers; the shared plates go with the last slot standing. */
|
|
1629
1682
|
dispose() {
|
|
1630
1683
|
this.uniformBuf.destroy();
|
|
@@ -2143,14 +2196,212 @@ var TRAY_LOOK = {
|
|
|
2143
2196
|
})(),
|
|
2144
2197
|
/** The lamp's angular radius, rad. */
|
|
2145
2198
|
lampSize: TRAY.lampSize,
|
|
2146
|
-
/** K5a: the accessories' powder coat, linear; each accessory's standing-off (pitches); their shadows' strength. */
|
|
2147
|
-
accessory: linear(rgb(TRAY.accessory.css)),
|
|
2148
|
-
accessoryHeight: TRAY.accessory.height,
|
|
2149
|
-
accessoryShadow: TRAY.accessory.shadow,
|
|
2150
2199
|
/** K5a: a hovered specimen's lift — a share of its kind's hold. */
|
|
2151
2200
|
hoverLift: TRAY.hoverLift
|
|
2152
2201
|
};
|
|
2153
2202
|
|
|
2203
|
+
// ../desk/src/tray/pass.ts
|
|
2204
|
+
var BLEND_PREMUL5 = {
|
|
2205
|
+
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
2206
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
2207
|
+
};
|
|
2208
|
+
function pcg(v) {
|
|
2209
|
+
const s = Math.imul(v >>> 0, 747796405) + 2891336453 >>> 0;
|
|
2210
|
+
const w = Math.imul((s >>> (s >>> 28) + 4 ^ s) >>> 0, 277803737) >>> 0;
|
|
2211
|
+
return (w >>> 22 ^ w) >>> 0;
|
|
2212
|
+
}
|
|
2213
|
+
var HASH_SIZE = 256;
|
|
2214
|
+
function hashTexels() {
|
|
2215
|
+
const N = HASH_SIZE;
|
|
2216
|
+
const h = new Uint8Array(N * N);
|
|
2217
|
+
for (let j = 0; j < N; j++) {
|
|
2218
|
+
const r = pcg(j);
|
|
2219
|
+
for (let i = 0; i < N; i++) h[j * N + i] = pcg((i ^ r) >>> 0) >>> 24;
|
|
2220
|
+
}
|
|
2221
|
+
const out = new Uint8Array(N * N * 4);
|
|
2222
|
+
for (let j = 0; j < N; j++) {
|
|
2223
|
+
for (let i = 0; i < N; i++) {
|
|
2224
|
+
const i1 = (i + 1) % N;
|
|
2225
|
+
const j1 = (j + 1) % N;
|
|
2226
|
+
const o = (j * N + i) * 4;
|
|
2227
|
+
out[o] = h[j * N + i];
|
|
2228
|
+
out[o + 1] = h[j * N + i1];
|
|
2229
|
+
out[o + 2] = h[j1 * N + i];
|
|
2230
|
+
out[o + 3] = h[j1 * N + i1];
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
return out;
|
|
2234
|
+
}
|
|
2235
|
+
function keep(fp, F) {
|
|
2236
|
+
const x = Math.min(Math.max((fp * F - 0.25) / 0.25, 0), 1);
|
|
2237
|
+
return 1 - x * x * (3 - 2 * x);
|
|
2238
|
+
}
|
|
2239
|
+
var TrayPass = class _TrayPass {
|
|
2240
|
+
device;
|
|
2241
|
+
mat;
|
|
2242
|
+
pipeline;
|
|
2243
|
+
/** The VEIL (design-018 rev 5): the plain board laid over everything the drawer holds at its top — its own entries on the same layout. */
|
|
2244
|
+
veilPipeline;
|
|
2245
|
+
layout;
|
|
2246
|
+
sampler;
|
|
2247
|
+
trayBuf;
|
|
2248
|
+
lightBuf;
|
|
2249
|
+
hash;
|
|
2250
|
+
tray = TrayUniforms.alloc(1);
|
|
2251
|
+
light = MatUniforms.alloc(1);
|
|
2252
|
+
sentTray = new Uint8Array(TrayUniforms.size);
|
|
2253
|
+
sentLight = new Uint8Array(MatUniforms.size);
|
|
2254
|
+
sent = false;
|
|
2255
|
+
/** The quads the last prepare laid: 0 while the drawer is shut (p 0) — then it draws nothing. */
|
|
2256
|
+
quads = 0;
|
|
2257
|
+
/** A host's foot inset this frame (I21): the veil lays a second quad, over the foot, in its one draw. */
|
|
2258
|
+
foot = 0;
|
|
2259
|
+
group = null;
|
|
2260
|
+
boundAssets = -1;
|
|
2261
|
+
last = null;
|
|
2262
|
+
constructor(device, mat, pipelines, layout) {
|
|
2263
|
+
this.device = device;
|
|
2264
|
+
this.mat = mat;
|
|
2265
|
+
[this.pipeline, this.veilPipeline] = pipelines;
|
|
2266
|
+
this.layout = layout;
|
|
2267
|
+
this.sampler = device.createSampler({ label: "tray/pegboard/noise", magFilter: "linear", minFilter: "linear", addressModeU: "repeat", addressModeV: "repeat" });
|
|
2268
|
+
this.trayBuf = uniformBuffer(device, TrayUniforms.size, "tray/pegboard/uniforms");
|
|
2269
|
+
this.lightBuf = uniformBuffer(device, MatUniforms.size, "tray/pegboard/light");
|
|
2270
|
+
this.hash = device.createTexture({ label: "tray/pegboard/hash", size: [HASH_SIZE, HASH_SIZE], format: "rgba8unorm", usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST });
|
|
2271
|
+
device.queue.writeTexture({ texture: this.hash }, hashTexels(), { bytesPerRow: HASH_SIZE * 4 }, [HASH_SIZE, HASH_SIZE]);
|
|
2272
|
+
}
|
|
2273
|
+
/** The pipeline on `format`, sampling `mat`'s blue noise (the root's: its assets are every slot's). */
|
|
2274
|
+
static async create(device, format, src, mat) {
|
|
2275
|
+
const module = await compile(device, compose(src));
|
|
2276
|
+
const layout = bindLayout(device, [
|
|
2277
|
+
{ binding: 0, stages: ["fragment"], buffer: "uniform" },
|
|
2278
|
+
{ binding: 1, stages: ["vertex", "fragment"], buffer: "uniform" },
|
|
2279
|
+
{ binding: 2, stages: ["fragment"], texture: "float" },
|
|
2280
|
+
{ binding: 3, stages: ["fragment"], sampler: "filtering" },
|
|
2281
|
+
{ binding: 4, stages: ["fragment"], texture: "float" }
|
|
2282
|
+
], "tray/pegboard");
|
|
2283
|
+
const pl = device.createPipelineLayout({ label: "tray/pegboard", bindGroupLayouts: [layout] });
|
|
2284
|
+
const pipelines = await Promise.all([
|
|
2285
|
+
renderPipeline(device, { label: "tray/pegboard", layout: pl, module, format, blend: BLEND_PREMUL5 }),
|
|
2286
|
+
renderPipeline(device, { label: "tray/pegboard/veil", layout: pl, module, format, blend: BLEND_PREMUL5, vertex: "vs_veil", fragment: "fs_veil" })
|
|
2287
|
+
]);
|
|
2288
|
+
return new _TrayPass(device, mat, pipelines, layout);
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Lay the drawer out for this frame and upload what changed (before the frame's pass begins): the view, the theme's light, the
|
|
2292
|
+
* root grid's grade, the frame's noise offset. Returns the quads that will draw: one (the view whole while it dims) — none while
|
|
2293
|
+
* the drawer is shut (p 0: it and its shadows lie below the view — nothing is uploaded, nothing drawn; design-018 §5).
|
|
2294
|
+
*/
|
|
2295
|
+
prepare(view, theme, grid, frame, inputs) {
|
|
2296
|
+
const P = DRAWER.pitch;
|
|
2297
|
+
const p = Math.min(Math.max(inputs.p, 0), 1);
|
|
2298
|
+
const rect = drawerRect(view.width, view.height, p);
|
|
2299
|
+
const { rowBase, frac } = carry(inputs.scroll, P);
|
|
2300
|
+
const foot = inputs.foot !== void 0 && inputs.foot > 0 ? inputs.foot : 0;
|
|
2301
|
+
this.foot = foot;
|
|
2302
|
+
if (p <= 0) {
|
|
2303
|
+
this.last = { rect, rowBase, frac, dim: 0, ...foot > 0 ? { foot } : {} };
|
|
2304
|
+
this.quads = 0;
|
|
2305
|
+
return 0;
|
|
2306
|
+
}
|
|
2307
|
+
const L = TRAY_LOOK.lamp;
|
|
2308
|
+
const g = Math.hypot(L[0], L[1]) || 1;
|
|
2309
|
+
const S = DRAWER.shadow.lamp;
|
|
2310
|
+
const Rm = DRAWER.shadow.room;
|
|
2311
|
+
const fp = 1 / (P * view.dpr);
|
|
2312
|
+
const dim = (DRAWER.dim.day + (DRAWER.dim.night - DRAWER.dim.day) * Math.min(Math.max(theme.matLight.night, 0), 1)) * p;
|
|
2313
|
+
const T = TRAY_LOOK;
|
|
2314
|
+
const values = {
|
|
2315
|
+
view: [view.width, view.height, view.dpr, P],
|
|
2316
|
+
rect: [rect.x, rect.y, rect.w, rect.h],
|
|
2317
|
+
rowBase,
|
|
2318
|
+
frac,
|
|
2319
|
+
fp,
|
|
2320
|
+
dim,
|
|
2321
|
+
shape: [DRAWER.radius, DRAWER.arris, DRAWER.inner.alpha, DRAWER.inner.width],
|
|
2322
|
+
hole: [PEG.holeR, PEG.holeHalf, PEG.rimK, PEG.border],
|
|
2323
|
+
depth: [PEG.thick, PEG.gap, PEG.colPhase, PEG.rowPhase],
|
|
2324
|
+
lamp: [L[0], L[1], L[2], T.lampSize],
|
|
2325
|
+
room: [Rm.sigma, Rm.alpha, 0, 0],
|
|
2326
|
+
shadow: [S.sigma, S.alpha, -L[0] / g * S.push, -L[1] / g * S.push],
|
|
2327
|
+
face: [...T.face, 0],
|
|
2328
|
+
faceSrgb: [...T.faceSrgb, 0],
|
|
2329
|
+
edge: [...T.edge, 0],
|
|
2330
|
+
cavity: [T.cavity.edge, T.cavity.heart, T.cavity.width, 0],
|
|
2331
|
+
keepFace: [keep(fp, 6 * Math.sqrt(10)), 0, keep(fp, 85), keep(fp, 190)],
|
|
2332
|
+
// the flecks fade by their cell; their strokes are anti-aliased in the shader (tray.wgsl `peg_flecks`)
|
|
2333
|
+
keepFine: [keep(fp, 210), keep(fp, 42), keep(fp, 105), 0],
|
|
2334
|
+
keepEdge: [keep(fp, 9), keep(fp, 18), keep(fp, 36), 0],
|
|
2335
|
+
fade: [DRAWER.fade, DRAWER.header, foot, Math.max(0, inputs.footFade ?? DRAWER.fade)]
|
|
2336
|
+
};
|
|
2337
|
+
this.tray.set(values);
|
|
2338
|
+
const gobo = grid.mat.gobo;
|
|
2339
|
+
const noise = frame?.noise ?? [0, 0];
|
|
2340
|
+
const light = {
|
|
2341
|
+
gobo: [gobo.opacity, gobo.blurTexels, gobo.shadeMix, gobo.darkFloor],
|
|
2342
|
+
grade: [gobo.saturate, 0, 0, 0],
|
|
2343
|
+
noise: [noise[0], noise[1], 1 / NOISE_SIZE, 0],
|
|
2344
|
+
...lightValues(theme.matLight)
|
|
2345
|
+
};
|
|
2346
|
+
this.light.set(light);
|
|
2347
|
+
this.upload(this.trayBuf, this.tray.view(), this.sentTray);
|
|
2348
|
+
this.upload(this.lightBuf, this.light.view(), this.sentLight);
|
|
2349
|
+
this.sent = true;
|
|
2350
|
+
this.last = { rect, rowBase, frac, dim, ...foot > 0 ? { foot } : {} };
|
|
2351
|
+
this.quads = 1;
|
|
2352
|
+
return 1;
|
|
2353
|
+
}
|
|
2354
|
+
/** A block to the GPU only when its bytes moved since the last upload (a drawer at rest costs no write). */
|
|
2355
|
+
upload(buf, bytes, sent) {
|
|
2356
|
+
let same = this.sent;
|
|
2357
|
+
for (let i = 0; same && i < bytes.length; i++) if (bytes[i] !== sent[i]) same = false;
|
|
2358
|
+
if (same) return;
|
|
2359
|
+
sent.set(bytes);
|
|
2360
|
+
this.device.queue.writeBuffer(buf, 0, bytes);
|
|
2361
|
+
}
|
|
2362
|
+
/** A pipeline and the group, bound (the group remade when the mat's assets change). */
|
|
2363
|
+
bind(pass, pipeline) {
|
|
2364
|
+
if (this.group === null || this.boundAssets !== this.mat.assetVersion) {
|
|
2365
|
+
this.group = bindGroup(this.device, this.layout, [this.lightBuf, this.trayBuf, this.mat.noiseTexture.createView(), this.sampler, this.hash.createView()], "tray/pegboard");
|
|
2366
|
+
this.boundAssets = this.mat.assetVersion;
|
|
2367
|
+
}
|
|
2368
|
+
pass.setPipeline(pipeline);
|
|
2369
|
+
pass.setBindGroup(0, this.group);
|
|
2370
|
+
}
|
|
2371
|
+
/**
|
|
2372
|
+
* The drawer UNDER its specimens into the open pass — over everything drawn so far (the caller left the scissor on the whole view):
|
|
2373
|
+
* the dim, the drawer's shadows, and the board to its edge.
|
|
2374
|
+
*/
|
|
2375
|
+
draw(pass) {
|
|
2376
|
+
if (this.quads === 0) return;
|
|
2377
|
+
pass.pushDebugGroup("tray/pegboard");
|
|
2378
|
+
this.bind(pass, this.pipeline);
|
|
2379
|
+
pass.draw(6, 1, 0, 0);
|
|
2380
|
+
pass.popDebugGroup();
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* THE VEIL (design-018 rev 5) — LAST, over everything the drawer holds (the caller left the scissor on the whole view): the plain board
|
|
2384
|
+
* whole in the header and fading out over its ramp, so what hangs there and the holes behind it fade into the board together — a
|
|
2385
|
+
* specimen never turns see-through over a hole. One quad — and with a host's foot (I21) a second, over the foot, in the same draw.
|
|
2386
|
+
*/
|
|
2387
|
+
drawVeil(pass) {
|
|
2388
|
+
if (this.quads === 0) return;
|
|
2389
|
+
pass.pushDebugGroup("tray/pegboard/veil");
|
|
2390
|
+
this.bind(pass, this.veilPipeline);
|
|
2391
|
+
pass.draw(this.foot > 0 ? 12 : 6, 1, 0, 0);
|
|
2392
|
+
pass.popDebugGroup();
|
|
2393
|
+
}
|
|
2394
|
+
/** What the last prepare laid (a rig's witness). */
|
|
2395
|
+
get laid() {
|
|
2396
|
+
return this.last;
|
|
2397
|
+
}
|
|
2398
|
+
dispose() {
|
|
2399
|
+
this.trayBuf.destroy();
|
|
2400
|
+
this.lightBuf.destroy();
|
|
2401
|
+
this.hash.destroy();
|
|
2402
|
+
}
|
|
2403
|
+
};
|
|
2404
|
+
|
|
2154
2405
|
// ../desk/src/tray/carry.ts
|
|
2155
2406
|
var CARRY = {
|
|
2156
2407
|
/** The copy at its full lift is this much larger than its specimen, about the grab point. */
|
|
@@ -2385,8 +2636,6 @@ function specimenFrames(specimens, drawn, env) {
|
|
|
2385
2636
|
};
|
|
2386
2637
|
const record = recordOf(s.kind, ctx, env.faults);
|
|
2387
2638
|
if (record === void 0) continue;
|
|
2388
|
-
const hx = x0 + s.rect.w / 2;
|
|
2389
|
-
const hy = s.accessory === "shelf" ? y0 + s.rect.h : y0;
|
|
2390
2639
|
out.push({
|
|
2391
2640
|
type: s.type,
|
|
2392
2641
|
kind: s.kind.name,
|
|
@@ -2396,53 +2645,11 @@ function specimenFrames(specimens, drawn, env) {
|
|
|
2396
2645
|
grid,
|
|
2397
2646
|
screen: { x0, y0, x1: x0 + s.rect.w, y1: y0 + s.rect.h },
|
|
2398
2647
|
object: { x0: drawn.rect.x + fit.x, y0: drawn.rect.y + fit.y - drawn.scroll, x1: drawn.rect.x + fit.x + fit.w, y1: drawn.rect.y + fit.y + fit.h - drawn.scroll },
|
|
2399
|
-
pegs: s.pegs.map(([dx, dy]) => [hx + dx * P, hy + dy * P]),
|
|
2400
|
-
accessory: s.accessory,
|
|
2401
2648
|
label: s.label
|
|
2402
2649
|
});
|
|
2403
2650
|
}
|
|
2404
2651
|
return out;
|
|
2405
2652
|
}
|
|
2406
|
-
var ACCESSORY_INDEX = { hook: 0, shelf: 1, clip: 2, rail: 3 };
|
|
2407
|
-
function accessoryOf(f) {
|
|
2408
|
-
const P = DRAWER.pitch;
|
|
2409
|
-
const lift = TRAY_LOOK.accessoryHeight[f.accessory] * P;
|
|
2410
|
-
const L = TRAY_LOOK.lamp;
|
|
2411
|
-
const blur = TRAY_LOOK.lampSize * lift / L[2] + 2;
|
|
2412
|
-
const pushX = Math.max(0, -L[0] / L[2] * lift);
|
|
2413
|
-
const pushY = Math.max(0, -L[1] / L[2] * lift);
|
|
2414
|
-
const r = f.screen;
|
|
2415
|
-
let x0 = Number.POSITIVE_INFINITY;
|
|
2416
|
-
let y0 = Number.POSITIVE_INFINITY;
|
|
2417
|
-
let x1 = Number.NEGATIVE_INFINITY;
|
|
2418
|
-
let y1 = Number.NEGATIVE_INFINITY;
|
|
2419
|
-
const add = (a, b, c, d) => {
|
|
2420
|
-
x0 = Math.min(x0, a);
|
|
2421
|
-
y0 = Math.min(y0, b);
|
|
2422
|
-
x1 = Math.max(x1, c);
|
|
2423
|
-
y1 = Math.max(y1, d);
|
|
2424
|
-
};
|
|
2425
|
-
for (const [x, y] of f.pegs) {
|
|
2426
|
-
add(x - 0.35 * P, y - 0.4 * P, x + 0.35 * P, y + 0.4 * P);
|
|
2427
|
-
if (f.accessory === "hook") add(x - 0.15 * P, y, x + 0.15 * P, y + 0.7 * P);
|
|
2428
|
-
if (f.accessory === "clip") add(x - 0.3 * P, y - 0.3 * P, x + 0.3 * P, Math.max(y, r.y0) + 0.6 * P);
|
|
2429
|
-
if (f.accessory === "shelf") add(x - 0.15 * P, Math.min(y, r.y1), x + 0.15 * P, Math.max(y, r.y1) + 0.1 * P);
|
|
2430
|
-
}
|
|
2431
|
-
if (f.accessory === "shelf") add(r.x0 - 0.35 * P, r.y1 - 0.05 * P, r.x1 + 0.35 * P, r.y1 + 0.3 * P);
|
|
2432
|
-
if (f.accessory === "rail" && f.pegs.length > 0) {
|
|
2433
|
-
const xs = f.pegs.map((q) => q[0]);
|
|
2434
|
-
const y = f.pegs[0][1];
|
|
2435
|
-
add(Math.min(...xs) - 0.45 * P, y - 0.2 * P, Math.max(...xs) + 0.45 * P, y + 0.2 * P);
|
|
2436
|
-
}
|
|
2437
|
-
const peg = (i) => f.pegs[i] ?? [0, 0];
|
|
2438
|
-
return {
|
|
2439
|
-
box: [x0 - blur, y0 - blur, x1 + pushX + blur, y1 + pushY + blur],
|
|
2440
|
-
kind: [ACCESSORY_INDEX[f.accessory], Math.min(f.pegs.length, 4), lift, 0],
|
|
2441
|
-
rect: [r.x0, r.y0, r.x1, r.y1],
|
|
2442
|
-
pegs0: [...peg(0), ...peg(1)],
|
|
2443
|
-
pegs1: [...peg(2), ...peg(3)]
|
|
2444
|
-
};
|
|
2445
|
-
}
|
|
2446
2653
|
var carrySlot = (type) => `carry:${type}`;
|
|
2447
2654
|
function carriedFrame(pose, src, env) {
|
|
2448
2655
|
const v = carryView(pose, src.rect);
|
|
@@ -2611,247 +2818,6 @@ var TraySlots = class {
|
|
|
2611
2818
|
}
|
|
2612
2819
|
};
|
|
2613
2820
|
|
|
2614
|
-
// ../desk/src/tray/pass.ts
|
|
2615
|
-
var BLEND_PREMUL5 = {
|
|
2616
|
-
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
2617
|
-
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
2618
|
-
};
|
|
2619
|
-
function pcg(v) {
|
|
2620
|
-
const s = Math.imul(v >>> 0, 747796405) + 2891336453 >>> 0;
|
|
2621
|
-
const w = Math.imul((s >>> (s >>> 28) + 4 ^ s) >>> 0, 277803737) >>> 0;
|
|
2622
|
-
return (w >>> 22 ^ w) >>> 0;
|
|
2623
|
-
}
|
|
2624
|
-
var HASH_SIZE = 256;
|
|
2625
|
-
function hashTexels() {
|
|
2626
|
-
const N = HASH_SIZE;
|
|
2627
|
-
const h = new Uint8Array(N * N);
|
|
2628
|
-
for (let j = 0; j < N; j++) {
|
|
2629
|
-
const r = pcg(j);
|
|
2630
|
-
for (let i = 0; i < N; i++) h[j * N + i] = pcg((i ^ r) >>> 0) >>> 24;
|
|
2631
|
-
}
|
|
2632
|
-
const out = new Uint8Array(N * N * 4);
|
|
2633
|
-
for (let j = 0; j < N; j++) {
|
|
2634
|
-
for (let i = 0; i < N; i++) {
|
|
2635
|
-
const i1 = (i + 1) % N;
|
|
2636
|
-
const j1 = (j + 1) % N;
|
|
2637
|
-
const o = (j * N + i) * 4;
|
|
2638
|
-
out[o] = h[j * N + i];
|
|
2639
|
-
out[o + 1] = h[j * N + i1];
|
|
2640
|
-
out[o + 2] = h[j1 * N + i];
|
|
2641
|
-
out[o + 3] = h[j1 * N + i1];
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
return out;
|
|
2645
|
-
}
|
|
2646
|
-
function keep(fp, F) {
|
|
2647
|
-
const x = Math.min(Math.max((fp * F - 0.25) / 0.25, 0), 1);
|
|
2648
|
-
return 1 - x * x * (3 - 2 * x);
|
|
2649
|
-
}
|
|
2650
|
-
var TrayPass = class _TrayPass {
|
|
2651
|
-
device;
|
|
2652
|
-
mat;
|
|
2653
|
-
pipeline;
|
|
2654
|
-
/** K5a: the accessories' own fragment entry on the same layout (a branch in one entry slowed the board). */
|
|
2655
|
-
accPipeline;
|
|
2656
|
-
/** The VEIL (design-018 rev 5): the plain board laid over everything the drawer holds at its top — its own entries on the same layout. */
|
|
2657
|
-
veilPipeline;
|
|
2658
|
-
layout;
|
|
2659
|
-
sampler;
|
|
2660
|
-
trayBuf;
|
|
2661
|
-
lightBuf;
|
|
2662
|
-
hash;
|
|
2663
|
-
tray = TrayUniforms.alloc(1);
|
|
2664
|
-
light = MatUniforms.alloc(1);
|
|
2665
|
-
sentTray = new Uint8Array(TrayUniforms.size);
|
|
2666
|
-
sentLight = new Uint8Array(MatUniforms.size);
|
|
2667
|
-
sent = false;
|
|
2668
|
-
/** The quads the last prepare laid: 0 while the drawer is shut (p 0) — then it draws nothing. */
|
|
2669
|
-
quads = 0;
|
|
2670
|
-
/** A host's foot inset this frame (I21): the veil lays a second quad, over the foot, in its one draw. */
|
|
2671
|
-
foot = 0;
|
|
2672
|
-
group = null;
|
|
2673
|
-
boundAssets = -1;
|
|
2674
|
-
last = null;
|
|
2675
|
-
// the accessories (K5a): one record per specimen, grown by doubling; uploaded only when their bytes moved
|
|
2676
|
-
acc = TrayAccessoryStruct.alloc(8);
|
|
2677
|
-
accBuf;
|
|
2678
|
-
accSent = new Uint8Array(0);
|
|
2679
|
-
accCount = 0;
|
|
2680
|
-
constructor(device, mat, pipelines, layout) {
|
|
2681
|
-
this.device = device;
|
|
2682
|
-
this.mat = mat;
|
|
2683
|
-
[this.pipeline, this.accPipeline, this.veilPipeline] = pipelines;
|
|
2684
|
-
this.layout = layout;
|
|
2685
|
-
this.sampler = device.createSampler({ label: "tray/pegboard/noise", magFilter: "linear", minFilter: "linear", addressModeU: "repeat", addressModeV: "repeat" });
|
|
2686
|
-
this.trayBuf = uniformBuffer(device, TrayUniforms.size, "tray/pegboard/uniforms");
|
|
2687
|
-
this.lightBuf = uniformBuffer(device, MatUniforms.size, "tray/pegboard/light");
|
|
2688
|
-
this.accBuf = storageBuffer(device, TrayAccessoryStruct.size * 8, "tray/pegboard/accessories");
|
|
2689
|
-
this.hash = device.createTexture({ label: "tray/pegboard/hash", size: [HASH_SIZE, HASH_SIZE], format: "rgba8unorm", usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST });
|
|
2690
|
-
device.queue.writeTexture({ texture: this.hash }, hashTexels(), { bytesPerRow: HASH_SIZE * 4 }, [HASH_SIZE, HASH_SIZE]);
|
|
2691
|
-
}
|
|
2692
|
-
/** The pipeline on `format`, sampling `mat`'s blue noise (the root's: its assets are every slot's). */
|
|
2693
|
-
static async create(device, format, src, mat) {
|
|
2694
|
-
const module = await compile(device, compose(src));
|
|
2695
|
-
const layout = bindLayout(device, [
|
|
2696
|
-
{ binding: 0, stages: ["fragment"], buffer: "uniform" },
|
|
2697
|
-
{ binding: 1, stages: ["vertex", "fragment"], buffer: "uniform" },
|
|
2698
|
-
{ binding: 2, stages: ["fragment"], texture: "float" },
|
|
2699
|
-
{ binding: 3, stages: ["fragment"], sampler: "filtering" },
|
|
2700
|
-
{ binding: 4, stages: ["fragment"], texture: "float" },
|
|
2701
|
-
{ binding: 5, stages: ["vertex", "fragment"], buffer: "read-only-storage" }
|
|
2702
|
-
], "tray/pegboard");
|
|
2703
|
-
const pl = device.createPipelineLayout({ label: "tray/pegboard", bindGroupLayouts: [layout] });
|
|
2704
|
-
const pipelines = await Promise.all([
|
|
2705
|
-
renderPipeline(device, { label: "tray/pegboard", layout: pl, module, format, blend: BLEND_PREMUL5 }),
|
|
2706
|
-
renderPipeline(device, { label: "tray/pegboard/accessories", layout: pl, module, format, blend: BLEND_PREMUL5, fragment: "fs_accessory" }),
|
|
2707
|
-
renderPipeline(device, { label: "tray/pegboard/veil", layout: pl, module, format, blend: BLEND_PREMUL5, vertex: "vs_veil", fragment: "fs_veil" })
|
|
2708
|
-
]);
|
|
2709
|
-
return new _TrayPass(device, mat, pipelines, layout);
|
|
2710
|
-
}
|
|
2711
|
-
/**
|
|
2712
|
-
* Lay the drawer out for this frame and upload what changed (before the frame's pass begins): the view, the theme's light, the
|
|
2713
|
-
* root grid's grade, the frame's noise offset. Returns the quads that will draw: one (the view whole while it dims) — none while
|
|
2714
|
-
* the drawer is shut (p 0: it and its shadows lie below the view — nothing is uploaded, nothing drawn; design-018 §5).
|
|
2715
|
-
*/
|
|
2716
|
-
prepare(view, theme, grid, frame, inputs) {
|
|
2717
|
-
const P = DRAWER.pitch;
|
|
2718
|
-
const p = Math.min(Math.max(inputs.p, 0), 1);
|
|
2719
|
-
const rect = drawerRect(view.width, view.height, p);
|
|
2720
|
-
const { rowBase, frac } = carry(inputs.scroll, P);
|
|
2721
|
-
const foot = inputs.foot !== void 0 && inputs.foot > 0 ? inputs.foot : 0;
|
|
2722
|
-
this.foot = foot;
|
|
2723
|
-
if (p <= 0) {
|
|
2724
|
-
this.last = { rect, rowBase, frac, dim: 0, accessories: [], ...foot > 0 ? { foot } : {} };
|
|
2725
|
-
this.quads = 0;
|
|
2726
|
-
return 0;
|
|
2727
|
-
}
|
|
2728
|
-
const L = TRAY_LOOK.lamp;
|
|
2729
|
-
const g = Math.hypot(L[0], L[1]) || 1;
|
|
2730
|
-
const S = DRAWER.shadow.lamp;
|
|
2731
|
-
const Rm = DRAWER.shadow.room;
|
|
2732
|
-
const fp = 1 / (P * view.dpr);
|
|
2733
|
-
const dim = (DRAWER.dim.day + (DRAWER.dim.night - DRAWER.dim.day) * Math.min(Math.max(theme.matLight.night, 0), 1)) * p;
|
|
2734
|
-
const T = TRAY_LOOK;
|
|
2735
|
-
const values = {
|
|
2736
|
-
view: [view.width, view.height, view.dpr, P],
|
|
2737
|
-
rect: [rect.x, rect.y, rect.w, rect.h],
|
|
2738
|
-
rowBase,
|
|
2739
|
-
frac,
|
|
2740
|
-
fp,
|
|
2741
|
-
dim,
|
|
2742
|
-
shape: [DRAWER.radius, DRAWER.arris, DRAWER.inner.alpha, DRAWER.inner.width],
|
|
2743
|
-
hole: [PEG.holeR, PEG.holeHalf, PEG.rimK, PEG.border],
|
|
2744
|
-
depth: [PEG.thick, PEG.gap, PEG.colPhase, PEG.rowPhase],
|
|
2745
|
-
lamp: [L[0], L[1], L[2], T.lampSize],
|
|
2746
|
-
room: [Rm.sigma, Rm.alpha, 0, 0],
|
|
2747
|
-
shadow: [S.sigma, S.alpha, -L[0] / g * S.push, -L[1] / g * S.push],
|
|
2748
|
-
face: [...T.face, 0],
|
|
2749
|
-
faceSrgb: [...T.faceSrgb, 0],
|
|
2750
|
-
edge: [...T.edge, 0],
|
|
2751
|
-
cavity: [T.cavity.edge, T.cavity.heart, T.cavity.width, 0],
|
|
2752
|
-
keepFace: [keep(fp, 6 * Math.sqrt(10)), 0, keep(fp, 85), keep(fp, 190)],
|
|
2753
|
-
// the flecks fade by their cell; their strokes are anti-aliased in the shader (tray.wgsl `peg_flecks`)
|
|
2754
|
-
keepFine: [keep(fp, 210), keep(fp, 42), keep(fp, 105), 0],
|
|
2755
|
-
keepEdge: [keep(fp, 9), keep(fp, 18), keep(fp, 36), 0],
|
|
2756
|
-
accessory: [...T.accessory, T.accessoryShadow],
|
|
2757
|
-
fade: [DRAWER.fade, DRAWER.header, foot, 0]
|
|
2758
|
-
};
|
|
2759
|
-
this.tray.set(values);
|
|
2760
|
-
const gobo = grid.mat.gobo;
|
|
2761
|
-
const noise = frame?.noise ?? [0, 0];
|
|
2762
|
-
const light = {
|
|
2763
|
-
gobo: [gobo.opacity, gobo.blurTexels, gobo.shadeMix, gobo.darkFloor],
|
|
2764
|
-
grade: [gobo.saturate, 0, 0, 0],
|
|
2765
|
-
noise: [noise[0], noise[1], 1 / NOISE_SIZE, 0],
|
|
2766
|
-
...lightValues(theme.matLight)
|
|
2767
|
-
};
|
|
2768
|
-
this.light.set(light);
|
|
2769
|
-
this.upload(this.trayBuf, this.tray.view(), this.sentTray);
|
|
2770
|
-
this.upload(this.lightBuf, this.light.view(), this.sentLight);
|
|
2771
|
-
this.sent = true;
|
|
2772
|
-
const accessories = (inputs.specimens ?? []).map(accessoryOf);
|
|
2773
|
-
this.layAccessories(accessories);
|
|
2774
|
-
this.last = { rect, rowBase, frac, dim, accessories, ...foot > 0 ? { foot } : {} };
|
|
2775
|
-
this.quads = 1;
|
|
2776
|
-
return 1;
|
|
2777
|
-
}
|
|
2778
|
-
/** The accessories' records to the GPU — grown by doubling, written only when their bytes moved (a drawer at rest costs no write). */
|
|
2779
|
-
layAccessories(list) {
|
|
2780
|
-
if (list.length > this.acc.count) {
|
|
2781
|
-
let n = this.acc.count;
|
|
2782
|
-
while (n < list.length) n *= 2;
|
|
2783
|
-
this.acc = TrayAccessoryStruct.alloc(n);
|
|
2784
|
-
this.accBuf.destroy();
|
|
2785
|
-
this.accBuf = storageBuffer(this.device, TrayAccessoryStruct.size * n, "tray/pegboard/accessories");
|
|
2786
|
-
this.accSent = new Uint8Array(0);
|
|
2787
|
-
this.group = null;
|
|
2788
|
-
}
|
|
2789
|
-
for (let i = 0; i < list.length; i++) this.acc.set(list[i], i);
|
|
2790
|
-
this.accCount = list.length;
|
|
2791
|
-
if (list.length === 0) return;
|
|
2792
|
-
const bytes = this.acc.view(list.length);
|
|
2793
|
-
let same = bytes.length === this.accSent.length;
|
|
2794
|
-
for (let i = 0; same && i < bytes.length; i++) if (bytes[i] !== this.accSent[i]) same = false;
|
|
2795
|
-
if (same) return;
|
|
2796
|
-
this.accSent = bytes.slice();
|
|
2797
|
-
this.device.queue.writeBuffer(this.accBuf, 0, bytes);
|
|
2798
|
-
}
|
|
2799
|
-
/** A block to the GPU only when its bytes moved since the last upload (a drawer at rest costs no write). */
|
|
2800
|
-
upload(buf, bytes, sent) {
|
|
2801
|
-
let same = this.sent;
|
|
2802
|
-
for (let i = 0; same && i < bytes.length; i++) if (bytes[i] !== sent[i]) same = false;
|
|
2803
|
-
if (same) return;
|
|
2804
|
-
sent.set(bytes);
|
|
2805
|
-
this.device.queue.writeBuffer(buf, 0, bytes);
|
|
2806
|
-
}
|
|
2807
|
-
/** A pipeline and the group, bound (the group remade when the mat's assets or the accessories' buffer changed). */
|
|
2808
|
-
bind(pass, pipeline) {
|
|
2809
|
-
if (this.group === null || this.boundAssets !== this.mat.assetVersion) {
|
|
2810
|
-
this.group = bindGroup(this.device, this.layout, [this.lightBuf, this.trayBuf, this.mat.noiseTexture.createView(), this.sampler, this.hash.createView(), this.accBuf], "tray/pegboard");
|
|
2811
|
-
this.boundAssets = this.mat.assetVersion;
|
|
2812
|
-
}
|
|
2813
|
-
pass.setPipeline(pipeline);
|
|
2814
|
-
pass.setBindGroup(0, this.group);
|
|
2815
|
-
}
|
|
2816
|
-
/**
|
|
2817
|
-
* The drawer UNDER its specimens into the open pass — over everything drawn so far (the caller left the scissor on the whole view):
|
|
2818
|
-
* the dim, the drawer's shadows, the board to its edge; then each specimen's accessory with its shadow on the board (K5a).
|
|
2819
|
-
*/
|
|
2820
|
-
draw(pass) {
|
|
2821
|
-
if (this.quads === 0) return;
|
|
2822
|
-
pass.pushDebugGroup("tray/pegboard");
|
|
2823
|
-
this.bind(pass, this.pipeline);
|
|
2824
|
-
pass.draw(6, 1, 0, 0);
|
|
2825
|
-
if (this.accCount > 0) {
|
|
2826
|
-
pass.setPipeline(this.accPipeline);
|
|
2827
|
-
pass.draw(6, this.accCount, 0, 1);
|
|
2828
|
-
}
|
|
2829
|
-
pass.popDebugGroup();
|
|
2830
|
-
}
|
|
2831
|
-
/**
|
|
2832
|
-
* THE VEIL (design-018 rev 5) — LAST, over everything the drawer holds (the caller left the scissor on the whole view): the plain board
|
|
2833
|
-
* whole in the header and fading out over its ramp, so what hangs there and the holes behind it fade into the board together — a
|
|
2834
|
-
* specimen never turns see-through over a hole. One quad — and with a host's foot (I21) a second, over the foot, in the same draw.
|
|
2835
|
-
*/
|
|
2836
|
-
drawVeil(pass) {
|
|
2837
|
-
if (this.quads === 0) return;
|
|
2838
|
-
pass.pushDebugGroup("tray/pegboard/veil");
|
|
2839
|
-
this.bind(pass, this.veilPipeline);
|
|
2840
|
-
pass.draw(this.foot > 0 ? 12 : 6, 1, 0, 0);
|
|
2841
|
-
pass.popDebugGroup();
|
|
2842
|
-
}
|
|
2843
|
-
/** What the last prepare laid (a rig's witness). */
|
|
2844
|
-
get laid() {
|
|
2845
|
-
return this.last;
|
|
2846
|
-
}
|
|
2847
|
-
dispose() {
|
|
2848
|
-
this.trayBuf.destroy();
|
|
2849
|
-
this.lightBuf.destroy();
|
|
2850
|
-
this.accBuf.destroy();
|
|
2851
|
-
this.hash.destroy();
|
|
2852
|
-
}
|
|
2853
|
-
};
|
|
2854
|
-
|
|
2855
2821
|
// ../desk/src/ground.ts
|
|
2856
2822
|
function closeScope(b, kinds) {
|
|
2857
2823
|
b.device.popErrorScope().then((e) => {
|
|
@@ -3021,10 +2987,11 @@ var SlotPool = class {
|
|
|
3021
2987
|
};
|
|
3022
2988
|
function drawSlot(pass, size, dpr, slot) {
|
|
3023
2989
|
if (!visible(slot.present)) return false;
|
|
3024
|
-
const
|
|
2990
|
+
const scissor = scissorOf(slot.present, dpr, size);
|
|
2991
|
+
const [x, y, w, h] = scissor;
|
|
3025
2992
|
if (w === 0 || h === 0) return false;
|
|
3026
2993
|
pass.setScissorRect(x, y, w, h);
|
|
3027
|
-
if (slot.bare !== true) slot.mat.
|
|
2994
|
+
if (slot.bare !== true) slot.mat.drawSurface(pass, scissor);
|
|
3028
2995
|
if (slot.underlays?.length) {
|
|
3029
2996
|
for (const u of slot.underlays) u.draw(pass);
|
|
3030
2997
|
pass.setScissorRect(x, y, w, h);
|
|
@@ -3123,6 +3090,7 @@ function drawSlot(pass, size, dpr, slot) {
|
|
|
3123
3090
|
}
|
|
3124
3091
|
}
|
|
3125
3092
|
for (const children of insides.values()) for (const child of children) inside(child);
|
|
3093
|
+
if (slot.bare !== true) slot.mat.drawRulers(pass, scissor);
|
|
3126
3094
|
return true;
|
|
3127
3095
|
}
|
|
3128
3096
|
function drawFrame(pass, size, dpr, incoming, outgoing) {
|
|
@@ -3560,7 +3528,7 @@ var Ground = class _Ground {
|
|
|
3560
3528
|
};
|
|
3561
3529
|
function tagsOf(tray) {
|
|
3562
3530
|
const P = DRAWER.pitch;
|
|
3563
|
-
return (tray?.specimens ?? []).map((f) => ({ label: f.label, x: (f.screen.x0 + f.screen.x1) / 2, y: f.screen.y1 +
|
|
3531
|
+
return (tray?.specimens ?? []).map((f) => ({ label: f.label, x: (f.screen.x0 + f.screen.x1) / 2, y: f.screen.y1 + 0.45 * P }));
|
|
3564
3532
|
}
|
|
3565
3533
|
function renderHeldFrame(device, hold, root, pool, grid, into, inputs, held, cache, label = "hold") {
|
|
3566
3534
|
const size = into.size();
|
|
@@ -5714,6 +5682,7 @@ function createPickSource(builder, opts = {}) {
|
|
|
5714
5682
|
var EPS2 = 1e-4;
|
|
5715
5683
|
function createTrayFlux(opts = {}) {
|
|
5716
5684
|
const foot = opts.foot ?? 0;
|
|
5685
|
+
const footFade = opts.footFade ?? DRAWER.fade;
|
|
5717
5686
|
let facts = null;
|
|
5718
5687
|
let p = 0;
|
|
5719
5688
|
let from = 0;
|
|
@@ -5788,7 +5757,7 @@ function createTrayFlux(opts = {}) {
|
|
|
5788
5757
|
const pb = P?.band ?? shown;
|
|
5789
5758
|
const rect = drawerRect(vw, vh, pp);
|
|
5790
5759
|
drawn = { x: rect.x, y: rect.y, w: rect.w, h: rect.h, p: pp, max: scrollRange(vw, vh, f.bottom ?? 0, foot), pitch: DRAWER.pitch, scroll: f.scroll + pb, face: rect.h, head: DRAWER.arris + DRAWER.header, ...foot > 0 ? { foot } : {} };
|
|
5791
|
-
return { p: pp, scroll: f.scroll + pb, ...foot > 0 ? { foot } : {} };
|
|
5760
|
+
return { p: pp, scroll: f.scroll + pb, ...foot > 0 ? { foot, footFade } : {} };
|
|
5792
5761
|
},
|
|
5793
5762
|
live: () => moving && pinned === null,
|
|
5794
5763
|
frame: () => drawn,
|
|
@@ -5839,7 +5808,7 @@ function createDeskReflector(opts) {
|
|
|
5839
5808
|
let gridGen = 0;
|
|
5840
5809
|
let pinGen = 0;
|
|
5841
5810
|
const wakes = { world: 0, removed: 0, reset: 0, order: 0, hover: 0, marks: 0, camera: 0, viewport: 0, nav: 0, theme: 0, grid: 0, pin: 0, ambient: 0, live: 0, ink: 0, tray: 0 };
|
|
5842
|
-
const tray = createTrayFlux(opts.tray
|
|
5811
|
+
const tray = createTrayFlux(opts.tray);
|
|
5843
5812
|
let drawnSpecimens = [];
|
|
5844
5813
|
const carry2 = createTrayCarry();
|
|
5845
5814
|
let drawnCarried = [];
|
|
@@ -7613,6 +7582,7 @@ function deskLayer(opts) {
|
|
|
7613
7582
|
looksOf(objectKinds, opts.palette, opts.theme);
|
|
7614
7583
|
const hold = holdOf(opts.hold);
|
|
7615
7584
|
const foot = hostNumber("tray.foot", opts.tray?.foot);
|
|
7585
|
+
const footFade = hostNumber("tray.footFade", opts.tray?.footFade);
|
|
7616
7586
|
const cursors = opts.cursors !== false;
|
|
7617
7587
|
const canvas = doc.createElement("canvas");
|
|
7618
7588
|
canvas.style.position = "absolute";
|
|
@@ -7843,7 +7813,7 @@ function deskLayer(opts) {
|
|
|
7843
7813
|
grid,
|
|
7844
7814
|
locals,
|
|
7845
7815
|
...opts.maxDpr !== void 0 ? { maxDpr: opts.maxDpr } : {},
|
|
7846
|
-
...foot !== void 0 ? { tray: { foot } } : {},
|
|
7816
|
+
...foot !== void 0 || footFade !== void 0 ? { tray: { ...foot !== void 0 ? { foot } : {}, ...footFade !== void 0 ? { footFade } : {} } } : {},
|
|
7847
7817
|
...opts.name !== void 0 ? { name: opts.name } : {},
|
|
7848
7818
|
// a frame asked for outside the flush — a pin, an ink landing, the ground arriving, a theme: a sleeping loop wakes (K7a)
|
|
7849
7819
|
onWake: (reason) => frame?.wake(`desk:${reason}`)
|
|
@@ -8369,8 +8339,8 @@ function deskLayer(opts) {
|
|
|
8369
8339
|
...compose2.tray.state(),
|
|
8370
8340
|
frame: compose2.tray.frame(),
|
|
8371
8341
|
laid: ground?.tray?.laid ?? null,
|
|
8372
|
-
// K5a: the specimens as the last frame drew them — each on screen,
|
|
8373
|
-
specimens: compose2.traySpecimens().map((f) => ({ type: f.type, kind: f.kind, label: f.label,
|
|
8342
|
+
// K5a: the specimens as the last frame drew them — each on screen, the scale its kind drew it at — its tags, its slots
|
|
8343
|
+
specimens: compose2.traySpecimens().map((f) => ({ type: f.type, kind: f.kind, label: f.label, screen: f.screen, zoom: f.view.zoom, object: f.object })),
|
|
8374
8344
|
tags: ground?.marks?.tagsLaid.length ?? 0,
|
|
8375
8345
|
slots: ground?.traySlots?.size ?? 0,
|
|
8376
8346
|
// K5b: what the tray carried last frame — the copy, a ghost growing or flying home — and the ghosts it drew for the desk
|
|
@@ -9112,4 +9082,4 @@ export {
|
|
|
9112
9082
|
STILL_PALETTE,
|
|
9113
9083
|
createStill
|
|
9114
9084
|
};
|
|
9115
|
-
//# sourceMappingURL=chunk-
|
|
9085
|
+
//# sourceMappingURL=chunk-M2HUDENL.js.map
|