@vibecook/ice 0.15.0 → 0.16.0-portals.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.
Files changed (48) hide show
  1. package/dist/{chunk-644DO6PN.js → chunk-6VY7I6VA.js} +2 -2
  2. package/dist/chunk-6VY7I6VA.js.map +1 -0
  3. package/dist/{chunk-US7WJNR6.js → chunk-NB4ALBIY.js} +349 -66
  4. package/dist/chunk-NB4ALBIY.js.map +1 -0
  5. package/dist/{chunk-SPG45AVV.js → chunk-SHU3HVMF.js} +72 -12
  6. package/dist/chunk-SHU3HVMF.js.map +1 -0
  7. package/dist/{chunk-A6PUTIL7.js → chunk-SUNUMQLC.js} +494 -57
  8. package/dist/chunk-SUNUMQLC.js.map +1 -0
  9. package/dist/desk-kit.js +14 -2
  10. package/dist/desk-objects.js +3 -3
  11. package/dist/desk.js +15 -3
  12. package/dist/devtools.js +1 -1
  13. package/dist/dom.js +2 -2
  14. package/dist/index.js +5 -3
  15. package/dist/react.js +20 -5
  16. package/dist/react.js.map +1 -1
  17. package/dist/types/packages/core/src/catalog/desk.d.ts +36 -1
  18. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +0 -10
  19. package/dist/types/packages/core/src/systems/held.d.ts +10 -3
  20. package/dist/types/packages/core/src/systems/l4-cursor.d.ts +9 -2
  21. package/dist/types/packages/core/src/widget/define-widget.d.ts +16 -22
  22. package/dist/types/packages/desk/src/card/card.d.ts +7 -2
  23. package/dist/types/packages/desk/src/encoder-guard.d.ts +16 -0
  24. package/dist/types/packages/desk/src/engine/budget.d.ts +4 -2
  25. package/dist/types/packages/desk/src/ground.d.ts +46 -0
  26. package/dist/types/packages/desk/src/hold/told.d.ts +15 -0
  27. package/dist/types/packages/desk/src/host/layer.d.ts +8 -2
  28. package/dist/types/packages/desk/src/index.d.ts +2 -1
  29. package/dist/types/packages/desk/src/kind.d.ts +5 -1
  30. package/dist/types/packages/desk/src/kinds/world.d.ts +93 -2
  31. package/dist/types/packages/desk/src/kit/editor.d.ts +9 -1
  32. package/dist/types/packages/desk/src/kit/index.d.ts +1 -0
  33. package/dist/types/packages/desk/src/kit/live.d.ts +260 -0
  34. package/dist/types/packages/desk/src/kit/mips.d.ts +11 -0
  35. package/dist/types/packages/desk/src/kit/wgsl.d.ts +5 -2
  36. package/dist/types/packages/desk/src/missing/slots.d.ts +9 -1
  37. package/dist/types/packages/desk/src/object.d.ts +1 -1
  38. package/dist/types/packages/desk/src/still.d.ts +3 -1
  39. package/dist/types/packages/dom/src/desk-host.d.ts +3 -2
  40. package/dist/types/packages/dom/src/input-ownership.d.ts +5 -3
  41. package/dist/types/packages/dom/src/widget-focus.d.ts +2 -2
  42. package/dist/types/packages/objects/src/minimat/layout.d.ts +1 -1
  43. package/dist/types/packages/react/src/keymap.d.ts +9 -3
  44. package/package.json +1 -1
  45. package/dist/chunk-644DO6PN.js.map +0 -1
  46. package/dist/chunk-A6PUTIL7.js.map +0 -1
  47. package/dist/chunk-SPG45AVV.js.map +0 -1
  48. package/dist/chunk-US7WJNR6.js.map +0 -1
@@ -12,7 +12,7 @@ import {
12
12
  defineQuery,
13
13
  field,
14
14
  init
15
- } from "./chunk-SPG45AVV.js";
15
+ } from "./chunk-SHU3HVMF.js";
16
16
 
17
17
  // ../desk/src/lattice/lod.ts
18
18
  var BASE_SPACING = 20;
@@ -759,7 +759,7 @@ var PIECES = {
759
759
  ruler: { file: "mat/ruler.wgsl" },
760
760
  book: { structs: [NbUniforms, NbBook], file: "kit/book.wgsl" }
761
761
  };
