isard 2.2.1 → 2.2.2

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
@@ -5,6 +5,25 @@ versions [Semantic Versioning](https://semver.org) (before 1.0.0, a minor versio
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [2.2.2] - 2026-11-01
9
+
10
+ With `isard-react-native` and `isard-map` (Python) 2.2.2.
11
+
12
+ ### Fixed
13
+
14
+ - The section box's handles let go when the button is released, even where the browser lets the pointer's capture go
15
+ (Safari): the box no longer went on following the pointer
16
+ - The models' translucent faces (an IFC window's glass, a glTF material's color with alpha under 1) drawn after the
17
+ others, their depth not written, casting no shadow: they no longer hid what stands behind them in squares nor
18
+ streaked between their two faces
19
+
20
+ ### Added
21
+
22
+ - `JsObject.value(then=fn)` in `isard-map`: an object of the page as plain data (`model.get("place").value(then=…)`)
23
+ - The example A section box in Python and React Native, its IFC files read in the page and given to the map as
24
+ handles; standing inside (`setFirstPerson`), the eye looks all around, up to the sky; the building's garden and the
25
+ terrain around it its ground
26
+
8
27
  ## [2.2.1] - 2026-11-01
9
28
 
10
29
  With `isard-react-native` and `isard-map` (Python) 2.2.1.
Binary file
Binary file
Binary file
@@ -89,6 +89,8 @@ export class ClipBoxHandles {
89
89
  disc.addEventListener('pointermove', (e) => this.move(e));
90
90
  disc.addEventListener('pointerup', (e) => this.up(e));
91
91
  disc.addEventListener('pointercancel', (e) => this.up(e));
92
+ // Safari may let the capture go: the release would then reach the map, not the disc
93
+ disc.addEventListener('lostpointercapture', (e) => this.up(e));
92
94
  return svg.appendChild(disc);
93
95
  });
94
96
  }
