three-text 0.5.0 → 0.5.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.5.0
3
+ * three-text v0.5.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.5.0
3
+ * three-text v0.5.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.5.0
3
+ * three-text v0.5.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.5.0
3
+ * three-text v0.5.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.5.0
3
+ * three-text v0.5.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.5.0
3
+ * three-text v0.5.1
4
4
  * Copyright © 2025-2026 Jeremy Tribby, Countertype LLC
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
@@ -25,5 +25,3 @@ export type { TextOptions, VectorTextResult as TextGeometryInfo, VectorGlyphInfo
25
25
  export type { HyphenationTrieNode };
26
26
  export { buildVectorGeometry, extractContours } from './LoopBlinnGeometry';
27
27
  export type { VectorGeometryData, VectorGlyphAttributes, GlyphRange, VectorContour, LoopBlinnInput, LoopBlinnGlyphInput, QuadraticSegment } from './LoopBlinnGeometry';
28
- export { createVectorMeshes } from './loopBlinnTSL';
29
- export type { VectorMeshes } from './loopBlinnTSL';
@@ -1,8 +1,8 @@
1
1
  import * as THREE from 'three';
2
2
  import type { VectorGeometryData } from './LoopBlinnGeometry';
3
3
  export interface VectorMeshes {
4
- interiorMesh: THREE.Mesh;
5
- curveMesh: THREE.Mesh;
4
+ interiorMesh: THREE.Object3D;
5
+ curveMesh: THREE.Object3D;
6
6
  fillMesh: THREE.Mesh;
7
7
  setOffset(x: number, y: number, z?: number): void;
8
8
  dispose(): void;
@@ -4,27 +4,6 @@ var Text$1 = require('../index.cjs');
4
4
  var sharedCaches = require('../index.cjs');
5
5
  var DrawCallbacks = require('../index.cjs');
6
6
  var TextRangeQuery = require('../index.cjs');
7
- var THREE = require('three');
8
- var tsl = require('three/tsl');
9
-
10
- function _interopNamespaceDefault(e) {
11
- var n = Object.create(null);
12
- if (e) {
13
- Object.keys(e).forEach(function (k) {
14
- if (k !== 'default') {
15
- var d = Object.getOwnPropertyDescriptor(e, k);
16
- Object.defineProperty(n, k, d.get ? d : {
17
- enumerable: true,
18
- get: function () { return e[k]; }
19
- });
20
- }
21
- });
22
- }
23
- n.default = e;
24
- return Object.freeze(n);
25
- }
26
-
27
- var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
28
7
 
29
8
  // 2D Vector
30
9
  class Vec2 {
@@ -1267,132 +1246,6 @@ function buildVectorGeometry(input) {
1267
1246
  };
1268
1247
  }
1269
1248
 
1270
- // Loop-Blinn TSL adapter for Three.js WebGPURenderer.
1271
- // Creates meshes with TSL node materials for Loop-Blinn curve evaluation
1272
- // and Kokojima stencil fill. Works on WebGL (r170+) and WebGPU (r182+).
1273
- // Requires peer dependencies: three, three/tsl
1274
- // @ts-ignore - three is a peer dependency
1275
- // TSL fragment node: evaluates u^2 - v = 0 per fragment with
1276
- // screen-space derivative antialiasing. Discards outside fragments.
1277
- // UV convention per triangle: p0=(0,0), p1=(0.5,0), p2=(1,1)
1278
- const loopBlinnFragment = tsl.Fn(() => {
1279
- const curveUV = tsl.uv();
1280
- const px = tsl.dFdx(curveUV);
1281
- const py = tsl.dFdy(curveUV);
1282
- const fx = tsl.float(2.0).mul(curveUV.x).mul(px.x).sub(px.y);
1283
- const fy = tsl.float(2.0).mul(curveUV.x).mul(py.x).sub(py.y);
1284
- const denom = tsl.sqrt(fx.mul(fx).add(fy.mul(fy)));
1285
- const f = curveUV.x.mul(curveUV.x).sub(curveUV.y);
1286
- const sd = f.div(denom.max(1e-6));
1287
- const alpha = tsl.clamp(tsl.float(0.5).sub(sd), 0.0, 1.0);
1288
- tsl.Discard(alpha.lessThanEqual(0.0));
1289
- return tsl.vec4(1.0, 1.0, 1.0, alpha);
1290
- });
1291
- function setGlyphAttrsOnGeometry(geo, attrs, offsetX = 0, offsetY = 0) {
1292
- if (!attrs)
1293
- return;
1294
- const glyphCenter = new Float32Array(attrs.glyphCenter);
1295
- if (offsetX !== 0 || offsetY !== 0) {
1296
- for (let i = 0; i < glyphCenter.length; i += 3) {
1297
- glyphCenter[i] += offsetX;
1298
- glyphCenter[i + 1] += offsetY;
1299
- }
1300
- }
1301
- geo.setAttribute('glyphCenter', new THREE__namespace.Float32BufferAttribute(glyphCenter, 3));
1302
- geo.setAttribute('glyphIndex', new THREE__namespace.Float32BufferAttribute(attrs.glyphIndex, 1));
1303
- geo.setAttribute('glyphProgress', new THREE__namespace.Float32BufferAttribute(attrs.glyphProgress, 1));
1304
- geo.setAttribute('glyphLineIndex', new THREE__namespace.Float32BufferAttribute(attrs.glyphLineIndex, 1));
1305
- geo.setAttribute('glyphBaselineY', new THREE__namespace.Float32BufferAttribute(attrs.glyphBaselineY, 1));
1306
- }
1307
- function applyStencilXOR(mat) {
1308
- mat.depthTest = false;
1309
- mat.depthWrite = false;
1310
- mat.side = THREE__namespace.DoubleSide;
1311
- mat.stencilWrite = true;
1312
- mat.stencilFunc = THREE__namespace.AlwaysStencilFunc;
1313
- mat.stencilRef = 0;
1314
- mat.stencilFuncMask = 0xFF;
1315
- mat.stencilWriteMask = 0xFF;
1316
- mat.stencilFail = THREE__namespace.KeepStencilOp;
1317
- mat.stencilZFail = THREE__namespace.KeepStencilOp;
1318
- mat.stencilZPass = THREE__namespace.InvertStencilOp;
1319
- }
1320
- // Three meshes that must render in order (via renderOrder or sequential draws):
1321
- // 1. interiorMesh - stencil XOR (fan triangulated interiors, no color output)
1322
- // 2. curveMesh - stencil XOR (Loop-Blinn curve eval, alpha-to-coverage)
1323
- // 3. fillMesh - color where stencil != 0, then zeros stencil
1324
- function createVectorMeshes(data, color) {
1325
- const interiorGeo = new THREE__namespace.BufferGeometry();
1326
- interiorGeo.setAttribute('position', new THREE__namespace.Float32BufferAttribute(data.interiorPositions, 3));
1327
- interiorGeo.setIndex(new THREE__namespace.BufferAttribute(data.interiorIndices, 1));
1328
- setGlyphAttrsOnGeometry(interiorGeo, data.interiorGlyphAttrs);
1329
- const curveGeo = new THREE__namespace.BufferGeometry();
1330
- curveGeo.setAttribute('position', new THREE__namespace.Float32BufferAttribute(data.curvePositions, 3));
1331
- const curveVertCount = data.curvePositions.length / 3;
1332
- const curveUVs = new Float32Array(curveVertCount * 2);
1333
- for (let i = 0; i < curveVertCount; i += 3) {
1334
- curveUVs[i * 2] = 0;
1335
- curveUVs[i * 2 + 1] = 0; // p0
1336
- curveUVs[i * 2 + 2] = 0.5;
1337
- curveUVs[i * 2 + 3] = 0; // p1
1338
- curveUVs[i * 2 + 4] = 1;
1339
- curveUVs[i * 2 + 5] = 1; // p2
1340
- }
1341
- curveGeo.setAttribute('uv', new THREE__namespace.Float32BufferAttribute(curveUVs, 2));
1342
- setGlyphAttrsOnGeometry(curveGeo, data.curveGlyphAttrs);
1343
- const fillGeo = new THREE__namespace.BufferGeometry();
1344
- fillGeo.setAttribute('position', new THREE__namespace.Float32BufferAttribute(data.fillPositions, 3));
1345
- fillGeo.setIndex(new THREE__namespace.BufferAttribute(data.fillIndices, 1));
1346
- setGlyphAttrsOnGeometry(fillGeo, data.fillGlyphAttrs);
1347
- // 1) Interior stencil material - no color output
1348
- const stencilInteriorMat = new THREE__namespace.MeshBasicNodeMaterial();
1349
- applyStencilXOR(stencilInteriorMat);
1350
- stencilInteriorMat.colorWrite = false;
1351
- // 2) Curve stencil material - Loop-Blinn fragment evaluation
1352
- const stencilCurveMat = new THREE__namespace.MeshBasicNodeMaterial();
1353
- applyStencilXOR(stencilCurveMat);
1354
- stencilCurveMat.colorWrite = false;
1355
- stencilCurveMat.alphaToCoverage = true;
1356
- stencilCurveMat.fragmentNode = loopBlinnFragment();
1357
- // 3) Color fill material - renders where stencil != 0
1358
- const colorMat = new THREE__namespace.MeshBasicNodeMaterial();
1359
- colorMat.depthTest = false;
1360
- colorMat.depthWrite = false;
1361
- colorMat.side = THREE__namespace.DoubleSide;
1362
- colorMat.stencilWrite = true;
1363
- colorMat.stencilFunc = THREE__namespace.NotEqualStencilFunc;
1364
- colorMat.stencilRef = 0;
1365
- colorMat.stencilFuncMask = 0xFF;
1366
- colorMat.stencilWriteMask = 0xFF;
1367
- colorMat.stencilFail = THREE__namespace.KeepStencilOp;
1368
- colorMat.stencilZFail = THREE__namespace.KeepStencilOp;
1369
- colorMat.stencilZPass = THREE__namespace.ZeroStencilOp;
1370
- if (color !== undefined) {
1371
- colorMat.color = new THREE__namespace.Color(color);
1372
- }
1373
- const interiorMesh = new THREE__namespace.Mesh(interiorGeo, stencilInteriorMat);
1374
- const curveMesh = new THREE__namespace.Mesh(curveGeo, stencilCurveMat);
1375
- const fillMesh = new THREE__namespace.Mesh(fillGeo, colorMat);
1376
- return {
1377
- interiorMesh,
1378
- curveMesh,
1379
- fillMesh,
1380
- setOffset(x, y, z = 0) {
1381
- interiorMesh.position.set(x, y, z);
1382
- curveMesh.position.set(x, y, z);
1383
- fillMesh.position.set(x, y, z);
1384
- },
1385
- dispose() {
1386
- interiorGeo.dispose();
1387
- curveGeo.dispose();
1388
- fillGeo.dispose();
1389
- stencilInteriorMat.dispose();
1390
- stencilCurveMat.dispose();
1391
- colorMat.dispose();
1392
- }
1393
- };
1394
- }
1395
-
1396
1249
  function buildVectorResult(layoutHandle, vectorBuilder, options) {
1397
1250
  const scale = layoutHandle.layoutData.pixelsPerFontUnit;
1398
1251
  const { loopBlinnInput, glyphs } = vectorBuilder.buildForLoopBlinn(layoutHandle.clustersByLine, scale);
@@ -1454,5 +1307,4 @@ class Text {
1454
1307
 
1455
1308
  exports.Text = Text;
1456
1309
  exports.buildVectorGeometry = buildVectorGeometry;
1457
- exports.createVectorMeshes = createVectorMeshes;
1458
1310
  exports.extractContours = extractContours;
@@ -1,7 +1,6 @@
1
1
  import { Text as Text$1 } from '../core/Text';
2
2
  import { VectorGlyphInfo, TextQueryOptions, TextRange, LoadedFont, TextOptions } from '../core/types';
3
3
  export { LoadedFont, TextOptions, VectorGlyphInfo } from '../core/types';
4
- import * as THREE from 'three';
5
4
 
6
5
  interface BoundingBox {
7
6
  min: {
@@ -90,15 +89,6 @@ interface HyphenationTrieNode {
90
89
  };
91
90
  }
92
91
 
93
- interface VectorMeshes {
94
- interiorMesh: THREE.Mesh;
95
- curveMesh: THREE.Mesh;
96
- fillMesh: THREE.Mesh;
97
- setOffset(x: number, y: number, z?: number): void;
98
- dispose(): void;
99
- }
100
- declare function createVectorMeshes(data: VectorGeometryData, color?: THREE.ColorRepresentation): VectorMeshes;
101
-
102
92
  interface VectorTextResult {
103
93
  glyphs: VectorGlyphInfo[];
104
94
  geometryData: VectorGeometryData;
@@ -119,4 +109,4 @@ declare class Text {
119
109
  static create(options: TextOptions): Promise<VectorTextResult>;
120
110
  }
121
111
 
122
- export { GlyphRange, HyphenationTrieNode, LoopBlinnGlyphInput, LoopBlinnInput, QuadraticSegment, Text, VectorTextResult as TextGeometryInfo, VectorContour, VectorGeometryData, VectorGlyphAttributes, VectorMeshes, VectorTextResult, buildVectorGeometry, createVectorMeshes, extractContours };
112
+ export { GlyphRange, HyphenationTrieNode, LoopBlinnGlyphInput, LoopBlinnInput, QuadraticSegment, Text, VectorTextResult as TextGeometryInfo, VectorContour, VectorGeometryData, VectorGlyphAttributes, VectorTextResult, buildVectorGeometry, extractContours };
@@ -2,8 +2,6 @@ import { Text as Text$1 } from '../index.js';
2
2
  import { globalOutlineCache } from '../index.js';
3
3
  import { getSharedDrawCallbackHandler } from '../index.js';
4
4
  import { TextRangeQuery } from '../index.js';
5
- import * as THREE from 'three';
6
- import { Fn, uv, dFdx, dFdy, float, sqrt, clamp, Discard, vec4 } from 'three/tsl';
7
5
 
8
6
  // 2D Vector
9
7
  class Vec2 {
@@ -1246,132 +1244,6 @@ function buildVectorGeometry(input) {
1246
1244
  };
1247
1245
  }
1248
1246
 
1249
- // Loop-Blinn TSL adapter for Three.js WebGPURenderer.
1250
- // Creates meshes with TSL node materials for Loop-Blinn curve evaluation
1251
- // and Kokojima stencil fill. Works on WebGL (r170+) and WebGPU (r182+).
1252
- // Requires peer dependencies: three, three/tsl
1253
- // @ts-ignore - three is a peer dependency
1254
- // TSL fragment node: evaluates u^2 - v = 0 per fragment with
1255
- // screen-space derivative antialiasing. Discards outside fragments.
1256
- // UV convention per triangle: p0=(0,0), p1=(0.5,0), p2=(1,1)
1257
- const loopBlinnFragment = Fn(() => {
1258
- const curveUV = uv();
1259
- const px = dFdx(curveUV);
1260
- const py = dFdy(curveUV);
1261
- const fx = float(2.0).mul(curveUV.x).mul(px.x).sub(px.y);
1262
- const fy = float(2.0).mul(curveUV.x).mul(py.x).sub(py.y);
1263
- const denom = sqrt(fx.mul(fx).add(fy.mul(fy)));
1264
- const f = curveUV.x.mul(curveUV.x).sub(curveUV.y);
1265
- const sd = f.div(denom.max(1e-6));
1266
- const alpha = clamp(float(0.5).sub(sd), 0.0, 1.0);
1267
- Discard(alpha.lessThanEqual(0.0));
1268
- return vec4(1.0, 1.0, 1.0, alpha);
1269
- });
1270
- function setGlyphAttrsOnGeometry(geo, attrs, offsetX = 0, offsetY = 0) {
1271
- if (!attrs)
1272
- return;
1273
- const glyphCenter = new Float32Array(attrs.glyphCenter);
1274
- if (offsetX !== 0 || offsetY !== 0) {
1275
- for (let i = 0; i < glyphCenter.length; i += 3) {
1276
- glyphCenter[i] += offsetX;
1277
- glyphCenter[i + 1] += offsetY;
1278
- }
1279
- }
1280
- geo.setAttribute('glyphCenter', new THREE.Float32BufferAttribute(glyphCenter, 3));
1281
- geo.setAttribute('glyphIndex', new THREE.Float32BufferAttribute(attrs.glyphIndex, 1));
1282
- geo.setAttribute('glyphProgress', new THREE.Float32BufferAttribute(attrs.glyphProgress, 1));
1283
- geo.setAttribute('glyphLineIndex', new THREE.Float32BufferAttribute(attrs.glyphLineIndex, 1));
1284
- geo.setAttribute('glyphBaselineY', new THREE.Float32BufferAttribute(attrs.glyphBaselineY, 1));
1285
- }
1286
- function applyStencilXOR(mat) {
1287
- mat.depthTest = false;
1288
- mat.depthWrite = false;
1289
- mat.side = THREE.DoubleSide;
1290
- mat.stencilWrite = true;
1291
- mat.stencilFunc = THREE.AlwaysStencilFunc;
1292
- mat.stencilRef = 0;
1293
- mat.stencilFuncMask = 0xFF;
1294
- mat.stencilWriteMask = 0xFF;
1295
- mat.stencilFail = THREE.KeepStencilOp;
1296
- mat.stencilZFail = THREE.KeepStencilOp;
1297
- mat.stencilZPass = THREE.InvertStencilOp;
1298
- }
1299
- // Three meshes that must render in order (via renderOrder or sequential draws):
1300
- // 1. interiorMesh - stencil XOR (fan triangulated interiors, no color output)
1301
- // 2. curveMesh - stencil XOR (Loop-Blinn curve eval, alpha-to-coverage)
1302
- // 3. fillMesh - color where stencil != 0, then zeros stencil
1303
- function createVectorMeshes(data, color) {
1304
- const interiorGeo = new THREE.BufferGeometry();
1305
- interiorGeo.setAttribute('position', new THREE.Float32BufferAttribute(data.interiorPositions, 3));
1306
- interiorGeo.setIndex(new THREE.BufferAttribute(data.interiorIndices, 1));
1307
- setGlyphAttrsOnGeometry(interiorGeo, data.interiorGlyphAttrs);
1308
- const curveGeo = new THREE.BufferGeometry();
1309
- curveGeo.setAttribute('position', new THREE.Float32BufferAttribute(data.curvePositions, 3));
1310
- const curveVertCount = data.curvePositions.length / 3;
1311
- const curveUVs = new Float32Array(curveVertCount * 2);
1312
- for (let i = 0; i < curveVertCount; i += 3) {
1313
- curveUVs[i * 2] = 0;
1314
- curveUVs[i * 2 + 1] = 0; // p0
1315
- curveUVs[i * 2 + 2] = 0.5;
1316
- curveUVs[i * 2 + 3] = 0; // p1
1317
- curveUVs[i * 2 + 4] = 1;
1318
- curveUVs[i * 2 + 5] = 1; // p2
1319
- }
1320
- curveGeo.setAttribute('uv', new THREE.Float32BufferAttribute(curveUVs, 2));
1321
- setGlyphAttrsOnGeometry(curveGeo, data.curveGlyphAttrs);
1322
- const fillGeo = new THREE.BufferGeometry();
1323
- fillGeo.setAttribute('position', new THREE.Float32BufferAttribute(data.fillPositions, 3));
1324
- fillGeo.setIndex(new THREE.BufferAttribute(data.fillIndices, 1));
1325
- setGlyphAttrsOnGeometry(fillGeo, data.fillGlyphAttrs);
1326
- // 1) Interior stencil material - no color output
1327
- const stencilInteriorMat = new THREE.MeshBasicNodeMaterial();
1328
- applyStencilXOR(stencilInteriorMat);
1329
- stencilInteriorMat.colorWrite = false;
1330
- // 2) Curve stencil material - Loop-Blinn fragment evaluation
1331
- const stencilCurveMat = new THREE.MeshBasicNodeMaterial();
1332
- applyStencilXOR(stencilCurveMat);
1333
- stencilCurveMat.colorWrite = false;
1334
- stencilCurveMat.alphaToCoverage = true;
1335
- stencilCurveMat.fragmentNode = loopBlinnFragment();
1336
- // 3) Color fill material - renders where stencil != 0
1337
- const colorMat = new THREE.MeshBasicNodeMaterial();
1338
- colorMat.depthTest = false;
1339
- colorMat.depthWrite = false;
1340
- colorMat.side = THREE.DoubleSide;
1341
- colorMat.stencilWrite = true;
1342
- colorMat.stencilFunc = THREE.NotEqualStencilFunc;
1343
- colorMat.stencilRef = 0;
1344
- colorMat.stencilFuncMask = 0xFF;
1345
- colorMat.stencilWriteMask = 0xFF;
1346
- colorMat.stencilFail = THREE.KeepStencilOp;
1347
- colorMat.stencilZFail = THREE.KeepStencilOp;
1348
- colorMat.stencilZPass = THREE.ZeroStencilOp;
1349
- if (color !== undefined) {
1350
- colorMat.color = new THREE.Color(color);
1351
- }
1352
- const interiorMesh = new THREE.Mesh(interiorGeo, stencilInteriorMat);
1353
- const curveMesh = new THREE.Mesh(curveGeo, stencilCurveMat);
1354
- const fillMesh = new THREE.Mesh(fillGeo, colorMat);
1355
- return {
1356
- interiorMesh,
1357
- curveMesh,
1358
- fillMesh,
1359
- setOffset(x, y, z = 0) {
1360
- interiorMesh.position.set(x, y, z);
1361
- curveMesh.position.set(x, y, z);
1362
- fillMesh.position.set(x, y, z);
1363
- },
1364
- dispose() {
1365
- interiorGeo.dispose();
1366
- curveGeo.dispose();
1367
- fillGeo.dispose();
1368
- stencilInteriorMat.dispose();
1369
- stencilCurveMat.dispose();
1370
- colorMat.dispose();
1371
- }
1372
- };
1373
- }
1374
-
1375
1247
  function buildVectorResult(layoutHandle, vectorBuilder, options) {
1376
1248
  const scale = layoutHandle.layoutData.pixelsPerFontUnit;
1377
1249
  const { loopBlinnInput, glyphs } = vectorBuilder.buildForLoopBlinn(layoutHandle.clustersByLine, scale);
@@ -1431,4 +1303,4 @@ class Text {
1431
1303
  }
1432
1304
  }
1433
1305
 
1434
- export { Text, buildVectorGeometry, createVectorMeshes, extractContours };
1306
+ export { Text, buildVectorGeometry, extractContours };
@@ -185,7 +185,9 @@ void main() {
185
185
  gl.enable(gl.STENCIL_TEST);
186
186
  gl.stencilMask(0xff);
187
187
  gl.stencilFunc(gl.ALWAYS, 0, 0xff);
188
- gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT);
188
+ // Nonzero winding: front faces increment, back faces decrement
189
+ gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP);
190
+ gl.stencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP);
189
191
  gl.colorMask(false, false, false, false);
190
192
  if (geometryResources.interiorIndexCount > 0) {
191
193
  gl.useProgram(interiorProgram.program);
@@ -183,7 +183,9 @@ void main() {
183
183
  gl.enable(gl.STENCIL_TEST);
184
184
  gl.stencilMask(0xff);
185
185
  gl.stencilFunc(gl.ALWAYS, 0, 0xff);
186
- gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT);
186
+ // Nonzero winding: front faces increment, back faces decrement
187
+ gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP);
188
+ gl.stencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP);
187
189
  gl.colorMask(false, false, false, false);
188
190
  if (geometryResources.interiorIndexCount > 0) {
189
191
  gl.useProgram(interiorProgram.program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-text",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "3D mesh font geometry and text layout engine for the web",
5
5
  "main": "dist/three/index.cjs",
6
6
  "module": "dist/three/index.js",