762
- var ALIASES = { lamp: "light", gobo: "light", night: "light", noise: "light" };
762
+ var ALIASES = { lamp: "light", gobo: "light", night: "light", noise: "light", mat: "light" };
763
763
  var KIT_WGSL_FILES = Object.fromEntries(
764
764
  Object.entries(PIECES).flatMap(([name, p]) => "file" in p ? [[name, p.file]] : [])
765
765
  );
@@ -1139,26 +1139,26 @@ var HOLD = {
1139
1139
  bar: { travelMs: 340, backMs: 200 }
1140
1140
  };
1141
1141
  var isNarrow = (vp) => vp.width < HOLD.narrow;
1142
- function readingTarget(extent, vp, spread = false, face = 0, reserves = HOLD) {
1142
+ function readingTarget(extent2, vp, spread = false, face = 0, reserves = HOLD) {
1143
1143
  const narrow = isNarrow(vp);
1144
1144
  const m = narrow ? HOLD.marginPhone : HOLD.margin;
1145
1145
  const top = narrow ? HOLD.topPhone : reserves.top;
1146
1146
  const boxW = Math.max(40, vp.width - 2 * m);
1147
1147
  const boxH = Math.max(40, vp.height - top - reserves.band);
1148
- let s = Math.min(boxW / extent.w, boxH / extent.h, HOLD.max);
1148
+ let s = Math.min(boxW / extent2.w, boxH / extent2.h, HOLD.max);
1149
1149
  let single = false;
1150
1150
  if (spread && narrow && vp.width < vp.height * 0.85) {
1151
1151
  const own = Math.max(40, vp.height - top - HOLD.band);
1152
- const s0 = Math.min(boxW / extent.w, own / extent.h, HOLD.max);
1153
- if (Math.min(boxW / (extent.w / 2), own / extent.h, HOLD.max) > s0 * 1.3) {
1154
- s = Math.min(boxW / (extent.w / 2), boxH / extent.h, HOLD.max);
1152
+ const s0 = Math.min(boxW / extent2.w, own / extent2.h, HOLD.max);
1153
+ if (Math.min(boxW / (extent2.w / 2), own / extent2.h, HOLD.max) > s0 * 1.3) {
1154
+ s = Math.min(boxW / (extent2.w / 2), boxH / extent2.h, HOLD.max);
1155
1155
  single = true;
1156
1156
  }
1157
1157
  }
1158
- return { cx: vp.width / 2 - (single ? extent.w / 4 * s * (1 - 2 * face) : 0), cy: top + boxH / 2, s, single };
1158
+ return { cx: vp.width / 2 - (single ? extent2.w / 4 * s * (1 - 2 * face) : 0), cy: top + boxH / 2, s, single };
1159
1159
  }
1160
- function homePose(extent, angle, cam) {
1161
- return { cx: (extent.cx - cam.x) * cam.zoom, cy: (extent.cy - cam.y) * cam.zoom, s: cam.zoom, angle };
1160
+ function homePose(extent2, angle, cam) {
1161
+ return { cx: (extent2.cx - cam.x) * cam.zoom, cy: (extent2.cy - cam.y) * cam.zoom, s: cam.zoom, angle };
1162
1162
  }
1163
1163
  var HELD_USER_REST = { zoom: 1, panX: 0, panY: 0 };
1164
1164
  function heldPose(home, target, user, e) {
@@ -1188,11 +1188,11 @@ function heldFocus(e, vp, theme) {
1188
1188
  light: night ? mixLight(theme.matLight, DAY_LIGHT, e) : theme.matLight
1189
1189
  };
1190
1190
  }
1191
- function heldCamera(pose, rect, extent, deskZoom, eye, vp) {
1191
+ function heldCamera(pose, rect, extent2, deskZoom, eye, vp) {
1192
1192
  const zoom = eye ? Math.min(deskZoom, pose.s) : pose.s;
1193
1193
  const grow = pose.s / zoom;
1194
- const ox = rect.cx - extent.cx;
1195
- const oy = rect.cy - extent.cy;
1194
+ const ox = rect.cx - extent2.cx;
1195
+ const oy = rect.cy - extent2.cy;
1196
1196
  const c = Math.cos(pose.angle);
1197
1197
  const sn = Math.sin(pose.angle);
1198
1198
  const sx = pose.cx + (c * ox - sn * oy) * pose.s;
@@ -1202,11 +1202,11 @@ function heldCamera(pose, rect, extent, deskZoom, eye, vp) {
1202
1202
  const ey = rect.cy - (sy - vp.height / 2) / (grow * zoom);
1203
1203
  return { cam: { x: ex - vp.width / (2 * zoom), y: ey - vp.height / (2 * zoom), zoom }, grow };
1204
1204
  }
1205
- function heldFrame(pose, extent, single, face = 0) {
1206
- if (!single) return { cx: pose.cx, cy: pose.cy, hx: extent.w / 2 * pose.s, hy: extent.h / 2 * pose.s, s: pose.s };
1207
- const half = extent.w / 4 * pose.s;
1205
+ function heldFrame(pose, extent2, single, face = 0) {
1206
+ if (!single) return { cx: pose.cx, cy: pose.cy, hx: extent2.w / 2 * pose.s, hy: extent2.h / 2 * pose.s, s: pose.s };
1207
+ const half = extent2.w / 4 * pose.s;
1208
1208
  const q = half * (1 - 2 * face);
1209
- return { cx: pose.cx + q * Math.cos(pose.angle), cy: pose.cy + q * Math.sin(pose.angle), hx: half, hy: extent.h / 2 * pose.s, s: pose.s };
1209
+ return { cx: pose.cx + q * Math.cos(pose.angle), cy: pose.cy + q * Math.sin(pose.angle), hx: half, hy: extent2.h / 2 * pose.s, s: pose.s };
1210
1210
  }
1211
1211
  var focusOf = (e, vp) => ({ blur: (isNarrow(vp) ? HOLD.blurPhone : HOLD.blur) * e, dim: HOLD.dim * e });
1212
1212
 
@@ -1675,6 +1675,329 @@ function eyeValues(e, reach = 900) {
1675
1675
  return { eye: [e.ex, e.ey, e.h, e.zoom], view: [e.vw, e.vh, near, far] };
1676
1676
  }
1677
1677
 
1678
+ // ../desk/src/kit/mips.ts
1679
+ var WGSL2 = (
1680
+ /* wgsl */
1681
+ `
1682
+ @group(0) @binding(0) var src: texture_2d<f32>;
1683
+ @group(0) @binding(1) var samp: sampler;
1684
+ struct VO { @builtin(position) pos: vec4f, @location(0) uv: vec2f }
1685
+ @vertex fn vs(@builtin(vertex_index) i: u32) -> VO {
1686
+ let p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0))[i];
1687
+ var o: VO; o.pos = vec4f(p, 0.0, 1.0); o.uv = vec2f(0.5 * p.x + 0.5, 0.5 - 0.5 * p.y); return o;
1688
+ }
1689
+ @fragment fn fs(v: VO) -> @location(0) vec4f { return textureSampleLevel(src, samp, v.uv, 0.0); }
1690
+ `
1691
+ );
1692
+ var cache = /* @__PURE__ */ new WeakMap();
1693
+ var mipCount = (w, h) => Math.floor(Math.log2(Math.max(w, h, 1))) + 1;
1694
+ function pipeOf(device, format) {
1695
+ let c = cache.get(device);
1696
+ if (!c) {
1697
+ c = { module: device.createShaderModule({ label: "photo/mips", code: WGSL2 }), sampler: device.createSampler({ minFilter: "linear", magFilter: "linear" }), pipes: /* @__PURE__ */ new Map() };
1698
+ cache.set(device, c);
1699
+ }
1700
+ let pipe = c.pipes.get(format);
1701
+ if (!pipe) {
1702
+ pipe = device.createRenderPipeline({
1703
+ label: `photo/mips ${format}`,
1704
+ layout: "auto",
1705
+ vertex: { module: c.module, entryPoint: "vs" },
1706
+ fragment: { module: c.module, entryPoint: "fs", targets: [{ format }] }
1707
+ });
1708
+ c.pipes.set(format, pipe);
1709
+ }
1710
+ return { pipe, sampler: c.sampler };
1711
+ }
1712
+ function generateMips(device, texture) {
1713
+ const { pipe, sampler } = pipeOf(device, texture.format);
1714
+ const encoder = device.createCommandEncoder({ label: "photo/mips" });
1715
+ for (let level = 1; level < texture.mipLevelCount; level++) {
1716
+ const src = texture.createView({ baseMipLevel: level - 1, mipLevelCount: 1 });
1717
+ const dst = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });
1718
+ const group = device.createBindGroup({ layout: pipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: src }, { binding: 1, resource: sampler }] });
1719
+ const pass = encoder.beginRenderPass({ colorAttachments: [{ view: dst, loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 0 } }] });
1720
+ pass.setPipeline(pipe);
1721
+ pass.setBindGroup(0, group);
1722
+ pass.draw(3);
1723
+ pass.end();
1724
+ }
1725
+ device.queue.submit([encoder.finish()]);
1726
+ }
1727
+ var chains = /* @__PURE__ */ new WeakMap();
1728
+ function mipsInto(device, encoder, texture, from, to) {
1729
+ const first = Math.max(1, Math.floor(from));
1730
+ const last = Math.min(Math.floor(to), texture.mipLevelCount - 1);
1731
+ if (last < first) return;
1732
+ let chain = chains.get(texture);
1733
+ if (chain === void 0) {
1734
+ const { pipe, sampler } = pipeOf(device, texture.format);
1735
+ chain = { pipe, sampler, views: [], groups: [] };
1736
+ chains.set(texture, chain);
1737
+ }
1738
+ const c = chain;
1739
+ const view = (level) => {
1740
+ let v = c.views[level];
1741
+ if (v === void 0) {
1742
+ v = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });
1743
+ c.views[level] = v;
1744
+ }
1745
+ return v;
1746
+ };
1747
+ for (let level = first; level <= last; level++) {
1748
+ let group = c.groups[level];
1749
+ if (group === void 0) {
1750
+ group = device.createBindGroup({ layout: c.pipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: view(level - 1) }, { binding: 1, resource: c.sampler }] });
1751
+ c.groups[level] = group;
1752
+ }
1753
+ const pass = encoder.beginRenderPass({ colorAttachments: [{ view: view(level), loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 0 } }] });
1754
+ pass.setPipeline(c.pipe);
1755
+ pass.setBindGroup(0, group);
1756
+ pass.draw(3);
1757
+ pass.end();
1758
+ }
1759
+ }
1760
+
1761
+ // ../desk/src/kit/live.ts
1762
+ function extent(what, v) {
1763
+ if (typeof v !== "number" || !Number.isFinite(v) || v < 1) throw new Error(`createLiveTexture: ${what} must be a finite number \u2265 1 (got ${String(v)})`);
1764
+ return Math.floor(v);
1765
+ }
1766
+ function logicalOf(l) {
1767
+ if (l === void 0) return null;
1768
+ const ok = (v) => typeof v === "number" && Number.isFinite(v) && v > 0;
1769
+ if (!Array.isArray(l) || !ok(l[0]) || !ok(l[1])) throw new Error(`LiveWriter: a logical size is [width, height], each finite and > 0 (got ${JSON.stringify(l)})`);
1770
+ return [l[0], l[1]];
1771
+ }
1772
+ var isVideoFrame = (s) => typeof s.close === "function" && typeof s.codedWidth === "number";
1773
+ function wholeOf(s) {
1774
+ if (isVideoFrame(s)) return { x: 0, y: 0, width: s.displayWidth, height: s.displayHeight };
1775
+ const c = s;
1776
+ return { x: 0, y: 0, width: c.width, height: c.height };
1777
+ }
1778
+ function createLiveTexture(device, o) {
1779
+ const format = o.format ?? "rgba8unorm-srgb";
1780
+ if (format !== "rgba8unorm-srgb" && format !== "rgba8unorm") throw new Error(`createLiveTexture: format must be "rgba8unorm-srgb" or "rgba8unorm" (got ${String(format)})`);
1781
+ if (typeof o.label !== "string") throw new Error("createLiveTexture: `label` is required \u2014 the caller's, `<kind>/live <key>` by convention");
1782
+ const chain = o.mips !== false;
1783
+ let width = extent("width", o.width);
1784
+ let height = extent("height", o.height);
1785
+ const make = (w, h) => device.createTexture({
1786
+ label: o.label,
1787
+ size: [w, h],
1788
+ format,
1789
+ mipLevelCount: chain ? mipCount(w, h) : 1,
1790
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT
1791
+ });
1792
+ let texture = make(width, height);
1793
+ let view = null;
1794
+ let revision = 0;
1795
+ let epoch = 0;
1796
+ let mipped = { epoch: -1, revision: -1, depth: 0 };
1797
+ let logical = null;
1798
+ let gone = false;
1799
+ const sized = (w, h) => {
1800
+ if (w === width && h === height) return;
1801
+ logical = null;
1802
+ texture.destroy();
1803
+ width = w;
1804
+ height = h;
1805
+ texture = make(w, h);
1806
+ view = null;
1807
+ epoch += 1;
1808
+ };
1809
+ const face = {
1810
+ get width() {
1811
+ return width;
1812
+ },
1813
+ get height() {
1814
+ return height;
1815
+ },
1816
+ format,
1817
+ get revision() {
1818
+ return revision;
1819
+ },
1820
+ get epoch() {
1821
+ return epoch;
1822
+ },
1823
+ view() {
1824
+ if (view === null) view = texture.createView();
1825
+ return view;
1826
+ },
1827
+ prepare(encoder, upTo) {
1828
+ if (gone || revision === 0) return;
1829
+ if (mipped.epoch !== epoch || mipped.revision !== revision) mipped = { epoch, revision, depth: 0 };
1830
+ const to = Math.min(Math.floor(upTo), texture.mipLevelCount - 1);
1831
+ if (!(to > mipped.depth)) return;
1832
+ mipsInto(device, encoder, texture, mipped.depth + 1, to);
1833
+ mipped.depth = to;
1834
+ },
1835
+ get bytes() {
1836
+ return chainBytes(width, height, texture.mipLevelCount);
1837
+ },
1838
+ get logical() {
1839
+ return logical ?? [width, height];
1840
+ }
1841
+ };
1842
+ return {
1843
+ face,
1844
+ present(source, rect, size) {
1845
+ try {
1846
+ if (gone) return;
1847
+ const r = rect ?? wholeOf(source);
1848
+ const w = extent("the source's width", r.width);
1849
+ const h = extent("the source's height", r.height);
1850
+ const l = logicalOf(size);
1851
+ sized(w, h);
1852
+ device.queue.copyExternalImageToTexture({ source, origin: [r.x, r.y] }, { texture, premultipliedAlpha: false }, [w, h]);
1853
+ logical = l;
1854
+ revision += 1;
1855
+ } finally {
1856
+ if (isVideoFrame(source)) source.close();
1857
+ }
1858
+ },
1859
+ presentBytes(bytes, w0, h0, size) {
1860
+ if (gone) return;
1861
+ const w = extent("width", w0);
1862
+ const h = extent("height", h0);
1863
+ if (bytes.byteLength < w * h * 4) throw new Error(`LiveWriter.presentBytes: ${bytes.byteLength} bytes for ${w} \xD7 ${h} RGBA8 rows (${w * h * 4} wanted)`);
1864
+ const l = logicalOf(size);
1865
+ sized(w, h);
1866
+ device.queue.writeTexture({ texture }, bytes, { bytesPerRow: w * 4, rowsPerImage: h }, [w, h]);
1867
+ logical = l;
1868
+ revision += 1;
1869
+ },
1870
+ presentTexture(src, rect, size) {
1871
+ if (gone) return;
1872
+ const r = rect ?? { x: 0, y: 0, width: src.width, height: src.height };
1873
+ const w = extent("the source's width", r.width);
1874
+ const h = extent("the source's height", r.height);
1875
+ const l = logicalOf(size);
1876
+ sized(w, h);
1877
+ const encoder = device.createCommandEncoder({ label: `${o.label} present` });
1878
+ encoder.copyTextureToTexture({ texture: src, origin: [r.x, r.y] }, { texture }, [w, h]);
1879
+ device.queue.submit([encoder.finish()]);
1880
+ logical = l;
1881
+ revision += 1;
1882
+ },
1883
+ resize(w, h) {
1884
+ if (gone) return;
1885
+ sized(extent("width", w), extent("height", h));
1886
+ },
1887
+ destroy() {
1888
+ if (gone) return;
1889
+ gone = true;
1890
+ texture.destroy();
1891
+ }
1892
+ };
1893
+ }
1894
+ function liveDepth(face, px) {
1895
+ const ratio = Math.max(face.width / Math.max(px[0], 1e-6), face.height / Math.max(px[1], 1e-6));
1896
+ return ratio <= 1 ? 0 : Math.ceil(Math.log2(ratio) - 1e-9);
1897
+ }
1898
+ var LIVE = serviceKey("live");
1899
+ var UNSEEN = { seen: false, px: [0, 0], held: false };
1900
+ var sameSeen = (a, b) => a.seen === b.seen && a.held === b.held && a.px[0] === b.px[0] && a.px[1] === b.px[1];
1901
+ function createSight(frames) {
1902
+ const facts = /* @__PURE__ */ new Map();
1903
+ const fold = /* @__PURE__ */ new Map();
1904
+ let foldAt = -1;
1905
+ let stepped = -1;
1906
+ return {
1907
+ saw(e, slot, face) {
1908
+ if (slot.target === "copy" || slot.target === "capture") return;
1909
+ if (frames !== void 0) {
1910
+ const n = frames();
1911
+ if (n !== foldAt) {
1912
+ fold.clear();
1913
+ foldAt = n;
1914
+ }
1915
+ }
1916
+ const k = slot.view.zoom * slot.view.dpr;
1917
+ const glimpse = { w: Math.round(face.w * k), h: Math.round(face.h * k), held: slot.target === "hand" };
1918
+ const had = fold.get(e);
1919
+ if (had === void 0) {
1920
+ fold.set(e, glimpse);
1921
+ return;
1922
+ }
1923
+ if (glimpse.w * glimpse.h > had.w * had.h) {
1924
+ had.w = glimpse.w;
1925
+ had.h = glimpse.h;
1926
+ }
1927
+ had.held ||= glimpse.held;
1928
+ },
1929
+ step() {
1930
+ const moved = /* @__PURE__ */ new Map();
1931
+ if (frames !== void 0) {
1932
+ const n = frames();
1933
+ if (foldAt === n) {
1934
+ fold.clear();
1935
+ foldAt = -1;
1936
+ }
1937
+ if (n === stepped) return moved;
1938
+ stepped = n;
1939
+ if (foldAt !== n - 1) fold.clear();
1940
+ }
1941
+ for (const [e, g] of fold) {
1942
+ const now = { seen: true, px: [g.w, g.h], held: g.held };
1943
+ const was = facts.get(e);
1944
+ if (was === void 0 || !sameSeen(was, now)) {
1945
+ facts.set(e, now);
1946
+ moved.set(e, now);
1947
+ }
1948
+ }
1949
+ for (const [e, was] of facts) {
1950
+ if (fold.has(e) || !was.seen) continue;
1951
+ facts.set(e, UNSEEN);
1952
+ moved.set(e, UNSEEN);
1953
+ }
1954
+ if (frames === void 0) fold.clear();
1955
+ return moved;
1956
+ },
1957
+ of: (e) => facts.get(e),
1958
+ owed: () => frames !== void 0 && frames() !== stepped,
1959
+ forget(e) {
1960
+ facts.delete(e);
1961
+ fold.delete(e);
1962
+ }
1963
+ };
1964
+ }
1965
+ function stillLive(device, frames) {
1966
+ const open = /* @__PURE__ */ new Set();
1967
+ return {
1968
+ open(key, spec) {
1969
+ if (open.has(key)) throw new Error(`stillLive: the face "${key}" is open twice \u2014 one face per key per desk (design-019 \xA73.2)`);
1970
+ open.add(key);
1971
+ const still = typeof frames === "function" ? frames(key, spec) : frames[key];
1972
+ let writer;
1973
+ let taken = false;
1974
+ let closed = false;
1975
+ return {
1976
+ key,
1977
+ texture: () => writer?.face,
1978
+ take() {
1979
+ if (taken || closed || still === void 0) return false;
1980
+ taken = true;
1981
+ writer = createLiveTexture(device, { label: `live/still ${key}`, width: still.width, height: still.height });
1982
+ writer.presentBytes(still.bytes, still.width, still.height, still.logical);
1983
+ return true;
1984
+ },
1985
+ state: () => closed ? { is: "closed" } : still === void 0 ? { is: "starting" } : { is: "live" },
1986
+ info: () => still?.info ?? {},
1987
+ demand: () => {
1988
+ },
1989
+ close() {
1990
+ if (closed) return;
1991
+ closed = true;
1992
+ writer?.destroy();
1993
+ writer = void 0;
1994
+ open.delete(key);
1995
+ }
1996
+ };
1997
+ }
1998
+ };
1999
+ }
2000
+
1678
2001
  // ../desk/src/kit/mesh.ts
