three-text 0.6.0 → 0.6.1

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/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * three-text v0.6.0
3
+ * three-text v0.6.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * three-text v0.6.0
3
+ * three-text v0.6.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * three-text v0.6.0
3
+ * three-text v0.6.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
package/dist/index.min.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * three-text v0.6.0
3
+ * three-text v0.6.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
package/dist/index.umd.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * three-text v0.6.0
3
+ * three-text v0.6.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * three-text v0.6.0
3
+ * three-text v0.6.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
@@ -283,28 +283,34 @@ function packSlugData(shapes, options) {
283
283
  let curveY = 0;
284
284
  for (const shape of shapes) {
285
285
  const entries = [];
286
+ const [ox, oy] = shape.bounds;
286
287
  for (const curve of shape.curves) {
287
288
  // Don't let a curve span across row boundary (needs 2 consecutive texels)
288
289
  if (curveX >= TEX_WIDTH - 1) {
289
290
  curveX = 0;
290
291
  curveY++;
291
292
  }
293
+ // Store control points in glyph-local space (relative to bounds min)
294
+ // so the fragment shader's renderCoord subtraction stays near zero
295
+ const lp1x = curve.p1[0] - ox, lp1y = curve.p1[1] - oy;
296
+ const lp2x = curve.p2[0] - ox, lp2y = curve.p2[1] - oy;
297
+ const lp3x = curve.p3[0] - ox, lp3y = curve.p3[1] - oy;
292
298
  const base = (curveY * TEX_WIDTH + curveX) * 4;
293
- curveData[base + 0] = curve.p1[0];
294
- curveData[base + 1] = curve.p1[1];
295
- curveData[base + 2] = curve.p2[0];
296
- curveData[base + 3] = curve.p2[1];
299
+ curveData[base + 0] = lp1x;
300
+ curveData[base + 1] = lp1y;
301
+ curveData[base + 2] = lp2x;
302
+ curveData[base + 3] = lp2y;
297
303
  const base2 = base + 4;
298
- curveData[base2 + 0] = curve.p3[0];
299
- curveData[base2 + 1] = curve.p3[1];
300
- const minX = Math.min(curve.p1[0], curve.p2[0], curve.p3[0]);
301
- const minY = Math.min(curve.p1[1], curve.p2[1], curve.p3[1]);
302
- const maxX = Math.max(curve.p1[0], curve.p2[0], curve.p3[0]);
303
- const maxY = Math.max(curve.p1[1], curve.p2[1], curve.p3[1]);
304
+ curveData[base2 + 0] = lp3x;
305
+ curveData[base2 + 1] = lp3y;
306
+ const minX = Math.min(lp1x, lp2x, lp3x);
307
+ const minY = Math.min(lp1y, lp2y, lp3y);
308
+ const maxX = Math.max(lp1x, lp2x, lp3x);
309
+ const maxY = Math.max(lp1y, lp2y, lp3y);
304
310
  entries.push({
305
- p1x: curve.p1[0], p1y: curve.p1[1],
306
- p2x: curve.p2[0], p2y: curve.p2[1],
307
- p3x: curve.p3[0], p3y: curve.p3[1],
311
+ p1x: lp1x, p1y: lp1y,
312
+ p2x: lp2x, p2y: lp2y,
313
+ p3x: lp3x, p3y: lp3y,
308
314
  minX, minY, maxX, maxY,
309
315
  curveTexX: curveX,
310
316
  curveTexY: curveY
@@ -339,12 +345,12 @@ function packSlugData(shapes, options) {
339
345
  const vBandCount = Math.min(bandCount, 255);
340
346
  const bandMaxY = hBandCount - 1;
341
347
  const bandMaxX = vBandCount - 1;
342
- // Build horizontal bands (partition y-axis)
348
+ // Build horizontal bands (partition y-axis, glyph-local coords)
343
349
  const hBands = [];
344
350
  const hLists = [];
345
351
  const bandH = h / hBandCount;
346
352
  for (let bi = 0; bi < hBandCount; bi++) {
347
- const bandMinY = bMinY + bi * bandH;
353
+ const bandMinY = bi * bandH;
348
354
  const bandMaxYCoord = bandMinY + bandH;
349
355
  // Collect curves whose y-range overlaps this band
350
356
  const list = [];
@@ -362,12 +368,12 @@ function packSlugData(shapes, options) {
362
368
  hBands.push({ curveCount: list.length, listOffset: 0 });
363
369
  hLists.push(flatList);
364
370
  }
365
- // Build vertical bands (partition x-axis)
371
+ // Build vertical bands (partition x-axis, glyph-local coords)
366
372
  const vBands = [];
367
373
  const vLists = [];
368
374
  const bandW = w / vBandCount;
369
375
  for (let bi = 0; bi < vBandCount; bi++) {
370
- const bandMinX = bMinX + bi * bandW;
376
+ const bandMinX = bi * bandW;
371
377
  const bandMaxXCoord = bandMinX + bandW;
372
378
  const list = [];
373
379
  for (const c of curves) {
@@ -537,12 +543,12 @@ function packSlugData(shapes, options) {
537
543
  [bMaxX, bMaxY],
538
544
  [bMinX, bMaxY],
539
545
  ];
540
- // Em-space sample coords at corners (same as object-space for 1:1 mapping)
546
+ // Em-space sample coords in glyph-local space (origin at bounds min)
541
547
  const emCorners = [
542
- [bMinX, bMinY],
543
- [bMaxX, bMinY],
544
- [bMaxX, bMaxY],
545
- [bMinX, bMaxY],
548
+ [0, 0],
549
+ [w, 0],
550
+ [w, h],
551
+ [0, h],
546
552
  ];
547
553
  // Pack tex.z: glyph location in band texture
548
554
  const texZ = uintAsFloat((glyph.x & 0xFFFF) | ((glyph.y & 0xFFFF) << 16));
@@ -551,11 +557,9 @@ function packSlugData(shapes, options) {
551
557
  if (evenOdd)
552
558
  texWBits |= 0x10000000; // E flag at bit 28
553
559
  const texW = uintAsFloat(texWBits);
554
- // Band transform: scale and offset to map em-coords to band indices
560
+ // Band transform: scale to map glyph-local em-coords to band indices
555
561
  const bandScaleX = w > 0 ? sd.vBands.length / w : 0;
556
562
  const bandScaleY = h > 0 ? sd.hBands.length / h : 0;
557
- const bandOffsetX = -bMinX * bandScaleX;
558
- const bandOffsetY = -bMinY * bandScaleY;
559
563
  for (let vi = 0; vi < 4; vi++) {
560
564
  const base = (si * 4 + vi) * FLOATS_PER_VERTEX;
561
565
  // pos: .xy = position, .zw = normal
@@ -568,16 +572,16 @@ function packSlugData(shapes, options) {
568
572
  vertices[base + 5] = emCorners[vi][1];
569
573
  vertices[base + 6] = texZ;
570
574
  vertices[base + 7] = texW;
571
- // jac: identity Jacobian (em-space = object-space)
575
+ // jac: identity Jacobian (em-space is a pure translation of object-space)
572
576
  vertices[base + 8] = 1.0;
573
577
  vertices[base + 9] = 0.0;
574
578
  vertices[base + 10] = 0.0;
575
579
  vertices[base + 11] = 1.0;
576
- // bnd: band scale and offset
580
+ // bnd: band scale (offset is zero in glyph-local space)
577
581
  vertices[base + 12] = bandScaleX;
578
582
  vertices[base + 13] = bandScaleY;
579
- vertices[base + 14] = bandOffsetX;
580
- vertices[base + 15] = bandOffsetY;
583
+ vertices[base + 14] = 0;
584
+ vertices[base + 15] = 0;
581
585
  // col: white with full alpha (caller overrides via uniform or attribute)
582
586
  vertices[base + 16] = 1.0;
583
587
  vertices[base + 17] = 1.0;
@@ -281,28 +281,34 @@ function packSlugData(shapes, options) {
281
281
  let curveY = 0;
282
282
  for (const shape of shapes) {
283
283
  const entries = [];
284
+ const [ox, oy] = shape.bounds;
284
285
  for (const curve of shape.curves) {
285
286
  // Don't let a curve span across row boundary (needs 2 consecutive texels)
286
287
  if (curveX >= TEX_WIDTH - 1) {
287
288
  curveX = 0;
288
289
  curveY++;
289
290
  }
291
+ // Store control points in glyph-local space (relative to bounds min)
292
+ // so the fragment shader's renderCoord subtraction stays near zero
293
+ const lp1x = curve.p1[0] - ox, lp1y = curve.p1[1] - oy;
294
+ const lp2x = curve.p2[0] - ox, lp2y = curve.p2[1] - oy;
295
+ const lp3x = curve.p3[0] - ox, lp3y = curve.p3[1] - oy;
290
296
  const base = (curveY * TEX_WIDTH + curveX) * 4;
291
- curveData[base + 0] = curve.p1[0];
292
- curveData[base + 1] = curve.p1[1];
293
- curveData[base + 2] = curve.p2[0];
294
- curveData[base + 3] = curve.p2[1];
297
+ curveData[base + 0] = lp1x;
298
+ curveData[base + 1] = lp1y;
299
+ curveData[base + 2] = lp2x;
300
+ curveData[base + 3] = lp2y;
295
301
  const base2 = base + 4;
296
- curveData[base2 + 0] = curve.p3[0];
297
- curveData[base2 + 1] = curve.p3[1];
298
- const minX = Math.min(curve.p1[0], curve.p2[0], curve.p3[0]);
299
- const minY = Math.min(curve.p1[1], curve.p2[1], curve.p3[1]);
300
- const maxX = Math.max(curve.p1[0], curve.p2[0], curve.p3[0]);
301
- const maxY = Math.max(curve.p1[1], curve.p2[1], curve.p3[1]);
302
+ curveData[base2 + 0] = lp3x;
303
+ curveData[base2 + 1] = lp3y;
304
+ const minX = Math.min(lp1x, lp2x, lp3x);
305
+ const minY = Math.min(lp1y, lp2y, lp3y);
306
+ const maxX = Math.max(lp1x, lp2x, lp3x);
307
+ const maxY = Math.max(lp1y, lp2y, lp3y);
302
308
  entries.push({
303
- p1x: curve.p1[0], p1y: curve.p1[1],
304
- p2x: curve.p2[0], p2y: curve.p2[1],
305
- p3x: curve.p3[0], p3y: curve.p3[1],
309
+ p1x: lp1x, p1y: lp1y,
310
+ p2x: lp2x, p2y: lp2y,
311
+ p3x: lp3x, p3y: lp3y,
306
312
  minX, minY, maxX, maxY,
307
313
  curveTexX: curveX,
308
314
  curveTexY: curveY
@@ -337,12 +343,12 @@ function packSlugData(shapes, options) {
337
343
  const vBandCount = Math.min(bandCount, 255);
338
344
  const bandMaxY = hBandCount - 1;
339
345
  const bandMaxX = vBandCount - 1;
340
- // Build horizontal bands (partition y-axis)
346
+ // Build horizontal bands (partition y-axis, glyph-local coords)
341
347
  const hBands = [];
342
348
  const hLists = [];
343
349
  const bandH = h / hBandCount;
344
350
  for (let bi = 0; bi < hBandCount; bi++) {
345
- const bandMinY = bMinY + bi * bandH;
351
+ const bandMinY = bi * bandH;
346
352
  const bandMaxYCoord = bandMinY + bandH;
347
353
  // Collect curves whose y-range overlaps this band
348
354
  const list = [];
@@ -360,12 +366,12 @@ function packSlugData(shapes, options) {
360
366
  hBands.push({ curveCount: list.length, listOffset: 0 });
361
367
  hLists.push(flatList);
362
368
  }
363
- // Build vertical bands (partition x-axis)
369
+ // Build vertical bands (partition x-axis, glyph-local coords)
364
370
  const vBands = [];
365
371
  const vLists = [];
366
372
  const bandW = w / vBandCount;
367
373
  for (let bi = 0; bi < vBandCount; bi++) {
368
- const bandMinX = bMinX + bi * bandW;
374
+ const bandMinX = bi * bandW;
369
375
  const bandMaxXCoord = bandMinX + bandW;
370
376
  const list = [];
371
377
  for (const c of curves) {
@@ -535,12 +541,12 @@ function packSlugData(shapes, options) {
535
541
  [bMaxX, bMaxY],
536
542
  [bMinX, bMaxY],
537
543
  ];
538
- // Em-space sample coords at corners (same as object-space for 1:1 mapping)
544
+ // Em-space sample coords in glyph-local space (origin at bounds min)
539
545
  const emCorners = [
540
- [bMinX, bMinY],
541
- [bMaxX, bMinY],
542
- [bMaxX, bMaxY],
543
- [bMinX, bMaxY],
546
+ [0, 0],
547
+ [w, 0],
548
+ [w, h],
549
+ [0, h],
544
550
  ];
545
551
  // Pack tex.z: glyph location in band texture
546
552
  const texZ = uintAsFloat((glyph.x & 0xFFFF) | ((glyph.y & 0xFFFF) << 16));
@@ -549,11 +555,9 @@ function packSlugData(shapes, options) {
549
555
  if (evenOdd)
550
556
  texWBits |= 0x10000000; // E flag at bit 28
551
557
  const texW = uintAsFloat(texWBits);
552
- // Band transform: scale and offset to map em-coords to band indices
558
+ // Band transform: scale to map glyph-local em-coords to band indices
553
559
  const bandScaleX = w > 0 ? sd.vBands.length / w : 0;
554
560
  const bandScaleY = h > 0 ? sd.hBands.length / h : 0;
555
- const bandOffsetX = -bMinX * bandScaleX;
556
- const bandOffsetY = -bMinY * bandScaleY;
557
561
  for (let vi = 0; vi < 4; vi++) {
558
562
  const base = (si * 4 + vi) * FLOATS_PER_VERTEX;
559
563
  // pos: .xy = position, .zw = normal
@@ -566,16 +570,16 @@ function packSlugData(shapes, options) {
566
570
  vertices[base + 5] = emCorners[vi][1];
567
571
  vertices[base + 6] = texZ;
568
572
  vertices[base + 7] = texW;
569
- // jac: identity Jacobian (em-space = object-space)
573
+ // jac: identity Jacobian (em-space is a pure translation of object-space)
570
574
  vertices[base + 8] = 1.0;
571
575
  vertices[base + 9] = 0.0;
572
576
  vertices[base + 10] = 0.0;
573
577
  vertices[base + 11] = 1.0;
574
- // bnd: band scale and offset
578
+ // bnd: band scale (offset is zero in glyph-local space)
575
579
  vertices[base + 12] = bandScaleX;
576
580
  vertices[base + 13] = bandScaleY;
577
- vertices[base + 14] = bandOffsetX;
578
- vertices[base + 15] = bandOffsetY;
581
+ vertices[base + 14] = 0;
582
+ vertices[base + 15] = 0;
579
583
  // col: white with full alpha (caller overrides via uniform or attribute)
580
584
  vertices[base + 16] = 1.0;
581
585
  vertices[base + 17] = 1.0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "three-text",
3
- "version": "0.6.0",
4
- "description": "3D mesh font geometry and text layout engine for the web",
3
+ "version": "0.6.1",
4
+ "description": "3D font rendering and text layout engine for the web",
5
5
  "main": "dist/three/index.cjs",
6
6
  "module": "dist/three/index.js",
7
7
  "type": "module",