');\n $(\"#glyphdiff\").append(place);\n\n glyph_diff.forEach((glyph) => {\n Object(_src_templates_shared__WEBPACK_IMPORTED_MODULE_1__[\"addAGlyph\"])(glyph, place);\n });\n $('[data-toggle=\"tooltip\"]').tooltip();\n }\n }\n\n renderWordDiff(script, diffs) {\n $(\"#worddiffinner\").append($(`
');\n $(\"#worddiffinner\").append(place);\n diffs.forEach((glyph) => {\n Object(_src_templates_shared__WEBPACK_IMPORTED_MODULE_1__[\"addAWord\"])(glyph, place);\n });\n $('[data-toggle=\"tooltip\"]').tooltip();\n }\n}\n\n$(function () {\n window.diffenator = new Diffenator();\n diffWorker.onmessage = (e) => window.diffenator.progress_callback(e.data);\n $(\"#bigLoadingModal\").show();\n\n $(\".fontdrop\").on(\"dragover dragenter\", function (e) {\n e.preventDefault();\n e.stopPropagation();\n $(this).addClass(\"dragging\");\n });\n $(\".fontdrop\").on(\"dragleave dragend\", function (e) {\n $(this).removeClass(\"dragging\");\n });\n\n $(\".fontdrop\").on(\"drop\", function (e) {\n $(this).removeClass(\"dragging\");\n if (\n e.originalEvent.dataTransfer &&\n e.originalEvent.dataTransfer.files.length\n ) {\n e.preventDefault();\n e.stopPropagation();\n diffenator.dropFile(e.originalEvent.dataTransfer.files, this);\n }\n });\n\n Object(_src_templates_shared__WEBPACK_IMPORTED_MODULE_1__[\"setupAnimation\"])();\n});\n\n\n//# sourceURL=webpack:///./index.js?");
/***/ }),
diff --git a/docs/0.bootstrap.worker.js b/docs/0.bootstrap.worker.js
index 334bc3a..5a2e00e 100644
--- a/docs/0.bootstrap.worker.js
+++ b/docs/0.bootstrap.worker.js
@@ -4,11 +4,11 @@ self["webpackChunk"]([0],{
/*!*****************************!*\
!*** ../pkg/diffenator3.js ***!
\*****************************/
-/*! exports provided: __wbg_set_wasm, diff_words, diff_glyphs, diff_tables, diff, axes, debugging, __wbindgen_object_drop_ref, __wbindgen_string_new, __wbg_call_b3ca7c6051f9bec1, __wbg_new_abda76e883ba8a5f, __wbg_stack_658279fe44541cf6, __wbg_error_f851667af71bcfc6, __wbindgen_debug_string, __wbindgen_throw */
+/*! exports provided: __wbg_set_wasm, diff_words, new_missing_glyphs, modified_glyphs, diff_tables, axes, debugging, __wbindgen_object_drop_ref, __wbindgen_string_new, __wbg_call_89af060b4e1523f2, __wbg_new_abda76e883ba8a5f, __wbg_stack_658279fe44541cf6, __wbg_error_f851667af71bcfc6, __wbindgen_debug_string, __wbindgen_throw */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _diffenator3_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./diffenator3_bg.wasm */ \"../pkg/diffenator3_bg.wasm\");\n/* harmony import */ var _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./diffenator3_bg.js */ \"../pkg/diffenator3_bg.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_set_wasm\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_set_wasm\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"diff_words\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"diff_words\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"diff_glyphs\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"diff_glyphs\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"diff_tables\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"diff_tables\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"diff\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"diff\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"axes\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"axes\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"debugging\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"debugging\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_object_drop_ref\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_string_new\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_string_new\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_call_b3ca7c6051f9bec1\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_call_b3ca7c6051f9bec1\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new_abda76e883ba8a5f\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_new_abda76e883ba8a5f\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_stack_658279fe44541cf6\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_stack_658279fe44541cf6\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_error_f851667af71bcfc6\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_error_f851667af71bcfc6\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_debug_string\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_debug_string\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_throw\"]; });\n\n\n\nObject(_diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_set_wasm\"])(_diffenator3_bg_wasm__WEBPACK_IMPORTED_MODULE_0__);\n\n\n\n//# sourceURL=webpack:///../pkg/diffenator3.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _diffenator3_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./diffenator3_bg.wasm */ \"../pkg/diffenator3_bg.wasm\");\n/* harmony import */ var _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./diffenator3_bg.js */ \"../pkg/diffenator3_bg.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_set_wasm\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_set_wasm\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"diff_words\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"diff_words\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"new_missing_glyphs\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"new_missing_glyphs\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"modified_glyphs\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"modified_glyphs\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"diff_tables\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"diff_tables\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"axes\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"axes\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"debugging\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"debugging\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_object_drop_ref\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_string_new\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_string_new\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_call_89af060b4e1523f2\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_call_89af060b4e1523f2\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new_abda76e883ba8a5f\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_new_abda76e883ba8a5f\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_stack_658279fe44541cf6\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_stack_658279fe44541cf6\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_error_f851667af71bcfc6\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_error_f851667af71bcfc6\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_debug_string\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_debug_string\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return _diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_throw\"]; });\n\n\n\n\nObject(_diffenator3_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_set_wasm\"])(_diffenator3_bg_wasm__WEBPACK_IMPORTED_MODULE_0__);\n\n\n\n//# sourceURL=webpack:///../pkg/diffenator3.js?");
/***/ }),
@@ -16,11 +16,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _dif
/*!********************************!*\
!*** ../pkg/diffenator3_bg.js ***!
\********************************/
-/*! exports provided: __wbg_set_wasm, diff_words, diff_glyphs, diff_tables, diff, axes, debugging, __wbindgen_object_drop_ref, __wbindgen_string_new, __wbg_call_b3ca7c6051f9bec1, __wbg_new_abda76e883ba8a5f, __wbg_stack_658279fe44541cf6, __wbg_error_f851667af71bcfc6, __wbindgen_debug_string, __wbindgen_throw */
+/*! exports provided: __wbg_set_wasm, diff_words, new_missing_glyphs, modified_glyphs, diff_tables, axes, debugging, __wbindgen_object_drop_ref, __wbindgen_string_new, __wbg_call_89af060b4e1523f2, __wbg_new_abda76e883ba8a5f, __wbg_stack_658279fe44541cf6, __wbg_error_f851667af71bcfc6, __wbindgen_debug_string, __wbindgen_throw */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(module) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_set_wasm\", function() { return __wbg_set_wasm; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"diff_words\", function() { return diff_words; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"diff_glyphs\", function() { return diff_glyphs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"diff_tables\", function() { return diff_tables; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"diff\", function() { return diff; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"axes\", function() { return axes; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"debugging\", function() { return debugging; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return __wbindgen_object_drop_ref; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_string_new\", function() { return __wbindgen_string_new; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_call_b3ca7c6051f9bec1\", function() { return __wbg_call_b3ca7c6051f9bec1; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new_abda76e883ba8a5f\", function() { return __wbg_new_abda76e883ba8a5f; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_stack_658279fe44541cf6\", function() { return __wbg_stack_658279fe44541cf6; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_error_f851667af71bcfc6\", function() { return __wbg_error_f851667af71bcfc6; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_debug_string\", function() { return __wbindgen_debug_string; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return __wbindgen_throw; });\nlet wasm;\nfunction __wbg_set_wasm(val) {\n wasm = val;\n}\n\n\nconst heap = new Array(128).fill(undefined);\n\nheap.push(undefined, null, true, false);\n\nfunction getObject(idx) { return heap[idx]; }\n\nlet heap_next = heap.length;\n\nfunction dropObject(idx) {\n if (idx < 132) return;\n heap[idx] = heap_next;\n heap_next = idx;\n}\n\nfunction takeObject(idx) {\n const ret = getObject(idx);\n dropObject(idx);\n return ret;\n}\n\nconst lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;\n\nlet cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });\n\ncachedTextDecoder.decode();\n\nlet cachedUint8Memory0 = null;\n\nfunction getUint8Memory0() {\n if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {\n cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);\n }\n return cachedUint8Memory0;\n}\n\nfunction getStringFromWasm0(ptr, len) {\n ptr = ptr >>> 0;\n return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));\n}\n\nfunction addHeapObject(obj) {\n if (heap_next === heap.length) heap.push(heap.length + 1);\n const idx = heap_next;\n heap_next = heap[idx];\n\n heap[idx] = obj;\n return idx;\n}\n\nfunction debugString(val) {\n // primitive types\n const type = typeof val;\n if (type == 'number' || type == 'boolean' || val == null) {\n return `${val}`;\n }\n if (type == 'string') {\n return `\"${val}\"`;\n }\n if (type == 'symbol') {\n const description = val.description;\n if (description == null) {\n return 'Symbol';\n } else {\n return `Symbol(${description})`;\n }\n }\n if (type == 'function') {\n const name = val.name;\n if (typeof name == 'string' && name.length > 0) {\n return `Function(${name})`;\n } else {\n return 'Function';\n }\n }\n // objects\n if (Array.isArray(val)) {\n const length = val.length;\n let debug = '[';\n if (length > 0) {\n debug += debugString(val[0]);\n }\n for(let i = 1; i < length; i++) {\n debug += ', ' + debugString(val[i]);\n }\n debug += ']';\n return debug;\n }\n // Test for built-in\n const builtInMatches = /\\[object ([^\\]]+)\\]/.exec(toString.call(val));\n let className;\n if (builtInMatches.length > 1) {\n className = builtInMatches[1];\n } else {\n // Failed to match the standard '[object ClassName]'\n return toString.call(val);\n }\n if (className == 'Object') {\n // we're a user defined class or Object\n // JSON.stringify avoids problems with cycles, and is generally much\n // easier than looping through ownProperties of `val`.\n try {\n return 'Object(' + JSON.stringify(val) + ')';\n } catch (_) {\n return 'Object';\n }\n }\n // errors\n if (val instanceof Error) {\n return `${val.name}: ${val.message}\\n${val.stack}`;\n }\n // TODO we could test for more things here, like `Set`s and `Map`s.\n return className;\n}\n\nlet WASM_VECTOR_LEN = 0;\n\nconst lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder;\n\nlet cachedTextEncoder = new lTextEncoder('utf-8');\n\nconst encodeString = (typeof cachedTextEncoder.encodeInto === 'function'\n ? function (arg, view) {\n return cachedTextEncoder.encodeInto(arg, view);\n}\n : function (arg, view) {\n const buf = cachedTextEncoder.encode(arg);\n view.set(buf);\n return {\n read: arg.length,\n written: buf.length\n };\n});\n\nfunction passStringToWasm0(arg, malloc, realloc) {\n\n if (realloc === undefined) {\n const buf = cachedTextEncoder.encode(arg);\n const ptr = malloc(buf.length, 1) >>> 0;\n getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);\n WASM_VECTOR_LEN = buf.length;\n return ptr;\n }\n\n let len = arg.length;\n let ptr = malloc(len, 1) >>> 0;\n\n const mem = getUint8Memory0();\n\n let offset = 0;\n\n for (; offset < len; offset++) {\n const code = arg.charCodeAt(offset);\n if (code > 0x7F) break;\n mem[ptr + offset] = code;\n }\n\n if (offset !== len) {\n if (offset !== 0) {\n arg = arg.slice(offset);\n }\n ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;\n const view = getUint8Memory0().subarray(ptr + offset, ptr + len);\n const ret = encodeString(arg, view);\n\n offset += ret.written;\n ptr = realloc(ptr, len, offset, 1) >>> 0;\n }\n\n WASM_VECTOR_LEN = offset;\n return ptr;\n}\n\nlet cachedInt32Memory0 = null;\n\nfunction getInt32Memory0() {\n if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {\n cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);\n }\n return cachedInt32Memory0;\n}\n\nfunction passArray8ToWasm0(arg, malloc) {\n const ptr = malloc(arg.length * 1, 1) >>> 0;\n getUint8Memory0().set(arg, ptr / 1);\n WASM_VECTOR_LEN = arg.length;\n return ptr;\n}\n\nlet stack_pointer = 128;\n\nfunction addBorrowedObject(obj) {\n if (stack_pointer == 1) throw new Error('out of js stack');\n heap[--stack_pointer] = obj;\n return stack_pointer;\n}\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {string} location\n* @param {Function} f\n*/\nfunction diff_words(font_a, font_b, location, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n const ptr2 = passStringToWasm0(location, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len2 = WASM_VECTOR_LEN;\n wasm.diff_words(ptr0, len0, ptr1, len1, ptr2, len2, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {string} location\n* @param {Function} f\n*/\nfunction diff_glyphs(font_a, font_b, location, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n const ptr2 = passStringToWasm0(location, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len2 = WASM_VECTOR_LEN;\n wasm.diff_glyphs(ptr0, len0, ptr1, len1, ptr2, len2, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {Function} f\n*/\nfunction diff_tables(font_a, font_b, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.diff_tables(ptr0, len0, ptr1, len1, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @returns {string}\n*/\nfunction diff(font_a, font_b) {\n let deferred3_0;\n let deferred3_1;\n try {\n const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.diff(retptr, ptr0, len0, ptr1, len1);\n var r0 = getInt32Memory0()[retptr / 4 + 0];\n var r1 = getInt32Memory0()[retptr / 4 + 1];\n deferred3_0 = r0;\n deferred3_1 = r1;\n return getStringFromWasm0(r0, r1);\n } finally {\n wasm.__wbindgen_add_to_stack_pointer(16);\n wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @returns {string}\n*/\nfunction axes(font_a, font_b) {\n let deferred3_0;\n let deferred3_1;\n try {\n const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.axes(retptr, ptr0, len0, ptr1, len1);\n var r0 = getInt32Memory0()[retptr / 4 + 0];\n var r1 = getInt32Memory0()[retptr / 4 + 1];\n deferred3_0 = r0;\n deferred3_1 = r1;\n return getStringFromWasm0(r0, r1);\n } finally {\n wasm.__wbindgen_add_to_stack_pointer(16);\n wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);\n }\n}\n\n/**\n*/\nfunction debugging() {\n wasm.debugging();\n}\n\nfunction handleError(f, args) {\n try {\n return f.apply(this, args);\n } catch (e) {\n wasm.__wbindgen_exn_store(addHeapObject(e));\n }\n}\n\nfunction __wbindgen_object_drop_ref(arg0) {\n takeObject(arg0);\n};\n\nfunction __wbindgen_string_new(arg0, arg1) {\n const ret = getStringFromWasm0(arg0, arg1);\n return addHeapObject(ret);\n};\n\nfunction __wbg_call_b3ca7c6051f9bec1() { return handleError(function (arg0, arg1, arg2) {\n const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));\n return addHeapObject(ret);\n}, arguments) };\n\nfunction __wbg_new_abda76e883ba8a5f() {\n const ret = new Error();\n return addHeapObject(ret);\n};\n\nfunction __wbg_stack_658279fe44541cf6(arg0, arg1) {\n const ret = getObject(arg1).stack;\n const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len1 = WASM_VECTOR_LEN;\n getInt32Memory0()[arg0 / 4 + 1] = len1;\n getInt32Memory0()[arg0 / 4 + 0] = ptr1;\n};\n\nfunction __wbg_error_f851667af71bcfc6(arg0, arg1) {\n let deferred0_0;\n let deferred0_1;\n try {\n deferred0_0 = arg0;\n deferred0_1 = arg1;\n console.error(getStringFromWasm0(arg0, arg1));\n } finally {\n wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);\n }\n};\n\nfunction __wbindgen_debug_string(arg0, arg1) {\n const ret = debugString(getObject(arg1));\n const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len1 = WASM_VECTOR_LEN;\n getInt32Memory0()[arg0 / 4 + 1] = len1;\n getInt32Memory0()[arg0 / 4 + 0] = ptr1;\n};\n\nfunction __wbindgen_throw(arg0, arg1) {\n throw new Error(getStringFromWasm0(arg0, arg1));\n};\n\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../www/node_modules/webpack/buildin/harmony-module.js */ \"./node_modules/webpack/buildin/harmony-module.js\")(module)))\n\n//# sourceURL=webpack:///../pkg/diffenator3_bg.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(module) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_set_wasm\", function() { return __wbg_set_wasm; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"diff_words\", function() { return diff_words; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"new_missing_glyphs\", function() { return new_missing_glyphs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"modified_glyphs\", function() { return modified_glyphs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"diff_tables\", function() { return diff_tables; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"axes\", function() { return axes; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"debugging\", function() { return debugging; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return __wbindgen_object_drop_ref; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_string_new\", function() { return __wbindgen_string_new; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_call_89af060b4e1523f2\", function() { return __wbg_call_89af060b4e1523f2; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new_abda76e883ba8a5f\", function() { return __wbg_new_abda76e883ba8a5f; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_stack_658279fe44541cf6\", function() { return __wbg_stack_658279fe44541cf6; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_error_f851667af71bcfc6\", function() { return __wbg_error_f851667af71bcfc6; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_debug_string\", function() { return __wbindgen_debug_string; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return __wbindgen_throw; });\nlet wasm;\nfunction __wbg_set_wasm(val) {\n wasm = val;\n}\n\n\nconst heap = new Array(128).fill(undefined);\n\nheap.push(undefined, null, true, false);\n\nfunction getObject(idx) { return heap[idx]; }\n\nlet heap_next = heap.length;\n\nfunction dropObject(idx) {\n if (idx < 132) return;\n heap[idx] = heap_next;\n heap_next = idx;\n}\n\nfunction takeObject(idx) {\n const ret = getObject(idx);\n dropObject(idx);\n return ret;\n}\n\nconst lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;\n\nlet cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });\n\ncachedTextDecoder.decode();\n\nlet cachedUint8ArrayMemory0 = null;\n\nfunction getUint8ArrayMemory0() {\n if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {\n cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);\n }\n return cachedUint8ArrayMemory0;\n}\n\nfunction getStringFromWasm0(ptr, len) {\n ptr = ptr >>> 0;\n return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));\n}\n\nfunction addHeapObject(obj) {\n if (heap_next === heap.length) heap.push(heap.length + 1);\n const idx = heap_next;\n heap_next = heap[idx];\n\n heap[idx] = obj;\n return idx;\n}\n\nfunction debugString(val) {\n // primitive types\n const type = typeof val;\n if (type == 'number' || type == 'boolean' || val == null) {\n return `${val}`;\n }\n if (type == 'string') {\n return `\"${val}\"`;\n }\n if (type == 'symbol') {\n const description = val.description;\n if (description == null) {\n return 'Symbol';\n } else {\n return `Symbol(${description})`;\n }\n }\n if (type == 'function') {\n const name = val.name;\n if (typeof name == 'string' && name.length > 0) {\n return `Function(${name})`;\n } else {\n return 'Function';\n }\n }\n // objects\n if (Array.isArray(val)) {\n const length = val.length;\n let debug = '[';\n if (length > 0) {\n debug += debugString(val[0]);\n }\n for(let i = 1; i < length; i++) {\n debug += ', ' + debugString(val[i]);\n }\n debug += ']';\n return debug;\n }\n // Test for built-in\n const builtInMatches = /\\[object ([^\\]]+)\\]/.exec(toString.call(val));\n let className;\n if (builtInMatches.length > 1) {\n className = builtInMatches[1];\n } else {\n // Failed to match the standard '[object ClassName]'\n return toString.call(val);\n }\n if (className == 'Object') {\n // we're a user defined class or Object\n // JSON.stringify avoids problems with cycles, and is generally much\n // easier than looping through ownProperties of `val`.\n try {\n return 'Object(' + JSON.stringify(val) + ')';\n } catch (_) {\n return 'Object';\n }\n }\n // errors\n if (val instanceof Error) {\n return `${val.name}: ${val.message}\\n${val.stack}`;\n }\n // TODO we could test for more things here, like `Set`s and `Map`s.\n return className;\n}\n\nlet WASM_VECTOR_LEN = 0;\n\nconst lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder;\n\nlet cachedTextEncoder = new lTextEncoder('utf-8');\n\nconst encodeString = (typeof cachedTextEncoder.encodeInto === 'function'\n ? function (arg, view) {\n return cachedTextEncoder.encodeInto(arg, view);\n}\n : function (arg, view) {\n const buf = cachedTextEncoder.encode(arg);\n view.set(buf);\n return {\n read: arg.length,\n written: buf.length\n };\n});\n\nfunction passStringToWasm0(arg, malloc, realloc) {\n\n if (realloc === undefined) {\n const buf = cachedTextEncoder.encode(arg);\n const ptr = malloc(buf.length, 1) >>> 0;\n getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);\n WASM_VECTOR_LEN = buf.length;\n return ptr;\n }\n\n let len = arg.length;\n let ptr = malloc(len, 1) >>> 0;\n\n const mem = getUint8ArrayMemory0();\n\n let offset = 0;\n\n for (; offset < len; offset++) {\n const code = arg.charCodeAt(offset);\n if (code > 0x7F) break;\n mem[ptr + offset] = code;\n }\n\n if (offset !== len) {\n if (offset !== 0) {\n arg = arg.slice(offset);\n }\n ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;\n const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);\n const ret = encodeString(arg, view);\n\n offset += ret.written;\n ptr = realloc(ptr, len, offset, 1) >>> 0;\n }\n\n WASM_VECTOR_LEN = offset;\n return ptr;\n}\n\nlet cachedDataViewMemory0 = null;\n\nfunction getDataViewMemory0() {\n if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {\n cachedDataViewMemory0 = new DataView(wasm.memory.buffer);\n }\n return cachedDataViewMemory0;\n}\n\nfunction passArray8ToWasm0(arg, malloc) {\n const ptr = malloc(arg.length * 1, 1) >>> 0;\n getUint8ArrayMemory0().set(arg, ptr / 1);\n WASM_VECTOR_LEN = arg.length;\n return ptr;\n}\n\nlet stack_pointer = 128;\n\nfunction addBorrowedObject(obj) {\n if (stack_pointer == 1) throw new Error('out of js stack');\n heap[--stack_pointer] = obj;\n return stack_pointer;\n}\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {string} location\n* @param {Function} f\n*/\nfunction diff_words(font_a, font_b, location, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n const ptr2 = passStringToWasm0(location, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len2 = WASM_VECTOR_LEN;\n wasm.diff_words(ptr0, len0, ptr1, len1, ptr2, len2, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {Function} f\n*/\nfunction new_missing_glyphs(font_a, font_b, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.new_missing_glyphs(ptr0, len0, ptr1, len1, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {string} location\n* @param {Function} f\n*/\nfunction modified_glyphs(font_a, font_b, location, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n const ptr2 = passStringToWasm0(location, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len2 = WASM_VECTOR_LEN;\n wasm.modified_glyphs(ptr0, len0, ptr1, len1, ptr2, len2, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @param {Function} f\n*/\nfunction diff_tables(font_a, font_b, f) {\n try {\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.diff_tables(ptr0, len0, ptr1, len1, addBorrowedObject(f));\n } finally {\n heap[stack_pointer++] = undefined;\n }\n}\n\n/**\n* @param {Uint8Array} font_a\n* @param {Uint8Array} font_b\n* @returns {string}\n*/\nfunction axes(font_a, font_b) {\n let deferred3_0;\n let deferred3_1;\n try {\n const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);\n const ptr0 = passArray8ToWasm0(font_a, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(font_b, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.axes(retptr, ptr0, len0, ptr1, len1);\n var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);\n var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);\n deferred3_0 = r0;\n deferred3_1 = r1;\n return getStringFromWasm0(r0, r1);\n } finally {\n wasm.__wbindgen_add_to_stack_pointer(16);\n wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);\n }\n}\n\n/**\n*/\nfunction debugging() {\n wasm.debugging();\n}\n\nfunction handleError(f, args) {\n try {\n return f.apply(this, args);\n } catch (e) {\n wasm.__wbindgen_exn_store(addHeapObject(e));\n }\n}\n\nfunction __wbindgen_object_drop_ref(arg0) {\n takeObject(arg0);\n};\n\nfunction __wbindgen_string_new(arg0, arg1) {\n const ret = getStringFromWasm0(arg0, arg1);\n return addHeapObject(ret);\n};\n\nfunction __wbg_call_89af060b4e1523f2() { return handleError(function (arg0, arg1, arg2) {\n const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));\n return addHeapObject(ret);\n}, arguments) };\n\nfunction __wbg_new_abda76e883ba8a5f() {\n const ret = new Error();\n return addHeapObject(ret);\n};\n\nfunction __wbg_stack_658279fe44541cf6(arg0, arg1) {\n const ret = getObject(arg1).stack;\n const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len1 = WASM_VECTOR_LEN;\n getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);\n getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);\n};\n\nfunction __wbg_error_f851667af71bcfc6(arg0, arg1) {\n let deferred0_0;\n let deferred0_1;\n try {\n deferred0_0 = arg0;\n deferred0_1 = arg1;\n console.error(getStringFromWasm0(arg0, arg1));\n } finally {\n wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);\n }\n};\n\nfunction __wbindgen_debug_string(arg0, arg1) {\n const ret = debugString(getObject(arg1));\n const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len1 = WASM_VECTOR_LEN;\n getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);\n getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);\n};\n\nfunction __wbindgen_throw(arg0, arg1) {\n throw new Error(getStringFromWasm0(arg0, arg1));\n};\n\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../www/node_modules/webpack/buildin/harmony-module.js */ \"./node_modules/webpack/buildin/harmony-module.js\")(module)))\n\n//# sourceURL=webpack:///../pkg/diffenator3_bg.js?");
/***/ }),
@@ -28,7 +28,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(f
/*!**********************************!*\
!*** ../pkg/diffenator3_bg.wasm ***!
\**********************************/
-/*! exports provided: memory, diff_words, diff_glyphs, diff_tables, diff, axes, debugging, __wbindgen_malloc, __wbindgen_realloc, __wbindgen_add_to_stack_pointer, __wbindgen_free, __wbindgen_exn_store */
+/*! exports provided: memory, diff_words, new_missing_glyphs, modified_glyphs, diff_tables, axes, debugging, __wbindgen_malloc, __wbindgen_realloc, __wbindgen_add_to_stack_pointer, __wbindgen_free, __wbindgen_exn_store */
/***/ (function(module, exports, __webpack_require__) {
eval("\"use strict\";\n// Instantiate WebAssembly module\nvar wasmExports = __webpack_require__.w[module.i];\n__webpack_require__.r(exports);\n// export exports from WebAssembly module\nfor(var name in wasmExports) if(name != \"__webpack_init__\") exports[name] = wasmExports[name];\n// exec imports from WebAssembly module (for esm order)\n/* harmony import */ var m0 = __webpack_require__(/*! ./diffenator3_bg.js */ \"../pkg/diffenator3_bg.js\");\n\n\n// exec wasm module\nwasmExports[\"__webpack_init__\"]()\n\n//# sourceURL=webpack:///../pkg/diffenator3_bg.wasm?");
diff --git a/docs/bootstrap.worker.js b/docs/bootstrap.worker.js
index 9810a6f..3946aeb 100644
--- a/docs/bootstrap.worker.js
+++ b/docs/bootstrap.worker.js
@@ -31,8 +31,8 @@
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/diffenator3_bg.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
-/******/ "__wbg_call_b3ca7c6051f9bec1": function(p0i32,p1i32,p2i32) {
-/******/ return installedModules["../pkg/diffenator3_bg.js"].exports["__wbg_call_b3ca7c6051f9bec1"](p0i32,p1i32,p2i32);
+/******/ "__wbg_call_89af060b4e1523f2": function(p0i32,p1i32,p2i32) {
+/******/ return installedModules["../pkg/diffenator3_bg.js"].exports["__wbg_call_89af060b4e1523f2"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbg_new_abda76e883ba8a5f": function() {
/******/ return installedModules["../pkg/diffenator3_bg.js"].exports["__wbg_new_abda76e883ba8a5f"]();
@@ -101,7 +101,7 @@
/******/ promises.push(installedWasmModuleData);
/******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId]();
-/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/diffenator3_bg.wasm":"4e63794b39b83b4a3b88"}[wasmModuleId] + ".module.wasm");
+/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/diffenator3_bg.wasm":"fd5dd7b693de39dfe6b0"}[wasmModuleId] + ".module.wasm");
/******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
@@ -192,7 +192,7 @@
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
-eval("var module = __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ../pkg/diffenator3.js */ \"../pkg/diffenator3.js\"));\nasync function init() {\n let wasm = await module;\n self.postMessage({ type: \"ready\" })\n console.log(\"Got wasm module\", wasm);\n wasm.debugging();\n self.onmessage = async (event) => {\n console.log(\"Worker received message\");\n console.log(event);\n const { command, beforeFont, location, afterFont } = event.data;\n if (command == \"axes\") {\n self.postMessage({\n \"type\": \"axes\",\n \"axes\": JSON.parse(wasm.axes(beforeFont, afterFont))[\"axes\"]\n });\n } else if (command == \"tables\") {\n wasm.diff_tables(beforeFont, afterFont, (tables) => {\n self.postMessage({\n \"type\": \"tables\",\n \"tables\": JSON.parse(tables)[\"tables\"]\n });\n });\n } else if (command == \"glyphs\") {\n wasm.diff_glyphs(beforeFont, afterFont, location, (glyphs) => {\n self.postMessage({\n \"type\": \"glyphs\",\n \"glyphs\": JSON.parse(glyphs)[\"glyphs\"]\n });\n });\n } else if (command == \"words\") {\n wasm.diff_words(beforeFont, afterFont, location, (words) => {\n self.postMessage({\n \"type\": \"words\",\n \"words\": JSON.parse(words)[\"words\"]\n });\n });\n }\n\n }\n return self;\n}\n\ninit();\n\n\n//# sourceURL=webpack:///./webworker.js?");
+eval("var module = __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ../pkg/diffenator3.js */ \"../pkg/diffenator3.js\"));\nasync function init() {\n let wasm = await module;\n self.postMessage({ type: \"ready\" });\n // console.log(\"Got wasm module\", wasm);\n wasm.debugging();\n self.onmessage = async (event) => {\n // console.log(\"Worker received message\");\n // console.log(event);\n const { command, beforeFont, location, afterFont } = event.data;\n if (command == \"axes\") {\n let obj = JSON.parse(wasm.axes(beforeFont, afterFont));\n obj[\"type\"] = \"axes\";\n self.postMessage(obj);\n } else if (command == \"tables\") {\n wasm.diff_tables(beforeFont, afterFont, (tables) => {\n self.postMessage({\n type: \"tables\",\n tables: JSON.parse(tables)[\"tables\"],\n });\n });\n } else if (command == \"new_missing_glyphs\") {\n wasm.new_missing_glyphs(beforeFont, afterFont, (new_missing_glyphs) => {\n self.postMessage({\n type: \"new_missing_glyphs\",\n cmap_diff: JSON.parse(new_missing_glyphs)[\"new_missing_glyphs\"],\n });\n });\n } else if (command == \"modified_glyphs\") {\n wasm.modified_glyphs(beforeFont, afterFont, location, (glyphs) => {\n self.postMessage({\n type: \"modified_glyphs\",\n modified_glyphs: JSON.parse(glyphs)[\"modified_glyphs\"],\n });\n });\n } else if (command == \"words\") {\n wasm.diff_words(beforeFont, afterFont, location, (words) => {\n self.postMessage({\n type: \"words\",\n words: JSON.parse(words)[\"words\"],\n });\n });\n }\n };\n return self;\n}\n\ninit();\n\n\n//# sourceURL=webpack:///./webworker.js?");
/***/ })
diff --git a/docs/4e63794b39b83b4a3b88.module.wasm b/docs/fd5dd7b693de39dfe6b0.module.wasm
similarity index 57%
rename from docs/4e63794b39b83b4a3b88.module.wasm
rename to docs/fd5dd7b693de39dfe6b0.module.wasm
index 32f6860..b184fef 100644
Binary files a/docs/4e63794b39b83b4a3b88.module.wasm and b/docs/fd5dd7b693de39dfe6b0.module.wasm differ
diff --git a/docs/index.html b/docs/index.html
index 53f31fe..f1f02c9 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,12 +1,15 @@
-
+
-
-
-
-
-
-
-
-
-
+ :root {
+ --node-pt-size: 60px;
+ }
+
+
+
@@ -231,23 +88,26 @@
Font after
-
-
Old
+
-
Table diff
-
+
-
Shaping Words
-
diff --git a/docs/style.css b/docs/style.css
new file mode 100644
index 0000000..30b3afc
--- /dev/null
+++ b/docs/style.css
@@ -0,0 +1,266 @@
+@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
+
+body {
+ background-color: #b3d4f5 !important;
+ font-family: "Montserrat", sans-serif !important;
+}
+
+.nav-pills .nav-item.show .nav-link, .nav-pills .nav-link.active {
+ background-color: #ced9e4 !important;
+}
+.nav-item {
+ width: 100%;
+ margin-bottom: 10px;
+ padding: 2px;
+}
+
+.nav-pills .nav-link{
+ background-color: #9fcaf5 !important;
+}
+h4 {
+ color: #6f7882 !important;
+}
+
+@font-face {
+ font-family: "Adobe NotDef";
+ src: url(https://cdn.jsdelivr.net/gh/adobe-fonts/adobe-notdef/AND-Regular.ttf);
+}
+
+.box-title {
+ width: 100%;
+ font-size: 8pt;
+ font-weight: 700;
+ border-top: 1px solid black;
+ padding-top: 5px;
+ margin-bottom: 10pt;
+ display: block;
+}
+
+.box {
+ margin-bottom: 20pt;
+ width: 100%;
+ float: left;
+}
+
+.box-text {}
+
+#ui-nav {
+ position: fixed;
+ right: 20px;
+ z-index: 100;
+}
+
+#font-toggle {}
+
+.ui-nav-item {
+ display: block;
+ cursor: pointer;
+ -webkit-user-select: none;
+ /* Safari */
+ -moz-user-select: none;
+ /* Firefox */
+ -ms-user-select: none;
+ /* IE10+/Edge */
+ user-select: none;
+ /* Standard */
+ text-align: center;
+ color: white;
+ background-color: black;
+ display: block;
+ font-size: 14pt;
+ padding: 5px;
+ margin: 2px;
+}
+
+/* Stuff needed for the table differ */
+body {
+ font-family: Helvetica;
+}
+
+.node {
+ font-family: courier;
+ cursor: pointer;
+ position: relative;
+ left: 30px;
+ padding: 5px;
+ display: block;
+ border: 1px dashed grey;
+ background-color: #e9e9ee;
+}
+
+.header {
+ font-weight: bold;
+}
+
+.attr-before {
+ color: red;
+ cursor: text;
+}
+
+.attr-after {
+ color: green;
+ cursor: text;
+}
+
+.leaf {
+ font-weight: bold;
+}
+
+.old .cell .new {
+ display: none;
+}
+
+.new .cell .old {
+ display: none;
+}
+
+.both .cell .old {
+ opacity: 0.75;
+ color: red;
+}
+
+.both .cell .new {
+ opacity: 0.75;
+ position: absolute;
+ top: 0;
+ color: green;
+}
+
+.spacer {
+ display: block;
+ float: left;
+ width: 100%;
+}
+
+#ot-panel {
+ max-height: 400px;
+ overflow-y: scroll;
+ background: white;
+ padding: 10px;
+ display: none;
+ }
+
+ .cell{
+ z-index: -100;
+ float: left;
+ display: block;
+ text-align: center;
+ padding: 5pt;
+ margin: 5pt;
+ width: 50pt;
+ font-size: var(--node-pt-size);
+ line-height: calc(var(--node-pt-size) * 1.5);
+ }
+ .cell-word{
+ z-index: -100;
+ float: left;
+ display: block;
+ text-align: center;
+ padding: 5pt;
+ margin: 5pt;
+ font-size: var(--node-pt-size);
+ line-height: calc(var(--node-pt-size) * 1.5);
+ box-shadow: rgba(0, 0, 0, 0.15) 1.95px 1.95px 2.6px;
+ }
+ .cell-glyph{
+ z-index: -100;
+ float: left;
+ display: block;
+ text-align: center;
+ border-radius: 5pt;
+ box-shadow: rgba(0, 0, 0, 0.15) 1.95px 1.95px 2.6px;
+ padding: 5pt;
+ margin: 5pt;
+ width: calc(var(--node-pt-size) * 2);
+ min-height: calc(var(--node-pt-size) * 2);
+ font-size: var(--node-pt-size);
+ }
+ .cell-glyph.font-before, .cell-word.font-before {
+ background: #eff6f2;
+ }
+ .cell-glyph.font-after, .cell-word.font-after {
+ background: #f7f4f4;
+ }
+
+ .cell-glyph:hover {
+ box-shadow: none;
+ background: #f0f0f5;
+ }
+ .cat-strings .cell {
+ clear: both;
+ position: static;
+ float: none;
+ text-align: left;
+ }
+ .codepoint {
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 10pt;
+ line-height: 10pt;
+ }
+ .box-title {
+ clear: both;
+ }
+ .node.closed::before {
+ content: "+";
+ margin-right: 5pt;
+ }
+ .node.open::before {
+ content: "-";
+ margin-right: 5pt;
+ }
+
+ .tooltip pre {
+ background-color: #6f7882;
+ padding: 5px;
+ white-space: pre-wrap;
+ word-break: break-all;
+ }
+ .tooltip {
+ line-height: 1em;
+ }
+ .tooltip-inner {
+ max-width: 300px;
+ }
+
+ h1,h2,h3,h4,h5 {
+ clear: both;
+ }
+
+ #locationnav li {
+ white-space: wrap;
+ }
+
+/* The following rules are used in the WASM version, not in the CLI version.
+ But we keep them here so we can share them between the two versions. */
+
+ .modal-dialog {
+ max-width: 100% !important;
+ margin: 0 !important;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100vh;
+ display: flex;
+ }
+
+ .fontdrop {
+ padding: 30px;
+ border-radius: 20px;
+ outline: 3px dashed #ffffffff;
+ outline-offset: -20px;
+ }
+
+ #fontbefore {
+ background-color: #ddffdddd;
+ }
+
+ #fontafter {
+ background-color: #ffdddddd;
+ }
+
+ .dragging {
+ background-image: linear-gradient(rgb(0 0 0/5%) 0 0);
+ outline: 5px dashed #ffffffff;
+ }