@ar-js-org/artoolkit5-ts 0.2.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.1] - 2026-09-19
11
+
12
+ ### Added
13
+
14
+ - `MarkerPose.vertex` — the four corners of the detected square, in camera
15
+ image coordinates with the origin at top-left. Closes #54.
16
+
17
+ The WASM binding already returned these; only the TypeScript types and
18
+ `processFrame` did not carry them through, so no rebuild of
19
+ `@ar-js-org/artoolkit5-wasm` was needed. `MarkerInfo.vertex` is declared
20
+ for the same reason.
21
+
22
+ Unlike `matrix` and `matrixGL`, which are views onto buffers reused every
23
+ frame, `vertex` is freshly allocated per frame and is safe to retain
24
+ without copying. Corner order depends on the marker's rotation —
25
+ `vertex[(4 - dir) % 4]` is the marker's top-left corner, the rest clockwise
26
+ from there — which matters for anything orientation-sensitive and not at all
27
+ for outlining the square.
28
+
29
+ Corners let a consumer draw a marker outline, hit-test or build an occlusion
30
+ mask without needing the camera projection matrix at all.
31
+
32
+ ### Changed
33
+
34
+ - `MarkerInfo` gained `vertex` as a **required** field. Nothing in the
35
+ library constructs a `MarkerInfo` — they come from the WASM binding, which
36
+ already supplied corners — but a hand-written `ARToolKitCore` double in a
37
+ consumer's tests now fails to typecheck until it supplies four points.
38
+
39
+ - Lockfile moved onto `@ar-js-org/artoolkit5-constants` 0.3.1, whose published
40
+ metadata now correctly declares MIT rather than GPL-3.0. No code changed
41
+ upstream; only the declaration was wrong. Closes #53.
42
+
10
43
  ## [0.2.0] - 2026-09-17
11
44
 
12
45
  ### Upgrading from 0.1.0
@@ -185,6 +218,7 @@ Pattern markers only. Barcode support is planned; NFT is out of scope for this
185
218
  project. Worker compatibility is untested — nothing in `src/` touches the DOM,
186
219
  which is necessary but not proof.
187
220
 
188
- [Unreleased]: https://github.com/AR-js-org/artoolkit5-ts/compare/v0.2.0...HEAD
221
+ [Unreleased]: https://github.com/AR-js-org/artoolkit5-ts/compare/v0.2.1...HEAD
222
+ [0.2.1]: https://github.com/AR-js-org/artoolkit5-ts/compare/v0.2.0...v0.2.1
189
223
  [0.2.0]: https://github.com/AR-js-org/artoolkit5-ts/compare/v0.1.0...v0.2.0
190
224
  [0.1.0]: https://github.com/AR-js-org/artoolkit5-ts/releases/tag/v0.1.0
package/README.md CHANGED
@@ -255,9 +255,25 @@ interface MarkerPose {
255
255
  confidence: number; // 0–1, from this marker's own family
256
256
  matrix: Float64Array; // 3x4, row-major, as ARToolKit produces it
257
257
  matrixGL: Float32Array; // 4x4, column-major, right-handed, WebGL-ready
258
+ vertex: [number, number][]; // the square's 4 corners, camera image coords
258
259
  }
