UNPKG

@sutton-signwriting/font-ttf

Version:

a javascript package for the web components and browser that generates SVG and PNG images for individual symbols and complete signs

2,123 lines 68.6 kB
/**
* Sutton SignWriting TrueType Font Module v1.2.0 (https://github.com/sutton-signwriting/font-ttf)
* Author: Steve Slevinski  (https://SteveSlevinski.me)
* index.js is released under the MIT License.
*/

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
  (global = global || self, factory((global.ssw = global.ssw || {}, global.ssw.ttf = {})));
}(this, (function (exports) { 'use strict';

  /**
   * Function that appends font-face CSS for the Sutton SignWriting fonts for system installed fonts, relative directory fonts, or content delivery network
   * @function font.cssAppend
   * @param {string} dir - an optional relative directory for font location
   * @example
   * font.cssAppend('./font/')
   */
  const cssAppend = function (dir = '') {
    const id = "SgnwFontCss";

    if (!document.getElementById(id)) {
      const style = document.createElement('style');
      style.setAttribute("id", "SgnwFontCss");
      style.appendChild(document.createTextNode(`
  @font-face {
    font-family: "SuttonSignWritingLine";
    src: 
      local('SuttonSignWritingLine'),
      ${dir ? `url('${dir}SuttonSignWritingLine.ttf') format('truetype'),` : ""}
      url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingLine.ttf') format('truetype');
  }
  @font-face {
    font-family: "SuttonSignWritingFill";
    src: 
      local('SuttonSignWritingFill'),
      ${dir ? `url('${dir}SuttonSignWritingFill.ttf') format('truetype'),` : ""}
      url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingFill.ttf') format('truetype');
  }
  @font-face {
    font-family: "SuttonSignWritingOneD";
    src: 
      local('SuttonSignWritingOneD'),
      ${dir ? `url('${dir}SuttonSignWritingOneD.ttf') format('truetype'),` : ""}
      url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingOneD.ttf') format('truetype');
  }
    `));
      document.head.appendChild(style);
    }
  };

  let sizes = {};
  const zoom = 2;
  const bound = 76 * zoom;
  const canvaser = document.createElement("canvas");
  canvaser.width = bound;
  canvaser.height = bound;
  const context = canvaser.getContext("2d");
  /**
   * Function that returns the size of a symbol using an id
   * @function font.symbolSize
   * @param {number} id - a 16-bit number of a symbol
   * @example
   * font.symbolSize(1)
   * 
   * return [15,30]
   */

  const symbolSize = function (id) {
    if (id in sizes) {
      return [...sizes[id]];
    }

    context.clearRect(0, 0, bound, bound);
    context.font = 30 * zoom + "px 'SuttonSignWritingLine'";
    context.fillText(String.fromCodePoint(id + 0xF0000), 0, 0);
    const imgData = context.getImageData(0, 0, bound, bound).data;
    let w, h, i, s;

    wloop: for (w = bound - 1; w >= 0; w--) {
      for (h = 0; h < bound; h += 1) {
        for (s = 0; s < 4; s += 1) {
          i = w * 4 + h * 4 * bound + s;

          if (imgData[i]) {
            break wloop;
          }
        }
      }
    }

    var width = w;

    hloop: for (h = bound - 1; h >= 0; h--) {
      for (w = 0; w < width; w += 1) {
        for (s = 0; s < 4; s += 1) {
          i = w * 4 + h * 4 * bound + s;

          if (imgData[i]) {
            break hloop;
          }
        }
      }
    }

    var height = h + 1;
    width = Math.ceil(width / zoom);
    height = Math.ceil(height / zoom); // Rounding error in chrome.  Manual fixes.

    if (14394 == id) {
      width = 19;
    }

    if ([10468, 10480, 10496, 10512, 10500, 10532, 10548, 10862, 10878, 10894, 11058, 11074, 11476, 11488, 11492, 11504, 11508, 11520, 10516, 10910, 10926, 11042, 11082, 10942].includes(id)) {
      width = 20;
    }

    if (31921 == id) {
      width = 22;
    }

    if (38460 == id) {
      width = 23;
    }

    if ([20164, 20212].includes(id)) {
      width = 25;
    }

    if (31894 == id) {
      width = 28;
    }

    if (46698 == id) {
      width = 29;
    }

    if (29606 == id) {
      width = 30;
    }

    if (44855 == id) {
      width = 40;
    }

    if (32667 == id) {
      width = 50;
    }

    if ([11088, 11474, 11490, 11506].includes(id)) {
      height = 20;
    }

    if (6285 == id) {
      height = 21;
    }

    if (40804 == id) {
      height = 31;
    }

    if (41475 == id) {
      height = 36;
    } // Error in chrome.  Manual fix.
    // if (width==0 && height==0) {


    if (width == 0 && height == 0) {
      const sizefix = {
        9: [15, 30],
        10: [21, 30],
        11: [30, 15],
        12: [30, 21],
        13: [15, 30],
        14: [21, 30]
      };

      if (id in sizefix) {
        width = sizefix[id][0];
        height = sizefix[id][1];
      }
    }

    if (width == 0 && height == 0) {
      return undefined;
    }

    sizes[id] = [width, height];
    return [width, height];
  };

  /**
   * Function that returns a plane 15 character for a symbol line using an id
   * @function font.symbolLine
   * @param {number} id - a 16-bit number of a symbol
   * @example
   * font.symbolLine(1)
   * 
   * return '󰀁'
   */
  const symbolLine = function (id) {
    return String.fromCodePoint(id + 0xF0000);
  };
  /**
   * Function that returns a plane 16 character for a symbol fill using an id
   * @function font.symbolFill
   * @param {number} id - a 16-bit number of a symbol
   * @example
   * font.symbolFill(1)
   * 
   * return '􀀁'
   */


  const symbolFill = function (id) {
    return String.fromCodePoint(id + 0x100000);
  };
  /**
   * Function that creates two text elements for a symbol using an id
   * @function font.symbolText
   * @param {number} id - a 16-bit number of a symbol
   * @example
   * font.symbolText(1)
   * 
   * return `    <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
   */


  const symbolText = function (id) {
    return `    <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">${symbolFill(id)}</text>
    <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">${symbolLine(id)}</text>`;
  };

  /**
   * Function that executes a callback function once the Sutton SignWriiting Line and Fill fonts are ready to use
   * @function font.cssLoaded
   * @param {function} callback - a callback function to execute when fonts are ready
   * @example
   * const callback = () => {
   *   console.log("Sutton SignWriting Line and Fill fonts are ready to use")
   * }
   * 
   * font.cssLoaded( callback )
   */

  const cssLoaded = function (callback) {
    let lineReady = false;
    let fillReady = false;
    cssLoadedLine(() => {
      lineReady = true;
    });
    cssLoadedFill(() => {
      fillReady = true;
    });
    const cssCheck = setInterval(function () {
      if (lineReady && fillReady) {
        clearInterval(cssCheck);
        callback();
      }
    }, 100);
  };
  /**
   * Function that executes a callback function once the Sutton SignWriiting Line font is ready to use
   * @function font.cssLoadedLine
   * @param {function} callback - a callback function to execute when line font is ready
   * @example
   * const callback = () => {
   *   console.log("Sutton SignWriting Line font is ready to use")
   * }
   * 
   * font.cssLoadedLine( callback )
   */


  const cssLoadedLine = function (callback) {
    if (!symbolSize(1)) {
      const cssCheck = setInterval(function () {
        if (symbolSize(1)) {
          clearInterval(cssCheck);
          callback();
        }
      }, 100);
    } else {
      callback();
    }
  };
  /**
   * Function that executes a callback function once the Sutton SignWriiting Fill font is ready to use
   * @function font.cssLoadedFill
   * @param {function} callback - a callback function to execute when fill font is ready
   * @example
   * const callback = () => {
   *   console.log("Sutton SignWriting Fill font is ready to use")
   * }
   * 
   * font.cssLoadedFill( callback )
   */


  const cssLoadedFill = function (callback) {
    const fillReady = function () {
      const canvaser = document.createElement("canvas");
      canvaser.width = 15;
      canvaser.height = 30;
      const context = canvaser.getContext("2d");
      context.font = "30px 'SuttonSignWritingFill'";
      context.fillText(symbolFill(1), 0, 0);
      const imgData = context.getImageData(0, 0, 15, 30).data;
      return !imgData.every(item => item === 0);
    };

    if (!fillReady()) {
      const cssCheck = setInterval(function () {
        if (fillReady()) {
          clearInterval(cssCheck);
          callback();
        }
      }, 100);
    } else {
      callback();
    }
  };

  /** The font module contains functions for handing the TrueType fonts.
   * @module font
   */

  var index = /*#__PURE__*/Object.freeze({
    __proto__: null,
    cssAppend: cssAppend,
    cssLoaded: cssLoaded,
    cssLoadedLine: cssLoadedLine,
    cssLoadedFill: cssLoadedFill,
    symbolSize: symbolSize,
    symbolLine: symbolLine,
    symbolFill: symbolFill,
    symbolText: symbolText
  });

  /**
  * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
  * Author: Steve Slevinski  (https://SteveSlevinski.me)
  * convert.mjs is released under the MIT License.
  */
  /**
   * Function to convert a number to an SWU number character
   * @function convert.num2swu
   * @param {number} num - Integer value for number
   * @returns {string} SWU number character
   * @example
   * convert.num2swu(500)
   * 
   * return '𝤆'
   */


  const num2swu = num => String.fromCodePoint(0x1D80C + parseInt(num) - 250);
  /**
   * Function to convert an array of x,y integers to two SWU number characters
   * @function convert.coord2swu
   * @param {number[]} coord - Array of x,y integers
   * @returns {string} Two SWU number character
   * @example
   * convert.coord2swu([500, 500])
   * 
   * return '𝤆𝤆'
   */


  const coord2swu = coord => coord.map(num => num2swu(num)).join('');
  /**
   * Function to convert an SWU symbol character to a code point on plane 4
   * @function convert.swu2code
   * @param {string} swuSym - SWU symbol character
   * @returns {number} Code point on plane 4
   * @example
   * convert.swu2code('񀀁')
   * 
   * return 0x40001
   */


  const swu2code = swuSym => parseInt(swuSym.codePointAt(0));
  /**
   * Function to convert an SWU symbol character to a 16-bit ID
   * @function convert.swu2id
   * @param {string} swuSym - SWU symbol character
   * @returns {number} 16-bit ID
   * @example
   * convert.swu2id('񀀁')
   * 
   * return 1
   */


  const swu2id = swuSym => swu2code(swuSym) - 0x40000;
  /**
   * Function to convert an FSW symbol key to a 16-bit ID
   * @function convert.key2id
   * @param {string} key - FSW symbol key
   * @returns {number} 16-bit ID
   * @example
   * convert.key2id('S10000')
   * 
   * return 1
   */


  const key2id = key => 1 + (parseInt(key.slice(1, 4), 16) - 256) * 96 + parseInt(key.slice(4, 5), 16) * 16 + parseInt(key.slice(5, 6), 16);

  /* support ongoing development on https://patreon.com/signwriting */

  /**
   * Function that returns the size of a symbol using an FSW symbol key
   * @function fsw.symbolSize
   * @param {string} fsw - an FSW symbol key
   * @example
   * fsw.symbolSize("S10000")
   * 
   * return [15,30]
   */

  const symbolSize$1 = function (fsw) {
    return symbolSize(key2id(fsw));
  };

  /**
   * Function that returns a plane 15 character for a symbol line using an FSW symbol key
   * @function fsw.symbolLine
   * @param {string} fsw - an FSW symbol key
   * @example
   * fsw.symbolLine('S10000')
   * 
   * return '󰀁'
   */

  const symbolLine$1 = function (fsw) {
    return symbolLine(key2id(fsw));
  };
  /**
   * Function that returns a plane 16 character for a symbol fill using an FSW symbol key
   * @function fsw.symbolFill
   * @param {string} fsw - an FSW symbol key
   * @example
   * font.symbolFill('S10000')
   * 
   * return '􀀁'
   */


  const symbolFill$1 = function (fsw) {
    return symbolFill(key2id(fsw));
  };
  /**
   * Function that creates two text elements for a symbol using an FSW symbol key
   * @function fsw.symbolText
   * @param {string} fsw - an FSW symbol key
   * @example
   * fsw.symbolText('S10000')
   * 
   * return `    <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
   */


  const symbolText$1 = function (fsw) {
    return symbolText(key2id(fsw));
  };

  /**
  * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
  * Author: Steve Slevinski  (https://SteveSlevinski.me)
  * style.mjs is released under the MIT License.
  */

  /**
   * Object of regular expressions for style strings
   * 
   *   { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
   * @alias style.re
   * @type {object}
   */
  let re = {
    'colorize': 'C',
    'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
    'colorname': '[a-zA-Z]+',
    'padding': 'P[0-9]{2}',
    'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
    'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
    'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
    'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
  };
  re.colorbase = `(?:${re.colorhex}|${re.colorname})`;
  re.color = `_${re.colorbase}_`;
  re.colors = `_${re.colorbase}(?:,${re.colorbase})?_`;
  re.background = `G${re.color}`;
  re.detail = `D${re.colors}`;
  re.detailsym = `D[0-9]{2}${re.colors}`;
  re.classes = `${re.classbase}(?: ${re.classbase})*`;
  re.full = `-(${re.colorize})?(${re.padding})?(${re.background})?(${re.detail})?(${re.zoom})?(?:-((?:${re.detailsym})*)((?:${re.zoomsym})*))?(?:-(${re.classes})?!(?:(${re.id})!)?)?`;

  const prefixColor = color => {
    const regex = new RegExp(`^${re.colorhex}$`);
    return (regex.test(color) ? '#' : '') + color;
  };
  /**
   * Function to parse style string to object
   * @function style.parse
   * @param {string} styleString - a style string
   * @returns {object} elements of style string
   * @example
   * style.parse('-CP10G_blue_D_red,Cyan_')
   * 
   * return {
   *  'colorize': true,
   *  'padding': 10,
   *  'background': 'blue',
   *  'detail': ['red', 'Cyan']
   * }
   */


  const parse = styleString => {
    const regex = `^${re.full}`;
    const m = (typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : []) || [];
    return {
      'colorize': !m[1] ? undefined : !!m[1],
      'padding': !m[2] ? undefined : parseInt(m[2].slice(1)),
      'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)),
      'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor),
      'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)),
      'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re.detailsym, 'g')).map(val => {
        const parts = val.split('_');
        const detail = parts[1].split(',').map(prefixColor);
        return {
          'index': parseInt(parts[0].slice(1)),
          'detail': detail
        };
      }),
      'zoomsym': !m[7] ? undefined : m[7].match(new RegExp(re.zoomsym, 'g')).map(val => {
        const parts = val.split(',');
        return {
          'index': parseInt(parts[0].slice(1)),
          'zoom': parseFloat(parts[1]),
          'offset': !parts[2] ? undefined : parts[2].split('x').map(val => parseInt(val) - 500)
        };
      }),
      'classes': !m[8] ? undefined : m[8],
      'id': !m[9] ? undefined : m[9]
    };
  };

  /* support ongoing development on https://patreon.com/signwriting */

  /**
  * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
  * Author: Steve Slevinski  (https://SteveSlevinski.me)
  * fsw.mjs is released under the MIT License.
  */

  /**
   * Object of regular expressions for FSW strings
   * 
   *   { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable }
   * @alias fsw.re
   * @type {object}
   */
  let re$1 = {
    'symbol': 'S[123][0-9a-f]{2}[0-5][0-9a-f]',
    'coord': '[0-9]{3}x[0-9]{3}',
    'sort': 'A',
    'box': '[BLMR]'
  };
  re$1.prefix = `(?:${re$1.sort}(?:${re$1.symbol})+)`;
  re$1.spatial = `${re$1.symbol}${re$1.coord}`;
  re$1.signbox = `${re$1.box}${re$1.coord}(?:${re$1.spatial})*`;
  re$1.sign = `${re$1.prefix}?${re$1.signbox}`;
  re$1.sortable = `${re$1.prefix}${re$1.signbox}`;

  /**
   * Object of regular expressions for style strings
   * 
   *   { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
   * @alias style.re
   * @type {object}
   */
  let re$1$1 = {
    'colorize': 'C',
    'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
    'colorname': '[a-zA-Z]+',
    'padding': 'P[0-9]{2}',
    'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
    'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
    'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
    'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
  };
  re$1$1.colorbase = `(?:${re$1$1.colorhex}|${re$1$1.colorname})`;
  re$1$1.color = `_${re$1$1.colorbase}_`;
  re$1$1.colors = `_${re$1$1.colorbase}(?:,${re$1$1.colorbase})?_`;
  re$1$1.background = `G${re$1$1.color}`;
  re$1$1.detail = `D${re$1$1.colors}`;
  re$1$1.detailsym = `D[0-9]{2}${re$1$1.colors}`;
  re$1$1.classes = `${re$1$1.classbase}(?: ${re$1$1.classbase})*`;
  re$1$1.full = `-(${re$1$1.colorize})?(${re$1$1.padding})?(${re$1$1.background})?(${re$1$1.detail})?(${re$1$1.zoom})?(?:-((?:${re$1$1.detailsym})*)((?:${re$1$1.zoomsym})*))?(?:-(${re$1$1.classes})?!(?:(${re$1$1.id})!)?)?`;

  /** The convert module contains functions to convert between Formal SignWriitng in ASCII (FSW) and SignWriting in Unicode (SWU) characters, along with other types of data.
   * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
   * @module convert
   */
  /**
   * Function to convert an FSW coordinate string to an array of x,y integers
   * @function convert.fsw2coord
   * @param {string} fswCoord - An FSW coordinate string
   * @returns {number[]} Array of x,y integers
   * @example
   * convert.fsw2coord('500x500')
   * 
   * return [500, 500]
   */


  const fsw2coord = fswCoord => fswCoord.split('x').map(num => parseInt(num));

  const parse$1 = {
    /**
     * Function to parse an fsw symbol with optional coordinate and style string
     * @function fsw.parse.symbol
     * @param {string} fswSym - an fsw symbol
     * @returns {object} elements of fsw symbol
     * @example
     * fsw.parse.symbol('S10000500x500-C')
     * 
     * return {
     *  'symbol': 'S10000',
     *  'coord': [500, 500],
     *  'style': '-C'
     * }
     */
    symbol: fswSym => {
      const regex = `^(${re$1.symbol})(${re$1.coord})?(${re$1$1.full})?`;
      const symbol = typeof fswSym === 'string' ? fswSym.match(new RegExp(regex)) : undefined;
      return {
        'symbol': symbol ? symbol[1] : undefined,
        'coord': symbol && symbol[2] ? fsw2coord(symbol[2]) : undefined,
        'style': symbol ? symbol[3] : undefined
      };
    },

    /**
     * Function to parse an fsw sign with style string
     * @function fsw.parse.sign
     * @param {string} fswSign - an fsw sign
     * @returns {object} elements of fsw sign
     * @example
     * fsw.parse.sign('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C')
     * 
     * return {
     *  sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
     *  box: 'M',
     *  max: [525, 535],
     *  spatials: [
     *    {
     *      symbol: 'S2e748',
     *      coord: [483, 510]
     *    },
     *    {
     *      symbol: 'S10011',
     *      coord: [501, 466]
     *    },
     *    {
     *      symbol: 'S2e704',
     *      coord: [510, 500]
     *    },
     *    {
     *      symbol: 'S10019',
     *      coord: [476, 475]
     *    }
     *  ],
     *  style: '-C'
     * }
     */
    sign: fswSign => {
      const regex = `^(${re$1.prefix})?(${re$1.signbox})(${re$1$1.full})?`;
      const sign = typeof fswSign === 'string' ? fswSign.match(new RegExp(regex)) : undefined;

      if (sign) {
        return {
          'sequence': sign[1] ? sign[1].slice(1).match(/.{6}/g) : undefined,
          'box': sign[2][0],
          'max': fsw2coord(sign[2].slice(1, 8)),
          'spatials': sign[2].length < 9 ? undefined : sign[2].slice(8).match(/(.{13})/g).map(m => {
            return {
              symbol: m.slice(0, 6),
              coord: [parseInt(m.slice(6, 9)), parseInt(m.slice(10, 13))]
            };
          }),
          'style': sign[3]
        };
      } else {
        return {};
      }
    }
  };
  /**
   * Array of numbers for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
   * @alias fsw.category
   * @type {array}
   */

  const category = [0x100, 0x205, 0x2f7, 0x2ff, 0x36d, 0x37f, 0x387];
  /**
   * Object of symbol ranges with starting and ending numbers.
   * 
   *   { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
   * @alias fsw.ranges
   * @type {object}
   */

  const ranges = {
    'all': [0x100, 0x38b],
    'writing': [0x100, 0x37e],
    'hand': [0x100, 0x204],
    'movement': [0x205, 0x2f6],
    'dynamic': [0x2f7, 0x2fe],
    'head': [0x2ff, 0x36c],
    'hcenter': [0x2ff, 0x36c],
    'vcenter': [0x2ff, 0x375],
    'trunk': [0x36d, 0x375],
    'limb': [0x376, 0x37e],
    'location': [0x37f, 0x386],
    'punctuation': [0x387, 0x38b]
  };

  /**
   * Array of colors associated with the seven symbol categories.
   * @alias fsw.colors
   * @type {array}
   */

  const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
  /**
   * Function that returns the standardized color for a symbol.
   * @function fsw.colorize
   * @param {string} key - an FSW symbol key
   * @returns {string} name of standardized color for symbol
   * @example
   * fsw.colorize('S10000')
   * 
   * return '#0000CC'
   */

  const colorize = key => {
    const parsed = parse$1.symbol(key);
    let color = '#000000';

    if (parsed.symbol) {
      const dec = parseInt(parsed.symbol.slice(1, 4), 16);
      const index = category.findIndex(val => val > dec);
      color = colors[index < 0 ? 6 : index - 1];
    }

    return color;
  };

  /* support ongoing development on https://patreon.com/signwriting */

  /**
   * Function that creates an SVG image from an FSW symbol key with an optional style string
   * @function fsw.symbolSvg
   * @param {string} fswSym - an FSW symbol key with optional style string
   * @example
   * fsw.symbolSvg('S10000')
   * 
   * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="15" height="30" viewBox="500 500 15 30">
   *   <text font-size="0">S10000</text>
   *   <g transform="translate(500,500)">
   *     <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>
   *   </g>
   * </svg>`
   */

  const symbolSvg = fswSym => {
    const parsed = parse$1.symbol(fswSym);
    const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';

    if (parsed.symbol) {
      let size = symbolSize$1(parsed.symbol);

      if (size) {
        let styling = parse(parsed.style);
        let line;
        let symSvg = symbolText$1(parsed.symbol);
        symSvg = `  <g transform="translate(500,500)">
${symSvg}
  </g>`;

        if (styling.colorize) {
          line = colorize(parsed.symbol);
        } else if (styling.detail) {
          line = styling.detail[0];
        }

        if (line) {
          symSvg = symSvg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${line}"`);
        }

        let fill = styling.detail && styling.detail[1];

        if (fill) {
          symSvg = symSvg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${fill}"`);
        }

        let x1 = 500;
        let y1 = 500;
        let background = '';

        if (styling.padding) {
          x1 -= styling.padding;
          y1 -= styling.padding;
          size[0] += styling.padding * 2;
          size[1] += styling.padding * 2;
        }

        if (styling.background) {
          background = `\n  <rect x="${x1}" y="${y1}" width="${size[0]}" height="${size[1]}" style="fill:${styling.background};" />`;
        }

        let sizing = '';

        if (styling.zoom != 'x') {
          sizing = ` width="${size[0] * (styling.zoom ? styling.zoom : 1)}" height="${size[1] * (styling.zoom ? styling.zoom : 1)}"`;
        }

        let classes = '';

        if (styling.classes) {
          classes = ` class="${styling.classes}"`;
        }

        let id = '';

        if (styling.id) {
          id = ` id="${styling.id}"`;
        }

        return `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${size[0]} ${size[1]}">
  <text font-size="0">${fswSym}</text>${background}
${symSvg}
</svg>`;
      }
    }

    return blank;
  };

  const symbolCanvas = function (fswSym) {
    const parsed = parse$1.symbol(fswSym);

    if (parsed.symbol) {
      let size = symbolSize$1(parsed.symbol);

      if (size) {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        let styling = parse(parsed.style);
        let line = 'black';

        if (styling.colorize) {
          line = colorize(parsed.symbol);
        } else if (styling.detail) {
          line = styling.detail[0];
        }

        let fill = styling.detail && styling.detail[1] || 'white';
        let x1 = 500;
        let x2 = x1 + size[0];
        let y1 = 500;
        let y2 = y1 + size[1];

        if (styling.padding) {
          x1 -= styling.padding;
          y1 -= styling.padding;
          x2 += styling.padding;
          y2 += styling.padding;
        }

        let sizing = 1;

        if (styling.zoom != 'x') {
          sizing = styling.zoom;
        }

        let w = (x2 - x1) * sizing;
        let h = (y2 - y1) * sizing;
        canvas.width = w ? w : 1;
        canvas.height = h ? h : 1;

        if (styling.background) {
          context.rect(0, 0, w, h);
          context.fillStyle = styling.background;
          context.fill();
        }

        context.font = 30 * sizing + "px 'SuttonSignWritingFill'";
        context.fillStyle = fill;
        context.fillText(symbolFill$1(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
        context.font = 30 * sizing + "px 'SuttonSignWritingLine'";
        context.fillStyle = line;
        context.fillText(symbolLine$1(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
        return canvas;
      }
    }
  };
  /**
   * Function that creates a binary PNG image from an FSW symbol key with an optional stle string
   * @function fsw.symbolPng
   * @param {string} fswSym - an FSW symbol key with optional style string
   * @example
   * fsw.symbolPng('S10000')
   * 
   * return 'data:image/png;base64,iVBORw...'
   */


  const symbolPng = fswSym => {
    const canvas = symbolCanvas(fswSym);
    const png = canvas.toDataURL("image/png");
    canvas.remove();
    return png;
  };

  const blank = null;
  /**
   * Function that normalizes a symbol with a minimum coordinate for a center of 500,500
   * @function fsw.symbolNormalize
   * @param {string} fswSym - an FSW symbol key with optional coordinate and style string
   * @example
   * fsw.symbolNormalize('S10000-CP10G_green_Z2')
   * 
   * return 'S10000493x485-CP10G_green_Z2'
   */

  const symbolNormalize = fswSym => {
    const parsed = parse$1.symbol(fswSym);

    if (parsed.symbol) {
      let size = symbolSize$1(parsed.symbol);

      if (size) {
        return `${parsed.symbol}${500 - parseInt(size[0] / 2)}x${500 - parseInt(size[1] / 2)}${parsed.style || ''}`;
      }
    } else {
      return blank;
    }
  };

  /**
   * Function that creates an SVG image from an FSW sign with an optional style string
   * @function fsw.signSvg
   * @param {string} fswSign - an FSW sign with optional style string
   * @example
   * fsw.signSvg('M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475')
   * 
   * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="49" height="69" viewBox="476 466 49 69">
   *   <text font-size="0">M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475</text>
   *   <g transform="translate(483,510)">
   *     <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􋛩</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󻛩</text>
   *   </g>
   *   <g transform="translate(501,466)">
   *     <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀒</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀒</text>
   *   </g>
   *   <g transform="translate(510,500)">
   *     <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􋚥</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󻚥</text>
   *   </g>
   *   <g transform="translate(476,475)">
   *     <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀚</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀚</text>
   *   </g>
   * </svg>`
   */

  const signSvg = fswSign => {
    let parsed = parse$1.sign(fswSign);
    const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';

    if (parsed.spatials) {
      let styling = parse(parsed.style);

      if (styling.detailsym) {
        styling.detailsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].detail = sym.detail;
          }
        });
      }

      let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
      let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
      let x2 = parsed.max[0];
      let y2 = parsed.max[1];

      if (styling.zoomsym) {
        styling.zoomsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].zoom = sym.zoom;

            if (sym.offset) {
              parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
              parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
            }

            let size = symbolSize$1(parsed.spatials[sym.index - 1].symbol);
            x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
            y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
          }
        });
      }

      let classes = '';

      if (styling.classes) {
        classes = ` class="${styling.classes}"`;
      }

      let id = '';

      if (styling.id) {
        id = ` id="${styling.id}"`;
      }

      let background = '';

      if (styling.padding) {
        x1 -= styling.padding;
        y1 -= styling.padding;
        x2 += styling.padding;
        y2 += styling.padding;
      }

      if (styling.background) {
        background = `\n  <rect x="${x1}" y="${y1}" width="${x2 - x1}" height="${y2 - y1}" style="fill:${styling.background};" />`;
      }

      let sizing = '';

      if (styling.zoom != 'x') {
        sizing = ` width="${(x2 - x1) * (styling.zoom ? styling.zoom : 1)}" height="${(y2 - y1) * (styling.zoom ? styling.zoom : 1)}"`;
      }

      let svg = `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${x2 - x1} ${y2 - y1}">
  <text font-size="0">${fswSign}</text>${background}`;
      const line = styling.detail && styling.detail[0];
      const fill = styling.detail && styling.detail[1];
      svg += '\n' + parsed.spatials.map(spatial => {
        let svg = symbolText$1(spatial.symbol);
        let symLine = line;

        if (spatial.detail) {
          symLine = spatial.detail[0];
        } else if (styling.colorize) {
          symLine = colorize(spatial.symbol);
        }

        if (symLine) {
          svg = svg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${symLine}"`);
        }

        let symFill = fill;

        if (spatial.detail && spatial.detail[1]) {
          symFill = spatial.detail[1];
        }

        if (symFill) {
          svg = svg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${symFill}"`);
        }

        if (spatial.zoom) {
          svg = `<g transform="scale(${spatial.zoom})">${svg}</g>`;
        }

        return `  <g transform="translate(${spatial.coord[0]},${spatial.coord[1]})">
${svg}
  </g>`;
      }).join('\n');
      svg += '\n</svg>';
      return svg;
    }

    return blank;
  };

  const signCanvas = function (fswSign) {
    const parsed = parse$1.sign(fswSign);

    if (parsed.spatials) {
      const canvas = document.createElement('canvas');
      const context = canvas.getContext('2d');
      let styling = parse(parsed.style);

      if (styling.detailsym) {
        styling.detailsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].detail = sym.detail;
          }
        });
      }

      let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
      let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
      let x2 = parsed.max[0];
      let y2 = parsed.max[1];

      if (styling.zoomsym) {
        styling.zoomsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].zoom = sym.zoom;

            if (sym.offset) {
              parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
              parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
            }

            let size = symbolSize$1(parsed.spatials[sym.index - 1].symbol);
            x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
            y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
          }
        });
      }

      if (styling.padding) {
        x1 -= styling.padding;
        y1 -= styling.padding;
        x2 += styling.padding;
        y2 += styling.padding;
      }

      let sizing = 1;

      if (styling.zoom != 'x') {
        sizing = styling.zoom;
      }

      let w = (x2 - x1) * sizing;
      let h = (y2 - y1) * sizing;
      canvas.width = w ? w : 1;
      canvas.height = h ? h : 1;

      if (styling.background) {
        context.rect(0, 0, w, h);
        context.fillStyle = styling.background;
        context.fill();
      }

      const line = styling.detail && styling.detail[0] || "black";
      const fill = styling.detail && styling.detail[1] || "white";
      parsed.spatials.forEach(spatial => {
        let symLine = line;

        if (spatial.detail) {
          symLine = spatial.detail[0];
        } else if (styling.colorize) {
          symLine = colorize(spatial.symbol);
        }

        let symFill = fill;

        if (spatial.detail && spatial.detail[1]) {
          symFill = spatial.detail[1];
        }

        let symZoom = spatial.zoom || 1;
        context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingFill'";
        context.fillStyle = symFill;
        context.fillText(symbolFill$1(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
        context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingLine'";
        context.fillStyle = symLine;
        context.fillText(symbolLine$1(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
      });
      return canvas;
    }
  };
  /**
   * Function that creates a binary PNG image from an FSW sign with an optional style string
   * @function fsw.signPng
   * @param {string} fswSign - an FSW sign with optional style string
   * @example
   * fsw.signPng('M525x535S2e748483x510S10011501x466S20544510x500S10019476x475')
   * 
   * return 'data:image/png;base64,iVBORw...'
   */


  const signPng = fswSign => {
    const canvas = signCanvas(fswSign);
    const png = canvas.toDataURL("image/png");
    canvas.remove();
    return png;
  };

  /**
   * Function that normalizes an FSW sign for a center of 500,500
   * @function fsw.signNormalize
   * @param {string} fswSign - an FSW sign with optional style string
   * @example
   * fsw.signNormalize('M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475')
   * 
   * return 'M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
   */

  const signNormalize = fswSign => {
    const parsed = parse$1.sign(fswSign);

    if (parsed.spatials) {
      const symbolsizes = parsed.spatials.reduce((output, spatial) => {
        const size = symbolSize$1(spatial.symbol);
        output[spatial.symbol] = {
          width: size[0],
          height: size[1]
        };
        return output;
      }, {});

      const bbox = symbols => {
        const x1 = Math.min(...symbols.map(spatial => spatial.coord[0]));
        const y1 = Math.min(...symbols.map(spatial => spatial.coord[1]));
        const x2 = Math.max(...symbols.map(spatial => spatial.coord[0] + parseInt(symbolsizes[spatial.symbol].width)));
        const y2 = Math.max(...symbols.map(spatial => spatial.coord[1] + parseInt(symbolsizes[spatial.symbol].height)));
        return {
          x1: x1,
          y1: y1,
          x2: x2,
          y2: y2
        };
      };

      const hrange = ranges['hcenter'];
      const hsyms = parsed.spatials.filter(spatial => {
        const dec = parseInt(spatial.symbol.slice(1, 4), 16);
        return hrange[0] <= dec && hrange[1] >= dec;
      });
      const vrange = ranges['vcenter'];
      const vsyms = parsed.spatials.filter(spatial => {
        const dec = parseInt(spatial.symbol.slice(1, 4), 16);
        return vrange[0] <= dec && vrange[1] >= dec;
      });
      let abox = bbox(parsed.spatials);
      let max = [abox.x2, abox.y2];

      if (hsyms.length) {
        const hbox = bbox(hsyms);
        abox.x1 = hbox.x1;
        abox.x2 = hbox.x2;
      }

      if (vsyms.length) {
        const vbox = bbox(vsyms);
        abox.y1 = vbox.y1;
        abox.y2 = vbox.y2;
      }

      const offset = [parseInt((abox.x2 + abox.x1) / 2) - 500, parseInt((abox.y2 + abox.y1) / 2) - 500];
      const fswout = (parsed.sequence ? 'A' + parsed.sequence.join('') : '') + parsed.box + (max[0] - offset[0]) + 'x' + (max[1] - offset[1]) + parsed.spatials.map(spatial => spatial.symbol + (spatial.coord[0] - offset[0]) + 'x' + (spatial.coord[1] - offset[1])).join('') + (parsed.style || '');
      return fswout;
    }
  };

  /** The fsw module contains functions for handling Formal SignWriitng in ASCII (FSW) characters.
   * [FSW characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.1)
   * @module fsw
   */

  var index$1 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    symbolSize: symbolSize$1,
    symbolLine: symbolLine$1,
    symbolFill: symbolFill$1,
    symbolText: symbolText$1,
    symbolSvg: symbolSvg,
    symbolPng: symbolPng,
    symbolNormalize: symbolNormalize,
    signSvg: signSvg,
    signPng: signPng,
    signNormalize: signNormalize
  });

  /**
   * Function that returns the size of a symbol using an SWU symbol character
   * @function swu.symbolSize
   * @param {string} swu - an SWU symbol character
   * @example
   * swu.symbolSize("񀀁")
   * 
   * return [15,30]
   */

  const symbolSize$2 = function (swu) {
    return symbolSize(swu2id(swu));
  };

  /**
   * Function that returns a plane 15 character for a symbol line using an SWU symbol character
   * @function swu.symbolLine
   * @param {string} swu - an SWU symbol character
   * @example
   * swu.symbolLine('񀀁')
   * 
   * return '󰀁'
   */

  const symbolLine$2 = function (swu) {
    return symbolLine(swu2id(swu));
  };
  /**
   * Function that returns a plane 165 character for a symbol fill using an SWU symbol character
   * @function swu.symbolFill
   * @param {string} swu - an SWU symbol character
   * @example
   * swu.symbolFill('񀀁')
   * 
   * return '􀀁'
   */


  const symbolFill$2 = function (swu) {
    return symbolFill(swu2id(swu));
  };
  /**
   * Function that creates two text elements for a symbol using an SWU symbol character
   * @function swu.symbolText
   * @param {string} swu - an SWU symbol character
   * @example
   * swu.symbolText('񀀁')
   * 
   * return `    <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
   *     <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
   */


  const symbolText$2 = function (swu) {
    return symbolText(swu2id(swu));
  };

  /**
  * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
  * Author: Steve Slevinski  (https://SteveSlevinski.me)
  * swu.mjs is released under the MIT License.
  */

  /**
   * Object of regular expressions for SWU strings in UTF-16
   * 
   *   { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable }
   * @alias swu.re
   * @type {object}
   */
  let re$2 = {
    'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
    'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}',
    'sort': '\uD836\uDC00',
    'box': '\uD836[\uDC01-\uDC04]'
  };
  re$2.prefix = `(?:${re$2.sort}(?:${re$2.symbol})+)`;
  re$2.spatial = `${re$2.symbol}${re$2.coord}`;
  re$2.signbox = `${re$2.box}${re$2.coord}(?:${re$2.spatial})*`;
  re$2.sign = `${re$2.prefix}?${re$2.signbox}`;
  re$2.sortable = `${re$2.prefix}${re$2.signbox}`;

  /**
   * Object of regular expressions for style strings
   * 
   *   { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
   * @alias style.re
   * @type {object}
   */
  let re$1$2 = {
    'colorize': 'C',
    'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
    'colorname': '[a-zA-Z]+',
    'padding': 'P[0-9]{2}',
    'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
    'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
    'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
    'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
  };
  re$1$2.colorbase = `(?:${re$1$2.colorhex}|${re$1$2.colorname})`;
  re$1$2.color = `_${re$1$2.colorbase}_`;
  re$1$2.colors = `_${re$1$2.colorbase}(?:,${re$1$2.colorbase})?_`;
  re$1$2.background = `G${re$1$2.color}`;
  re$1$2.detail = `D${re$1$2.colors}`;
  re$1$2.detailsym = `D[0-9]{2}${re$1$2.colors}`;
  re$1$2.classes = `${re$1$2.classbase}(?: ${re$1$2.classbase})*`;
  re$1$2.full = `-(${re$1$2.colorize})?(${re$1$2.padding})?(${re$1$2.background})?(${re$1$2.detail})?(${re$1$2.zoom})?(?:-((?:${re$1$2.detailsym})*)((?:${re$1$2.zoomsym})*))?(?:-(${re$1$2.classes})?!(?:(${re$1$2.id})!)?)?`;

  /** The convert module contains functions to convert between Formal SignWriitng in ASCII (FSW) and SignWriting in Unicode (SWU) characters, along with other types of data.
   * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
   * @module convert
   */
  /**
   * Function to convert an SWU number character to an integer
   * @function convert.swu2num
   * @param {string} swuNum - SWU number character
   * @returns {number} Integer value for number
   * @example
   * convert.swu2num('𝤆')
   * 
   * return 500
   */


  const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250;
  /**
   * Function to convert two SWU number characters to an array of x,y integers
   * @function convert.swu2coord
   * @param {string} swuCoord - Two SWU number character
   * @returns {number[]} Array of x,y integers
   * @example
   * convert.swu2coord('𝤆𝤆')
   * 
   * return [500, 500]
   */


  const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))];
  /**
   * Function to convert an SWU symbol character to a code point on plane 4
   * @function convert.swu2code
   * @param {string} swuSym - SWU symbol character
   * @returns {number} Code point on plane 4
   * @example
   * convert.swu2code('񀀁')
   * 
   * return 0x40001
   */


  const swu2code$1 = swuSym => parseInt(swuSym.codePointAt(0));

  const parse$2 = {
    /**
     * Function to parse an swu symbol with optional coordinate and style string
     * @function swu.parse.symbol
     * @param {string} swuSym - an swu symbol
     * @returns {object} elements of swu symbol
     * @example
     * swu.parse.symbol('񀀁𝤆𝤆-C')
     * 
     * return {
     *  'symbol': '񀀁',
     *  'coord': [500, 500],
     *  'style': '-C'
     * }
     */
    symbol: swuSym => {
      const regex = `^(${re$2.symbol})(${re$2.coord})?(${re$1$2.full})?`;
      const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
      return {
        'symbol': symbol ? symbol[1] : undefined,
        'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
        'style': symbol ? symbol[3] : undefined
      };
    },

    /**
      * Function to parse an swu sign with style string
      * @function swu.parse.sign
      * @param {string} swuSign - an swu sign
      * @returns {object} elements of swu sign
      * @example
      * swu.parse.sign('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C')
      * 
      * return {
      *  sequence: ['񀀒','񀀚','񋚥','񋛩''],
      *  box: '𝠃',
      *  max: [525, 535],
      *  spatials: [
      *    {
      *      symbol: '񋛩',
      *      coord: [483, 510]
      *    },
      *    {
      *      symbol: '񀀒',
      *      coord: [501, 466]
      *    },
      *    {
      *      symbol: '񋚥',
      *      coord: [510, 500]
      *    },
      *    {
      *      symbol: '񀀚',
      *      coord: [476, 475]
      *    }
      *  ],
      *  style: '-C'
      * }
      */
    sign: swuSign => {
      const regex = `^(${re$2.prefix})?(${re$2.signbox})(${re$1$2.full})?`;
      const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;

      if (sign) {
        return {
          'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
          'box': sign[2].slice(0, 2),
          'max': swu2coord(sign[2].slice(2, 6)),
          'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
            return {
              symbol: m.slice(0, 2),
              coord: swu2coord(m.slice(2))
            };
          }),
          'style': sign[3]
        };
      } else {
        return {};
      }
    }
  };
  /**
   * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
   * @alias swu.category
   * @type {array}
   */

  const category$1 = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
  /**
   * Object of symbol ranges with starting and ending code points on plane 4.
   * 
   *   { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
   * @alias swu.ranges
   * @type {object}
   */

  const ranges$1 = {
    'all': [0x40001, 0x4f480],
    'writing': [0x40001, 0x4efa0],
    'hand': [0x40001, 0x461e0],
    'movement': [0x461e1, 0x4bca0],
    'dynamic': [0x4bca1, 0x4bfa0],
    'head': [0x4bfa1, 0x4e8e0],
    'hcenter': [0x4bfa1, 0x4e8e0],
    'vcenter': [0x4bfa1, 0x4ec40],
    'trunk': [0x4e8e1, 0x4ec40],
    'limb': [0x4ec41, 0x4efa0],
    'location': [0x4efa1, 0x4f2a0],
    'punctuation': [0x4f2a1, 0x4f480]
  };

  /**
   * Array of colors associated with the seven symbol categories.
   * @alias swu.colors
   * @type {array}
   */

  const colors$1 = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
  /**
   * Function that returns the standardized color for a symbol.
   * @function swu.colorize
   * @param {string} swuSym - an SWU symbol character
   * @returns {string} name of standardized color for symbol
   * @example
   * swu.colorize('񀀁')
   * 
   * return '#0000CC'
   */

  const colorize$1 = swuSym => {
    const parsed = parse$2.symbol(swuSym);
    let color = '#000000';

    if (parsed.symbol) {
      const code = swu2code$1(parsed.symbol);
      const index = category$1.findIndex(val => val > code);
      color = colors$1[index < 0 ? 6 : index - 1];
    }

    return color;
  };

  /* support ongoing development on https://patreon.com/signwriting */

  /**
   * Function that creates an SVG image from an SWU symbol character with an optional style string
   * @function swu.symbolSvg
   * @param {string} swuSym - an SWU symbol character with optional style string
   * @example
   * swu.symbolSvg('񀀁-CP10G_green_Z2')
   * 
   * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="70" height="100" viewBox="490 490 35 50">
   *   <text font-size="0">񀀁-CP10G_green_Z2</text>
   *   <rect x="490" y="490" width="35" height="50" style="fill:green;" />
   *   <g transform="translate(500,500)">
   *     <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
   *     <text class="sym-line" fill="#0000CC" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>
   *   </g>
   * </svg>`
   */

  const symbolSvg$1 = swuSym => {
    const parsed = parse$2.symbol(swuSym);
    const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';

    if (parsed.symbol) {
      let size = symbolSize$2(parsed.symbol);

      if (size) {
        let styling = parse(parsed.style);
        let line;
        let symSvg = symbolText$2(parsed.symbol);
        symSvg = `  <g transform="translate(500,500)">
${symSvg}
  </g>`;

        if (styling.colorize) {
          line = colorize$1(parsed.symbol);
        } else if (styling.detail) {
          line = styling.detail[0];
        }

        if (line) {
          symSvg = symSvg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${line}"`);
        }

        let fill = styling.detail && styling.detail[1];

        if (fill) {
          symSvg = symSvg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${fill}"`);
        }

        let x1 = 500;
        let y1 = 500;
        let background = '';

        if (styling.padding) {
          x1 -= styling.padding;
          y1 -= styling.padding;
          size[0] += styling.padding * 2;
          size[1] += styling.padding * 2;
        }

        if (styling.background) {
          background = `\n  <rect x="${x1}" y="${y1}" width="${size[0]}" height="${size[1]}" style="fill:${styling.background};" />`;
        }

        let sizing = '';

        if (styling.zoom != 'x') {
          sizing = ` width="${size[0] * (styling.zoom ? styling.zoom : 1)}" height="${size[1] * (styling.zoom ? styling.zoom : 1)}"`;
        }

        let classes = '';

        if (styling.classes) {
          classes = ` class="${styling.classes}"`;
        }

        let id = '';

        if (styling.id) {
          id = ` id="${styling.id}"`;
        }

        return `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${size[0]} ${size[1]}">
  <text font-size="0">${swuSym}</text>${background}
${symSvg}
</svg>`;
      }
    }

    return blank;
  };

  const symbolCanvas$1 = function (swuSym) {
    const parsed = parse$2.symbol(swuSym);

    if (parsed.symbol) {
      let size = symbolSize$2(parsed.symbol);

      if (size) {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        let styling = parse(parsed.style);
        let line = 'black';

        if (styling.colorize) {
          line = colorize$1(parsed.symbol);
        } else if (styling.detail) {
          line = styling.detail[0];
        }

        let fill = styling.detail && styling.detail[1] || 'white';
        let x1 = 500;
        let x2 = x1 + size[0];
        let y1 = 500;
        let y2 = y1 + size[1];

        if (styling.padding) {
          x1 -= styling.padding;
          y1 -= styling.padding;
          x2 += styling.padding;
          y2 += styling.padding;
        }

        let sizing = 1;

        if (styling.zoom != 'x') {
          sizing = styling.zoom;
        }

        let w = (x2 - x1) * sizing;
        let h = (y2 - y1) * sizing;
        canvas.width = w ? w : 1;
        canvas.height = h ? h : 1;

        if (styling.background) {
          context.rect(0, 0, w, h);
          context.fillStyle = styling.background;
          context.fill();
        }

        context.font = 30 * sizing + "px 'SuttonSignWritingFill'";
        context.fillStyle = fill;
        context.fillText(symbolFill$2(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
        context.font = 30 * sizing + "px 'SuttonSignWritingLine'";
        context.fillStyle = line;
        context.fillText(symbolLine$2(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
        return canvas;
      }
    }
  };
  /**
   * Function that creates a binary PNG image from an SWU symbol character with an optional stle string
   * @function swu.symbolPng
   * @param {string} swuSym - an SWU symbol character with optional style string
   * @example
   * swu.symbolPng('񀀁-CP10G_green_Z2')
   * 
   * return 'data:image/png;base64,iVBORw...'
   */


  const symbolPng$1 = swuSym => {
    const canvas = symbolCanvas$1(swuSym);
    const png = canvas.toDataURL("image/png");
    canvas.remove();
    return png;
  };

  const blank$1 = null;
  /**
   * Function that normalizes a symbol with a minimum coordinate for a center of 500,500
   * @function swu.symbolNormalize
   * @param {string} swuSym - an SWU symbol character with optional coordinate and style string
   * @example
   * swu.symbolNormalize('񀀁')
   * 
   * return '񀀁𝣿𝣷'
   */

  const symbolNormalize$1 = swuSym => {
    const parsed = parse$2.symbol(swuSym);

    if (parsed.symbol) {
      let size = symbolSize$2(parsed.symbol);

      if (size) {
        return `${parsed.symbol}${coord2swu([500 - parseInt(size[0] / 2), 500 - parseInt(size[1] / 2)])}${parsed.style || ''}`;
      }
    } else {
      return blank$1;
    }
  };

  /**
   * Function that creates an SVG image from an SWU sign with an optional style string
   * @function swu.signSvg
   * @param {string} swuSign - an SWU sign with optional style string
   * @example
   * swu.signSvg('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-P10G_green_D_yellow,ff0ff0_Z2')
   * 
   * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="138" height="178" viewBox="466 456 69 89">
   *   <text font-size="0">𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-P10G_green_D_yellow,ff0ff0_Z2</text>
   *   <rect x="466" y="456" width="69" height="89" style="fill:green;" />
   *   <g transform="translate(483,510)">
   *     <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􋛩</text>
   *     <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󻛩</text>
   *   </g>
   *   <g transform="translate(501,466)">
   *     <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􀀒</text>
   *     <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󰀒</text>
   *   </g>
   *   <g transform="translate(510,500)">
   *     <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􋚥</text>
   *     <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󻚥</text>
   *   </g>
   *   <g transform="translate(476,475)">
   *     <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􀀚</text>
   *     <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󰀚</text>
   *   </g>
   * </svg>`
   */

  const signSvg$1 = swuSign => {
    let parsed = parse$2.sign(swuSign);
    const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';

    if (parsed.spatials) {
      let styling = parse(parsed.style);

      if (styling.detailsym) {
        styling.detailsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].detail = sym.detail;
          }
        });
      }

      let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
      let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
      let x2 = parsed.max[0];
      let y2 = parsed.max[1];

      if (styling.zoomsym) {
        styling.zoomsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].zoom = sym.zoom;

            if (sym.offset) {
              parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
              parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
            }

            let size = symbolSize$2(parsed.spatials[sym.index - 1].symbol);
            x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
            y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
          }
        });
      }

      let classes = '';

      if (styling.classes) {
        classes = ` class="${styling.classes}"`;
      }

      let id = '';

      if (styling.id) {
        id = ` id="${styling.id}"`;
      }

      let background = '';

      if (styling.padding) {
        x1 -= styling.padding;
        y1 -= styling.padding;
        x2 += styling.padding;
        y2 += styling.padding;
      }

      if (styling.background) {
        background = `\n  <rect x="${x1}" y="${y1}" width="${x2 - x1}" height="${y2 - y1}" style="fill:${styling.background};" />`;
      }

      let sizing = '';

      if (styling.zoom != 'x') {
        sizing = ` width="${(x2 - x1) * (styling.zoom ? styling.zoom : 1)}" height="${(y2 - y1) * (styling.zoom ? styling.zoom : 1)}"`;
      }

      let svg = `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${x2 - x1} ${y2 - y1}">
  <text font-size="0">${swuSign}</text>${background}`;
      const line = styling.detail && styling.detail[0];
      const fill = styling.detail && styling.detail[1];
      svg += '\n' + parsed.spatials.map(spatial => {
        let svg = symbolText$2(spatial.symbol, spatial.coord);
        let symLine = line;

        if (spatial.detail) {
          symLine = spatial.detail[0];
        } else if (styling.colorize) {
          symLine = colorize$1(spatial.symbol);
        }

        if (symLine) {
          svg = svg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${symLine}"`);
        }

        let symFill = fill;

        if (spatial.detail && spatial.detail[1]) {
          symFill = spatial.detail[1];
        }

        if (symFill) {
          svg = svg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${symFill}"`);
        }

        if (spatial.zoom) {
          svg = `<g transform="scale(${spatial.zoom})">${svg}</g>`;
        }

        return `  <g transform="translate(${spatial.coord[0]},${spatial.coord[1]})">
${svg}
  </g>`;
      }).join('\n');
      svg += '\n</svg>';
      return svg;
    }

    return blank;
  };

  const signCanvas$1 = function (swuSign) {
    const parsed = parse$2.sign(swuSign);

    if (parsed.spatials) {
      const canvas = document.createElement('canvas');
      const context = canvas.getContext('2d');
      let styling = parse(parsed.style);

      if (styling.detailsym) {
        styling.detailsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].detail = sym.detail;
          }
        });
      }

      let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
      let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
      let x2 = parsed.max[0];
      let y2 = parsed.max[1];

      if (styling.zoomsym) {
        styling.zoomsym.forEach(sym => {
          if (parsed.spatials[sym.index - 1]) {
            parsed.spatials[sym.index - 1].zoom = sym.zoom;

            if (sym.offset) {
              parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
              parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
            }

            let size = symbolSize$2(parsed.spatials[sym.index - 1].symbol);
            x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
            y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
          }
        });
      }

      if (styling.padding) {
        x1 -= styling.padding;
        y1 -= styling.padding;
        x2 += styling.padding;
        y2 += styling.padding;
      }

      let sizing = 1;

      if (styling.zoom != 'x') {
        sizing = styling.zoom;
      }

      let w = (x2 - x1) * sizing;
      let h = (y2 - y1) * sizing;
      canvas.width = w ? w : 1;
      canvas.height = h ? h : 1;

      if (styling.background) {
        context.rect(0, 0, w, h);
        context.fillStyle = styling.background;
        context.fill();
      }

      const line = styling.detail && styling.detail[0] || "black";
      const fill = styling.detail && styling.detail[1] || "white";
      parsed.spatials.forEach(spatial => {
        let symLine = line;

        if (spatial.detail) {
          symLine = spatial.detail[0];
        } else if (styling.colorize) {
          symLine = colorize$1(spatial.symbol);
        }

        let symFill = fill;

        if (spatial.detail && spatial.detail[1]) {
          symFill = spatial.detail[1];
        }

        let symZoom = spatial.zoom || 1;
        context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingFill'";
        context.fillStyle = symFill;
        context.fillText(symbolFill$2(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
        context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingLine'";
        context.fillStyle = symLine;
        context.fillText(symbolLine$2(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
      });
      return canvas;
    }
  };
  /**
   * Function that creates a binary PNG image from an SWU sign with an optional style string
   * @function swu.signPng
   * @param {string} swuSign - an SWU sign with optional style string
   * @example
   * swu.signPng('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭')
   * 
   * return 'data:image/png;base64,iVBORw...'
   */


  const signPng$1 = swuSign => {
    const canvas = signCanvas$1(swuSign);
    const png = canvas.toDataURL("image/png");
    canvas.remove();
    return png;
  };

  /**
   * Function that normalizes an SWU sign for a center of 500,500
   * @function swu.signNormalize
   * @param {string} swuSign - an SWU sign with optional style string
   * @example
   * swu.signNormalize('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭')
   * 
   * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
   */

  const signNormalize$1 = swuSign => {
    const parsed = parse$2.sign(swuSign);

    if (parsed.spatials) {
      const symbolsizes = parsed.spatials.reduce((output, spatial) => {
        const size = symbolSize$2(spatial.symbol);
        output[spatial.symbol] = {
          width: size[0],
          height: size[1]
        };
        return output;
      }, {});

      const bbox = symbols => {
        const x1 = Math.min(...symbols.map(spatial => spatial.coord[0]));
        const y1 = Math.min(...symbols.map(spatial => spatial.coord[1]));
        const x2 = Math.max(...symbols.map(spatial => spatial.coord[0] + parseInt(symbolsizes[spatial.symbol].width)));
        const y2 = Math.max(...symbols.map(spatial => spatial.coord[1] + parseInt(symbolsizes[spatial.symbol].height)));
        return {
          x1: x1,
          y1: y1,
          x2: x2,
          y2: y2
        };
      };

      const hrange = ranges$1['hcenter'];
      const hsyms = parsed.spatials.filter(spatial => {
        const dec = parseInt(spatial.symbol.slice(1, 4), 16);
        return hrange[0] <= dec && hrange[1] >= dec;
      });
      const vrange = ranges$1['vcenter'];
      const vsyms = parsed.spatials.filter(spatial => {
        const dec = parseInt(spatial.symbol.slice(1, 4), 16);
        return vrange[0] <= dec && vrange[1] >= dec;
      });
      let abox = bbox(parsed.spatials);
      let max = [abox.x2, abox.y2];

      if (hsyms.length) {
        const hbox = bbox(hsyms);
        abox.x1 = hbox.x1;
        abox.x2 = hbox.x2;
      }

      if (vsyms.length) {
        const vbox = bbox(vsyms);
        abox.y1 = vbox.y1;
        abox.y2 = vbox.y2;
      }

      const offset = [parseInt((abox.x2 + abox.x1) / 2) - 500, parseInt((abox.y2 + abox.y1) / 2) - 500];
      const swuout = (parsed.sequence ? '𝠀' + parsed.sequence.join('') : '') + parsed.box + coord2swu([max[0] - offset[0], max[1] - offset[1]]) + parsed.spatials.map(spatial => spatial.symbol + coord2swu([spatial.coord[0] - offset[0], spatial.coord[1] - offset[1]])).join('') + (parsed.style || '');
      return swuout;
    }
  };

  /** The swu module contains functions for handling SignWriting in Unicode (SWU) characters.
   * [SWU characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.1)
   * @module swu
   */

  var index$2 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    symbolSize: symbolSize$2,
    symbolLine: symbolLine$2,
    symbolFill: symbolFill$2,
    symbolText: symbolText$2,
    symbolSvg: symbolSvg$1,
    symbolPng: symbolPng$1,
    symbolNormalize: symbolNormalize$1,
    signSvg: signSvg$1,
    signPng: signPng$1,
    signNormalize: signNormalize$1
  });

  exports.font = index;
  exports.fsw = index$1;
  exports.swu = index$2;

  Object.defineProperty(exports, '__esModule', { value: true });

})));

/* support ongoing development on https://patreon.com/signwriting */