@@ -165,6 +167,11 @@ export class ClipBoxHandles {
165
167
  move(e) {
166
168
  if (!this.held)
167
169
  return;
170
+ // No button held any more: its release was missed (the capture lost), the drag is over
171
+ if (e.buttons === 0) {
172
+ this.up(e);
173
+ return;
174
+ }
168
175
  e.stopPropagation();
169
176
  const { handle, start, box, grab } = this.held;
170
177
  const at = this.local(e);
@@ -1 +1 @@
1
- {"version":3,"file":"clip-box.js","sourceRoot":"","sources":["../../src/map/clip-box.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The clipping box (`GeoMap.setClipBox`): given to the engine, and its handles over the map, an outline of its edges\n * and a disc on each face to size it, one at its middle to move it, placed after every frame.\n */\n\nimport { rgb } from '../settings.ts';\nimport type { ClipBox, LonLat, Point } from '../types.ts';\nimport type { Positioned } from '../ui/overlay.ts';\nimport type { Engine } from '../wasm/isard_webgpu.js';\n\n/** The faces' color by default: plaster, as a section on a plan */\nconst SECTION = '#d9cfc1';\n/** Metres a side of the box keeps at least */\nconst SMALLEST = 0.2;\nconst SVG = 'http://www.w3.org/2000/svg';\n\n/** Sets the box in the engine, or clears it without one */\nexport const applyClipBox = (engine: Engine, box: ClipBox | undefined): void => {\n if (!box) {\n engine.clearClipBox();\n\n return;\n }\n\n const [width, length, height] = box.size;\n const section = box.sectionColor === null ? [] : rgb(box.sectionColor ?? SECTION);\n\n engine.setClipBox(\n new Float64Array([\n box.position[0],\n box.position[1],\n box.altitude ?? 0,\n width,\n length,\n height,\n box.heading ?? 0,\n box.cut === 'outside' ? 0 : 1,\n box.altitudeReference === 'sea' ? 0 : 1,\n ]),\n new Float32Array(section),\n );\n};\n\n/** What the handles need from the map */\nexport interface ClipBoxHost {\n project(lonLat: LonLat, height?: number): Point | undefined;\n unproject(point: Point): LonLat | undefined;\n elevationAt(lonLat: LonLat): number | undefined;\n getCanvas(): HTMLCanvasElement;\n /** The box changed by a handle: set, and told */\n moved(box: ClipBox): void;\n}\n\n/** A face's handle: its axis (0 across, 1 along, 2 up) and side */\ninterface Face {\n axis: 0 | 1 | 2;\n side: -1 | 1;\n}\n\n/** A handle: on a face, or at the middle (moves the box, clear of the bottom face's) */\ntype Handle = Face | 'move';\n\n/** Metres across, along and up from the foot's center of a face's center, `out` metres out of it */\nconst faceAt = (box: ClipBox, { axis, side }: Face, out = 0): [number, number, number] => {\n const [, , h] = box.size;\n const offset: [number, number, number] = [0, 0, h / 2];\n\n offset[axis] = axis === 2 ? (side > 0 ? h : 0) + side * out : side * (box.size[axis] / 2 + out);\n\n return offset;\n};\n\n/** The 12 edges of the box, as pairs of corners (bit 0 across, 1 along, 2 up) */\nconst EDGES: [number, number][] = [\n [0, 1],\n [2, 3],\n [4, 5],\n [6, 7],\n [0, 2],\n [1, 3],\n [4, 6],\n [5, 7],\n [0, 4],\n [1, 5],\n [2, 6],\n [3, 7],\n];\n\nconst HANDLES: Handle[] = [\n { axis: 0, side: -1 },\n { axis: 0, side: 1 },\n { axis: 1, side: -1 },\n { axis: 1, side: 1 },\n { axis: 2, side: -1 },\n { axis: 2, side: 1 },\n 'move',\n];\n\n/** The handles of a box, over the map */\nexport class ClipBoxHandles implements Positioned {\n /** Over the canvas, its drawing within */\n readonly element: HTMLDivElement;\n private readonly lines: SVGLineElement[];\n private readonly discs: SVGCircleElement[];\n /** The handle held (its disc), the pointer and the box where it was pressed */\n private held: { handle: Handle; disc: SVGCircleElement; start: Point; box: ClipBox; grab: Point } | undefined;\n\n constructor(\n private readonly host: ClipBoxHost,\n private box: ClipBox,\n /** Metres of the body's radius (metres to degrees) */\n private readonly radius: number,\n ) {\n const svg = document.createElementNS(SVG, 'svg');\n\n this.element = document.createElement('div');\n this.element.className = 'isard-clipbox';\n this.element.append(svg);\n this.lines = EDGES.map(() => svg.appendChild(document.createElementNS(SVG, 'line')));\n this.discs = HANDLES.map((handle) => {\n const disc = document.createElementNS(SVG, 'circle');\n\n disc.setAttribute('r', handle === 'move' ? '8' : '6');\n disc.setAttribute('class', handle === 'move' ? 'isard-clipbox-move' : 'isard-clipbox-face');\n disc.addEventListener('pointerdown', (e) => this.down(e, handle, disc));\n disc.addEventListener('pointermove', (e) => this.move(e));\n disc.addEventListener('pointerup', (e) => this.up(e));\n disc.addEventListener('pointercancel', (e) => this.up(e));\n\n return svg.appendChild(disc);\n });\n }\n\n /** The box the handles follow from the next placing (`position`, after each frame) */\n set(box: ClipBox): void {\n this.box = box;\n }\n\n position(): void {\n const corners = this.corners(this.box);\n const centers = HANDLES.map((handle) => this.handleAt(this.box, handle));\n\n EDGES.forEach(([a, b], i) => {\n const [p, q] = [corners[a], corners[b]];\n const line = this.lines[i];\n\n if (!line) return;\n line.style.display = p && q ? '' : 'none';\n if (!p || !q) return;\n line.setAttribute('x1', String(p[0]));\n line.setAttribute('y1', String(p[1]));\n line.setAttribute('x2', String(q[0]));\n line.setAttribute('y2', String(q[1]));\n });\n centers.forEach((p, i) => {\n const disc = this.discs[i];\n\n if (!disc) return;\n disc.style.display = p ? '' : 'none';\n if (!p) return;\n disc.setAttribute('cx', String(p[0]));\n disc.setAttribute('cy', String(p[1]));\n });\n }\n\n /** A point of the box, metres across and along its heading from its foot's center and up from its foot */\n private at(box: ClipBox, across: number, along: number, up: number): Point | undefined {\n const heading = ((box.heading ?? 0) * Math.PI) / 180;\n const [sin, cos] = [Math.sin(heading), Math.cos(heading)];\n const lonLat = this.offset(box.position, across * cos + along * sin, along * cos - across * sin);\n // `project` measures from the relief: an altitude above the ellipsoid less the relief under the box\n const ground = box.altitudeReference === 'sea' ? (this.host.elevationAt(box.position) ?? 0) : 0;\n\n return this.host.project(lonLat, (box.altitude ?? 0) - ground + up);\n }\n\n private corners(box: ClipBox): (Point | undefined)[] {\n const [w, l, h] = box.size;\n\n return Array.from({ length: 8 }, (_, k) =>\n this.at(box, (k & 1 ? 0.5 : -0.5) * w, (k & 2 ? 0.5 : -0.5) * l, k & 4 ? h : 0),\n );\n }\n\n /** Where a handle stands on the screen: a face's center, or the box's */\n private handleAt(box: ClipBox, handle: Handle): Point | undefined {\n return handle === 'move' ? this.at(box, 0, 0, box.size[2] / 2) : this.at(box, ...faceAt(box, handle));\n }\n\n private local(e: PointerEvent): Point {\n const rect = this.host.getCanvas().getBoundingClientRect();\n\n return [e.clientX - rect.left, e.clientY - rect.top];\n }\n\n private down(e: PointerEvent, handle: Handle, disc: SVGCircleElement): void {\n if (e.button !== 0) return;\n\n const start = this.local(e);\n // The spot of the ground grabbed, kept under the pointer as the box moves\n const grab = handle === 'move' ? this.host.unproject(start) : undefined;\n\n // The map must not pan under the handle\n e.stopPropagation();\n e.preventDefault();\n disc.setPointerCapture(e.pointerId);\n this.held = {\n handle,\n disc,\n start,\n box: { ...this.box, size: [...this.box.size] },\n grab: grab ? [grab[0] - this.box.position[0], grab[1] - this.box.position[1]] : [0, 0],\n };\n }\n\n private move(e: PointerEvent): void {\n if (!this.held) return;\n e.stopPropagation();\n\n const { handle, start, box, grab } = this.held;\n const at = this.local(e);\n\n if (handle === 'move') {\n // The ground under the pointer, the grabbed spot kept under it\n const lonLat = this.host.unproject(at);\n\n if (lonLat) this.host.moved({ ...box, position: [lonLat[0] - grab[0], lonLat[1] - grab[1]] });\n\n return;\n }\n\n const metres = this.dragged(box, handle, [at[0] - start[0], at[1] - start[1]]);\n\n if (metres !== undefined) this.host.moved(this.resized(box, handle, metres));\n }\n\n /** Metres the pointer dragged a face outward: the drag along the face's axis on the screen */\n private dragged(box: ClipBox, face: Face, [dx, dy]: Point): number | undefined {\n const from = this.at(box, ...faceAt(box, face));\n // Where the face's center goes a metre out, on the screen: pixels per metre along its axis\n const to = this.at(box, ...faceAt(box, face, 1));\n\n if (!from || !to) return undefined;\n\n const [ax, ay] = [to[0] - from[0], to[1] - from[1]];\n const squared = ax * ax + ay * ay;\n\n return squared > 1e-6 ? (dx * ax + dy * ay) / squared : undefined;\n }\n\n /** The box with a face moved `metres` outward, the opposite face where it was */\n private resized(box: ClipBox, { axis, side }: Face, metres: number): ClipBox {\n const size: [number, number, number] = [...box.size];\n const grown = Math.max(SMALLEST, size[axis] + metres);\n const moved = grown - size[axis];\n\n size[axis] = grown;\n if (axis === 2) {\n // The foot lowered when the bottom face goes down\n return side > 0 ? { ...box, size } : { ...box, size, altitude: (box.altitude ?? 0) - moved };\n }\n\n // The center half-way along the move, on the side of the face moved\n const heading = ((box.heading ?? 0) * Math.PI) / 180;\n const [sin, cos] = [Math.sin(heading), Math.cos(heading)];\n const shift = (side * moved) / 2;\n const [east, north] = axis === 0 ? [shift * cos, -shift * sin] : [shift * sin, shift * cos];\n return { ...box, size, position: this.offset(box.position, east, north) };\n }\n\n /** A position `east` and `north` metres from another */\n private offset([lon, lat]: LonLat, east: number, north: number): LonLat {\n return [\n lon + (east / (this.radius * Math.cos((lat * Math.PI) / 180))) * (180 / Math.PI),\n lat + (north / this.radius) * (180 / Math.PI),\n ];\n }\n\n private up(e: PointerEvent): void {\n if (!this.held) return;\n e.stopPropagation();\n if (this.held.disc.hasPointerCapture(e.pointerId)) this.held.disc.releasePointerCapture(e.pointerId);\n this.held = undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"clip-box.js","sourceRoot":"","sources":["../../src/map/clip-box.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The clipping box (`GeoMap.setClipBox`): given to the engine, and its handles over the map, an outline of its edges\n * and a disc on each face to size it, one at its middle to move it, placed after every frame.\n */\n\nimport { rgb } from '../settings.ts';\nimport type { ClipBox, LonLat, Point } from '../types.ts';\nimport type { Positioned } from '../ui/overlay.ts';\nimport type { Engine } from '../wasm/isard_webgpu.js';\n\n/** The faces' color by default: plaster, as a section on a plan */\nconst SECTION = '#d9cfc1';\n/** Metres a side of the box keeps at least */\nconst SMALLEST = 0.2;\nconst SVG = 'http://www.w3.org/2000/svg';\n\n/** Sets the box in the engine, or clears it without one */\nexport const applyClipBox = (engine: Engine, box: ClipBox | undefined): void => {\n if (!box) {\n engine.clearClipBox();\n\n return;\n }\n\n const [width, length, height] = box.size;\n const section = box.sectionColor === null ? [] : rgb(box.sectionColor ?? SECTION);\n\n engine.setClipBox(\n new Float64Array([\n box.position[0],\n box.position[1],\n box.altitude ?? 0,\n width,\n length,\n height,\n box.heading ?? 0,\n box.cut === 'outside' ? 0 : 1,\n box.altitudeReference === 'sea' ? 0 : 1,\n ]),\n new Float32Array(section),\n );\n};\n\n/** What the handles need from the map */\nexport interface ClipBoxHost {\n project(lonLat: LonLat, height?: number): Point | undefined;\n unproject(point: Point): LonLat | undefined;\n elevationAt(lonLat: LonLat): number | undefined;\n getCanvas(): HTMLCanvasElement;\n /** The box changed by a handle: set, and told */\n moved(box: ClipBox): void;\n}\n\n/** A face's handle: its axis (0 across, 1 along, 2 up) and side */\ninterface Face {\n axis: 0 | 1 | 2;\n side: -1 | 1;\n}\n\n/** A handle: on a face, or at the middle (moves the box, clear of the bottom face's) */\ntype Handle = Face | 'move';\n\n/** Metres across, along and up from the foot's center of a face's center, `out` metres out of it */\nconst faceAt = (box: ClipBox, { axis, side }: Face, out = 0): [number, number, number] => {\n const [, , h] = box.size;\n const offset: [number, number, number] = [0, 0, h / 2];\n\n offset[axis] = axis === 2 ? (side > 0 ? h : 0) + side * out : side * (box.size[axis] / 2 + out);\n\n return offset;\n};\n\n/** The 12 edges of the box, as pairs of corners (bit 0 across, 1 along, 2 up) */\nconst EDGES: [number, number][] = [\n [0, 1],\n [2, 3],\n [4, 5],\n [6, 7],\n [0, 2],\n [1, 3],\n [4, 6],\n [5, 7],\n [0, 4],\n [1, 5],\n [2, 6],\n [3, 7],\n];\n\nconst HANDLES: Handle[] = [\n { axis: 0, side: -1 },\n { axis: 0, side: 1 },\n { axis: 1, side: -1 },\n { axis: 1, side: 1 },\n { axis: 2, side: -1 },\n { axis: 2, side: 1 },\n 'move',\n];\n\n/** The handles of a box, over the map */\nexport class ClipBoxHandles implements Positioned {\n /** Over the canvas, its drawing within */\n readonly element: HTMLDivElement;\n private readonly lines: SVGLineElement[];\n private readonly discs: SVGCircleElement[];\n /** The handle held (its disc), the pointer and the box where it was pressed */\n private held: { handle: Handle; disc: SVGCircleElement; start: Point; box: ClipBox; grab: Point } | undefined;\n\n constructor(\n private readonly host: ClipBoxHost,\n private box: ClipBox,\n /** Metres of the body's radius (metres to degrees) */\n private readonly radius: number,\n ) {\n const svg = document.createElementNS(SVG, 'svg');\n\n this.element = document.createElement('div');\n this.element.className = 'isard-clipbox';\n this.element.append(svg);\n this.lines = EDGES.map(() => svg.appendChild(document.createElementNS(SVG, 'line')));\n this.discs = HANDLES.map((handle) => {\n const disc = document.createElementNS(SVG, 'circle');\n\n disc.setAttribute('r', handle === 'move' ? '8' : '6');\n disc.setAttribute('class', handle === 'move' ? 'isard-clipbox-move' : 'isard-clipbox-face');\n disc.addEventListener('pointerdown', (e) => this.down(e, handle, disc));\n disc.addEventListener('pointermove', (e) => this.move(e));\n disc.addEventListener('pointerup', (e) => this.up(e));\n disc.addEventListener('pointercancel', (e) => this.up(e));\n // Safari may let the capture go: the release would then reach the map, not the disc\n disc.addEventListener('lostpointercapture', (e) => this.up(e));\n\n return svg.appendChild(disc);\n });\n }\n\n /** The box the handles follow from the next placing (`position`, after each frame) */\n set(box: ClipBox): void {\n this.box = box;\n }\n\n position(): void {\n const corners = this.corners(this.box);\n const centers = HANDLES.map((handle) => this.handleAt(this.box, handle));\n\n EDGES.forEach(([a, b], i) => {\n const [p, q] = [corners[a], corners[b]];\n const line = this.lines[i];\n\n if (!line) return;\n line.style.display = p && q ? '' : 'none';\n if (!p || !q) return;\n line.setAttribute('x1', String(p[0]));\n line.setAttribute('y1', String(p[1]));\n line.setAttribute('x2', String(q[0]));\n line.setAttribute('y2', String(q[1]));\n });\n centers.forEach((p, i) => {\n const disc = this.discs[i];\n\n if (!disc) return;\n disc.style.display = p ? '' : 'none';\n if (!p) return;\n disc.setAttribute('cx', String(p[0]));\n disc.setAttribute('cy', String(p[1]));\n });\n }\n\n /** A point of the box, metres across and along its heading from its foot's center and up from its foot */\n private at(box: ClipBox, across: number, along: number, up: number): Point | undefined {\n const heading = ((box.heading ?? 0) * Math.PI) / 180;\n const [sin, cos] = [Math.sin(heading), Math.cos(heading)];\n const lonLat = this.offset(box.position, across * cos + along * sin, along * cos - across * sin);\n // `project` measures from the relief: an altitude above the ellipsoid less the relief under the box\n const ground = box.altitudeReference === 'sea' ? (this.host.elevationAt(box.position) ?? 0) : 0;\n\n return this.host.project(lonLat, (box.altitude ?? 0) - ground + up);\n }\n\n private corners(box: ClipBox): (Point | undefined)[] {\n const [w, l, h] = box.size;\n\n return Array.from({ length: 8 }, (_, k) =>\n this.at(box, (k & 1 ? 0.5 : -0.5) * w, (k & 2 ? 0.5 : -0.5) * l, k & 4 ? h : 0),\n );\n }\n\n /** Where a handle stands on the screen: a face's center, or the box's */\n private handleAt(box: ClipBox, handle: Handle): Point | undefined {\n return handle === 'move' ? this.at(box, 0, 0, box.size[2] / 2) : this.at(box, ...faceAt(box, handle));\n }\n\n private local(e: PointerEvent): Point {\n const rect = this.host.getCanvas().getBoundingClientRect();\n\n return [e.clientX - rect.left, e.clientY - rect.top];\n }\n\n private down(e: PointerEvent, handle: Handle, disc: SVGCircleElement): void {\n if (e.button !== 0) return;\n\n const start = this.local(e);\n // The spot of the ground grabbed, kept under the pointer as the box moves\n const grab = handle === 'move' ? this.host.unproject(start) : undefined;\n\n // The map must not pan under the handle\n e.stopPropagation();\n e.preventDefault();\n disc.setPointerCapture(e.pointerId);\n this.held = {\n handle,\n disc,\n start,\n box: { ...this.box, size: [...this.box.size] },\n grab: grab ? [grab[0] - this.box.position[0], grab[1] - this.box.position[1]] : [0, 0],\n };\n }\n\n private move(e: PointerEvent): void {\n if (!this.held) return;\n // No button held any more: its release was missed (the capture lost), the drag is over\n if (e.buttons === 0) {\n this.up(e);\n\n return;\n }\n e.stopPropagation();\n\n const { handle, start, box, grab } = this.held;\n const at = this.local(e);\n\n if (handle === 'move') {\n // The ground under the pointer, the grabbed spot kept under it\n const lonLat = this.host.unproject(at);\n\n if (lonLat) this.host.moved({ ...box, position: [lonLat[0] - grab[0], lonLat[1] - grab[1]] });\n\n return;\n }\n\n const metres = this.dragged(box, handle, [at[0] - start[0], at[1] - start[1]]);\n\n if (metres !== undefined) this.host.moved(this.resized(box, handle, metres));\n }\n\n /** Metres the pointer dragged a face outward: the drag along the face's axis on the screen */\n private dragged(box: ClipBox, face: Face, [dx, dy]: Point): number | undefined {\n const from = this.at(box, ...faceAt(box, face));\n // Where the face's center goes a metre out, on the screen: pixels per metre along its axis\n const to = this.at(box, ...faceAt(box, face, 1));\n\n if (!from || !to) return undefined;\n\n const [ax, ay] = [to[0] - from[0], to[1] - from[1]];\n const squared = ax * ax + ay * ay;\n\n return squared > 1e-6 ? (dx * ax + dy * ay) / squared : undefined;\n }\n\n /** The box with a face moved `metres` outward, the opposite face where it was */\n private resized(box: ClipBox, { axis, side }: Face, metres: number): ClipBox {\n const size: [number, number, number] = [...box.size];\n const grown = Math.max(SMALLEST, size[axis] + metres);\n const moved = grown - size[axis];\n\n size[axis] = grown;\n if (axis === 2) {\n // The foot lowered when the bottom face goes down\n return side > 0 ? { ...box, size } : { ...box, size, altitude: (box.altitude ?? 0) - moved };\n }\n\n // The center half-way along the move, on the side of the face moved\n const heading = ((box.heading ?? 0) * Math.PI) / 180;\n const [sin, cos] = [Math.sin(heading), Math.cos(heading)];\n const shift = (side * moved) / 2;\n const [east, north] = axis === 0 ? [shift * cos, -shift * sin] : [shift * sin, shift * cos];\n return { ...box, size, position: this.offset(box.position, east, north) };\n }\n\n /** A position `east` and `north` metres from another */\n private offset([lon, lat]: LonLat, east: number, north: number): LonLat {\n return [\n lon + (east / (this.radius * Math.cos((lat * Math.PI) / 180))) * (180 / Math.PI),\n lat + (north / this.radius) * (180 / Math.PI),\n ];\n }\n\n private up(e: PointerEvent): void {\n if (!this.held) return;\n e.stopPropagation();\n if (this.held.disc.hasPointerCapture(e.pointerId)) this.held.disc.releasePointerCapture(e.pointerId);\n this.held = undefined;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isard",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "A WebGL2 map engine for large, interactive data layers, labels and 3D Tiles over raster or vector basemaps (Rust core in WebAssembly)",
5
5
  "license": "MIT",
6
6
  "author": "Kevin Graff",