{"mappings":"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","sources":["packages/pixelmanipulator/src/src/renderers.ts","packages/pixelmanipulator/src/src/neighborhoods.ts","packages/pixelmanipulator/src/src/pixelmanipulator.ts","packages/pixelmanipulator/src/pixelmanipulator.ts"],"sourcesContent":[null,null,null,"/** This is a cellular automata JavaScript library called PixelManipulator. For\n *  information about how to use this script, see\n *  https://github.com/Lazerbeak12345/pixelmanipulator\n *\n *  Copyright (C) 2018-2024  Nathan Fritzler\n *\n *  This program is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  This program is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with this program.  If not, see http://www.gnu.org/licenses.\n */\nimport * as package_json from '../package.json'\nimport type { Hitbox } from './neighborhoods'\nimport type { Renderer, Location } from './renderers'\nimport * as _renderers from './renderers'\n// export * as neighborhoods from './neighborhoods'\nimport * as _neighborhoods from './neighborhoods'\nexport { _neighborhoods as neighborhoods }\nexport * from './renderers'\nfunction startAnimation(callback: () => void): number | ReturnType<typeof setInterval> {\n  if (typeof requestAnimationFrame === 'undefined') {\n    const SMALLEST_INTERVAL_POSSIBLE = 1\n    return setInterval(callback, SMALLEST_INTERVAL_POSSIBLE)\n  } else {\n    return requestAnimationFrame(callback)\n  }\n}\nfunction resumeAnimation(num: ReturnType<typeof startAnimation>, callback: () => void): ReturnType<typeof startAnimation> {\n  if (typeof requestAnimationFrame === 'undefined') {\n    return num\n  } else {\n    return requestAnimationFrame(callback)\n  }\n}\nfunction cancelAnimation(num: ReturnType<typeof startAnimation>): void {\n  if (typeof cancelAnimationFrame === 'undefined') {\n    clearInterval(num)\n  } else if (typeof num === \"number\") {\n    cancelAnimationFrame(num)\n  }\n}\nfunction boolToNumber(bool: boolean): number {\n  const TRUE = 1\n  const FALSE = 0\n  return bool ? TRUE : FALSE\n}\n/** The argument to {@link ElementDataUnknown.liveCell} and\n* {@link ElementDataUnknown.deadCell}\n*/\nexport interface Rel {\n  /** The X location of this pixel. */\n  x: number\n  /** The Y location of this pixel. */\n  y: number\n  /** The ID number of the current pixel. Reccommended if performance profiling\n  * shows string comparision is a bottleneck.\n  */\n  oldId: number\n  /** The ID of the element for which this is being called. (in a\n  * {@link ElementDataUnknown.liveCell} that's the same as {@link Rel.oldId}, but in a\n  * {@link ElementDataUnknown.deadCell} it's the id that the deadCell belongs to.\n  */\n  thisId: number\n}\n/** Much like {@link ElementDataUnknown} but all fields except {@link ElementData.madeWithRule},\n* {@link ElementData.liveCell} and {@link ElementData.deadCell} are mandatory. */\nexport interface ElementData<T> extends ElementDataUnknownNameMandatory<T> {\n  renderAs: T\n  hitbox: Hitbox\n}\n/** Information about an element. */\nexport interface ElementDataUnknown<T> {\n  /** The name of the element. */\n  name?: string\n  /** Information on how to render this element */\n  renderAs?: T\n  /** {@link ElementDataUnknown.deadCell} will only be called on empty\n  * pixels within the hitbox of a live cell. Array of relative coordinate pairs.\n  * Optional, defaults to the result of {@link neighborhoods.moore}\n  * called with no arguments.\n  */\n  hitbox?: Hitbox\n  /** Every frame of animation, pixelmanipulator iterates through each and every pixel on the screen. If this element is found, it calls this function.\n  */\n  liveCell?: (rel: Rel) => void\n  /** Every frame of animation, pixelmanipulator iterates through each and every\n  * pixel on the screen. If this element is found, it calls this function on\n  * each of the locations defined in {@link ElementDataUnknown.hitbox} so long as\n  * the pixel matches the value in {@link PixelManipulator.defaultId}, without\n  * calling the same dead pixel twice.\n  */\n  deadCell?: (rel: Rel) => void\n  /** If present, indicates that this element was auto-generated */\n  madeWithRule?: true\n}\n/** Much like {@link ElementDataUnknown} but the name is mandatory. */\nexport interface ElementDataUnknownNameMandatory<T> extends ElementDataUnknown<T> {\n  name: string\n}\nfunction _convertNumListToBf(nl: string): number {\n  // While I used to use string with each digit in it, I found that since\n  // there are 0-8, I could use a 9bit field (remember: off by one)\n  let out = 0\n  for (const item of nl) {\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- largest binary digit\n    out |= 1 << parseInt(item)\n  }\n  return out\n}\n/** Template generators for your elements. */\nexport const rules = {\n  /** Generates elements like conway's game of life.\n  * @param p - `lifelike` needs to be able to call {@link PixelManipulator.mooreNearbyCounter}\n  * @param pattern - The B/S syntax indicator of on how many cells of the same\n  * type in the moore radius around each pixel should survive, and on how many\n  * should be born.\n  * @param loop - Should this loop around screen edges? (Passed to {@link renderers.Location.loop})\n  */\n  lifelike: function <T>(p: PixelManipulator<T>, pattern: string, loop?: boolean): ElementDataUnknown<T> {\n    const numbers = pattern.split(/\\/?[a-z]/gi)// \"B\",born,die\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- after the pattern\n    const bfdie = _convertNumListToBf(numbers[2])\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- before the pattern\n    const bflive = _convertNumListToBf(numbers[1])\n    const SMALLEST_BINARY_DIGIT = 1\n    const PREV_FRAME = 1\n    const NO_MATCH = 0\n    return {\n      madeWithRule: true,\n      hitbox: _neighborhoods.moore(),\n      liveCell: function llive({ x, y, thisId }) {\n        // if any match (of how many moore are nearby) is found, it dies\n        if ((bfdie & SMALLEST_BINARY_DIGIT << p.mooreNearbyCounter({ x, y, frame: PREV_FRAME, loop }, thisId)) === NO_MATCH) {\n          p.setPixel({ x, y }, p.defaultId)\n        }\n      },\n      deadCell: function ldead({ x, y, thisId }) {\n        // if any match (of how many moore are nearby) is found, it lives\n        if ((bflive & SMALLEST_BINARY_DIGIT << p.mooreNearbyCounter({ x, y, frame: PREV_FRAME, loop }, thisId)) !== NO_MATCH) {\n          p.setPixel({ x, y }, thisId)\n        }\n      }\n    }\n  },\n  /** Generates fundamental cellular automata\n  * @param p - `wolfram` needs to be able to call {@link PixelManipulator.wolframNearbyCounter}\n  * @param pattern - The Rule num syntax, where the 8-bit number is translated\n  * into a binary list, each where the inverted 3-binary-digit index represents\n  * the state of cells in the row above. On a match, the cell becomes the state\n  * specified in the initial 8-bit number.\n  * @param loop - Should this loop around screen edges? (Passed to {@link PixelManipulator.wolframNearby})\n  */\n  wolfram: function <T>(p: PixelManipulator<T>, pattern: string, loop?: boolean): ElementDataUnknown<T> {\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- after the pattern\n    const binStates = parseInt(pattern.split(/Rule /gi)[1])\n    const FIRST_ROW = 0\n    const PREV_FRAME = 1\n    return {\n      madeWithRule: true,\n      // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- default values\n      hitbox: _neighborhoods.wolfram(1, 1),\n      // The current state is used as the index in the binstates, as binstates is a bit array of every state\n      liveCell: function wlive({ x, y, thisId }) {\n        if (y === FIRST_ROW) return\n        if (!p.wolframNewState({ x, y, frame: PREV_FRAME, loop }, binStates, thisId)) {\n          p.setPixel({ x, y, loop }, p.defaultId)\n        }\n      },\n      deadCell: function wdead({ x, y, thisId }) {\n        if (p.wolframNewState({ x, y, frame: PREV_FRAME, loop }, binStates, thisId)) {\n          p.setPixel({ x, y, loop }, thisId)\n        }\n      }\n    }\n  }\n}\n/** Sizes to set the canvases to. If a value below is absent, old value is used.\n*/\nexport interface CanvasSizes {\n  /** width of the canvas */\n  canvasW?: number\n  /** height of the canvas */\n  canvasH?: number\n}\n/** A cellular automata engine */\nexport class PixelManipulator<T> {\n  /**\n  * @param renderer - The target to render things to.\n  * @param width - How wide should the initial target be?\n  * @param height - How tall should the initial target be?\n  */\n  constructor(renderer: Renderer<T>, width: number, height: number) {\n    if (typeof window !== 'undefined') console.log(licence)\n    this.renderer = renderer\n    this.defaultId = this.addElement({\n      renderAs: this.renderer.defaultRenderAs,\n      hitbox: [],\n      name: 'blank'\n    })\n    this.reset({ canvasW: width, canvasH: height })\n  }\n\n  /** An instanace of the object that shows the state to the user. */\n  renderer: Renderer<T>\n  /**\n  * This is the number that indicates what animation frame the iterate function\n  * is being called with.\n  *\n  * You can use this to mannually stop the iterations like so:\n  * `cancelAnimationFrame(this.loopint)` (not reccommended)\n  */\n  loopint: ReturnType<typeof startAnimation> = 0 // eslint-disable-line @typescript-eslint/no-magic-numbers -- default value\n  /**\n  * A low-level listing of the availiable elements.\n  *\n  * Format is much like the argument to\n  * {@link PixelManipulator.addMultipleElements}, but is not sanitized.\n  */\n  readonly elements: Array<ElementData<T>> = []\n\n  /**\n  * A mapping from old names for elements to new names for elements.\n  *\n  * Allows a user to modify the name of an element at runtime.\n  */\n  nameAliases = new Map<string, string>()\n  /**\n  * A string indicating weather it is currently animating or not.\n  *\n  * It is `\"playing\"` if it is currently animating, or `\"paused\"` if not\n  * currently animating.\n  *\n  * This has been around since early version 0, and once was the `innerText`\n  * value of a pause/play button!\n  */\n  mode: 'playing' | 'paused' = 'paused'\n  /**\n  * The elm that pixelmanipulator will fill the screen with upon initialization,\n  * and what elements should return to when they are \"dead\". Default value is\n  * 0, an element with the color `#000F`\n  *\n  * If you update this, be sure to update {@link renderers.Renderer.defaultRenderAs} in {@link PixelManipulator.renderer}\n  */\n  defaultId: number\n  /** Called before {@link PixelManipulator.iterate} does its work.\n  * @returns false to postposne iteration.\n  */\n  onIterate: () => (boolean | undefined) = () => undefined // eslint-disable-line @typescript-eslint/class-methods-use-this -- event handler\n  /** Called after {@link PixelManipulator.iterate} does its work. */\n  onAfterIterate: () => undefined = () => undefined // eslint-disable-line @typescript-eslint/class-methods-use-this -- event handler\n\n  /** Gets called after a call to {@link PixelManipulator.modifyElement}. The ID is\n  * passed as the only argument.\n  * @param id - The element that was modified.\n  */\n  onElementModified: (id: number) => void = () => undefined // eslint-disable-line @typescript-eslint/class-methods-use-this -- event handler\n  /** @returns the width of the canvas */\n  get_width(): number {\n    return this.renderer.get_width()\n  }\n\n  /** @param value - The new width of the canvas */\n  set_width(value: number): void {\n    this.renderer.set_width(value)\n  }\n\n  /** @returns the height of the canvas */\n  get_height(): number {\n    return this.renderer.get_height()\n  }\n\n  /** @param value - The new height of the canvas */\n  set_height(value: number): void {\n    this.renderer.set_height(value)\n  }\n\n  /** fills the screen with value, at an optional given percent\n  * @param value - The element to put on the screen\n  * @param pr - The percent as a number from 1 to 100, defaulting at 15\n  */\n  randomlyFill(value: string | number, pr?: number): void {\n    const DEFAULT_PERCENT = 15\n    const MAX_PERCENT = 100\n    pr ??= DEFAULT_PERCENT\n    const w = this.get_width()\n    const h = this.get_height()\n    for (let x = 0; x < w; x++) {\n      for (let y = 0; y < h; y++) { // iterate through x and y\n        if (Math.random() * MAX_PERCENT < pr) { this.setPixel({ x, y }, value) }\n      }\n    }\n  }\n\n  /** Adds multiple elements.\n  *\n  * @param elements - Index is the element name, value is the element data (and\n  * does not require the name). Value is passed to\n  * {@link PixelManipulator.addElement}\n  */\n  addMultipleElements(elements: Record<string, ElementDataUnknown<T>>): void {\n    Object.keys(elements).forEach(name =>\n      this.addElement({ name, ...elements[name] })\n    )\n  }\n\n  /** Add an element with the given element data\n  * @param data - The details about the element.\n  * @returns The generated {@link PixelManipulator.elements} index\n  */\n  addElement(\n    data: ElementDataUnknownNameMandatory<T>\n  ): number { // adds a single element\n    const { name, renderAs } = data\n    if (typeof name === 'undefined') throw new Error('Name is required for element')\n    if (typeof data.name === 'undefined') data.name = name\n    // @ts-expect-error renderAs might be undefined here, but it's fixed in the call to this.modifyElement below\n    this.elements.push({ name, renderAs })\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- last item in list\n    this.modifyElement(this.elements.length - 1, data)\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- last item in list (might not be the same as before modifyElement was called)\n    return this.elements.length - 1\n  }\n\n  /**\n  * @param id - How to identify what element to modify.\n  * @param data - Values to apply to the pre-existing element.\n  *\n  * Automatically calls {@link PixelManipulator.aliasElements} if\n  * {@link ElementDataUnknown.name} is present in `data`\n  */\n  modifyElement(id: number, data: ElementDataUnknown<T>): void {\n    const oldData: Omit<ElementData<T>, \"hitbox\"> | ElementData<T> = this.elements[id]\n    if (typeof data.name !== 'undefined' && data.name !== oldData.name) {\n      this.aliasElements(oldData.name, data.name)\n    }\n    const newData = {\n      hitbox: _neighborhoods.moore(),\n      ...oldData,\n      ...data,\n    }\n    newData.renderAs = this.renderer.modifyElement(id, newData.renderAs)\n    this.elements[id] = newData\n    this.onElementModified(id)\n  }\n\n  /**\n  * @param oldName - The old {@link ElementData.name}\n  * @param newName - The new {@link ElementData.name}\n  *\n  * Adds the name to {@link PixelManipulator.nameAliases}, and ensures no alias\n  * loops are present.\n  */\n  aliasElements(oldName: string, newName: string): void {\n    // Intentionally ignores aliases when checking for duplicate name.\n    if (this.elements.find(elm => elm.name === newName) != null) {\n      throw new Error('The name ' + newName + ' is already in use!')\n    }\n    this.nameAliases.delete(newName)\n    this.nameAliases.set(oldName, newName)\n  }\n\n  /** Respecting aliases, convert an element name into its number.\n  * @param name - name of element\n  * @returns The number of the element\n  */\n  nameToId(name: string): number {\n    let unaliased: string | undefined = name\n    while (typeof unaliased !== 'undefined') {\n      name = unaliased\n      unaliased = this.nameAliases.get(name)\n    }\n    return this.elements.findIndex(elm => elm.name === name)\n  }\n\n  /**\n  * @param name - Name of the (possibly aliased) element.\n  * @returns The element from {@link PixelManipulator.elements}, respecting\n  * aliases in {@link PixelManipulator.nameAliases}, or {@link undefined} if not found.\n  */\n  getElementByName(name: string): ElementData<T> | undefined {\n    return this.elements[this.nameToId(name)]\n  }\n\n  /**\n  * @param loc - Location of the element.\n  * @returns Name of element at passed-in location. See {@link ElementData.name}\n  */\n  whatIs(loc: Location): string {\n    return this.elements[this.getPixelId(loc)].name\n  }\n\n  /** Start iterations on all of the elements on the canvas.\n  * Sets {@link PixelManipulator.mode} to `\"playing\"`, and requests a new animation\n  * frame, saving it in {@link PixelManipulator.loopint}.\n  *\n  * @param canvasSizes - If {@link PixelManipulator.mode} is already `\"playing\"` then\n  * canvasSizes is passed to {@link PixelManipulator.reset}. Otherwise reset is not\n  * called.\n  */\n  play(canvasSizes?: CanvasSizes): void {\n    if (this.mode === 'playing') this.reset(canvasSizes)\n    this.mode = 'playing'\n    this.loopint = startAnimation(() => {\n      this.iterate()\n    })\n  }\n\n  /** Reset, resize and initialize the canvas(es).\n  * Calls {@link PixelManipulator.pause} then\n  * {@link PixelManipulator.update}. Resets all internal state, excluding the\n  * element definitions.\n  *\n  * @param canvasSizes - Allows one to change the size of the canvases during\n  * the reset.\n  */\n  reset(canvasSizes?: CanvasSizes): void {\n    const CURRENT_FRAME = 0\n    const NEXT_FRAME = 1\n    const MAX_PERCENT = 100\n    if (typeof canvasSizes === 'undefined') { canvasSizes = {} }\n    this.pause()\n    const w = canvasSizes.canvasW ?? this.get_width()\n    const h = canvasSizes.canvasH ?? this.get_height()\n    this.set_width(w)\n    this.set_height(h)\n    this.frames[CURRENT_FRAME] = new Uint32Array(w * h)\n    this.frames[NEXT_FRAME] = new Uint32Array(w * h)\n    this.renderer.reset()\n    this.randomlyFill(this.defaultId, MAX_PERCENT)\n    this.update()\n  }\n\n  /** pause canvas iterations\n  * Sets {@link PixelManipulator.mode} to `\"paused\"` and cancels the animation frame\n  * referenced in {@link PixelManipulator.loopint}\n  */\n  pause(): void {\n    this.mode = 'paused'\n    cancelAnimation(this.loopint)\n  }\n\n  /**\n  * @param loc - Location of the pixel (could be out of bounds).\n  * @returns null if out-of-bounds when loop setting is false, or the location (loop set to false).\n  */\n  locationBoundsCheck(loc: Location): null | Location { // eslint-disable-line complexity -- close enough for me tbh\n    const LEFTMOST = 0\n    const TOPMOST = 0\n\n    const w = this.get_width()\n    const h = this.get_height()\n\n    const overflowLeft = loc.x < LEFTMOST\n    const overflowRight = loc.x >= w\n    const overflowTop = loc.y < TOPMOST\n    const overflowBottom = loc.y >= h\n\n    if (loc.loop ?? true) {\n      loc.x %= w\n      loc.y %= h\n\n      if (overflowLeft) loc.x += w\n      if (overflowTop) loc.y += h\n\n      loc.loop = false\n    } else if (overflowLeft || overflowRight || overflowTop || overflowBottom) {\n      return null\n    }\n    return loc\n  }\n\n  /**\n  * @param loc - Location of the pixel\n  * @returns the element id at a given location\n  */\n  getPixelId(loc: Location): number {\n    const fixedLoc = this.locationBoundsCheck(loc)\n    if (fixedLoc == null) return this.defaultId\n    const w = this.get_width()\n    const CURRENT_FRAME = 0 // TODO: dedupe this const\n    return this.frames[fixedLoc.frame ?? CURRENT_FRAME][_renderers.location2Index(fixedLoc, w)]\n  }\n\n  /**\n  * Applies any changes made with {@link renderers.Renderer.renderPixel} on {@link PixelManipulator.renderer} to the canvas\n  */\n  update(): void {\n    this.renderer.update()\n  }\n\n  /**\n  * @param loc - Where to confirm the element\n  * @param id - The elm you expect it to be\n  * @returns Does the cell at `loc` match `ident`?\n  */\n  confirmElm(loc: Location, id: number | string): boolean {\n    return this.getPixelId(loc) === (typeof id === 'string' ? this.nameToId(id) : id)\n  }\n\n  /** Calculate the total number of elements within an area\n  * @param area - The locations to total up.\n  * @param search - The element to look for\n  * @returns The total\n  */\n  totalWithin(area: Location[], search: number | string): number {\n    return area\n      .filter(loc => this.confirmElm(loc, search))\n      .length\n  }\n\n  private static readonly _moore = _neighborhoods.moore()\n  /** @param name - element to look for\n  * @param center - location of the center of the moore area\n  * @returns Number of matching elements in moore radius */\n  mooreNearbyCounter(center: Location, search: number | string): number {\n    return this.totalWithin(_renderers.transposeLocations(PixelManipulator._moore, center), search)\n  }\n\n  /** @param area - The Area to search within\n  * @param ruleNum - A bitfield of what states a pixel should live or die on.\n  * @param search - The element to search for\n  * @see {@link PixelManipulator.wolframNewState} for higher-level tool\n  * @see {@link PixelManipulator.fundamentalStatesWithin} for lower-level tool\n  * @returns The state that the bitfied says this pixel should be in the next frame.\n  */\n  fundamentalNewState(area: Location[], ruleNum: number, search: number | string): boolean {\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 1 is largest binary digit, nonzero if matches\n    return (ruleNum & 1 << this.fundamentalStatesWithin(area, search)) !== 0\n  }\n\n  /** @param area - Locations to look at.\n  * @param search - Locations to mark as a true bit.\n  * @see {@link PixelManipulator.fundamentalNewState} for higher-level tool\n  * @returns number as a bitfied array, in order of the items in area, from left to right.\n  *\n  * That means that `(fundamentalStatesWithin([loc], search) & 1) === boolToNumber(confirmElm(loc, search))`\n  *\n  * You may want to see [this page](https://www.wolframscience.com/nks/notes-5-2--general-rules-for-multidimensional-cellular-automata/)\n  * for more details on how this might be used.\n  */\n  fundamentalStatesWithin(area: Location[], search: number | string): number {\n    // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 1 is the SMALLEST_BINARY_DIGIT\n    return area.map(loc => boolToNumber(this.confirmElm(loc, search))).reduce((res, x) => res << 1 | x)\n  }\n\n  private static readonly _wolfram = _neighborhoods.wolfram()\n\n  /** @param loc - The pixel to change. (Defaults {@link renderers.Location.loop} to false)\n  * @param ruleNum - A bitfield of what states a pixel should live or die on.\n  * @param search - The element to search for\n  * @see {@link PixelManipulator.fundamentalNewState} for more general tool.\n  * @returns The state that the bitfied says this pixel should be in the next frame.\n  */\n  wolframNewState(loc: Location, ruleNum: number, search: number | string): boolean {\n    // one-dimentional detectors by default don't loop around edges\n    loc.loop ??= false\n    return this.fundamentalNewState(\n      _renderers.transposeLocations(PixelManipulator._wolfram, loc),\n      ruleNum,\n      search\n    )\n  }\n\n  /**\n  * @param current - \"Current\" pixel location. (Defaults {@link renderers.Location.loop} to false)\n  * @param search - element to look for\n  * @see {@link PixelManipulator.fundamentalStatesWithin} for lower-level tool\n  * @returns Number used as bit area to indicate occupied cells\n  */\n  wolframNearby(current: Location, search: number | string): number {\n    // one-dimentional detectors by default don't loop around edges\n    current.loop ??= false\n    return this.fundamentalStatesWithin(\n      _renderers.transposeLocations(PixelManipulator._wolfram, current),\n      search\n    )\n  }\n\n  /** Counter tool used in slower wolfram algorithim.\n  * @deprecated Replaced with {@link PixelManipulator.wolframNearby} for use in faster\n  * algorithms\n  * @param current - \"Current\" pixel location\n  * @param name - element to look for\n  * @param bindex - Either a string like `\"001\"` to match to, or the same\n  * encoded as a number.\n  * @returns Number of elements in wolfram radius */\n  wolframNearbyCounter(current: Location, name: number | string, binDex: number | string): boolean {\n    if (typeof binDex === 'string') {\n      // Old format was a string of ones and zeros, three long.\n      binDex = parseInt(binDex, 2)\n    }\n    return this.wolframNearby(current, name) === binDex\n  }\n\n  /** Set a pixel in a given location.\n  *\n  * @param x - X position.\n  * @param y - Y position.\n  * @param ident - Value to identify the element.\n  *\n  * - If a string, it assumes it's an element name.\n  * - If a number, it assumes it's an element ID\n  *\n  * @param loop - Defaults to {@link true}. Wraps `x` and `y` around canvas borders.\n  */\n  setPixel(loc: Location, ident: string | number): void {\n    const NOT_FOUND = -1\n    let id = 0\n    if (typeof ident === 'string') {\n      id = this.nameToId(ident)\n      if (id === NOT_FOUND) {\n        throw new Error(`Element name ${ident} is invalid`)\n      }\n    } else {\n      id = ident\n    }\n    const fixedLoc = this.locationBoundsCheck(loc)\n    if (fixedLoc == null) return\n    this.renderer.renderPixel(fixedLoc, id)\n    const w = this.get_width()\n    const CURRENT_FRAME = 0\n    this.frames[CURRENT_FRAME][_renderers.location2Index(fixedLoc, w)] = id\n  }\n\n  /** Number of pixels per element in the last frame */\n  pixelCounts: Record<number, number> = {}\n\n  /** A single frame of animation. Media functions pass this into\n  * {@link requestAnimationFrame}.\n  *\n  * Be careful! Calling this while {@link PixelManipulator.mode} is `\"playing\"`\n  * might cause two concurrent calls to this function. If any of your automata\n  * have \"hidden state\" - that is they don't represent every detail about\n  * themselves as data within the pixels - it might cause conflicts.\n  */\n  iterate(): void { // eslint-disable-line complexity -- TODO: break this down a bit\n    if (this.onIterate() ?? true) {\n      // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- last item in list\n      for (let frame = this.frames.length - 1; frame >= 0; frame--) {\n        // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- nonzero\n        if (frame > 0) {\n          // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- next is minus one\n          const nextFrame = frame - 1\n          this.frames[frame].set(this.frames[nextFrame])\n        }\n      }\n      const w = this.get_width()\n      const h = this.get_height()\n      const typedUpdatedDead = new Array<Uint8Array>(this.elements.length)\n      this.pixelCounts = {}\n      const NEXT_FRAME = 1\n      for (let x = 0; x < w; x++) {\n        for (let y = 0; y < h; y++) { // iterate through x and y\n          const currentPixId = this.getPixelId({ x, y, frame: NEXT_FRAME })\n          if (currentPixId === this.defaultId) continue\n          const { elements: { [currentPixId]: elm } } = this\n          if (typeof elm === \"undefined\") {\n            throw new Error(\n              'This isn\\'t supposed to happen, but the internal pixel buffer was ' +\n              'currupted. This is likely a bug, or a symptom of improper direct ' +\n              'access to the current memory buffer'\n            )\n          }\n          if (typeof elm.liveCell !== \"undefined\") {\n            elm.liveCell({\n              x,\n              y,\n              oldId: currentPixId,\n              thisId: currentPixId\n            })\n          }\n          if (typeof this.pixelCounts[currentPixId] === \"undefined\") {\n            // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- starting at 1\n            this.pixelCounts[currentPixId] = 1\n          } else this.pixelCounts[currentPixId]++\n          if (typeof elm.deadCell !== \"undefined\") {\n            const UPDATED_SIZE = 8 // TODO: this is a guess. document this better, or rewrite this.\n            typedUpdatedDead[currentPixId] ??= new Uint8Array(Math.ceil((w * h) / UPDATED_SIZE));\n            elm.hitbox.forEach(pixel => {\n              // We are looping, so it can't be null. Eslint doesn't like non-null assertions, so we must do this.\n              const hblocStupidFallback: Location = {\n                x: x + pixel.x,\n                y: y + pixel.y\n              }\n              const hbLoc: Location = this.locationBoundsCheck(hblocStupidFallback) ?? hblocStupidFallback;\n              const index = Math.floor(_renderers.location2Index(hbLoc, w) / UPDATED_SIZE)\n              const { [currentPixId]: { [index]: oldValue } } = typedUpdatedDead\n              // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- SMALLEST_BINARY_DIGIT\n              const bitMask = 1 << (hbLoc.x % UPDATED_SIZE)\n              // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- compare to zero\n              if ((oldValue & bitMask) !== 0) { return }\n              // I timed it, and confirmOldElm is slower than all the math above.\n              if (!this.confirmElm({ x: hbLoc.x, y: hbLoc.y, frame: NEXT_FRAME }, this.defaultId)) {\n                return\n              }\n              if (typeof elm.deadCell !== \"undefined\") {\n                elm.deadCell({\n                  x: hbLoc.x,\n                  y: hbLoc.y,\n                  oldId: this.defaultId,\n                  thisId: currentPixId\n                })\n              }\n              typedUpdatedDead[currentPixId][index] = oldValue | bitMask\n            })\n          }\n        }\n      }\n      this.update()\n      this.onAfterIterate()\n    }\n    if (this.mode === 'playing') {\n      this.loopint = resumeAnimation(this.loopint, () => {\n        this.iterate()\n      })\n    }\n  }\n\n  /**\n  * A List of {@link Uint32Array}s each the length of width times height of the\n  * canvas. Frame 0 is the new frame, frame one is the prior, etc. Each item\n  * holds the element id of each element on screen, from left to right, top to\n  * bottom.\n  */\n  frames: Uint32Array[] = [new Uint32Array(0), new Uint32Array(0)] // eslint-disable-line @typescript-eslint/no-magic-numbers -- default values\n}// end class PixelManipulator\n/** Version of library **for logging purposes only**. Uses semver. */\nexport const { version } = package_json\n/** Licence disclaimer for PixelManipulator */\nexport const licence = 'PixelManipulator v' + version + ' Copyright (C) ' +\n  '2018-2024 Nathan Fritzler\\nThis program comes with ABSOLUTELY NO ' +\n  'WARRANTY\\nThis is free software, and you are welcome to redistribute it\\n' +\n  'under certain conditions, as according to the GNU GENERAL PUBLIC LICENSE ' +\n  'version 3 or later.'\n// This is called a \"modeline\". It's a (n)vi(m)|ex thing.\n// vi: tabstop=2 shiftwidth=2 expandtab\n"],"names":[],"version":3,"file":"types.d.ts.map","sourceRoot":"../../../"}