insomni 0.2.0-alpha.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/LICENSE.md +674 -0
- package/README.md +234 -0
- package/dist/advanced.d.mts +76 -0
- package/dist/advanced.mjs +81 -0
- package/dist/assemble-BT3CXbSx.mjs +1574 -0
- package/dist/camera-view-DHmMiKvP.d.mts +326 -0
- package/dist/frame-mHNdKRpF.mjs +135 -0
- package/dist/index-CmMZCMJT.d.mts +39 -0
- package/dist/index-DkJfpntS.d.mts +2417 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6612 -0
- package/dist/internal.d.mts +892 -0
- package/dist/internal.mjs +566 -0
- package/dist/logger-DSyBF3Y_.mjs +15 -0
- package/dist/particles.d.mts +816 -0
- package/dist/particles.mjs +4804 -0
- package/dist/pipeline-BWCAZTKx.mjs +470 -0
- package/dist/pipeline-DE3a1Pnk.d.mts +115 -0
- package/dist/reactivity-B7I0pvzm.mjs +191 -0
- package/dist/reactivity.d.mts +2 -0
- package/dist/reactivity.mjs +2 -0
- package/dist/renderer-DzZqd1bY.d.mts +4566 -0
- package/dist/root-CHradZKM.mjs +30 -0
- package/dist/shape-DfZP9Jdk.mjs +349 -0
- package/dist/space-CeDnj6eu.mjs +11240 -0
- package/dist/spatial-Bd3Ay8I2.d.mts +85 -0
- package/dist/spatial-hash-C1crBjTo.mjs +77 -0
- package/dist/spatial.d.mts +2 -0
- package/dist/spatial.mjs +121 -0
- package/dist/text-font-D7GGDtTK.d.mts +185 -0
- package/dist/text-ttf.d.mts +91 -0
- package/dist/text-ttf.mjs +298 -0
- package/dist/texture-dABoqFoP.mjs +131 -0
- package/dist/viewport.d.mts +2 -0
- package/dist/viewport.mjs +274 -0
- package/package.json +69 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import tgpu from "typegpu";
|
|
2
|
+
//#region src/core/root.ts
|
|
3
|
+
const ROOT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function isRoot(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && "device" in value && "configureContext" in value && "createBuffer" in value;
|
|
6
|
+
}
|
|
7
|
+
function getOrCreateRoot(device) {
|
|
8
|
+
let root = ROOT_CACHE.get(device);
|
|
9
|
+
if (!root) {
|
|
10
|
+
root = tgpu.initFromDevice({ device });
|
|
11
|
+
ROOT_CACHE.set(device, root);
|
|
12
|
+
}
|
|
13
|
+
return root;
|
|
14
|
+
}
|
|
15
|
+
function resolveRoot(owner) {
|
|
16
|
+
if (isRoot(owner)) {
|
|
17
|
+
ROOT_CACHE.set(owner.device, owner);
|
|
18
|
+
return owner;
|
|
19
|
+
}
|
|
20
|
+
if (typeof owner === "object" && owner !== null && "device" in owner) {
|
|
21
|
+
if (owner.root) {
|
|
22
|
+
ROOT_CACHE.set(owner.device, owner.root);
|
|
23
|
+
return owner.root;
|
|
24
|
+
}
|
|
25
|
+
return getOrCreateRoot(owner.device);
|
|
26
|
+
}
|
|
27
|
+
return getOrCreateRoot(owner);
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { resolveRoot as n, getOrCreateRoot as t };
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
//#region src/text/shape.ts
|
|
2
|
+
const SPACE_CP = 32;
|
|
3
|
+
const LF_CP = 10;
|
|
4
|
+
const HIGH_SURROGATE_START = 55296;
|
|
5
|
+
/**
|
|
6
|
+
* Shape `text` starting at world-space origin (x, y).
|
|
7
|
+
*
|
|
8
|
+
* Origin convention: y is the *top* of the first line. Subsequent lines are
|
|
9
|
+
* below (higher y).
|
|
10
|
+
*/
|
|
11
|
+
function shapeText(text, font, atlas, x, y, options) {
|
|
12
|
+
const { fontSize, align = "left", maxWidth, lineHeight = fontSize * 1.2, simple = false } = options;
|
|
13
|
+
if (simple) return shapeSingleLine(text, font, atlas, x, y, fontSize, align, lineHeight, false);
|
|
14
|
+
if (align === "left" && maxWidth === void 0 && text.indexOf("\n") < 0) return shapeSingleLine(text, font, atlas, x, y, fontSize, "left", lineHeight, true);
|
|
15
|
+
const hardLines = text.split("\n");
|
|
16
|
+
const lines = [];
|
|
17
|
+
for (const hl of hardLines) {
|
|
18
|
+
if (maxWidth === void 0) {
|
|
19
|
+
lines.push(hl);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
wrapLine(hl, font, atlas, fontSize, maxWidth, lines);
|
|
23
|
+
}
|
|
24
|
+
const glyphs = [];
|
|
25
|
+
let minX = Infinity;
|
|
26
|
+
let minY = Infinity;
|
|
27
|
+
let maxX_ = -Infinity;
|
|
28
|
+
let maxY_ = -Infinity;
|
|
29
|
+
let maxLineWidth = 0;
|
|
30
|
+
for (let li = 0; li < lines.length; li++) {
|
|
31
|
+
const line = lines[li];
|
|
32
|
+
if (line.length === 0) continue;
|
|
33
|
+
const lineWidth = measureLineWidth(line, font, atlas, fontSize, false);
|
|
34
|
+
if (lineWidth > maxLineWidth) maxLineWidth = lineWidth;
|
|
35
|
+
let cursorX = x;
|
|
36
|
+
if (align === "center") cursorX = x - lineWidth / 2;
|
|
37
|
+
else if (align === "right") cursorX = x - lineWidth;
|
|
38
|
+
const lineTopY = y + li * lineHeight;
|
|
39
|
+
let prevCp = -1;
|
|
40
|
+
for (const ch of line) {
|
|
41
|
+
const cp = ch.codePointAt(0);
|
|
42
|
+
const g = atlas.getGlyph(cp);
|
|
43
|
+
if (!g) {
|
|
44
|
+
prevCp = cp;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (prevCp >= 0) cursorX += font.getKerning(prevCp, cp) * fontSize;
|
|
48
|
+
if (g.width > 0 && g.height > 0) {
|
|
49
|
+
const wx = cursorX + g.bearingX * fontSize;
|
|
50
|
+
const wy = lineTopY + (font.ascender - g.bearingY) * fontSize;
|
|
51
|
+
const ww = g.width * fontSize;
|
|
52
|
+
const wh = g.height * fontSize;
|
|
53
|
+
glyphs.push({
|
|
54
|
+
glyph: g,
|
|
55
|
+
worldX: wx,
|
|
56
|
+
worldY: wy,
|
|
57
|
+
worldW: ww,
|
|
58
|
+
worldH: wh
|
|
59
|
+
});
|
|
60
|
+
if (wx < minX) minX = wx;
|
|
61
|
+
if (wy < minY) minY = wy;
|
|
62
|
+
if (wx + ww > maxX_) maxX_ = wx + ww;
|
|
63
|
+
if (wy + wh > maxY_) maxY_ = wy + wh;
|
|
64
|
+
}
|
|
65
|
+
cursorX += g.advance * fontSize;
|
|
66
|
+
prevCp = cp;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const totalHeight = lines.length * lineHeight;
|
|
70
|
+
if (!isFinite(minX)) return {
|
|
71
|
+
glyphs,
|
|
72
|
+
bbox: {
|
|
73
|
+
minX: x,
|
|
74
|
+
minY: y,
|
|
75
|
+
maxX: x,
|
|
76
|
+
maxY: y + totalHeight
|
|
77
|
+
},
|
|
78
|
+
height: totalHeight,
|
|
79
|
+
lineCount: lines.length,
|
|
80
|
+
maxLineWidth
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
glyphs,
|
|
84
|
+
bbox: {
|
|
85
|
+
minX,
|
|
86
|
+
minY,
|
|
87
|
+
maxX: maxX_,
|
|
88
|
+
maxY: maxY_
|
|
89
|
+
},
|
|
90
|
+
height: totalHeight,
|
|
91
|
+
lineCount: lines.length,
|
|
92
|
+
maxLineWidth
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Single-pass single-line shaper. One walk over the chars: places glyphs and
|
|
97
|
+
* tracks the running max-x in the same loop, so there's no pre-measure pass.
|
|
98
|
+
*
|
|
99
|
+
* `kerning=false` skips the kerning lookup entirely (simple mode).
|
|
100
|
+
*/
|
|
101
|
+
function shapeSingleLine(text, font, atlas, x, y, fontSize, align, lineHeight, kerning) {
|
|
102
|
+
const glyphs = [];
|
|
103
|
+
let minX = Infinity;
|
|
104
|
+
let minY = Infinity;
|
|
105
|
+
let maxX_ = -Infinity;
|
|
106
|
+
let maxY_ = -Infinity;
|
|
107
|
+
let cursor = 0;
|
|
108
|
+
let prevCp = -1;
|
|
109
|
+
const len = text.length;
|
|
110
|
+
for (let i = 0; i < len; i++) {
|
|
111
|
+
let cp = text.charCodeAt(i);
|
|
112
|
+
if (cp >= HIGH_SURROGATE_START) {
|
|
113
|
+
cp = text.codePointAt(i);
|
|
114
|
+
if (cp > 65535) i++;
|
|
115
|
+
}
|
|
116
|
+
const g = atlas.getGlyph(cp);
|
|
117
|
+
if (!g) {
|
|
118
|
+
prevCp = cp;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (kerning && prevCp >= 0) cursor += font.getKerning(prevCp, cp) * fontSize;
|
|
122
|
+
if (g.width > 0 && g.height > 0) {
|
|
123
|
+
const wx = cursor + g.bearingX * fontSize;
|
|
124
|
+
const wy = y + (font.ascender - g.bearingY) * fontSize;
|
|
125
|
+
const ww = g.width * fontSize;
|
|
126
|
+
const wh = g.height * fontSize;
|
|
127
|
+
glyphs.push({
|
|
128
|
+
glyph: g,
|
|
129
|
+
worldX: wx,
|
|
130
|
+
worldY: wy,
|
|
131
|
+
worldW: ww,
|
|
132
|
+
worldH: wh
|
|
133
|
+
});
|
|
134
|
+
if (wx < minX) minX = wx;
|
|
135
|
+
if (wy < minY) minY = wy;
|
|
136
|
+
if (wx + ww > maxX_) maxX_ = wx + ww;
|
|
137
|
+
if (wy + wh > maxY_) maxY_ = wy + wh;
|
|
138
|
+
}
|
|
139
|
+
cursor += g.advance * fontSize;
|
|
140
|
+
prevCp = cp;
|
|
141
|
+
}
|
|
142
|
+
const lineWidth = cursor;
|
|
143
|
+
let shift = x;
|
|
144
|
+
if (align === "center") shift = x - lineWidth / 2;
|
|
145
|
+
else if (align === "right") shift = x - lineWidth;
|
|
146
|
+
if (shift !== 0) {
|
|
147
|
+
for (let k = 0; k < glyphs.length; k++) glyphs[k].worldX += shift;
|
|
148
|
+
minX += shift;
|
|
149
|
+
maxX_ += shift;
|
|
150
|
+
}
|
|
151
|
+
if (!isFinite(minX)) return {
|
|
152
|
+
glyphs,
|
|
153
|
+
bbox: {
|
|
154
|
+
minX: x,
|
|
155
|
+
minY: y,
|
|
156
|
+
maxX: x,
|
|
157
|
+
maxY: y + lineHeight
|
|
158
|
+
},
|
|
159
|
+
height: lineHeight,
|
|
160
|
+
lineCount: 1,
|
|
161
|
+
maxLineWidth: lineWidth
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
glyphs,
|
|
165
|
+
bbox: {
|
|
166
|
+
minX,
|
|
167
|
+
minY,
|
|
168
|
+
maxX: maxX_,
|
|
169
|
+
maxY: maxY_
|
|
170
|
+
},
|
|
171
|
+
height: lineHeight,
|
|
172
|
+
lineCount: 1,
|
|
173
|
+
maxLineWidth: lineWidth
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const TEXT_INSTANCE_FLOATS_LOCAL = 10;
|
|
177
|
+
/**
|
|
178
|
+
* Single-line shaper that writes glyph floats directly into the caller's
|
|
179
|
+
* instance Float32Array. Skips the ShapedGlyph[] intermediate entirely — the
|
|
180
|
+
* caller is expected to write `blockId` into slots 8/9 of each instance after
|
|
181
|
+
* style interning.
|
|
182
|
+
*
|
|
183
|
+
* `out` must have room for at least `text.length * TEXT_INSTANCE_FLOATS`
|
|
184
|
+
* floats past `floatOffset`.
|
|
185
|
+
*/
|
|
186
|
+
function shapeAndPackSingleLine(text, font, atlas, x, y, fontSize, align, kerning, lineHeight, out, floatOffset) {
|
|
187
|
+
let off = floatOffset;
|
|
188
|
+
let cursor = 0;
|
|
189
|
+
let prevCp = -1;
|
|
190
|
+
let minX = Infinity;
|
|
191
|
+
let minY = Infinity;
|
|
192
|
+
let maxX_ = -Infinity;
|
|
193
|
+
let maxY_ = -Infinity;
|
|
194
|
+
let written = 0;
|
|
195
|
+
const len = text.length;
|
|
196
|
+
const baseY = y + font.ascender * fontSize;
|
|
197
|
+
for (let i = 0; i < len; i++) {
|
|
198
|
+
let cp = text.charCodeAt(i);
|
|
199
|
+
if (cp >= HIGH_SURROGATE_START) {
|
|
200
|
+
cp = text.codePointAt(i);
|
|
201
|
+
if (cp > 65535) i++;
|
|
202
|
+
}
|
|
203
|
+
const g = atlas.getGlyph(cp);
|
|
204
|
+
if (!g) {
|
|
205
|
+
prevCp = cp;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (kerning && prevCp >= 0) cursor += font.getKerning(prevCp, cp) * fontSize;
|
|
209
|
+
const gw = g.width;
|
|
210
|
+
const gh = g.height;
|
|
211
|
+
if (gw > 0 && gh > 0) {
|
|
212
|
+
const wx = cursor + g.bearingX * fontSize;
|
|
213
|
+
const wy = baseY - g.bearingY * fontSize;
|
|
214
|
+
const ww = gw * fontSize;
|
|
215
|
+
const wh = gh * fontSize;
|
|
216
|
+
out[off] = wx;
|
|
217
|
+
out[off + 1] = wy;
|
|
218
|
+
out[off + 2] = ww;
|
|
219
|
+
out[off + 3] = wh;
|
|
220
|
+
out[off + 4] = g.uvMinX;
|
|
221
|
+
out[off + 5] = g.uvMinY;
|
|
222
|
+
out[off + 6] = g.uvMaxX;
|
|
223
|
+
out[off + 7] = g.uvMaxY;
|
|
224
|
+
off += TEXT_INSTANCE_FLOATS_LOCAL;
|
|
225
|
+
written++;
|
|
226
|
+
if (wx < minX) minX = wx;
|
|
227
|
+
if (wy < minY) minY = wy;
|
|
228
|
+
if (wx + ww > maxX_) maxX_ = wx + ww;
|
|
229
|
+
if (wy + wh > maxY_) maxY_ = wy + wh;
|
|
230
|
+
}
|
|
231
|
+
cursor += g.advance * fontSize;
|
|
232
|
+
prevCp = cp;
|
|
233
|
+
}
|
|
234
|
+
let shift = x;
|
|
235
|
+
if (align === "center") shift = x - cursor / 2;
|
|
236
|
+
else if (align === "right") shift = x - cursor;
|
|
237
|
+
if (shift !== 0 && written > 0) {
|
|
238
|
+
let p = floatOffset;
|
|
239
|
+
for (let k = 0; k < written; k++) {
|
|
240
|
+
out[p] += shift;
|
|
241
|
+
p += TEXT_INSTANCE_FLOATS_LOCAL;
|
|
242
|
+
}
|
|
243
|
+
minX += shift;
|
|
244
|
+
maxX_ += shift;
|
|
245
|
+
}
|
|
246
|
+
if (written === 0) return {
|
|
247
|
+
glyphCount: 0,
|
|
248
|
+
minX: x,
|
|
249
|
+
minY: y,
|
|
250
|
+
maxX: x,
|
|
251
|
+
maxY: y + lineHeight,
|
|
252
|
+
lineWidth: cursor,
|
|
253
|
+
lineHeight
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
glyphCount: written,
|
|
257
|
+
minX,
|
|
258
|
+
minY,
|
|
259
|
+
maxX: maxX_,
|
|
260
|
+
maxY: maxY_,
|
|
261
|
+
lineWidth: cursor,
|
|
262
|
+
lineHeight
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Measure-only fast path. Walks advances + (optional) kerning without
|
|
267
|
+
* allocating any glyph objects or computing positions. Returns the laid-out
|
|
268
|
+
* width of a single line.
|
|
269
|
+
*/
|
|
270
|
+
function measureBlockWidth(text, font, atlas, fontSize, simple = false) {
|
|
271
|
+
let max = 0;
|
|
272
|
+
let lineStart = 0;
|
|
273
|
+
const len = text.length;
|
|
274
|
+
for (let i = 0; i <= len; i++) if (i === len || text.charCodeAt(i) === LF_CP) {
|
|
275
|
+
if (i > lineStart) {
|
|
276
|
+
const w = measureLineRange(text, lineStart, i, font, atlas, fontSize, !simple);
|
|
277
|
+
if (w > max) max = w;
|
|
278
|
+
}
|
|
279
|
+
lineStart = i + 1;
|
|
280
|
+
}
|
|
281
|
+
return max;
|
|
282
|
+
}
|
|
283
|
+
function measureLineWidth(line, font, atlas, fontSize, simple) {
|
|
284
|
+
return measureLineRange(line, 0, line.length, font, atlas, fontSize, !simple);
|
|
285
|
+
}
|
|
286
|
+
function measureLineRange(s, start, end, font, atlas, fontSize, kerning) {
|
|
287
|
+
let w = 0;
|
|
288
|
+
let prevCp = -1;
|
|
289
|
+
for (let i = start; i < end; i++) {
|
|
290
|
+
let cp = s.charCodeAt(i);
|
|
291
|
+
if (cp >= HIGH_SURROGATE_START) {
|
|
292
|
+
cp = s.codePointAt(i);
|
|
293
|
+
if (cp > 65535) i++;
|
|
294
|
+
}
|
|
295
|
+
const g = atlas.getGlyph(cp);
|
|
296
|
+
if (!g) {
|
|
297
|
+
prevCp = cp;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (kerning && prevCp >= 0) w += font.getKerning(prevCp, cp) * fontSize;
|
|
301
|
+
w += g.advance * fontSize;
|
|
302
|
+
prevCp = cp;
|
|
303
|
+
}
|
|
304
|
+
return w;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Greedy whitespace-based wrapping. Pushes wrapped lines into `out`.
|
|
308
|
+
* Single words longer than `maxWidth` are placed on their own line uncut.
|
|
309
|
+
*/
|
|
310
|
+
function wrapLine(line, font, atlas, fontSize, maxWidth, out) {
|
|
311
|
+
if (line.length === 0) {
|
|
312
|
+
out.push("");
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const tokens = [];
|
|
316
|
+
let i = 0;
|
|
317
|
+
while (i < line.length) {
|
|
318
|
+
let j = i;
|
|
319
|
+
while (j < line.length && line.charCodeAt(j) === SPACE_CP) j++;
|
|
320
|
+
if (j > i) tokens.push({
|
|
321
|
+
text: line.slice(i, j),
|
|
322
|
+
width: 0
|
|
323
|
+
});
|
|
324
|
+
const wordStart = j;
|
|
325
|
+
while (j < line.length && line.charCodeAt(j) !== SPACE_CP) j++;
|
|
326
|
+
if (j > wordStart) tokens.push({
|
|
327
|
+
text: line.slice(wordStart, j),
|
|
328
|
+
width: 0
|
|
329
|
+
});
|
|
330
|
+
i = j;
|
|
331
|
+
}
|
|
332
|
+
for (const t of tokens) t.width = measureLineWidth(t.text, font, atlas, fontSize, false);
|
|
333
|
+
let buf = "";
|
|
334
|
+
let bufW = 0;
|
|
335
|
+
for (const t of tokens) {
|
|
336
|
+
if (buf.length === 0 && t.text.charCodeAt(0) === SPACE_CP) continue;
|
|
337
|
+
if (bufW + t.width > maxWidth && buf.length > 0) {
|
|
338
|
+
out.push(buf);
|
|
339
|
+
buf = "";
|
|
340
|
+
bufW = 0;
|
|
341
|
+
if (t.text.charCodeAt(0) === SPACE_CP) continue;
|
|
342
|
+
}
|
|
343
|
+
buf += t.text;
|
|
344
|
+
bufW += t.width;
|
|
345
|
+
}
|
|
346
|
+
if (buf.length > 0) out.push(buf);
|
|
347
|
+
}
|
|
348
|
+
//#endregion
|
|
349
|
+
export { shapeAndPackSingleLine as n, shapeText as r, measureBlockWidth as t };
|