1679
2002
  var VERTEX_FLOATS = 16;
1680
2003
  var VERTEX_BYTES = VERTEX_FLOATS * 4;
@@ -1752,52 +2075,6 @@ var MeshWriter = class {
1752
2075
  }
1753
2076
  };
1754
2077
 
1755
- // ../desk/src/kit/mips.ts
1756
- var WGSL2 = (
1757
- /* wgsl */
1758
- `
1759
- @group(0) @binding(0) var src: texture_2d<f32>;
1760
- @group(0) @binding(1) var samp: sampler;
1761
- struct VO { @builtin(position) pos: vec4f, @location(0) uv: vec2f }
1762
- @vertex fn vs(@builtin(vertex_index) i: u32) -> VO {
1763
- let p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0))[i];
1764
- var o: VO; o.pos = vec4f(p, 0.0, 1.0); o.uv = vec2f(0.5 * p.x + 0.5, 0.5 - 0.5 * p.y); return o;
1765
- }
1766
- @fragment fn fs(v: VO) -> @location(0) vec4f { return textureSampleLevel(src, samp, v.uv, 0.0); }
1767
- `
1768
- );
1769
- var cache = /* @__PURE__ */ new WeakMap();
1770
- var mipCount = (w, h) => Math.floor(Math.log2(Math.max(w, h, 1))) + 1;
1771
- function generateMips(device, texture) {
1772
- let c = cache.get(device);
1773
- if (!c) {
1774
- c = { module: device.createShaderModule({ label: "photo/mips", code: WGSL2 }), sampler: device.createSampler({ minFilter: "linear", magFilter: "linear" }), pipes: /* @__PURE__ */ new Map() };
1775
- cache.set(device, c);
1776
- }
1777
- let pipe = c.pipes.get(texture.format);
1778
- if (!pipe) {
1779
- pipe = device.createRenderPipeline({
1780
- label: `photo/mips ${texture.format}`,
1781
- layout: "auto",
1782
- vertex: { module: c.module, entryPoint: "vs" },
1783
- fragment: { module: c.module, entryPoint: "fs", targets: [{ format: texture.format }] }
1784
- });
1785
- c.pipes.set(texture.format, pipe);
1786
- }
1787
- const encoder = device.createCommandEncoder({ label: "photo/mips" });
1788
- for (let level = 1; level < texture.mipLevelCount; level++) {
1789
- const src = texture.createView({ baseMipLevel: level - 1, mipLevelCount: 1 });
1790
- const dst = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });
1791
- const group = device.createBindGroup({ layout: pipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: src }, { binding: 1, resource: c.sampler }] });
1792
- const pass = encoder.beginRenderPass({ colorAttachments: [{ view: dst, loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 0 } }] });
1793
- pass.setPipeline(pipe);
1794
- pass.setBindGroup(0, group);
1795
- pass.draw(3);
1796
- pass.end();
1797
- }
1798
- device.queue.submit([encoder.finish()]);
1799
- }
1800
-
1801
2078
  // ../desk/src/kit/paper-tex.ts
1802
2079
  var PAPER_TEX = 256;
1803
2080
  var TOOTH_SCALE = 48;
@@ -2356,12 +2633,18 @@ export {
2356
2633
  unproject,
2357
2634
  rayThrough,
2358
2635
  eyeValues,
2636
+ mipCount,
2637
+ generateMips,
2638
+ mipsInto,
2639
+ createLiveTexture,
2640
+ liveDepth,
2641
+ LIVE,
2642
+ createSight,
2643
+ stillLive,
2359
2644
  VERTEX_FLOATS,
2360
2645
  VERTEX_BYTES,
2361
2646
  FLAG_TWO_SIDED,
2362
2647
  MeshWriter,
2363
- mipCount,
2364
- generateMips,
2365
2648
  PAPER_TEX,
2366
2649
  TOOTH_SCALE,
2367
2650
  paperTexture,
@@ -2399,4 +2682,4 @@ export {
2399
2682
  writeChanged,
2400
2683
  lineWeight
2401
2684
  };
2402
- //# sourceMappingURL=chunk-US7WJNR6.js.map
2685
+ //# sourceMappingURL=chunk-NB4ALBIY.js.map