259
260
  ```
260
261
 
262
+ `vertex` gives the four corners of the detected square in camera image
263
+ coordinates, origin at top-left — enough to outline a marker, hit-test it or
264
+ build an occlusion mask without touching the camera projection matrix. Two
265
+ things differ from the pose matrices:
266
+
267
+ - **It is freshly allocated per frame**, not a view onto a reused buffer, so it is
268
+ safe to retain without copying. `matrix` and `matrixGL` are the opposite.
269
+ - **Corner order follows the marker's rotation.** `vertex[(4 - dir) % 4]` is
270
+ the marker's own top-left corner, the rest clockwise from there. Outlining
271
+ the square can ignore this; anything orientation-sensitive cannot.
272
+
273
+ The webcam example draws exactly this outline, marking corner 0 so the
274
+ ordering is visible: see `createOutlineDrawer` in
275
+ [`examples/webcam/main.ts`](examples/webcam/main.ts).
276
+
261
277
  `confidence` is read from the field belonging to the marker's family — `cfPatt` or `cfMatrix` — so it is comparable within a family but not across them. See [`minConfidence`](#minconfidence--rejecting-weak-matches) for measured ranges.
262
278
 
263
279
  `type` says which family a detection came from. The engine reports the two through separate fields — `idPatt` for pattern markers, `idMatrix` for barcode markers — and each is matched only against its own registry, so `type` follows from which registry answered rather than from any value the engine supplies. This is also why the families have independent ID spaces: the same integer in each is two unrelated markers.
@@ -143,22 +143,23 @@ function I(e) {
143
143
  function L(e) {
144
144
  let t = [], n = e.core.getMarkerNum();
145
145
  for (let r = 0; r < n; r++) {
146
- let n = e.core.getMarkerInfo(r), i = R(e.patternMarkers, e, r, n.idPatt, n.cfPatt, "pattern", e.minConfidence.pattern);
146
+ let n = e.core.getMarkerInfo(r), i = R(e.patternMarkers, e, r, n.idPatt, n.cfPatt, "pattern", e.minConfidence.pattern, n.vertex);
147
147
  i && t.push(i);
148
- let a = R(e.barcodeMarkers, e, r, n.idMatrix, n.cfMatrix, "barcode", e.minConfidence.barcode);
148
+ let a = R(e.barcodeMarkers, e, r, n.idMatrix, n.cfMatrix, "barcode", e.minConfidence.barcode, n.vertex);
149
149
  a && t.push(a);
150
150
  }
151
151
  return t;
152
152
  }
153
- function R(e, t, n, r, i, a, o) {
153
+ function R(e, t, n, r, i, a, o, s) {
154
154
  if (r === D) return;
155
- let s = e[r];
156
- if (s && !(i < o)) return s.inCurrent = !0, B(t, n, s), {
157
- id: s.id,
155
+ let c = e[r];
156
+ if (c && !(i < o)) return c.inCurrent = !0, B(t, n, c), {
157
+ id: c.id,
158
158
  type: a,
159
159
  confidence: i,
160
- matrix: s.matrix,
161
- matrixGL: s.matrixGL
160
+ matrix: c.matrix,
161
+ matrixGL: c.matrixGL,
162
+ vertex: s
162
163
  };
163
164
  }
164
165
  function z(e) {
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@ar-js-org/artoolkit5-wasm")):typeof define==`function`&&define.amd?define([`exports`,`@ar-js-org/artoolkit5-wasm`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ARToolkit5TS={},e.ARToolkit5Wasm))})(this,function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=class e extends Error{constructor(t){super(t),this.name=`ARToolKitError`,Object.setPrototypeOf(this,e.prototype)}};function r(e,t){if(e.disposed)throw new n(`${t} was called on a disposed ARToolKitState. Create a new one with createARToolKitState().`)}async function i(e,n,r,i){let a=(await(0,t.createARToolKit)({locateFile:e=>i&&e.endsWith(`.wasm`)?i:e})).mod,o=new a.ARToolKitCore,s=await(0,t.loadCameraFromUrl)(a,o,r);return await o.setup(e,n,s),{mod:a,core:o,width:e,height:n,patternMarkers:{},barcodeMarkers:{},minConfidence:{pattern:0,barcode:0},disposed:!1}}function a(e){e.disposed||=(e.core.teardown(),e.core.delete(),e.patternMarkers={},e.barcodeMarkers={},!0)}var o=1028,s=1029,c=1285,l={color:0,mono:1,matrix:2,color_and_matrix:3,mono_and_matrix:4},u={"3x3":3,"3x3_PARITY65":259,"3x3_HAMMING63":515,"4x4":4,"4x4_BCH_13_9_3":772,"4x4_BCH_13_5_5":o,"5x5":5,"5x5_BCH_22_7_7":c,"5x5_BCH_22_12_5":s,"6x6":6},d={manual:0,auto_median:1,auto_otsu:2,auto_bracketing:4},f={frame:0,field:1},p={white_region:0,black_region:1};function m(e,t,r){let i=Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0;if(i===void 0){let i=Object.keys(e).join(`, `);throw new n(`Invalid value ${JSON.stringify(t)} for '${r}'. Valid values are: ${i}.`)}return i}function h(e,t){if(r(e,`configureDetector`),t.detectionMode!==void 0&&e.core.setPatternDetectionMode(m(l,t.detectionMode,`detectionMode`)),t.matrixCodeType!==void 0&&e.core.setMatrixCodeType(m(u,t.matrixCodeType,`matrixCodeType`)),t.threshold!==void 0&&e.core.setThreshold(g(t.threshold)),t.thresholdMode!==void 0&&e.core.setThresholdMode(m(d,t.thresholdMode,`thresholdMode`)),t.labelingMode!==void 0&&e.core.setLabelingMode(m(p,t.labelingMode,`labelingMode`)),t.imageProcMode!==void 0&&e.core.setImageProcMode(m(f,t.imageProcMode,`imageProcMode`)),t.patternRatio!==void 0&&e.core.setPattRatio(_(t.patternRatio)),t.minConfidence!==void 0){let{pattern:n,barcode:r}=t.minConfidence;n!==void 0&&(e.minConfidence.pattern=v(n,`minConfidence.pattern`)),r!==void 0&&(e.minConfidence.barcode=v(r,`minConfidence.barcode`))}t.nearPlane!==void 0&&e.core.setProjectionNearPlane(t.nearPlane),t.farPlane!==void 0&&e.core.setProjectionFarPlane(t.farPlane),(t.nearPlane!==void 0||t.farPlane!==void 0)&&e.core.recalculateCameraLens()}function g(e){if(!Number.isInteger(e)||e<0||e>255)throw new n(`Invalid value ${e} for 'threshold'. Must be an integer between 0 and 255 inclusive.`);return e}function _(e){if(!Number.isFinite(e)||e<=0||e>=1)throw new n(`Invalid value ${e} for 'patternRatio'. Must be a finite number greater than 0 and less than 1.`);return e}function v(e,t){if(!Number.isFinite(e)||e<0||e>1)throw new n(`Invalid value ${e} for '${t}'. Must be a finite number between 0 and 1 inclusive.`);return e}async function y(e,n){return r(e,`loadPatternMarker`),(0,t.addMarkerFromUrl)(e.mod,e.core,n)}var b=16;function x(e){return r(e,`getCameraProjectionMatrix`),e.core.getCameraLens()}function S(e,t=new Float32Array(b)){return t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=0,t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=0,t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=0,t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=1,t}function C(e,t=new Float32Array(b),n){return t[0]=e[0],t[4]=e[4],t[8]=e[8],t[12]=e[12],t[1]=-e[1],t[5]=-e[5],t[9]=-e[9],t[13]=-e[13],t[2]=-e[2],t[6]=-e[6],t[10]=-e[10],t[14]=-e[14],t[3]=0,t[7]=0,t[11]=0,t[15]=1,n!==void 0&&n!==0&&(t[12]*=n,t[13]*=n,t[14]*=n),t}var w=12,T=3,E=-1,D=[],O=!0,k=new Float32Array(16);function A(e,t,n=1){r(e,`trackMarker`),e.patternMarkers[t]=M(t,n)}function j(e,t,n=1){r(e,`trackBarcodeMarker`),e.barcodeMarkers[t]=M(t,n)}function M(e,t){return{id:e,markerWidth:t,inPrevious:!1,inCurrent:!1,matrix:new Float64Array(w),matrixGL:new Float32Array(16)}}function N(e,t){return r(e,`processFrame`),P(e,t),F(e),{detected:I(e),lost:R(e)}}function P(e,t){e.core.passVideoData(t,D,O),e.core.detectMarker()}function F(e){for(let t of[e.patternMarkers,e.barcodeMarkers])for(let e in t){let n=t[e];n.inPrevious=n.inCurrent,n.inCurrent=!1}}function I(e){let t=[],n=e.core.getMarkerNum();for(let r=0;r<n;r++){let n=e.core.getMarkerInfo(r),i=L(e.patternMarkers,e,r,n.idPatt,n.cfPatt,`pattern`,e.minConfidence.pattern);i&&t.push(i);let a=L(e.barcodeMarkers,e,r,n.idMatrix,n.cfMatrix,`barcode`,e.minConfidence.barcode);a&&t.push(a)}return t}function L(e,t,n,r,i,a,o){if(r===E)return;let s=e[r];if(s&&!(i<o))return s.inCurrent=!0,z(t,n,s),{id:s.id,type:a,confidence:i,matrix:s.matrix,matrixGL:s.matrixGL}}function R(e){let t=[],n=[[e.patternMarkers,`pattern`],[e.barcodeMarkers,`barcode`]];for(let[e,r]of n)for(let n in e){let i=e[n];i.inPrevious&&!i.inCurrent&&t.push({id:i.id,type:r})}return t}function z(e,t,n){n.inPrevious?e.core.getTransMatSquareCont(t,n.markerWidth):e.core.getTransMatSquare(t,n.markerWidth),B(e,n.matrix),S(n.matrix,k),C(k,n.matrixGL)}function B(e,t){let n=e.core.getTransform()>>T;t.set(e.mod.HEAPF64.subarray(n,n+w))}e.ARToolKitError=n,e.arglCameraViewRHf=C,e.configureDetector=h,e.createARToolKitState=i,e.disposeARToolKitState=a,e.getCameraProjectionMatrix=x,e.loadPatternMarker=y,e.processFrame=N,e.trackBarcodeMarker=j,e.trackMarker=A,e.transMatToGLMat=S});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@ar-js-org/artoolkit5-wasm")):typeof define==`function`&&define.amd?define([`exports`,`@ar-js-org/artoolkit5-wasm`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ARToolkit5TS={},e.ARToolkit5Wasm))})(this,function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=class e extends Error{constructor(t){super(t),this.name=`ARToolKitError`,Object.setPrototypeOf(this,e.prototype)}};function r(e,t){if(e.disposed)throw new n(`${t} was called on a disposed ARToolKitState. Create a new one with createARToolKitState().`)}async function i(e,n,r,i){let a=(await(0,t.createARToolKit)({locateFile:e=>i&&e.endsWith(`.wasm`)?i:e})).mod,o=new a.ARToolKitCore,s=await(0,t.loadCameraFromUrl)(a,o,r);return await o.setup(e,n,s),{mod:a,core:o,width:e,height:n,patternMarkers:{},barcodeMarkers:{},minConfidence:{pattern:0,barcode:0},disposed:!1}}function a(e){e.disposed||=(e.core.teardown(),e.core.delete(),e.patternMarkers={},e.barcodeMarkers={},!0)}var o=1028,s=1029,c=1285,l={color:0,mono:1,matrix:2,color_and_matrix:3,mono_and_matrix:4},u={"3x3":3,"3x3_PARITY65":259,"3x3_HAMMING63":515,"4x4":4,"4x4_BCH_13_9_3":772,"4x4_BCH_13_5_5":o,"5x5":5,"5x5_BCH_22_7_7":c,"5x5_BCH_22_12_5":s,"6x6":6},d={manual:0,auto_median:1,auto_otsu:2,auto_bracketing:4},f={frame:0,field:1},p={white_region:0,black_region:1};function m(e,t,r){let i=Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0;if(i===void 0){let i=Object.keys(e).join(`, `);throw new n(`Invalid value ${JSON.stringify(t)} for '${r}'. Valid values are: ${i}.`)}return i}function h(e,t){if(r(e,`configureDetector`),t.detectionMode!==void 0&&e.core.setPatternDetectionMode(m(l,t.detectionMode,`detectionMode`)),t.matrixCodeType!==void 0&&e.core.setMatrixCodeType(m(u,t.matrixCodeType,`matrixCodeType`)),t.threshold!==void 0&&e.core.setThreshold(g(t.threshold)),t.thresholdMode!==void 0&&e.core.setThresholdMode(m(d,t.thresholdMode,`thresholdMode`)),t.labelingMode!==void 0&&e.core.setLabelingMode(m(p,t.labelingMode,`labelingMode`)),t.imageProcMode!==void 0&&e.core.setImageProcMode(m(f,t.imageProcMode,`imageProcMode`)),t.patternRatio!==void 0&&e.core.setPattRatio(_(t.patternRatio)),t.minConfidence!==void 0){let{pattern:n,barcode:r}=t.minConfidence;n!==void 0&&(e.minConfidence.pattern=v(n,`minConfidence.pattern`)),r!==void 0&&(e.minConfidence.barcode=v(r,`minConfidence.barcode`))}t.nearPlane!==void 0&&e.core.setProjectionNearPlane(t.nearPlane),t.farPlane!==void 0&&e.core.setProjectionFarPlane(t.farPlane),(t.nearPlane!==void 0||t.farPlane!==void 0)&&e.core.recalculateCameraLens()}function g(e){if(!Number.isInteger(e)||e<0||e>255)throw new n(`Invalid value ${e} for 'threshold'. Must be an integer between 0 and 255 inclusive.`);return e}function _(e){if(!Number.isFinite(e)||e<=0||e>=1)throw new n(`Invalid value ${e} for 'patternRatio'. Must be a finite number greater than 0 and less than 1.`);return e}function v(e,t){if(!Number.isFinite(e)||e<0||e>1)throw new n(`Invalid value ${e} for '${t}'. Must be a finite number between 0 and 1 inclusive.`);return e}async function y(e,n){return r(e,`loadPatternMarker`),(0,t.addMarkerFromUrl)(e.mod,e.core,n)}var b=16;function x(e){return r(e,`getCameraProjectionMatrix`),e.core.getCameraLens()}function S(e,t=new Float32Array(b)){return t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=0,t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=0,t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=0,t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=1,t}function C(e,t=new Float32Array(b),n){return t[0]=e[0],t[4]=e[4],t[8]=e[8],t[12]=e[12],t[1]=-e[1],t[5]=-e[5],t[9]=-e[9],t[13]=-e[13],t[2]=-e[2],t[6]=-e[6],t[10]=-e[10],t[14]=-e[14],t[3]=0,t[7]=0,t[11]=0,t[15]=1,n!==void 0&&n!==0&&(t[12]*=n,t[13]*=n,t[14]*=n),t}var w=12,T=3,E=-1,D=[],O=!0,k=new Float32Array(16);function A(e,t,n=1){r(e,`trackMarker`),e.patternMarkers[t]=M(t,n)}function j(e,t,n=1){r(e,`trackBarcodeMarker`),e.barcodeMarkers[t]=M(t,n)}function M(e,t){return{id:e,markerWidth:t,inPrevious:!1,inCurrent:!1,matrix:new Float64Array(w),matrixGL:new Float32Array(16)}}function N(e,t){return r(e,`processFrame`),P(e,t),F(e),{detected:I(e),lost:R(e)}}function P(e,t){e.core.passVideoData(t,D,O),e.core.detectMarker()}function F(e){for(let t of[e.patternMarkers,e.barcodeMarkers])for(let e in t){let n=t[e];n.inPrevious=n.inCurrent,n.inCurrent=!1}}function I(e){let t=[],n=e.core.getMarkerNum();for(let r=0;r<n;r++){let n=e.core.getMarkerInfo(r),i=L(e.patternMarkers,e,r,n.idPatt,n.cfPatt,`pattern`,e.minConfidence.pattern,n.vertex);i&&t.push(i);let a=L(e.barcodeMarkers,e,r,n.idMatrix,n.cfMatrix,`barcode`,e.minConfidence.barcode,n.vertex);a&&t.push(a)}return t}function L(e,t,n,r,i,a,o,s){if(r===E)return;let c=e[r];if(c&&!(i<o))return c.inCurrent=!0,z(t,n,c),{id:c.id,type:a,confidence:i,matrix:c.matrix,matrixGL:c.matrixGL,vertex:s}}function R(e){let t=[],n=[[e.patternMarkers,`pattern`],[e.barcodeMarkers,`barcode`]];for(let[e,r]of n)for(let n in e){let i=e[n];i.inPrevious&&!i.inCurrent&&t.push({id:i.id,type:r})}return t}function z(e,t,n){n.inPrevious?e.core.getTransMatSquareCont(t,n.markerWidth):e.core.getTransMatSquare(t,n.markerWidth),B(e,n.matrix),S(n.matrix,k),C(k,n.matrixGL)}function B(e,t){let n=e.core.getTransform()>>T;t.set(e.mod.HEAPF64.subarray(n,n+w))}e.ARToolKitError=n,e.arglCameraViewRHf=C,e.configureDetector=h,e.createARToolKitState=i,e.disposeARToolKitState=a,e.getCameraProjectionMatrix=x,e.loadPatternMarker=y,e.processFrame=N,e.trackBarcodeMarker=j,e.trackMarker=A,e.transMatToGLMat=S});
package/dist/domain.d.ts CHANGED
@@ -57,6 +57,20 @@ export interface MarkerPose {
57
57
  * camera noise and calibration in the millimetre range.
58
58
  */
59
59
  matrixGL: Float32Array;
60
+ /**
61
+ * The four corners of the detected square, in camera image coordinates
62
+ * with the origin at top-left.
63
+ *
64
+ * Unlike `matrix` and `matrixGL`, this is **not** a view onto a reused
65
+ * buffer — the engine builds a fresh array each frame, so it is safe to
66
+ * retain without copying.
67
+ *
68
+ * Corner order depends on the marker's rotation: `vertex[(4 - dir) % 4]`
69
+ * is the top-left corner of the marker itself, with the rest proceeding
70
+ * clockwise from there. Anything that merely outlines the square can
71
+ * ignore that; anything orientation-sensitive cannot.
72
+ */
73
+ vertex: [number, number][];
60
74
  }
61
75
  /**
62
76
  * Outcome of a single call to `processFrame`.
@@ -143,6 +157,12 @@ export interface MarkerInfo {
143
157
  cfPatt: number;
144
158
  /** Matrix-code confidence, 0.0-1.0, or -1.0 when there was no match. */
145
159
  cfMatrix: number;
160
+ /**
161
+ * 2D positions of the square's four corners, in camera image coordinates
162
+ * with the origin at top-left. Populated in every detection mode, unlike
163
+ * the id and confidence fields above.
164
+ */
165
+ vertex: [number, number][];
146
166
  }
147
167
  /**
148
168
  * The C++ `ARToolKitCore` instance, narrowed to the methods this library calls.
@@ -39,9 +39,11 @@ export declare function trackBarcodeMarker(state: ARToolKitState, barcodeId: num
39
39
  * so a consumer emitting found/updated/lost events does not have to diff
40
40
  * successive results to recover information tracking already had.
41
41
  *
42
- * Called once per animation frame, so it allocates no typed arrays: every pose
43
- * is written into buffers owned by the marker's tracking state. Those buffers
44
- * are reused next frame — copy them if you need to retain values.
42
+ * Called once per animation frame, so it allocates no typed arrays: `matrix`
43
+ * and `matrixGL` are written into buffers owned by the marker's tracking
44
+ * state, and those buffers are reused next frame — copy them if you need to
45
+ * retain values. `vertex` is the exception; it is a fresh array every frame
46
+ * and can be retained as it is.
45
47
  *
46
48
  * @param videoFrame RGBA pixels matching the width and height the state was
47
49
  * created with.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ar-js-org/artoolkit5-ts",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "TypeScript marker tracking for the browser, built on a WebAssembly build of ARToolkit5 (WebARKitLib). Composable and tree-shakeable: state is plain data, operations are functions.",