{
  "version": 3,
  "sources": ["../src/core/utils.js", "../src/core/commands.js", "../src/core/screen-manager.js", "../src/renderer/renderer.js", "../src/renderer/shaders/display.vert", "../src/renderer/shaders/display.frag", "../src/renderer/shaders.js", "../src/api/blends.js", "../src/renderer/shaders/point.vert", "../src/renderer/shaders/point.frag", "../src/renderer/shaders/image.vert", "../src/renderer/shaders/image.frag", "../src/renderer/shaders/geometry.vert", "../src/renderer/batches.js", "../src/renderer/draw/batch-helpers.js", "../src/renderer/draw/geometry.js", "../src/renderer/textures.js", "../src/renderer/readback.js", "../src/renderer/draw/sprites.js", "../src/renderer/draw/primitives.js", "../src/renderer/draw/arcs.js", "../src/renderer/draw/bezier.js", "../src/renderer/draw/lines.js", "../src/renderer/draw/rects.js", "../src/renderer/draw/circles.js", "../src/renderer/draw/ellipses.js", "../src/renderer/effects.js", "../src/api/graphics.js", "../src/api/colors.js", "../src/api/images.js", "../src/core/plugins.js", "../src/api/pixels.js", "../src/api/paint.js", "../src/api/draw.js", "../src/text/fonts.js", "../src/text/print.js", "../src/text/fonts/font-6x6.webp", "../src/text/fonts/font-6x8.js", "../src/text/fonts/font-8x8.webp", "../src/text/fonts/font-8x14.webp", "../src/text/fonts/font-8x16.webp", "../src/index.js"],
  "sourceRoot": "../src/",
  "sourcesContent": ["/**\r\n * Pi.js - Utilities Module\r\n * \r\n * Common utility functions for math, colors, types, and data manipulation.\r\n * \r\n * @module core/utils\r\n */\r\n\r\n\"use strict\";\r\n\r\n\r\n/***************************************************************************************************\r\n * General Utility Functions\r\n **************************************************************************************************/\r\n\r\n\r\nexport const errFn = ( commandName ) => {\r\n\tconst error = new Error(\r\n\t\t`${commandName}: No screens available for command. You must first create a ` +\r\n\t\t`screen with $.screen command.`\r\n\t);\r\n\terror.code = \"NO_SCREEN\";\r\n\tthrow error;\r\n};\r\n\r\n/**\r\n * Parse options - normalizes input arguments into an object with named parameters.\r\n *\r\n * @param {Array<any>} args - Arguments passed to the command (from rest parameters like `...args`).\r\n * @param {Array<string>} parameterNames - Array of parameter names in expected order.\r\n * @returns {Object<string, any>} \tAn object where keys are `parameterNames` and values are the \r\n * \t\t\t\t\t\t\t\t\tparsed arguments. Missing values will be `null`.\r\n */\r\nexport function parseOptions( args, parameterNames ) {\r\n\tconst resultOptions = {};\r\n\r\n\t// Initialize all named parameters to null\r\n\tfor( const name of parameterNames ) {\r\n\t\tresultOptions[ name ] = null;\r\n\t}\r\n\r\n\tlet isNamedParameterFound = false;\r\n\r\n\t// Case 1: First argument is an object literal\r\n\tif( args.length > 0 && isObjectLiteral( args[ 0 ] ) ) {\r\n\t\tconst inputOptions = args[ 0 ];\r\n\r\n\t\tfor( const name of parameterNames ) {\r\n\t\t\tif( name in inputOptions ) {\r\n\t\t\t\tisNamedParameterFound = true;\r\n\t\t\t\tresultOptions[ name ] = inputOptions[ name ];\r\n\t\t\t}\r\n\t\t}\r\n\t} \r\n\t\r\n\t// If no named parameters found then treat as positional array\r\n\tif( !isNamedParameterFound ) {\r\n\r\n\t\t// Case 2: Arguments are passed positionally\r\n\t\t// Map the positional arguments to the named parameters\r\n\t\t// If args[ i ] is out of bounds, it remains null from initialization\r\n\t\tfor( let i = 0; i < parameterNames.length; i++ ) {\r\n\t\t\tif( i < args.length ) {\r\n\t\t\t\tresultOptions[ parameterNames[ i ] ] = args[ i ];\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn resultOptions;\r\n}\r\n\r\n// Type checking utilities\r\nexport const isFunction = ( fn ) => typeof fn === \"function\";\r\nexport const isDomElement = ( el ) => el instanceof Element;\r\nexport const isObjectLiteral = ( obj ) => {\r\n\tif( typeof obj !== \"object\" || obj === null || Array.isArray( obj ) ) {\r\n\t\treturn false;\r\n\t}\r\n\tconst proto = Object.getPrototypeOf( obj );\r\n\treturn proto === null || proto === Object.prototype;\r\n};\r\n\r\n// Data conversion utilities\r\n\r\n/**\r\n * Convert hex string to 2D data array\r\n * \r\n * @param {string} hex - Hex string\r\n * @param {number} width - Width of data\r\n * @param {number} height - Height of data\r\n * @returns {Array<Array<number>>} 2D array of binary data\r\n */\r\nexport function hexToData( hex, width, height ) {\r\n\thex = hex.toUpperCase();\r\n\tconst data = [];\r\n\tlet i = 0;\r\n\tlet digits = \"\";\r\n\tlet digitIndex = 0;\r\n\r\n\tfor( let y = 0; y < height; y++ ) {\r\n\t\tdata.push( [] );\r\n\t\tfor( let x = 0; x < width; x++ ) {\r\n\t\t\tif( digitIndex >= digits.length ) {\r\n\t\t\t\tlet hexPart = parseInt( hex[ i ], 16 );\r\n\t\t\t\tif( isNaN( hexPart ) ) {\r\n\t\t\t\t\thexPart = 0;\r\n\t\t\t\t}\r\n\t\t\t\tdigits = padL( hexPart.toString( 2 ), 4, \"0\" );\r\n\t\t\t\ti += 1;\r\n\t\t\t\tdigitIndex = 0;\r\n\t\t\t}\r\n\t\t\tdata[ y ].push( parseInt( digits[ digitIndex ] ) );\r\n\t\t\tdigitIndex += 1;\r\n\t\t}\r\n\t}\r\n\treturn data;\r\n}\r\n\r\n// Math utilities\r\n\r\n/**\r\n * Clamp a number between min and max\r\n * \r\n * @param {number} num - Number to clamp\r\n * @param {number} min - Minimum value\r\n * @param {number} max - Maximum value\r\n * @returns {number} Clamped value\r\n */\r\nexport function clamp( num, min, max ) {\r\n\treturn Math.min( Math.max( num, min ), max );\r\n}\r\n\r\n/**\r\n * Check if a point is in a rectangle\r\n * \r\n * @param {Object} point - Point with x, y properties\r\n * @param {Object} hitBox - Rectangle with x, y, width, height properties\r\n * @returns {boolean} True if point is inside rectangle\r\n */\r\nexport function inRange( point, hitBox ) {\r\n\treturn point.x >= hitBox.x && point.x < hitBox.x + hitBox.width &&\r\n\t\tpoint.y >= hitBox.y && point.y < hitBox.y + hitBox.height;\r\n}\r\n\r\n/**\r\n * Check if coordinates are in a rectangle\r\n * \r\n * @param {number} x1 - Point x\r\n * @param {number} y1 - Point y\r\n * @param {number} x2 - Rectangle x\r\n * @param {number} y2 - Rectangle y\r\n * @param {number} width - Rectangle width\r\n * @param {number} height - Rectangle height\r\n * @returns {boolean} True if point is inside rectangle\r\n */\r\nexport function inRange2( x1, y1, x2, y2, width, height ) {\r\n\treturn x1 >= x2 && x1 < x2 + width &&\r\n\t\ty1 >= y2 && y1 < y2 + height;\r\n}\r\n\r\n/**\r\n * Generate random number in range\r\n * \r\n * @param {number} min - Minimum value\r\n * @param {number} max - Maximum value\r\n * @returns {number} Random number between min and max\r\n */\r\nexport function rndRange( min, max ) {\r\n\treturn Math.random() * ( max - min ) + min;\r\n}\r\n\r\n/**\r\n * Convert degrees to radians\r\n * \r\n * @param {number} deg - Degrees\r\n * @returns {number} Radians\r\n */\r\nexport function degreesToRadian( deg ) {\r\n\treturn deg * ( Math.PI / 180 );\r\n}\r\n\r\n/**\r\n * Convert radians to degrees\r\n * \r\n * @param {number} rad - Radians\r\n * @returns {number} Degrees\r\n */\r\nexport function radiansToDegrees( rad ) {\r\n\treturn rad * ( 180 / Math.PI );\r\n}\r\n\r\n// String utilities\r\n\r\n/**\r\n * Pad string on left\r\n * \r\n * @param {string} str - String to pad\r\n * @param {number} len - Target length\r\n * @param {string} c - Padding character\r\n * @returns {string} Padded string\r\n */\r\nexport function padL( str, len, c ) {\r\n\tif( typeof c !== \"string\" ) {\r\n\t\tc = \" \";\r\n\t}\r\n\tlet pad = \"\";\r\n\tstr = str + \"\";\r\n\tfor( let i = str.length; i < len; i++ ) {\r\n\t\tpad += c;\r\n\t}\r\n\treturn pad + str;\r\n}\r\n\r\n/**\r\n * Pad string on both sides\r\n * \r\n * @param {string} str - String to pad\r\n * @param {number} len - Target length\r\n * @param {string} c - Padding character\r\n * @returns {string} Padded string\r\n */\r\nexport function pad( str, len, c ) {\r\n\tif( typeof c !== \"string\" || c.length === 0 ) {\r\n\t\tc = \" \";\r\n\t}\r\n\tstr = str + \"\";\r\n\twhile( str.length < len ) {\r\n\t\tstr = c + str + c;\r\n\t}\r\n\tif( str.length > len ) {\r\n\t\tstr = str.substring( 0, len );\r\n\t}\r\n\treturn str;\r\n}\r\n\r\n/**\r\n * Parse integer with default value\r\n * \r\n * @param {*} val - Value to parse\r\n * @param {number} def - Default value if parsing fails\r\n * @returns {number} Parsed integer or default\r\n */\r\nexport function getInt( val, def ) {\r\n\tif( val === null || val === undefined ) {\r\n\t\treturn def;\r\n\t}\r\n\tconst parsed = Number( val );\r\n\tif( !Number.isFinite( parsed ) ) {\r\n\t\treturn def;\r\n\t}\r\n\r\n\treturn Math.round( parsed );\r\n}\r\n\r\n/**\r\n * Parse float with default value\r\n * \r\n * @param {*} val - Value to parse\r\n * @param {number} def - Default value if parsing fails\r\n * @returns {number} Parsed float or default\r\n */\r\nexport function getFloat( val, def ) {\r\n\tif( val === null || val === undefined ) {\r\n\t\treturn def;\r\n\t}\r\n\tconst parsed = Number( val );\r\n\tif( !Number.isFinite( parsed ) ) {\r\n\t\treturn def;\r\n\t}\r\n\r\n\treturn parsed;\r\n}\r\n\r\n// Queue microtask (built-in in modern browsers)\r\n// Wrap to preserve window context\r\nexport const queueMicrotask = ( callback ) => {\r\n\tif( window.queueMicrotask ) {\r\n\t\twindow.queueMicrotask( callback );\r\n\t} else {\r\n\t\tsetTimeout( callback, 0 );\r\n\t}\r\n};\r\n\r\n\r\n/***************************************************************************************************\r\n * Color Utility Functions\r\n **************************************************************************************************/\r\n\r\n\r\nconst m_colorCheckerContext = document.createElement( \"canvas\" ).getContext(\r\n\t\"2d\", { \"willReadFrequently\": true }\r\n);\r\nconst COLOR_PROTO = {\r\n\t\"key\": 0,\r\n\t\"r\": 0,\r\n\t\"g\": 0,\r\n\t\"b\": 0,\r\n\t\"a\": 0,\r\n\t\"array\": null\r\n};\r\n\r\n/**\r\n * Creates a color object based on a Uint8Array\r\n *\r\n * @param {Uint8Array} colorArray - Contains [ r, g, b, a ]\r\n * @returns {number} A 32-bit integer representing the color.\r\n */\r\nexport function createColor( colorArray ) {\r\n\tconst color = Object.create( COLOR_PROTO );\r\n\tcolor.array = colorArray;\r\n\tcolor.r = colorArray[ 0 ];\r\n\tcolor.g = colorArray[ 1 ];\r\n\tcolor.b = colorArray[ 2 ];\r\n\tcolor.a = colorArray[ 3 ];\r\n\tcolor.key = ( colorArray[ 0 ] << 24 ) |\r\n\t\t( colorArray[ 1 ] << 16 ) |\r\n\t\t( colorArray[ 2 ] << 8 ) |\r\n\t\tcolorArray[ 3 ];\r\n\treturn color;\r\n}\r\n\r\n/**\r\n * Generates a unique 32-bit integer key for an opaque RGB color.\r\n * Each color component (R, G, B) is assumed to be an 8-bit integer (0-255).\r\n * The components are packed in the order: Red | Green | Blue.\r\n *\r\n * @param {number} r - Red component (0-255)\r\n * @param {number} g - Green component (0-255)\r\n * @param {number} b - Blue component (0-255)\r\n * @param {number} a - Alpha component (0-255)\r\n * @returns {number} A 32-bit integer representing the color.\r\n */\r\nexport function generateColorKey( r, g, b, a ) {\r\n\treturn ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;\r\n}\r\n\r\n/**\r\n * Convert RGB to color object\r\n * \r\n * @param {number} r - Red component (0-255)\r\n * @param {number} g - Green component (0-255)\r\n * @param {number} b - Blue component (0-255)\r\n * @param {number} a - Alpha component (0-255)\r\n * @returns {Object} Color object\r\n */\r\nexport function rgbToColor( r, g, b, a ) {\r\n\tconst colorArray = new Uint8Array( 4 );\r\n\tcolorArray.set( [ r, g, b, a ] );\r\n\treturn createColor( colorArray );\r\n}\r\n\r\n/**\r\n * Convert various color formats to color object\r\n * \r\n * @param {*} color - Color in various formats\r\n * @returns {Object|null} Color object or null if invalid\r\n */\r\nexport function convertToColor( color ) {\r\n\tif( color === undefined || color === null || color === \"\" ) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\t// Check if color is already a color prototype object\r\n\tif( Object.getPrototypeOf( color ) === COLOR_PROTO ) {\r\n\t\treturn color;\r\n\t} else if( Array.isArray( color ) ) {\r\n\r\n\t\t// Array must at least have red green and blue\r\n\t\tif( color.length < 3 ) {\r\n\t\t\treturn null;\r\n\t\t} else if( color.length === 3 ) {\r\n\t\t\tcolor.push( 255 );\r\n\t\t}\r\n\t} else if( typeof color === \"string\" ) {\r\n\r\n\t\t// Check if is hex format\r\n\t\tconst checkHexColor = /(^#[0-9A-F]{8}$)|(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i;\r\n\t\tif( checkHexColor.test( color ) ) {\r\n\t\t\treturn hexToColor( color );\r\n\t\t}\r\n\r\n\t\t// RGB/RGBA format\r\n\t\tif( color.indexOf( \"rgb\" ) === 0 ) {\r\n\t\t\tcolor = splitRgb( color );\r\n\t\t\tif( color.length < 3 ) {\r\n\t\t\t\treturn null;\r\n\t\t\t} else if( color.length === 3 ) {\r\n\t\t\t\tcolor.push( 255 );\r\n\t\t\t}\r\n\t\t} else {\r\n\r\n\t\t\t// Named color or other CSS color\r\n\t\t\treturn colorStringToColor( color );\r\n\t\t}\r\n\t} else if(\r\n\t\tcolor.r !== undefined &&\r\n\t\tcolor.g !== undefined &&\r\n\t\tcolor.b !== undefined &&\r\n\t\tcolor.a !== undefined\r\n\t) {\r\n\t\tcolor = [ color.r, color.g, color.b, color.a ];\r\n\t}\r\n\t\r\n\t// Parse rgb colors\r\n\tfor( let i = 0; i < 3; i += 1 ) {\r\n\t\tcolor[ i ] = getInt( color[ i ], 0 );\r\n\t}\r\n\r\n\t// Parse alpha\r\n\tcolor[ 3 ] = getFloat( color[ 3 ], 0 );\r\n\tif( color[ 3 ] <= 1 ) {\r\n\t\tcolor[ 3 ] = Math.round( color[ 3 ] * 255 );\r\n\t} else {\r\n\t\tcolor[ 3 ] = Math.round( color[ 3 ] );\r\n\t}\r\n\t\r\n\treturn rgbToColor( color[ 0 ], color[ 1 ], color[ 2 ], color[ 3 ] );\r\n}\r\n\r\nexport function calcColorDifference( c1, c2, w = [ 0.2, 0.68, 0.07, 0.05 ] ) {\r\n\tconst dr = c1.array[ 0 ] - c2.array[ 0 ];\r\n\tconst dg = c1.array[ 1 ] - c2.array[ 1 ];\r\n\tconst db = c1.array[ 2 ] - c2.array[ 2 ];\r\n\tconst da = c1.array[ 3 ] - c2.array[ 3 ];\r\n\r\n\treturn ( dr * dr * w[ 0 ] + dg * dg * w[ 1 ] + db * db * w[ 2 ] + da * da * w[ 3 ] );\r\n}\r\n\r\nexport function copyColor( colorSrc, colorDest ) {\r\n\tcolorDest.key = colorSrc.key;\r\n\tcolorDest.array[ 0 ] = colorSrc.array[ 0 ];\r\n\tcolorDest.array[ 1 ] = colorSrc.array[ 1 ];\r\n\tcolorDest.array[ 2 ] = colorSrc.array[ 2 ];\r\n\tcolorDest.array[ 3 ] = colorSrc.array[ 3 ];\r\n}\r\n\r\n/**\r\n * Convert hex color to color object\r\n * \r\n * @param {string} hex - Hex color string (#RGB, #RRGGBB, or #RRGGBBAA)\r\n * @returns {Object} Color object with r, g, b, a, s, s2 properties\r\n */\r\nfunction hexToColor( hex ) {\r\n\tlet r, g, b, a;\r\n\r\n\tif( hex.length === 4 ) {\r\n\t\tr = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 );\r\n\t\tg = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 );\r\n\t\tb = parseInt( hex.charAt( 3 ) + hex.charAt( 3 ), 16 );\r\n\t} else {\r\n\t\tr = parseInt( hex.substring( 1, 3 ), 16 );\r\n\t\tg = parseInt( hex.substring( 3, 5 ), 16 );\r\n\t\tb = parseInt( hex.substring( 5, 7 ), 16 );\r\n\t}\r\n\r\n\tif( hex.length === 9 ) {\r\n\t\ta = parseInt( hex.substring( 7, 9 ), 16 );\r\n\t} else {\r\n\t\ta = 255;\r\n\t}\r\n\r\n\treturn rgbToColor( r, g, b, a );\r\n}\r\n\r\n/**\r\n * Convert color component to hex\r\n * \r\n * @param {number} c - Color component (0-255)\r\n * @returns {string} Hex string\r\n */\r\nfunction cToHex( c ) {\r\n\tif( !Number.isInteger( c ) ) {\r\n\t\tc = Math.round( c );\r\n\t}\r\n\tc = clamp( c, 0, 255 );\r\n\tconst hex = Number( c ).toString( 16 );\r\n\treturn hex.length < 2 ? \"0\" + hex : hex.toUpperCase();\r\n}\r\n\r\n/**\r\n * Convert Color Object to hex string\r\n * \r\n * @param {Object} r - Red component (0-255)\r\n * @returns {string} Hex color string\r\n */\r\nexport function colorToHex( color ) {\r\n\treturn \"#\" + cToHex( color.r ) + cToHex( color.g ) + cToHex( color.b ) + cToHex( color.a );\r\n}\r\n\r\n/**\r\n * Split RGB/RGBA string into components\r\n * \r\n * @param {string} s - RGB or RGBA string\r\n * @returns {Array<number>} Array of color components\r\n */\r\nfunction splitRgb( s ) {\r\n\ts = s.slice( s.indexOf( \"(\" ) + 1, s.indexOf( \")\" ) );\r\n\tconst parts = s.split( \",\" );\r\n\tconst colors = [];\r\n\tfor( let i = 0; i < parts.length; i++ ) {\r\n\t\tlet val;\r\n\t\tif( i === 3 ) {\r\n\t\t\tval = parseFloat( parts[ i ].trim() );\r\n\t\t\tif( val <= 1 ) {\r\n\t\t\t\tval *= 255;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tval = parseInt( parts[ i ].trim() );\r\n\t\t}\r\n\t\tcolors.push( val );\r\n\t}\r\n\treturn colors;\r\n}\r\n\r\n/**\r\n * Convert color string to color object using canvas\r\n * \r\n * @param {string} colorStr - CSS color string\r\n * @returns {Object} Color object\r\n */\r\nfunction colorStringToColor( colorStr ) {\r\n\tm_colorCheckerContext.clearRect( 0, 0, 1, 1 );\r\n\tm_colorCheckerContext.fillStyle = colorStr;\r\n\tm_colorCheckerContext.fillRect( 0, 0, 1, 1 );\r\n\tconst data = m_colorCheckerContext.getImageData( 0, 0, 1, 1 ).data;\r\n\treturn rgbToColor( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ] );\r\n}\r\n", "/**\n * Pi.js - Command System Module\n * \n * Command registration and processing for Pi.js.\n * Handles ready command and set command.\n * \n * @module core/commands\n */\n\n\"use strict\";\n\nimport * as g_utils from \"./utils.js\";\nimport * as g_screenManager from \"./screen-manager.js\";\n\nconst m_settings = {};\nconst m_commands = [];\nlet m_api = null;\nlet m_readyCallbacks = [];\nlet m_isDocumentReady = false;\nlet m_waitCount = 0;\nlet m_checkReadyTimeout = null;\n\n\n/**************************************************************************************************\n * Module Commands\n **************************************************************************************************/\n\n\nexport function init( api ) {\n\tm_api = api;\n\n\t// Set up document ready detection\n\tif( typeof document !== \"undefined\" ) {\n\t\tif( document.readyState === \"loading\" ) {\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", onDocumentReady );\n\t\t} else {\n\n\t\t\t// Document already ready\n\t\t\tm_isDocumentReady = true;\n\t\t}\n\t} else {\n\n\t\t// Not in browser environment, mark as ready immediately\n\t\tm_isDocumentReady = true;\n\t}\n\n\tregisterCommands();\n\tg_screenManager.addScreenInitFunction( processScreenCommands );\n}\n\nfunction registerCommands() {\n\n\t// Register non screen commands\n\taddCommand( \"ready\", ready, false, [ \"callback\" ] );\n\taddCommand( \"set\", set, true, [ \"options\" ], true );\n}\n\n\n/**************************************************************************************************\n * Command processing\n **************************************************************************************************/\n\n\nexport function addCommand( name, fn, isScreen, parameterNames, isScreenOptional ) {\n\tm_commands.push( { name, fn, isScreen, parameterNames, isScreenOptional } );\n\t\n\t// Auto-register set commands as settings\n\tif( name.startsWith( \"set\" ) && name !== \"set\" ) {\n\t\tconst settingName = name.substring( 3, 4 ).toLowerCase() + name.substring( 4 );\n\t\tm_settings[ settingName ] = {\n\t\t\tfn, isScreen, \"parameterNames\": parameterNames, isProcessed: false\n\t\t};\n\t}\n}\n\nexport function processCommands( api ) {\n\tfor( const command of m_commands ) {\n\t\tif( !command.isProcessed ) {\n\t\t\tprocessCommand( api, command );\n\t\t}\n\t}\n}\n\nfunction processCommand( api, command ) {\n\tconst { name, fn, isScreen, parameterNames, isScreenOptional } = command;\n\tif( isScreen ) {\n\t\tapi[ name ] = ( ...args ) => {\n\t\t\tconst options = g_utils.parseOptions( args, parameterNames );\n\t\t\tconst screenData = g_screenManager.getActiveScreen( name, isScreenOptional );\n\t\t\treturn fn( screenData, options );\n\t\t};\n\t} else {\n\t\tapi[ name ] = ( ...args ) => {\n\t\t\tconst options = g_utils.parseOptions( args, parameterNames );\n\t\t\treturn fn( options );\n\t\t};\n\t}\n}\n\nfunction processScreenCommands( screenData ) {\n\tfor( const command of m_commands ) {\n\t\tconst { name, fn, isScreen, parameterNames } = command;\n\t\tif( isScreen ) {\n\t\t\tscreenData.api[ name ] = ( ...args ) => {\n\t\t\t\tconst options = g_utils.parseOptions( args, parameterNames );\n\t\t\t\treturn fn( screenData, options );\n\t\t\t};\n\t\t}\n\t}\n}\n\n\n/**************************************************************************************************\n * Resource Loader - Ready Command\n **************************************************************************************************/\n\n/**\n * ready command - waits for document ready and all pending resources\n * \n * Supports both callback and promise patterns:\n *   - $.ready( callback )        // Callback style\n *   - await $.ready()            // Promise style\n *   - $.ready().then( ... )      // Promise .then() style\n */\nfunction ready( options ) {\n\n\tconst callback = options.callback;\n\t\n\t// Validate callback if provided\n\tif( callback != null && !g_utils.isFunction( callback ) ) {\n\t\tconst error = new TypeError( \"ready: Parameter callback must be a function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\n\t// Never execute immediately - always defer to next tick\n\treturn new Promise( ( resolve ) => {\n\t\tm_readyCallbacks.push( {\n\t\t\t\"callback\": callback,\n\t\t\t\"resolve\": resolve,\n\t\t\t\"triggered\": false\n\t\t} );\n\n\t\t// Schedule a check for next tick (allows more resources to be added in same thread)\n\t\tscheduleReadyCheck();\n\t} );\n}\n\nexport function wait() {\n\tm_waitCount++;\n}\n\nexport function done() {\n\tm_waitCount--;\n\tif( m_waitCount < 0 ) {\n\t\tm_waitCount = 0;\n\t}\n\n\t// Check if ready to trigger callbacks\n\tscheduleReadyCheck();\n}\n\nfunction onDocumentReady() {\n\tm_isDocumentReady = true;\n\tscheduleReadyCheck();\n}\n\nfunction scheduleReadyCheck() {\n\n\t// Clear any existing timeout\n\tif( m_checkReadyTimeout !== null ) {\n\t\tclearTimeout( m_checkReadyTimeout );\n\t}\n\n\t// Schedule check for next tick\n\tm_checkReadyTimeout = setTimeout( checkReady, 0 );\n}\n\nfunction checkReady() {\n\n\t// TODO-LATER: [Violation] 'setTimeout' handler took 381ms\n\t// Long running tasks in callback should be handled - maybe we should track callback times?\n\n\tm_checkReadyTimeout = null;\n\n\t// Don't check if document not ready\n\tif( !m_isDocumentReady ) {\n\t\treturn;\n\t}\n\n\t// Don't trigger if resources are still loading\n\tif( m_waitCount !== 0 ) {\n\t\treturn;\n\t}\n\n\t// Trigger all pending ready callbacks together\n\tconst callbacks = m_readyCallbacks.slice();\n\tm_readyCallbacks = [];\n\n\tfor( const item of callbacks ) {\n\n\t\t// Skip if already triggered\n\t\tif( item.triggered ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mark as triggered\n\t\titem.triggered = true;\n\n\t\t// Execute callback and resolve promise\n\t\tif( item.callback ) {\n\t\t\titem.callback();\n\t\t}\n\t\titem.resolve();\n\t}\n}\n\n\n/**************************************************************************************************\n * Settings and set command\n **************************************************************************************************/\n\n/**\n * Global settings command\n * \n * This can get called from either the global api or directly from a screenData.api.\n * screenData can be null if no screen is available\n */\nexport function set( screenData, options ) {\n\n\t// Unpack options\n\toptions = options.options;\n\n\t// Loop through all the options\n\tfor( const optionName in options ) {\n\n\t\t// Skip blanks\n\t\tif( options[ optionName ] === null ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// If the option is a valid setting\n\t\tif( m_settings[ optionName ] ) {\n\n\t\t\t// Get the setting data\n\t\t\tconst setting = m_settings[ optionName ];\n\t\t\tconst optionValues = options[ optionName ];\n\n\t\t\t// Parse the options from the setting\n\t\t\tconst argsArray = [ optionValues ];\n\t\t\tconst parsedOptions = g_utils.parseOptions( argsArray, setting.parameterNames );\n\n\t\t\t// Call the setting function\n\t\t\tif( setting.isScreen ) {\n\t\t\t\tsetting.fn( screenData, parsedOptions );\n\t\t\t} else {\n\t\t\t\tsetting.fn( parsedOptions );\n\t\t\t}\n\n\t\t\t// If we just set the screen then update the screenData to the new active screen\n\t\t\tif( optionName === \"screen\" ) {\n\t\t\t\tscreenData = g_screenManager.getActiveScreen();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function addSetting( name, fn, isScreen ) {\n\tm_settings[ name ] = { fn, isScreen };\n}\n\n", "/**\n * Pi.js - Screen Manager Core Module\n * \n * Screen creation and management for Pi.js.\n * Creates canvas elements, manages multiple screens, handles aspect ratios.\n * WebGL2 only - no Canvas2D fallback.\n * \n * @module core/screen-manager\n */\n\n/**\n * IDEA:\n * \n * Simplify \"m\" multiple mode to use this formula:\n * scaleX = floor(canvas.width / FBO_WIDTH)\n * scaleY = floor(canvas.height / FBO_HEIGHT)\n * finalScale = min(scaleX, scaleY)\n *  \n * Even when I use \"m\" mode I still see artifacts, maybe handle the upscaling manually by setting\n * the canvas.width and canvas.height to match the CSS width and height and then when I copy the\n * FBO to the canvas it will apply gl.NEAREST when display to canvas is run, this is already \n * implemented I just need to set canvas.width and canvas.height to match.\n * \n * I did a test 640m480 and even it still has pixels that are uneven in size some pixels are 2x2,\n * other pixels are 1x2. Even with a css resolution of 1280x960 still resulted in uneven pixel\n * sizes.\n * \n * My main reason for letting CSS handle upscaling was I liked being able to copy and paste the\n * image and get the image with target resolution. But a work-around could be adding a copy\n * image that command that copies the canvas to clipboard.\n * \n * IDEA:\n * \n * Add a hardPalette flag to the screen command. When set it adds a hard requirement on palette\n * colors. This means that only colors from the palette can be used.\n * \n * Need to find an optimal solution to enforce the hardPalette flag and to update FBO when palette\n * changes. I can try adding a 1D array or texture with color lookups and try to do it in the\n * shader. If I have to I can do a CPU filter on the colors when palette changes, but this is not\n * optimal. I can also enforce the colors in the color lookups but that would require more\n * complex code in multiple places.  Need to really think about a good strategy for this.\n */\n\"use strict\";\n\nimport * as g_utils from \"./utils.js\";\nimport * as g_commands from \"./commands.js\";\nimport * as g_renderer from \"../renderer/renderer.js\";\nimport * as g_graphics from \"../api/graphics.js\";\n\nconst SCREEN_API_PROTO = { \"screen\": true, \"id\": 0 };\nconst m_screens = {};\nconst m_screenCanvasMap = new Map();\nconst m_screenDataItems = {};\nconst m_screenDataItemGetters = [];\nconst m_screenDataInitFunctions = [];\nconst m_screenDataCleanupFunctions = [];\nconst MAX_CANVAS_DIMENSION = 8192;\nconst m_observedContainers = new Set();\n\nlet m_nextScreenId = 0;\nlet m_activeScreenData = null;\nlet m_resizeObserver = null;\nlet m_offscreenCanvas = null;\n\n\n/***************************************************************************************************\n * Module Commands\n ***************************************************************************************************/\n\n\nexport { m_activeScreenData as activeScreenData };\nexport { m_screenCanvasMap as screenCanvasMap };\n\nexport function init( api ) {\n\n\t// TODO-LATER: Add matchMedia to watch for DPR changes\n\n\t// Create a single ResizeObserver for all screen containers\n\tm_resizeObserver = new ResizeObserver( ( entries ) => {\n\t\tfor( const entry of entries ) {\n\t\t\tconst container = entry.target;\n\t\t\t\n\t\t\t// Find all canvas elements in this container\n\t\t\tconst canvases = container.querySelectorAll( \"canvas[data-screen-id]\" );\n\t\t\tif( canvases.length === 0 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Resize all screens in this container\n\t\t\tfor( const canvas of canvases ) {\n\t\t\t\tconst screenId = parseInt( canvas.dataset.screenId, 10 );\n\t\t\t\tconst screenData = m_screens[ screenId ];\n\t\t\t\t\n\t\t\t\tif( screenData ) {\n\t\t\t\t\tresizeScreen( screenData, false );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\n\tregisterCommands();\n\n\t// Special command removeScreen\n\tapi.removeScreen = ( screenId ) => {\n\t\tif( Object.getPrototypeOf( screenId ) === SCREEN_API_PROTO ) {\n\t\t\tscreenId = screenId.id;\n\t\t}\n\t\tif( m_screens[ screenId ] ) {\n\t\t\treturn removeScreen( m_screens[ screenId ] );\n\t\t}\n\t};\n\n\t// Add screenObj remove screen command\n\taddScreenInitFunction( ( screenData ) => {\n\t\tscreenData.api.removeScreen = () => removeScreen( screenData );\n\t} );\n}\n\nfunction registerCommands() {\n\n\t// Global commands\n\tg_commands.addCommand(\n\t\t\"screen\", screen, false, [ \"aspect\", \"container\", \"isOffscreen\", \"resizeCallback\" ]\n\t);\n\tg_commands.addCommand( \"setScreen\", setScreen, false, [ \"screen\" ] );\n\tg_commands.addCommand( \"getScreen\", getScreen, false, [ \"screenId\" ] );\n\tg_commands.addCommand( \"getAllScreens\", getAllScreens, false, [] );\n\tg_commands.addCommand( \"removeAllScreens\", removeAllScreens, false, [] );\n\n\t// Screen-scoped info commands\n\tg_commands.addCommand( \"width\", widthCmd, true, [] );\n\tg_commands.addCommand( \"height\", heightCmd, true, [] );\n\tg_commands.addCommand( \"canvas\", canvasCmd, true, [] );\n}\n\nexport function addScreenDataItem( name, val ) {\n\tm_screenDataItems[ name ] = val;\n}\n\nexport function addScreenDataItemGetter( name, fn ) {\n\tm_screenDataItemGetters.push( { name, fn } );\n}\n\nexport function addScreenInitFunction( fn ) {\n\tm_screenDataInitFunctions.push( fn );\n}\n\nexport function addScreenCleanupFunction( fn ) {\n\tm_screenDataCleanupFunctions.push( fn );\n}\n\nexport function getActiveScreen( fnName, isScreenOptional ) {\n\tif( m_activeScreenData === null && !isScreenOptional ) {\n\t\tconst error = new Error(\n\t\t\tfnName + \": You are attempting to call a method that requires a screen but there \" +\n\t\t\t\"there is currently no active screen. Call $.screen() before calling any graphics \" +\n\t\t\t\"commands.\"\n\t\t);\n\t\terror.code = \"NO_ACTIVE_SCREEN\";\n\t\tthrow error;\n\t}\n\treturn m_activeScreenData;\n}\n\nexport function getScreenData( fnName, screenId ) {\n\tif( !m_screens[ screenId ] ) {\n\t\tconst error = new Error( `${fnName}: Invalid screen id.` );\n\t\terror.code = \"INVALID_SCREEN_ID\";\n\t\tthrow error;\n\t}\n\treturn m_screens[ screenId ];\n}\n\n/**\n * Get all active screens\n * \n * @returns {Array<Object>} Array of all screen data objects\n */\nexport function getAllScreensData() {\n\tconst screens = [];\n\tfor( const id in m_screens ) {\n\t\tscreens.push( m_screens[ id ] );\n\t}\n\treturn screens;\n}\n\n\n/***************************************************************************************************\n * Screen Command\n ***************************************************************************************************/\n\n\nfunction screen( options ) {\n\n\t// Validate resize callback\n\tif( options.resizeCallback != null && !g_utils.isFunction( options.resizeCallback ) ) {\n\t\tconst error = new TypeError( \"screen: Parameter resizeCallback must be a function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\n\t// Validate aspect - \"Now Required\"\n\tif( typeof options.aspect !== \"string\" || options.aspect === \"\" ) {\n\t\tconst error = new Error( \"screen: Parameter aspect must be a non-empty string.\" );\n\t\terror.code = \"INVALID_ASPECT\";\n\t\tthrow error;\n\t}\n\n\tconst screenData = {\n\t\t\"id\": m_nextScreenId,\n\t\t\"isOffscreen\": !!options.isOffscreen,\n\t\t\"resizeCallback\": options.resizeCallback,\n\t\t\"api\": Object.create( SCREEN_API_PROTO ),\n\t\t\"canvas\": null,\n\t\t\"width\": null,\n\t\t\"height\": null,\n\t\t\"container\": null,\n\t\t\"aspectData\": null,\n\t\t\"clientRect\": null,\n\t\t\"previousOffsetSize\": null\n\t};\n\n\tscreenData.api.id = screenData.id;\n\n\t// Append additional items onto the screendata\n\tObject.assign( screenData, structuredClone( m_screenDataItems ) );\n\n\t// Append dynamic screendata items (items with dynamic defaults)\n\tfor( const itemGetter of m_screenDataItemGetters ) {\n\t\tscreenData[ itemGetter.name ] = structuredClone( itemGetter.fn() );\n\t}\n\n\t// Increment to the next screen id\n\tm_nextScreenId += 1;\n\n\t// Parse aspect ratio\n\tscreenData.aspectData = parseAspect( options.aspect.toLowerCase() );\n\tif( !screenData.aspectData ) {\n\t\tconst error = new Error( \"screen: Parameter aspect is not valid.\" );\n\t\terror.code = \"INVALID_ASPECT\";\n\t\tthrow error;\n\t}\n\n\t// If it's not a ratio validate the dimensions\n\tvalidateDimensions( screenData.aspectData.width, screenData.aspectData.height );\n\n\t// Setup options for offscreen canvas\n\tif( screenData.isOffscreen ) {\n\n\t\t// Create a shared canvas for offscreen screens\n\t\tif( !m_offscreenCanvas ) {\n\t\t\tm_offscreenCanvas = document.createElement( \"canvas\" );\n\t\t}\n\n\t\t// Create a mock canvas for offscreen screen\n\t\tscreenData.canvas = {\n\t\t\t\"isMock\": true,\n\t\t\t\"canvas\": m_offscreenCanvas,\n\t\t\t\"dataset\": { \"screenId\": screenData.id },\n\t\t\t\"width\": screenData.aspectData.width,\n\t\t\t\"height\": screenData.aspectData.height,\n\t\t\t\"style\": {}\n\t\t};\n\n\t\tif( screenData.aspectData.splitter !== \"x\" ) {\n\t\t\tconst error = new Error(\n\t\t\t\t\"screen: You must use aspect ratio with e(x)act pixel dimensions for offscreen \" +\n\t\t\t\t\"screens. For example: 320x200 for width of 320 and height of 200 pixels.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_OFFSCREEN_ASPECT\";\n\t\t\tthrow error;\n\t\t}\n\t\tsetupOffscreenCanvasOptions( screenData );\n\t\tscreenData.width = screenData.aspectData.width;\n\t\tscreenData.height = screenData.aspectData.height;\n\t} else {\n\n\t\t// Create the canvas\n\t\tscreenData.canvas = document.createElement( \"canvas\" );\n\t\tscreenData.canvas.dataset.screenId = screenData.id;\n\n\t\t// Setup options for onscreen canvas\n\t\tscreenData.canvas.tabIndex = 0;\n\n\t\t// Get the container element from the dom if it's available\n\t\tif( typeof options.container === \"string\" ) {\n\t\t\tscreenData.container = document.getElementById( options.container );\n\t\t} else if( !options.container ) {\n\t\t\tscreenData.container = document.body;\n\t\t} else {\n\t\t\tscreenData.container = options.container;\n\t\t}\n\n\t\tif( !g_utils.isDomElement( screenData.container ) ) {\n\t\t\tconst error = new TypeError(\n\t\t\t\t\"screen: Invalid argument container. Container must be a DOM element or a string \" +\n\t\t\t\t\"id of a DOM element.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_CONTAINER\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Create a default canvas\n\t\tsetDefaultCanvasOptions( screenData );\n\n\t\t// Append the canvas to the container\n\t\tscreenData.container.appendChild( screenData.canvas );\n\n\t\t// Add container to the global resize observer (only if not already observed)\n\t\tif(\n\t\t\tm_resizeObserver && screenData.container &&\n\t\t\t!m_observedContainers.has( screenData.container )\n\t\t) {\n\t\t\tm_resizeObserver.observe( screenData.container );\n\t\t\tm_observedContainers.add( screenData.container );\n\t\t}\n\t}\n\n\t// Map the canvas to the screenData\n\tm_screenCanvasMap.set( screenData.canvas, screenData );\n\t\n\tif( !screenData.isOffscreen ) {\n\t\tresizeScreen( screenData, true );\n\t}\n\n\t// Assign screen to active screen\n\tm_activeScreenData = screenData;\n\tm_screens[ screenData.id ] = screenData;\n\n\t// Setup WebGL2 renderer\n\tg_renderer.createContext( screenData )\n\n\t// Call init functions for all modules that need initialization\n\tfor( const fn of m_screenDataInitFunctions ) {\n\t\tfn( screenData );\n\t}\n\n\treturn screenData.api;\n}\n\nfunction parseAspect( aspect ) {\n\tconst match = aspect.replaceAll( \" \", \"\" ).match( /^(\\d+)(x|e|m)(\\d+)$/ );\n\tif( !match ) {\n\t\treturn null;\n\t}\n\n\tconst width = Number( match[ 1 ] );\n\tconst splitter = match[ 2 ];\n\tconst height = Number( match[ 3 ] );\n\n\tif( isNaN( width ) || width === 0 || isNaN( height ) || height === 0 ) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\t\"width\": width,\n\t\t\"height\": height,\n\t\t\"splitter\": splitter,\n\t\t\"isFixedSize\": splitter !== \"e\"\n\t};\n}\n\nfunction setupOffscreenCanvasOptions( screenData ) {\n\tscreenData.canvas.width = screenData.aspectData.width;\n\tscreenData.canvas.height = screenData.aspectData.height;\n\tscreenData.container = null;\n\tscreenData.isOffscreen = true;\n\tscreenData.resizeCallback = null;\n\tscreenData.previousOffsetSize = null;\n}\n\nfunction setDefaultCanvasOptions( screenData ) {\n\tscreenData.canvas.style.outline = \"none\";\n\tscreenData.canvas.style.backgroundColor = \"black\";\n\tscreenData.canvas.style.position = \"absolute\";\n\tscreenData.canvas.style.imageRendering = \"pixelated\";\n\n\t// Check if the container is document.body\n\tif( screenData.container === document.body ) {\n\t\tdocument.documentElement.style.height = \"100%\";\n\t\tdocument.documentElement.style.margin = \"0\";\n\t\tdocument.documentElement.style.padding = \"0\";\n\t\tdocument.body.style.height = \"100%\";\n\t\tdocument.body.style.margin = \"0\";\n\t\tdocument.body.style.padding = \"0\";\n\t\tscreenData.canvas.style.left = \"0\";\n\t\tscreenData.canvas.style.top = \"0\";\n\t}\n\n\t// No scrolling within a container as canvases fit to size of container and are meant to \n\t// overlap. If scrolling is required use an outer container that scrolls.\n\tscreenData.container.style.overflow = \"hidden\";\n\n\t// Make sure container is not blank\n\tif( screenData.container.offsetHeight === 0 ) {\n\t\tscreenData.container.style.height = \"200px\";\n\t}\n}\n\nfunction validateDimensions( width, height ) {\n\tif( width <= 0 || height <= 0 ) {\n\t\tconst error = new Error( \"screen: Canvas dimensions must be positive.\" );\n\t\terror.code = \"INVALID_DIMENSIONS\";\n\t\tthrow error;\n\t}\n\tif( width > MAX_CANVAS_DIMENSION || height > MAX_CANVAS_DIMENSION ) {\n\t\tconst error = new Error(\n\t\t\t`screen: Canvas dimensions exceed maximum of ${MAX_CANVAS_DIMENSION}px.`\n\t\t);\n\t\terror.code = \"DIMENSION_TOO_LARGE\";\n\t\tthrow error;\n\t}\n}\n\n\n/**************************************************************************************************\n * Other External API Commands\n **************************************************************************************************/\n\n\nfunction removeAllScreens() {\n\tconst allScreenDatas = getAllScreensData();\n\tfor( const screenData of allScreenDatas ) {\n\t\tremoveScreen( screenData );\n\t}\n}\n\nfunction removeScreen( screenData ) {\n\n\t// Get the id for reference\n\tconst screenId = screenData.id;\n\n\t// Call cleanup functions for all modules that need cleanup\n\tfor( const fn of m_screenDataCleanupFunctions ) {\n\t\tfn( screenData );\n\t}\n\n\t// Replace all commands from screen object\n\tfor( const key in screenData.api ) {\n\t\tif( typeof screenData.api[ key ] === \"function\" ) {\n\n\t\t\t// Use string replacement to avoid capturing screenData in closure\n\t\t\tscreenData.api[ key ] = () => {\n\t\t\t\tconst error = new TypeError( \n\t\t\t\t\t`Cannot call ${key}() on removed screen (id: ${screenId}). ` +\n\t\t\t\t\t`The screen has been removed from the page.`\n\t\t\t\t);\n\t\t\t\terror.code = \"DELETED_METHOD\";\n\t\t\t\tthrow error;\n\t\t\t};\n\t\t}\n\t}\n\n\t// Remove from the screenCanvasMap\n\tm_screenCanvasMap.delete( screenData.canvas );\n\n\t// Remove the canvas from the page\n\tif( screenData.canvas && screenData.canvas.parentElement ) {\n\t\tscreenData.canvas.parentElement.removeChild( screenData.canvas );\n\t}\n\n\t// Unobserve the container from the global resize observer\n\tif( screenData.container && m_observedContainers.has( screenData.container ) ) {\n\t\t\n\t\t// Check if any other screens are using this container\n\t\tlet hasOtherScreens = false;\n\t\tfor( const id in m_screens ) {\n\t\t\tconst otherScreen = m_screens[ id ];\n\t\t\tif( otherScreen !== screenData && otherScreen.container === screenData.container ) {\n\t\t\t\thasOtherScreens = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Only unobserve if no other screens are using this container\n\t\tif( !hasOtherScreens ) {\n\t\t\tm_resizeObserver.unobserve( screenData.container );\n\t\t\tm_observedContainers.delete( screenData.container );\n\t\t}\n\t}\n\n\t// Clean up all references to prevent memory leaks\n\tscreenData.canvas = null;\n\tscreenData.commands = null;\n\tscreenData.resizeCallback = null;\n\tscreenData.container = null;\n\tscreenData.aspectData = null;\n\tscreenData.clientRect = null;\n\tscreenData.previousOffsetSize = null;\n\n\t// Remove additional screenData items\n\tfor( const i in m_screenDataItems ) {\n\t\tscreenData[ i ] = null;\n\t}\n\tfor( const getter of m_screenDataItemGetters ) {\n\t\tscreenData[ getter.name ] = null;\n\t}\n\n\t// If the current screen is the active screen then set to next screen available\n\tif( screenData === m_activeScreenData ) {\n\t\tm_activeScreenData = null;\n\t\tfor( const i in m_screens ) {\n\t\t\tif( m_screens[ i ] !== screenData ) {\n\t\t\t\tm_activeScreenData = m_screens[ i ];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Delete the screen from the screens container\n\tdelete m_screens[ screenId ];\n}\n\nfunction setScreen( options ) {\n\tconst screenObj = options.screen;\n\tlet screenId;\n\n\tif( Number.isInteger( screenObj ) ) {\n\t\tscreenId = screenObj;\n\t} else if( screenObj && Number.isInteger( screenObj.id ) ) {\n\t\tscreenId = screenObj.id;\n\t}\n\tif( !m_screens[ screenId ] ) {\n\t\tconst error = new Error( \"screen: Invalid screen.\" );\n\t\terror.code = \"INVALID_SCREEN\";\n\t\tthrow error;\n\t}\n\n\t// Note: there is no need to check if m_activeScreenData is null because it cannot be null\n\t// unless there are no screens in which case an error would already have been thrown.\n\tconst previousScreenId = m_activeScreenData.id;\n\tm_activeScreenData = m_screens[ screenId ];\n\n\tif( previousScreenId !== m_activeScreenData.id  ) {\n\t\tg_graphics.buildApi( m_activeScreenData );\n\t}\n}\n\nfunction getScreen( options ) {\n\tconst screenId = g_utils.getInt( options.screenId, null );\n\tif( screenId === null || screenId < 0 ) {\n\t\tconst error = new Error( \"screen: Invalid screen id.\" );\n\t\terror.code = \"INVALID_SCREEN_ID\";\n\t\tthrow error;\n\t}\n\tconst screen = m_screens[ screenId ];\n\tif( !screen ) {\n\t\tconst error = new Error( `screen: Screen \"${screenId}\" not found.` );\n\t\terror.code = \"SCREEN_NOT_FOUND\";\n\t\tthrow error;\n\t}\n\treturn screen.api;\n}\n\nfunction getAllScreens() {\n\tconst screens = [];\n\tfor( const id in m_screens ) {\n\t\tscreens.push( m_screens[ id ].api );\n\t}\n\treturn screens;\n}\n\nfunction widthCmd( screenData ) {\n\treturn screenData.width;\n}\n\nfunction heightCmd( screenData ) {\n\treturn screenData.height;\n}\n\nfunction canvasCmd( screenData ) {\n\tif( screenData.isOffscreen ) {\n\t\tconsole.warn(\n\t\t\t\"Offscreen screens use a shared canvas that draws to textures to simulate an \" +\n\t\t\t\"offscreen canvas. The canvas returned is that shared canvas. Proceed with caution \" +\n\t\t\t\"changes to this canvas could cause unexpected results.\" \n\t\t);\n\t\treturn screenData.canvas.canvas;\n\t}\n\treturn screenData.canvas;\n}\n\n\n/***************************************************************************************************\n * Resize Screen\n ***************************************************************************************************/\n\n\nfunction resizeScreen( screenData, isInit ) {\n\n\t// Skip if screen is not visible or should not be resized\n\tif( screenData.isOffscreen || screenData.canvas.offsetParent === null ) {\n\t\treturn;\n\t}\n\n\t// Get the previous size (if stored from last time)\n\tlet fromSize = screenData.previousOffsetSize;\n\n\t// Track previous screenData dimensions for \"e\"xtend mode\n\tconst lastScreenWidth = screenData.width;\n\tconst lastScreenHeight = screenData.height;\n\n\t// Update the canvas to the new size\n\tconst size = getSize( screenData.container );\n\tsetCanvasSize( screenData, size.width, size.height );\n\n\t// Resize the client rectangle\n\tscreenData.clientRect = screenData.canvas.getBoundingClientRect();\n\n\t// Get the new size after resize\n\tconst toSize = {\n\t\t\"width\": screenData.canvas.offsetWidth,\n\t\t\"height\": screenData.canvas.offsetHeight\n\t};\n\n\tif( !isInit ) {\n\n\t\t// Handle \"e\"xtend mode resize the renderer\n\t\tif( lastScreenWidth !== screenData.width || lastScreenHeight !== screenData.height ) {\n\t\t\tg_renderer.resizeScreen( screenData, lastScreenWidth, lastScreenHeight );\n\t\t}\n\t}\n\t\n\t// Send the resize data to the client\n\tif( screenData.resizeCallback ) {\n\t\tif(\n\t\t\tfromSize !== null &&\n\t\t\t( fromSize.width !== toSize.width || fromSize.height !== toSize.height )\n\t\t) {\n\t\t\tscreenData.resizeCallback( screenData.api, fromSize, toSize );\n\t\t}\n\t}\n\n\t// Store the new size for next time\n\tscreenData.previousOffsetSize = toSize;\n}\n\nfunction setCanvasSize( screenData, maxWidth, maxHeight ) {\n\tconst aspectData = screenData.aspectData;\n\tconst canvas = screenData.canvas;\n\tlet width = aspectData.width;\n\tlet height = aspectData.height;\n\tconst splitter = aspectData.splitter;\n\tlet newCssWidth, newCssHeight;\n\n\t// If set size to multiple or extend\n\tif( splitter === \"m\" || splitter === \"e\" ) {\n\t\tconst factorX = Math.floor( maxWidth / width );\n\t\tconst factorY = Math.floor( maxHeight / height );\n\t\tlet factor = factorX > factorY ? factorY : factorX;\n\t\tif( factor < 1 ) {\n\t\t\tfactor = 1;\n\t\t}\n\t\tnewCssWidth = width * factor;\n\t\tnewCssHeight = height * factor;\n\n\t\t// Extending the canvas to match container size\n\t\tif( splitter === \"e\" ) {\n\t\t\twidth = Math.floor( maxWidth / factor );\n\t\t\theight = Math.floor( maxHeight / factor );\n\t\t\tnewCssWidth = width * factor;\n\t\t\tnewCssHeight = height * factor;\n\t\t}\n\t} else {\n\n\t\t// Calculate the screen ratios\n\t\tconst ratio1 = height / width;\n\t\tconst ratio2 = width / height;\n\t\tnewCssWidth = maxHeight * ratio2;\n\t\tnewCssHeight = maxWidth * ratio1;\n\n\t\t// Calculate the best fit\n\t\tif( newCssWidth > maxWidth ) {\n\t\t\tnewCssWidth = maxWidth;\n\t\t\tnewCssHeight = newCssWidth * ratio1;\n\t\t} else {\n\t\t\tnewCssHeight = maxHeight;\n\t\t}\n\t}\n\n\t// Set screen data width/height\n\tscreenData.width = width;\n\tscreenData.height = height;\n\n\t// Set the size\n\tcanvas.style.width = Math.floor( newCssWidth ) + \"px\";\n\tcanvas.style.height = Math.floor( newCssHeight ) + \"px\";\n\n\t// Set the margins\n\tcanvas.style.marginLeft = Math.floor( ( maxWidth - newCssWidth ) / 2 ) + \"px\";\n\tcanvas.style.marginTop = Math.floor( ( maxHeight - newCssHeight ) / 2 ) + \"px\";\n\n\t// Set the actual canvas pixel dimensions\n\t// TODO-LATER: Change size to css size and use custom upscaling - needs testing\n\t// canvas.width = Math.min( Math.floor( newCssWidth ), MAX_CANVAS_DIMENSION );\n\t// canvas.height = Math.min( Math.floor( newCssHeight ), MAX_CANVAS_DIMENSION );\n\tcanvas.width = Math.min( width, MAX_CANVAS_DIMENSION );\n\tcanvas.height = Math.min( height, MAX_CANVAS_DIMENSION );\n}\n\nfunction getSize( element ) {\n\treturn {\n\t\t\"width\": element.offsetWidth || element.clientWidth || element.width,\n\t\t\"height\": element.offsetHeight || element.clientHeight || element.height\n\t};\n}\n\n", "/**\n * Pi.js - Renderer Module\n * \n * WebGL2 context creation, module orchestration, and public API exports.\n * Main orchestrator for all renderer modules.\n * \n * @module renderer/renderer\n */\n\n\"use strict\";\n\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_utils from \"../core/utils.js\";\n\n// Import renderer modules\nimport * as g_shaders from \"./shaders.js\";\nimport * as g_batches from \"./batches.js\";\n\n// Import shapes module for geometry drawing\nimport * as g_geometry from \"./draw/geometry.js\";\nimport * as g_textures from \"./textures.js\";\nimport * as g_readback from \"./readback.js\";\n\n\n/***************************************************************************************************\n * Public API Exports\n ***************************************************************************************************/\n\n\n// Re-export batch constants\nexport {\n\tPOINTS_BATCH, IMAGE_BATCH, GEOMETRY_BATCH, POINTS_REPLACE_BATCH, IMAGE_REPLACE_BATCH\n} from \"./batches.js\";\n\n// Re-export drawing functions\nexport { drawImage, drawSprite } from \"./draw/sprites.js\";\nexport { drawPixel, drawPixelUnsafe } from \"./draw/primitives.js\";\nexport { drawArc } from \"./draw/arcs.js\";\nexport { drawBezier } from \"./draw/bezier.js\";\nexport { drawLine } from \"./draw/lines.js\";\nexport { drawCachedGeometry } from \"./draw/geometry.js\";\nexport { drawRect, drawRectFilled } from \"./draw/rects.js\";\nexport { drawCircle, drawCircleFilled } from \"./draw/circles.js\";\nexport { drawEllipse } from \"./draw/ellipses.js\";\nexport { shiftImageUp, cls } from \"./effects.js\";\n\n// Re-export batch management\nexport { prepareBatch, flushBatches, displayToCanvas } from \"./batches.js\";\n\n// Re-export texture management\nexport {\n\tgetWebGL2Texture, deleteWebGL2Texture, updateWebGL2TextureImage, updateWebGL2TextureSubImage\n} from \"./textures.js\";\n\n// Re-export readback functions\nexport {\n\treadPixel, readPixelAsync, readPixels, readPixelsAsync, readPixelsRaw\n} from \"./readback.js\";\n\n\n/***************************************************************************************************\n * Module Initialization\n ***************************************************************************************************/\n\nconst m_isDebug = window.location.search.includes( \"webgl-debug\" );\nlet m_offscreenContext = null;\n\n\n/**\n * Initialize all renderer modules\n * \n * @param {Object} api - The main Pi.js API object\n * @returns {void}\n */\nexport function init( api ) {\n\n\t// Add screenData items\n\tg_screenManager.addScreenDataItem( \"contextLost\", false );\n\tg_screenManager.addScreenDataItem( \"isRenderScheduled\", false );\n\tg_screenManager.addScreenDataItem( \"isFirstRender\", true );\n\tg_screenManager.addScreenDataItem( \"gl\", null );\n\tg_screenManager.addScreenDataItem( \"fboTexture\", null );\n\tg_screenManager.addScreenDataItem( \"FBO\", null );\n\tg_screenManager.addScreenDataItem( \"bufferFboTexture\", null );\n\tg_screenManager.addScreenDataItem( \"bufferFBO\", null );\n\n\t// Register renderer cleanup function\n\tg_screenManager.addScreenCleanupFunction( cleanup );\n\n\t// Initialize renderer modules in order\n\tg_shaders.init();\n\tg_batches.init();\n\tg_textures.init();\n\tg_readback.init();\n\tg_geometry.init();\n}\n\n/**\n * Create WebGL2 context for screen\n * \n * @param {Object} screenData - Screen data object\n * @returns {boolean} True if context created successfully\n */\nexport function createContext( screenData ) {\n\n\tlet canvas = screenData.canvas;\n\tconst width = screenData.width;\n\tconst height = screenData.height;\n\t\n\tif( screenData.isOffscreen ) {\n\t\tcanvas = screenData.canvas.canvas;\n\t\tif( !m_offscreenContext ) {\n\t\t\tm_offscreenContext = canvas.getContext( \"webgl2\", { \n\t\t\t\t\"alpha\": true, \n\t\t\t\t\"premultipliedAlpha\": false,\n\t\t\t\t\"antialias\": false,\n\t\t\t\t\"preserveDrawingBuffer\": true,\n\t\t\t\t\"desynchronized\": false,\n\t\t\t\t\"colorType\": \"unorm8\"\n\t\t\t} );\n\t\t}\n\t\tscreenData.gl = m_offscreenContext;\n\t} else {\n\t\tscreenData.gl = canvas.getContext( \"webgl2\", { \n\t\t\t\"alpha\": true, \n\t\t\t\"premultipliedAlpha\": false,\n\t\t\t\"antialias\": false,\n\t\t\t\"preserveDrawingBuffer\": true,\n\t\t\t\"desynchronized\": false,\n\t\t\t\"colorType\": \"unorm8\"\n\t\t} );\n\t}\n\t\n\t// WebGL2 not available\n\tif( !screenData.gl ) {\n\t\tconst error = new Error( \"screen: Failed to create WebGL2 context. WebGL2 is required.\" );\n\t\terror.code = \"WEBGL_ERROR\";\n\t\tthrow error;\n\t}\n\n\t// Setup viewport\n\tscreenData.gl.viewport( 0, 0, width, height );\n\t\n\t// Create texture and FBO\n\tconst fboAndTexture = createTextureAndFBO( screenData );\n\tscreenData.fboTexture = fboAndTexture.fboTexture;\n\tscreenData.FBO = fboAndTexture.FBO;\n\t\n\t// Create a buffer texture and FBO\n\tconst bufferFboAndTexture = createTextureAndFBO( screenData );\n\tscreenData.bufferFboTexture = bufferFboAndTexture.fboTexture;\n\tscreenData.bufferFBO = bufferFboAndTexture.FBO;\n\n\t// Create all the batches\n\tg_batches.createBatches( screenData );\n\n\t// Setup display shader\n\tg_shaders.setupDisplayShader( screenData );\n\n\t// Enable WebGL debugging extensions\n\tif( m_isDebug) {\n\t\tconst debugExt = screenData.gl.getExtension( \"WEBGL_debug_renderer_info\" );\n\t\tif( debugExt ) {\n\t\t\tconsole.log( \"GPU:\", screenData.gl.getParameter( debugExt.UNMASKED_RENDERER_WEBGL ) );\n\t\t}\n\t}\n\t\n\t// Track if webglcontext gets lost\n\tcanvas.addEventListener( \"webglcontextlost\", ( e ) => {\n\t\te.preventDefault();\n\t\tconsole.warn( \"WebGL context lost\" );\n\t\tscreenData.contextLost = true;\n\t} );\n\t\n\t// Reinit canvas when webglcontext gets restored\n\tcanvas.addEventListener( \"webglcontextrestored\", () => {\n\t\tconsole.log( \"WebGL context restored\" );\n\n\t\t// TODO-LATER: Reinitialize WebGL resources\n\t\t// initWebGL( screenData );\n\t\tscreenData.contextLost = false;\n\n\t\t// TODO-LATER: Reset blend mode\n\t\t// blendModeChanged( screenData );\n\t} );\n}\n\n/**\n * Create FBO and texture for screen\n * \n * @param {Object} screenData - Screen data object\n * @returns {boolean} True if FBO created successfully\n */\nfunction createTextureAndFBO( screenData ) {\n\n\tconst gl = screenData.gl;\n\tconst width = screenData.width;\n\tconst height = screenData.height;\n\t\n\t// Create texture\n\tconst fboTexture = gl.createTexture();\n\tif( !fboTexture ) {\n\t\tconst error = new Error( \"screen: Failed to create WebGL2 texture.\" );\n\t\terror.code = \"WEBGL_ERROR\";\n\t\tthrow error;\n\t}\n\n\tgl.bindTexture( gl.TEXTURE_2D, fboTexture );\n\tgl.texImage2D( \n\t\tgl.TEXTURE_2D, 0, gl.RGBA8, \n\t\twidth, height, 0, \n\t\tgl.RGBA, gl.UNSIGNED_BYTE, null \n\t);\n\t\n\t// Set texture parameters for pixel-perfect rendering\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\t\n\t// Create FBO\n\tconst FBO = gl.createFramebuffer();\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, FBO );\n\t\n\t// Attach texture to FBO\n\tgl.framebufferTexture2D(\n\t\tgl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, \n\t\tgl.TEXTURE_2D, fboTexture, 0 \n\t);\n\n\t// Make sure that framebuffer is complete\n\tconst status = gl.checkFramebufferStatus( gl.FRAMEBUFFER );\n\tif( status !== gl.FRAMEBUFFER_COMPLETE ) {\n\t\tconst error = new Error( `screen: WebGL2 Framebuffer incomplete. ${status}` );\n\t\terror.code = \"WEBGL_ERROR\";\n\t\tthrow error;\n\t}\n\n\t// Unbind\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n\tgl.bindTexture( gl.TEXTURE_2D, null );\n\n\treturn { fboTexture, FBO };\n}\n\n/**\n * Cleanup renderer resources for screen\n * \n * @param {Object} screenData - Screen data object\n * @returns {void}\n */\nexport function cleanup( screenData ) {\n\tconst gl = screenData.gl;\n\n\t// Make sure no render gets executed in the microtask\n\tscreenData.isRenderScheduled = false;\n\t\n\t// Cleanup batches\n\tg_batches.cleanup( screenData );\n\n\t// Cleanup display shader\n\tif( screenData.displayProgram ) {\n\t\tgl.deleteProgram( screenData.displayProgram );\n\t\tgl.deleteBuffer( screenData.displayPositionBuffer );\n\t}\n\t\n\t// Cleanup FBO\n\tif( screenData.FBO ) {\n\t\tgl.deleteFramebuffer( screenData.FBO );\n\t\tgl.deleteTexture( screenData.fboTexture );\n\t}\n\n\t// Cleanup Buffe FBO\n\tif( screenData.bufferFBO ) {\n\t\tgl.deleteFramebuffer( screenData.bufferFBO );\n\t\tgl.deleteTexture( screenData.bufferFboTexture );\n\t}\n}\n\n/**\n * Sets the image dirty / Queue automatic render\n * @param {Object} screenData - Screen data object\n * @returns {void}\n */\nexport function setImageDirty( screenData ) {\n\n\tif( !screenData.isRenderScheduled ) {\n\t\tscreenData.isRenderScheduled = true;\n\t\tg_utils.queueMicrotask( () => {\n\t\t\t\n\t\t\t// Make sure render hasn't been cancelled\n\t\t\tif( !screenData.isRenderScheduled ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tg_batches.flushBatches( screenData );\n\t\t\tg_batches.displayToCanvas( screenData );\n\t\t\tscreenData.isRenderScheduled = false;\n\t\t} );\n\t}\n}\n\n/**\n * Called when blend mode changes, flush current batch with old blend mode\n * @param {Object} screenData - Screen data object\n * @param {Object} previousBlends - Blends data including blend mode, noise, seed or null default\n * @returns {void}\n */\nexport function blendModeChanged( screenData, previousBlends ) {\n\n\t// Flush existing batch with old blend mode\n\tg_batches.flushBatches( screenData, previousBlends );\n\tg_batches.displayToCanvas( screenData );\n}\n\nexport function resizeScreen( screenData, oldWidth, oldHeight ) {\n\n\t// Finish rendering to the FBO before resizing\n\tg_batches.flushBatches( screenData );\n\n\tconst gl = screenData.gl;\n\tconst newWidth = screenData.width;\n\tconst newHeight = screenData.height;\n\n\t// Preserve the current contents in the buffer FBO before reallocating\n\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, screenData.FBO );\n\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, screenData.bufferFBO );\n\tgl.clearColor( 0, 0, 0, 0 );\n\tgl.clear( gl.COLOR_BUFFER_BIT );\n\tgl.blitFramebuffer(\n\t\t0, 0, oldWidth, oldHeight,\n\t\t0, 0, oldWidth, oldHeight,\n\t\tgl.COLOR_BUFFER_BIT, gl.NEAREST\n\t);\n\n\t// Resize the primary FBO texture\n\tgl.bindTexture( gl.TEXTURE_2D, screenData.fboTexture );\n\tgl.texImage2D( \n\t\tgl.TEXTURE_2D, 0, gl.RGBA8, \n\t\tnewWidth, newHeight, 0,\n\t\tgl.RGBA, gl.UNSIGNED_BYTE, null \n\t);\n\tgl.bindTexture( gl.TEXTURE_2D, null );\n\n\t// Copy the preserved pixels back into the resized primary FBO\n\tconst copyWidth = Math.min( oldWidth, newWidth );\n\tconst copyHeight = Math.min( oldHeight, newHeight );\n\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, screenData.bufferFBO );\n\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, screenData.FBO );\n\n\t// Need to flip the y-index so the top-left of the screen is preserved if the screen is smaller\n\tconst srcY = Math.max( 0, oldHeight - newHeight );\n\tgl.blitFramebuffer(\n\t\t0, srcY, copyWidth, srcY + copyHeight,\n\t\t0, 0, copyWidth, copyHeight,\n\t\tgl.COLOR_BUFFER_BIT, gl.NEAREST\n\t);\n\n\t// Resize the buffer FBO texture to match the new dimensions\n\tgl.bindTexture( gl.TEXTURE_2D, screenData.bufferFboTexture );\n\tgl.texImage2D( \n\t\tgl.TEXTURE_2D, 0, gl.RGBA8, \n\t\tnewWidth, newHeight, 0,\n\t\tgl.RGBA, gl.UNSIGNED_BYTE, null \n\t);\n\tgl.bindTexture( gl.TEXTURE_2D, null );\n\n\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );\n\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );\n}\n", "#version 300 es\nin vec2 a_position;\nout vec2 v_texCoord;\n\nvoid main() {\n\tgl_Position = vec4(a_position, 0.0, 1.0);\n\n\t// Flip Y coordinate when sampling texture\n\tv_texCoord = (a_position + 1.0) * 0.5;\n}\n\n", "#version 300 es\nprecision mediump float;\nin vec2 v_texCoord;\nuniform sampler2D u_texture;\nout vec4 fragColor;\n\nvoid main() {\n\tvec4 texColor = texture(u_texture, v_texCoord);\n\t\n\t// The FBO already contains STRAIGHT ALPHA, so just output it directly.\n\tfragColor = texColor;\n}\n\n", "/**\n * Pi.js - Shaders Module\n * \n * Shader compilation, program creation, and display shader setup.\n * \n * @module renderer/shaders\n */\n\n\"use strict\";\n\nimport * as g_screenManager from \"../core/screen-manager.js\";\n\n// Shaders are imported from external files via esbuild text loader\nimport m_displayVertSrc from \"./shaders/display.vert\";\nimport m_displayFragSrc from \"./shaders/display.frag\";\n\n\n/***************************************************************************************************\n * Module Initialization\n ***************************************************************************************************/\n\n\n/**\n * Initialize shaders module\n * \n * @returns {void}\n */\nexport function init() {\n\n\tg_screenManager.addScreenDataItem( \"displayProgram\", null );\n\tg_screenManager.addScreenDataItem( \"displayPositionBuffer\", null );\n\tg_screenManager.addScreenDataItem( \"displayLocations\", null );\n}\n\n/**\n * Compile a single shader\n * \n * @param {WebGL2RenderingContext} gl - WebGL2 context\n * @param {number} type - Shader type (VERTEX_SHADER or FRAGMENT_SHADER)\n * @param {string} source - Shader source code\n * @returns {WebGLShader|null} Compiled shader or null on error\n */\nexport function compileShader( gl, type, source ) {\n\n\tconst shader = gl.createShader( type );\n\tgl.shaderSource( shader, source );\n\tgl.compileShader( shader );\n\t\n\tif( !gl.getShaderParameter( shader, gl.COMPILE_STATUS ) ) {\n\t\tconsole.error( \"Shader compile error:\", gl.getShaderInfoLog( shader ) );\n\t\tgl.deleteShader( shader );\n\t\treturn null;\n\t}\n\t\n\treturn shader;\n}\n\n/**\n * Create a linked shader program\n * \n * @param {WebGL2RenderingContext} gl - WebGL2 context\n * @param {string} vertexSrc - Vertex shader source\n * @param {string} fragSrc - Fragment shader source\n * @returns {WebGLProgram|null} Linked program or null on error\n */\nexport function createShaderProgram( gl, vertexSrc, fragSrc ) {\n\n\tconst vertexShader = compileShader( gl, gl.VERTEX_SHADER, vertexSrc );\n\tconst fragmentShader = compileShader( gl, gl.FRAGMENT_SHADER, fragSrc );\n\t\n\tif( !vertexShader || !fragmentShader ) {\n\t\tconst error = new Error( \"screen: Unable to compile shaders.\" );\n\t\terror.code = \"INVALID_SHADERS\";\n\t\tthrow error;\n\t}\n\t\n\tconst program = gl.createProgram();\n\tgl.attachShader( program, vertexShader );\n\tgl.attachShader( program, fragmentShader );\n\tgl.linkProgram( program );\n\n\t// Cleanup shader programs\n\tgl.deleteShader( vertexShader );\n\tgl.deleteShader( fragmentShader );\n\t\n\tif( !gl.getProgramParameter( program, gl.LINK_STATUS ) ) {\n\t\tconst errLog = gl.getProgramInfoLog( program );\n\t\tgl.deleteProgram( program );\n\t\tconst error = new Error( `screen: Shader program error:, ${errLog}.` );\n\t\terror.code = \"SHADER_PROGRAM_ERROR\";\n\t\tthrow error;\n\t}\n\t\n\treturn program;\n}\n\n/**\n * Setup display shader for rendering FBO to screen\n * \n * @param {Object} screenData - Screen data object\n * @returns {void}\n */\nexport function setupDisplayShader( screenData ) {\n\t\n\tconst gl = screenData.gl;\n\t\n\t// Create shader program\n\tconst program = createShaderProgram( gl, m_displayVertSrc, m_displayFragSrc );\n\t\n\t// Create fullscreen quad vertices (NDC: -1 to 1)\n\tconst positions = new Float32Array( [\n\t\t-1, -1, // Bottom left\n\t\t 1, -1, // Bottom right\n\t\t-1,  1, // Top left\n\t\t-1,  1, // Top left\n\t\t 1, -1, // Bottom right\n\t\t 1,  1  // Top right\n\t] );\n\t\n\t// Create vertex buffer\n\tconst positionBuffer = gl.createBuffer();\n\tgl.bindBuffer( gl.ARRAY_BUFFER, positionBuffer );\n\tgl.bufferData( gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW );\n\t\n\t// Get attribute/uniform locations\n\tconst positionLoc = gl.getAttribLocation( program, \"a_position\" );\n\tconst textureLoc = gl.getUniformLocation( program, \"u_texture\" );\n\t\n\t// Store in screen data\n\tscreenData.displayProgram = program;\n\tscreenData.displayPositionBuffer = positionBuffer;\n\tscreenData.displayLocations = {\n\t\t\"position\": positionLoc,\n\t\t\"texture\": textureLoc\n\t};\n}\n\n", "/**\r\n * Pi.js - Blends Module\r\n * \r\n * Manages the api for blending in WebGL2.\r\n * \r\n * @module api/blends\r\n */\r\n\r\n\"use strict\";\r\n\r\n// Import modules directly\r\nimport * as g_screenManager from \"../core/screen-manager.js\";\r\nimport * as g_commands from \"../core/commands.js\";\r\nimport * as g_utils from \"../core/utils.js\";\r\nimport * as g_renderer from \"../renderer/renderer.js\";\r\n\r\n// Blends\r\nexport const BLEND_REPLACE = \"replace\";\r\nexport const BLEND_ALPHA = \"alpha\";\r\nexport const BLENDS = new Set( [ BLEND_REPLACE, BLEND_ALPHA ] );\r\n\r\n\r\n/***************************************************************************************************\r\n * Module Commands\r\n ***************************************************************************************************/\r\n\r\n\r\n// Initialize the blends\r\nexport function init( api ) {\r\n\t\r\n\t// Add Render Screen Data - Store pen and blend configuration only\r\n\tg_screenManager.addScreenDataItem( \"blends\", {\r\n\t\t\"blend\": BLEND_REPLACE, \"noise\": null, \"noiseSeed\": null, \"noiseData\": []\r\n\t} );\r\n\r\n\tregisterCommands();\r\n}\r\n\r\n\r\nfunction registerCommands() {\r\n\tg_commands.addCommand( \"setBlend\", setBlend, true, [ \"blend\" ] );\r\n\tg_commands.addCommand( \"setNoise\", setNoise, true, [ \"noise\", \"seed\" ] );\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * External API Commands\r\n ***************************************************************************************************/\r\n\r\n\r\n// Set Blend Command\r\nfunction setBlend( screenData, options ) {\r\n\tlet blend = options.blend ?? screenData.blends.blend;\r\n\r\n\tif( !BLENDS.has( blend ) ) {\r\n\t\tconst error = new TypeError(\r\n\t\t\t`setBlend: Parameter blend is not a valid blend. Valid blends are (` +\r\n\t\t\t`${Array.from( BLENDS ).join( \", \" )}).`\r\n\t\t);\r\n\t\terror.code = \"INVALID_BLEND_MODE\";\r\n\t\tthrow error;\r\n\t}\r\n\r\n\t// Set blend data on screen\r\n\tconst previousBlend = screenData.blends.blend;\r\n\tconst previousBlends = structuredClone( screenData.blends );\r\n\tscreenData.blends.blend = blend;\r\n\r\n\t// Notify renderer that blend mode has changed\r\n\tif( previousBlend !== blend ) {\r\n\t\tg_renderer.blendModeChanged( screenData, previousBlends );\r\n\t}\r\n}\r\n\r\n\r\n// Set Noise Command\r\nfunction setNoise( screenData, options ) {\r\n\tlet noise = options.noise;\r\n\tlet seed = options.seed;\r\n\r\n\tconst noiseErrorMsg = \"setNoise: Parameter noise must either be a number ie: 32, a 1d array \" +\r\n\t\t\"with numbers ie: [23, 13, 15, 0], or a 2d array where the inner array is two arrays \" +\r\n\t\t\"first array is min values second array is max values for each ie: \" +\r\n\t\t\"[[23, 15, 18, 0], [32,18, 12, 0]]. The order of items in the inner array is \" +\r\n\t\t\"[red, green, blue, alpha].\";\r\n\r\n\tlet noiseResult = null;\r\n\r\n\t// Only process noise if it's provided\r\n\tif( noise !== null ) {\r\n\r\n\t\t// Validate the noise option\r\n\t\tconst validateNoiseValFn = ( noiseVal ) => {\r\n\t\t\tif( noiseVal === null ) {\r\n\t\t\t\tconst error = new TypeError( noiseErrorMsg );\r\n\t\t\t\terror.code = \"INVALID_NOISE_VALUE\";\r\n\t\t\t\tthrow error;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// First validate noise if it's an array\r\n\t\tif( Array.isArray( noise ) ) {\r\n\r\n\t\t\t// Create a blank noise result\r\n\t\t\tnoiseResult = [\r\n\t\t\t\tnew Float32Array( [ 0, 0, 0, 0 ] ), new Float32Array( [ 0, 0, 0, 0 ] )\r\n\t\t\t];\r\n\r\n\t\t\t// Loop through the array max of 4 items\r\n\t\t\tfor( let i = 0; i < noise.length && i < 4; i += 1 ) {\r\n\r\n\t\t\t\tconst noiseRow = noise[ i ];\r\n\t\t\r\n\t\t\t\t// Validate if 2d array\r\n\t\t\t\tif( Array.isArray( noiseRow ) ) {\r\n\r\n\t\t\t\t\t// If 2d array ignore any result after 2nd item\r\n\t\t\t\t\tif( i >= 2 ) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Loop through inner array max of 4 items\r\n\t\t\t\t\tfor( let j = 0; j < noiseRow.length && j < 4; j += 1 ) {\r\n\t\t\t\t\t\tconst noiseVal = g_utils.getInt( noiseRow[ j ], null );\r\n\t\t\t\t\t\tvalidateNoiseValFn( noiseVal );\r\n\t\t\t\t\t\tnoiseResult[ i ][ j ] = noiseVal / 255;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst noiseVal = g_utils.getInt( noiseRow, null );\r\n\t\t\t\t\tvalidateNoiseValFn( noiseVal );\r\n\r\n\t\t\t\t\t// Update min and max values based on parallel values\r\n\t\t\t\t\tnoiseResult[ 0 ][ i ] = -noiseVal / 255;\r\n\t\t\t\t\tnoiseResult[ 1 ][ i ] = noiseVal / 255;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\r\n\t\t\t// Validate if noise is an integer\r\n\t\t\tconst noiseVal = g_utils.getInt( noise, null );\r\n\r\n\t\t\t// If noise is an integer it will not be null\r\n\t\t\tif( noiseVal !== null ) {\r\n\t\t\t\tconst val = noiseVal / 255;\r\n\t\t\t\tnoiseResult = [\r\n\t\t\t\t\tnew Float32Array( [ -val, -val, -val, -val ] ),\r\n\t\t\t\t\tnew Float32Array( [  val,  val,  val,  val ] ),\r\n\t\t\t\t];\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// Set seed - if null, use time\r\n\tlet noiseSeed = g_utils.getFloat( seed, null );\r\n\r\n\t// Set noise data on screen\r\n\tconst previousNoise = screenData.blends.noise;\r\n\tconst previousSeed = screenData.blends.noiseSeed;\r\n\tconst previousBlends = structuredClone( screenData.blends );\r\n\r\n\tscreenData.blends.noise = noiseResult;\r\n\tscreenData.blends.noiseSeed = noiseSeed;\r\n\r\n\t// Check if noise has changed\r\n\tlet isNoiseChanged = false;\r\n\tif( previousNoise === null && noiseResult === null ) {\r\n\t\tisNoiseChanged = false;\r\n\t} else if(\r\n\t\tpreviousNoise === null && noiseResult !== null ||\r\n\t\tpreviousNoise !== null && noiseResult === null\r\n\t) {\r\n\t\tisNoiseChanged = true;\r\n\t} else {\r\n\t\tisNoiseChanged = JSON.stringify( previousNoise ) !== JSON.stringify( noiseResult );\r\n\t}\r\n\r\n\t// Check if seed has changed\r\n\tconst isSeedChanged = previousSeed !== noiseSeed;\r\n\r\n\t// Notify renderer that noise or seed has changed\r\n\tif( isNoiseChanged || isSeedChanged ) {\r\n\t\tg_renderer.blendModeChanged( screenData, previousBlends );\r\n\t}\r\n}\r\n", "#version 300 es\nin vec2 a_position;\nin vec4 a_color;\nuniform vec2 u_resolution;\nout vec4 v_color;\n\nvoid main() {\n\n\t// Convert screen coords to NDC with pixel center adjustment\n\t// Add 0.5 to center the pixel, then convert to NDC\n\tvec2 pixelCenter = a_position + 0.5;\n\tvec2 ndc = ((pixelCenter / u_resolution) * 2.0 - 1.0) * vec2(1.0, -1.0);\n\tgl_Position = vec4(ndc, 0.0, 1.0);\n\tgl_PointSize = 1.0;\n\tv_color = a_color;\n}\n\n", "#version 300 es\nprecision mediump float;\nin vec4 v_color;\nuniform vec4 u_noiseMin;\nuniform vec4 u_noiseMax;\nuniform float u_time;\nout vec4 fragColor;\n\n// A hash function that works with integer coordinates\n// This tends to be very effective at breaking coherence.\nfloat hash(vec2 p) {\n\tp = fract(p * vec2(5.3983, 5.4439));\n\tp += dot(p, p.yx + 2.153); // Add a small value to break symmetry\n\treturn fract(p.x * p.y * 954.3121);\n}\n\n// Map value from [0,1] range to [min,max] range\nfloat mapRange(float value, float min, float max) {\n\treturn min + value * (max - min);\n}\n\nvoid main() {\n\n\tvec4 baseColor = v_color;\n\tvec4 pixelNoise = vec4(0.0);\n\n\tfloat noiseRange = abs(u_noiseMax.r - u_noiseMin.r) +\n\t                   abs(u_noiseMax.g - u_noiseMin.g) +\n\t                   abs(u_noiseMax.b - u_noiseMin.b) +\n\t                   abs(u_noiseMax.a - u_noiseMin.a);\n\n\tif (noiseRange > 0.0001) {\n\n\t\t// Use integer coordinates for the hash function\n\t\t// This is critical for noise that looks truly random at pixel level\n\t\tvec2 iFragCoord = floor(gl_FragCoord.xy);\n\n\t\t// Combine iFragCoord with u_time and different offsets for each channel\n\t\t// The offsets here can be smaller because the hash itself is strong.\n\t\tfloat noiseR = hash(iFragCoord + vec2(u_time * 0.01, u_time * 0.02) + vec2(10.0, 20.0));\n\t\tfloat noiseG = hash(iFragCoord + vec2(u_time * 0.03, u_time * 0.04) + vec2(30.0, 40.0));\n\t\tfloat noiseB = hash(iFragCoord + vec2(u_time * 0.05, u_time * 0.06) + vec2(50.0, 60.0));\n\t\tfloat noiseA = hash(iFragCoord + vec2(u_time * 0.07, u_time * 0.08) + vec2(70.0, 80.0));\n\n\t\tpixelNoise.r = mapRange(noiseR, u_noiseMin.r, u_noiseMax.r);\n\t\tpixelNoise.g = mapRange(noiseG, u_noiseMin.g, u_noiseMax.g);\n\t\tpixelNoise.b = mapRange(noiseB, u_noiseMin.b, u_noiseMax.b);\n\t\tpixelNoise.a = mapRange(noiseA, u_noiseMin.a, u_noiseMax.a);\n\t}\n\n\tvec4 finalColor = baseColor + pixelNoise;\n\tfragColor = clamp(finalColor, 0.0, 1.0);\n}", "#version 300 es\nin vec4 a_position;\nin vec4 a_color;\nin vec2 a_texCoord;\n\nuniform vec2 u_resolution;\n\nout vec4 v_color;\nout vec2 v_texCoord;\n\nvoid main() {\n\t\n\t// Convert from pixel space (0 to u_resolution) to clip space (-1 to 1)\n\tvec2 zeroToOne = a_position.xy / u_resolution;\n\tvec2 zeroToTwo = zeroToOne * 2.0;\n\tvec2 clipSpace = zeroToTwo - 1.0;\n\n\t// Flip the Y-coordinate to match standard 2D graphics (top-left origin)\n\t// In WebGL, +Y is typically up, but for 2D, we want +Y down.\n\tgl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\n\tv_color = a_color;\n\tv_texCoord = a_texCoord;\n}\n\n", "#version 300 es\nprecision highp float;\n\nin vec4 v_color;\nin vec2 v_texCoord;\n\nuniform sampler2D u_texture;\n\nout vec4 outColor;\n\nvoid main() {\n\n\t// Sample the color from the texture at the given texture coordinates\n\tvec4 texColor = texture(u_texture, v_texCoord);\n\n\t// Multiply the texture color by the vertex color (which can be used for tinting/alpha)\n\t// If v_color is white (1,1,1,1), it will just use the texColor.\n\toutColor = texColor * v_color;\n}\n\n", "#version 300 es\nin vec2 a_position;\nin vec4 a_color;\nuniform vec2 u_resolution;\nout vec4 v_color;\n\nvoid main() {\n\t\n\t// For TRIANGLES/LINES, a_position directly represents the desired vertex\n\t// position (e.g., top-left of a pixel boundary).\n\t// No 0.5 offset needed for precise geometry rasterization.\n\tvec2 ndc = ((a_position / u_resolution) * 2.0 - 1.0) * vec2(1.0, -1.0);\n\tgl_Position = vec4(ndc, 0.0, 1.0);\n\tv_color = a_color;\n}", "/**\r\n * Pi.js - Batches and Rendering Module\r\n * \r\n * Batch system for rendering points and images efficiently.\r\n * Combines batch management and rendering operations.\r\n * \r\n * @module api/renderer/batches\r\n */\r\n\r\n\"use strict\";\r\n\r\nimport * as g_shaders from \"./shaders.js\";\r\nimport * as g_screenManager from \"../core/screen-manager.js\";\r\n\r\n// Import blend mode constants\r\nimport * as g_blends from \"../api/blends.js\";\r\n\r\n// Shaders are imported from external files via esbuild text loader\r\nimport m_pointVertSrc from \"./shaders/point.vert\";\r\nimport m_pointFragSrc from \"./shaders/point.frag\";\r\nimport m_imageVertSrc from \"./shaders/image.vert\";\r\nimport m_imageFragSrc from \"./shaders/image.frag\";\r\nimport m_gemoetryVertSrc from \"./shaders/geometry.vert\";\r\n\r\n\r\n/***************************************************************************************************\r\n * Constants\r\n ***************************************************************************************************/\r\n\r\n\r\nexport const POINTS_BATCH = 0;\r\nexport const IMAGE_BATCH = 1;\r\nexport const GEOMETRY_BATCH = 2;\r\nexport const POINTS_REPLACE_BATCH = 3;\r\nexport const IMAGE_REPLACE_BATCH = 4;\r\n\r\n// Resize by doubling up to 8 times\r\nconst MAX_SIZE_MULTIPLIER = Math.pow( 2, 8 );\r\n\r\n// Set point batch size to 7500 defautl up to 1_920_000\r\nconst DEFAULT_POINT_BATCH_SIZE = 7500;\r\nconst MAX_POINT_BATCH_SIZE = DEFAULT_POINT_BATCH_SIZE * MAX_SIZE_MULTIPLIER;\r\n\r\n// Set image batch size to 700 defautl up to 179_200\r\nconst DEFAULT_IMAGE_BATCH_SIZE = 700;\r\nconst MAX_IMAGE_BATCH_SIZE = DEFAULT_IMAGE_BATCH_SIZE * MAX_SIZE_MULTIPLIER;\r\n\r\n// Set geometry batch size to 800 default up to 204_800\r\nconst DEFAULT_GEOMETRY_BATCH_SIZE = 800;\r\nconst MAX_GEOMETRY_BATCH_SIZE = DEFAULT_GEOMETRY_BATCH_SIZE * MAX_SIZE_MULTIPLIER;\r\n\r\n// Batch will automatically shrink by 1/2 every 5 seconds if capacity is not used\r\nconst BATCH_CAPACITY_SHRINK_INTERVAL = 5000;\r\n\r\n// String constants to identify batch system names\r\nconst BATCH_TYPES = [ \"POINTS\", \"IMAGE\", \"GEOMETRY\", \"POINTS_REPLACE\", \"IMAGE_REPLACE\" ];\r\n\r\n// Batch prototype\r\nconst m_batchProto = {\r\n\t\r\n\t// Type of batch POINTS_BATCH, IMAGE_BATCH, etc...\r\n\t\"type\": null,\r\n\t\"overrideGlobalBlend\": null,   // Tri-state: null = use default, true = alpha, false = replace\r\n\r\n\t\"program\": null,\r\n\t\"vertices\": null,\r\n\t\"colors\": null,\r\n\t\"count\": 0,\r\n\r\n\t// Capacity\r\n\t\"minCapacity\": 0,\r\n\t\"capacity\": 0,\r\n\t\"maxCapacity\": 0,\r\n\t\"capacityChanged\": true,\r\n\t\"capacityLocalMax\": 0,\r\n\t\"capacityShrinkCheckTime\": 0,\r\n\r\n\t// Components\r\n\t\"vertexComps\": 2,\r\n\t\"colorComps\": 4,\r\n\t\"texCoordComps\": 2,\r\n\r\n\t// WebGL resources\r\n\t\"vertexVBO\": null,\r\n\t\"colorVBO\": null,\r\n\t\"texCoordVBO\": null,\r\n\t\"vao\": null,\r\n\r\n\t// Image Specific items\r\n\t\"useTexture\": false,\r\n\t\"texture\": null,\r\n\r\n\t// Drawing mode, e.g., gl.POINTS or gl.TRIANGLES\r\n\t\"mode\": null,\r\n\r\n\t// Cached shader locations\r\n\t\"locations\": null\r\n};\r\n\r\nconst m_isDebug = window.location.search.includes( \"webgl-debug\" );\r\n\r\n\r\n/***************************************************************************************************\r\n * Module Initialization\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Initialize batch and rendering module\r\n * \r\n * @returns {void}\r\n */\r\nexport function init() {\r\n\r\n\t// Initialize screenData items owned by the batch system\r\n\tg_screenManager.addScreenDataItem( \"batches\", {} );\r\n\tg_screenManager.addScreenDataItem( \"batchInfo\", {\r\n\t\t\"currentBatch\": null,\r\n\t\t\"drawOrder\": [],\r\n\t\t\"textureBatchSet\": new Set()\r\n\t} );\r\n}\r\n\r\n/**\r\n * Creates all the batches\r\n * \r\n * @returns {void}\r\n */\r\nexport function createBatches( screenData ) {\r\n\r\n\t// Create the point batch\r\n\tscreenData.batches[ POINTS_BATCH ] = createBatch( screenData, POINTS_BATCH );\r\n\tscreenData.batches[ IMAGE_BATCH ] = createBatch( screenData, IMAGE_BATCH );\r\n\tscreenData.batches[ GEOMETRY_BATCH ] = createBatch( screenData, GEOMETRY_BATCH );\r\n\tscreenData.batches[ POINTS_REPLACE_BATCH ] = createBatch( screenData, POINTS_REPLACE_BATCH );\r\n\tscreenData.batches[ IMAGE_REPLACE_BATCH ] = createBatch( screenData, IMAGE_REPLACE_BATCH );\r\n}\r\n\r\n/**\r\n * Create batch system for points or images\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {number} type - Batch type (POINTS_BATCH or IMAGE_BATCH, etc..)\r\n * @returns {Object|null} Batch object or null on error\r\n */\r\nexport function createBatch( screenData, type ) {\r\n\r\n\tconst gl = screenData.gl;\r\n\tconst batch = Object.create( m_batchProto );\r\n\r\n\t// Get shader sources based on batch type\r\n\tlet vertSrc, fragSrc;\r\n\tif( type === POINTS_BATCH ) {\r\n\t\tvertSrc = m_pointVertSrc;\r\n\t\tfragSrc = m_pointFragSrc;\r\n\t\tbatch.capacity = DEFAULT_POINT_BATCH_SIZE;\r\n\t\tbatch.minCapacity = DEFAULT_POINT_BATCH_SIZE;\r\n\t\tbatch.maxCapacity = MAX_POINT_BATCH_SIZE;\r\n\t\tbatch.mode = gl.POINTS;\r\n\t} else if( type === IMAGE_BATCH || type === IMAGE_REPLACE_BATCH ) {\r\n\t\tvertSrc = m_imageVertSrc;\r\n\t\tfragSrc = m_imageFragSrc;\r\n\t\tbatch.capacity = DEFAULT_IMAGE_BATCH_SIZE;\r\n\t\tbatch.minCapacity = DEFAULT_IMAGE_BATCH_SIZE;\r\n\t\tbatch.maxCapacity = MAX_IMAGE_BATCH_SIZE;\r\n\t\tbatch.mode = gl.TRIANGLES;\r\n\t\tbatch.useTexture = true;\r\n\t\tif( type === IMAGE_BATCH ) {\r\n\t\t\tbatch.overrideGlobalBlend = true;\r\n\t\t}\r\n\t} else if( type === GEOMETRY_BATCH ) {\r\n\t\tvertSrc = m_gemoetryVertSrc;\r\n\t\tfragSrc = m_pointFragSrc;\r\n\t\tbatch.capacity = DEFAULT_GEOMETRY_BATCH_SIZE;\r\n\t\tbatch.minCapacity = DEFAULT_GEOMETRY_BATCH_SIZE;\r\n\t\tbatch.maxCapacity = MAX_GEOMETRY_BATCH_SIZE;\r\n\t\tbatch.mode = gl.TRIANGLES;\r\n\t} else if( type === POINTS_REPLACE_BATCH ) {\r\n\t\tvertSrc = m_pointVertSrc;\r\n\t\tfragSrc = m_pointFragSrc;\r\n\t\tbatch.capacity = DEFAULT_POINT_BATCH_SIZE;\r\n\t\tbatch.minCapacity = DEFAULT_POINT_BATCH_SIZE;\r\n\t\tbatch.maxCapacity = MAX_POINT_BATCH_SIZE;\r\n\t\tbatch.mode = gl.POINTS;\r\n\t\tbatch.overrideGlobalBlend = false;\r\n\t} else {\r\n\t\tthrow `createBatch: Unknown batch type ${type}`;\r\n\t}\r\n\r\n\t// Create the batch shader program\r\n\tbatch.program = g_shaders.createShaderProgram( gl, vertSrc, fragSrc );\r\n\r\n\t// Cache shader locations for efficiency\r\n\tbatch.locations = {\r\n\t\t\"position\": gl.getAttribLocation( batch.program, \"a_position\" ),\r\n\t\t\"color\": gl.getAttribLocation( batch.program, \"a_color\" ),\r\n\t\t\"resolution\": gl.getUniformLocation( batch.program, \"u_resolution\" )\r\n\t};\r\n\r\n\t// Add noise uniform locations for batches that use point shaders\r\n\tif(\r\n\t\ttype === POINTS_BATCH || type === POINTS_REPLACE_BATCH || type === GEOMETRY_BATCH\r\n\t) {\r\n\t\tbatch.locations.noiseMin = gl.getUniformLocation( batch.program, \"u_noiseMin\" );\r\n\t\tbatch.locations.noiseMax = gl.getUniformLocation( batch.program, \"u_noiseMax\" );\r\n\t\tbatch.locations.time = gl.getUniformLocation( batch.program, \"u_time\" );\r\n\t}\r\n\r\n\t// Setup batch type and capacity\r\n\tbatch.type = type;\r\n\r\n\t// Setup image specific webgl variables\r\n\tif( batch.useTexture === true ) {\r\n\r\n\t\t// Image-specific shader locations\r\n\t\tbatch.locations.texCoord = gl.getAttribLocation( batch.program, \"a_texCoord\" );\r\n\t\tbatch.locations.texture = gl.getUniformLocation( batch.program, \"u_texture\" );\r\n\r\n\t\t// Image-specific data array\r\n\t\tbatch.texCoords = new Float32Array( batch.capacity * batch.texCoordComps );\r\n\r\n\t\t// Image-specific VBO\r\n\t\tbatch.texCoordVBO = gl.createBuffer();\r\n\t}\r\n\r\n\t// These are created for all batches\r\n\tbatch.vertices = new Float32Array( batch.capacity * batch.vertexComps );\r\n\tbatch.colors = new Uint8Array( batch.capacity * batch.colorComps );\r\n\tbatch.vertexVBO = gl.createBuffer();\r\n\tbatch.colorVBO = gl.createBuffer();\r\n\r\n\t// Create VAO (WebGL2 only)\r\n\tbatch.vao = gl.createVertexArray();\r\n\tgl.bindVertexArray( batch.vao );\r\n\r\n\t// Setup position attribute\r\n\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.vertexVBO );\r\n\tgl.enableVertexAttribArray( batch.locations.position );\r\n\tgl.vertexAttribPointer(\r\n\t\tbatch.locations.position, batch.vertexComps, gl.FLOAT, false, 0, 0\r\n\t);\r\n\r\n\t// Setup color attribute\r\n\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.colorVBO );\r\n\tgl.enableVertexAttribArray( batch.locations.color );\r\n\tgl.vertexAttribPointer(\r\n\t\tbatch.locations.color, batch.colorComps, gl.UNSIGNED_BYTE, true, 0, 0\r\n\t);\r\n\r\n\t// Setup texCoord attribute for image batches\r\n\tif( batch.useTexture === true ) {\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.texCoordVBO );\r\n\t\tgl.enableVertexAttribArray( batch.locations.texCoord );\r\n\t\tgl.vertexAttribPointer(\r\n\t\t\tbatch.locations.texCoord, batch.texCoordComps, gl.FLOAT, false, 0, 0\r\n\t\t);\r\n\t}\r\n\r\n\tgl.bindVertexArray( null );\r\n\r\n\t// Set the next shrink check time\r\n\tbatch.capacityShrinkCheckTime = Date.now() + BATCH_CAPACITY_SHRINK_INTERVAL;\r\n\r\n\treturn batch;\r\n}\r\n\r\n/**\r\n * Resize batch to new capacity\r\n * \r\n * @param {Object} batch - Batch object\r\n * @param {number} newCapacity - New capacity\r\n * @returns {void}\r\n */\r\nfunction resizeBatch( batch, newCapacity ) {\r\n\r\n\t// Resize arrays\r\n\tconst newVertices = new Float32Array( newCapacity * batch.vertexComps );\r\n\tconst newColors = new Uint8Array( newCapacity * batch.colorComps );\r\n\t\r\n\t// Copy existing data only if there is data to copy\r\n\t// When shrinking after flush, count is 0 so no copy is needed\r\n\tif( batch.count > 0 ) {\r\n\t\tnewVertices.set( batch.vertices.subarray( 0, batch.count * batch.vertexComps ) );\r\n\t\tnewColors.set( batch.colors.subarray( 0, batch.count * batch.colorComps ) );\r\n\t}\r\n\t\r\n\tbatch.vertices = newVertices;\r\n\tbatch.colors = newColors;\r\n\t\r\n\tif( batch.useTexture === true ) {\r\n\t\tconst newTexCoords = new Float32Array( newCapacity * batch.texCoordComps );\r\n\t\t\r\n\t\t// Copy existing texture coordinates only if there is data to copy\r\n\t\tif( batch.count > 0 ) {\r\n\t\t\tnewTexCoords.set( batch.texCoords.subarray( 0, batch.count * batch.texCoordComps ) );\r\n\t\t}\r\n\t\t\r\n\t\tbatch.texCoords = newTexCoords;\r\n\t}\r\n\r\n\tif( m_isDebug ) {\r\n\t\tconsole.log(\r\n\t\t\t`Batch ${BATCH_TYPES[ batch.type ]} resized from ${batch.capacity} to ${newCapacity}`\r\n\t\t);\r\n\t}\r\n\r\n\t// Update batch\r\n\tbatch.capacity = newCapacity;\r\n\tbatch.capacityChanged = true;\r\n\r\n\t// Set the time capacity last changed\r\n\tbatch.capacityShrinkCheckTime = Date.now() + BATCH_CAPACITY_SHRINK_INTERVAL;\r\n}\r\n\r\n/**\r\n * Ensure batch has capacity for items\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {number} batchType - Batch type\r\n * @param {number} itemCount - Number of items needed\r\n * @param {WebGLTexture} [texture] - Texture for images\r\n * @returns {void}\r\n */\r\nexport function prepareBatch( screenData, batchType, itemCount, texture ) {\r\n\r\n\t// Get the batch\r\n\tconst batch = screenData.batches[ batchType ];\r\n\r\n\t// Track if the batch type is changing or texture is changing (for image batches)\r\n\tconst batchInfo = screenData.batchInfo;\r\n\tconst batchTypeChanging = batchInfo.currentBatch !== batch;\r\n\tconst textureChanging = batch.useTexture === true &&\r\n\t\tbatchInfo.currentBatch === batch && batch.texture !== texture;\r\n\r\n\tif( batchTypeChanging || textureChanging ) {\r\n\t\t\r\n\t\t// Set the end index for the last drawOrderItem to it's current count\r\n\t\tif( batchInfo.drawOrder.length > 0 ) {\r\n\t\t\tconst lastDrawOrderItem = batchInfo.drawOrder[ batchInfo.drawOrder.length - 1 ];\r\n\t\t\tlastDrawOrderItem.endIndex = lastDrawOrderItem.batch.count;\r\n\t\t}\r\n\r\n\t\t// Create a new draw order item\r\n\t\tconst drawOrderItem = {\r\n\t\t\t\"batch\": batch,\r\n\t\t\t\"startIndex\": batch.count,\r\n\t\t\t\"endIndex\": null,\r\n\t\t\t\"overrideGlobalBlend\": batch.overrideGlobalBlend\r\n\t\t};\r\n\t\t\r\n\t\t// For image batches, track the current image/texture for this segment\r\n\t\tif( batch.useTexture === true ) {\r\n\t\t\tbatch.texture = texture;\r\n\t\t\tdrawOrderItem.texture = texture;\r\n\t\t\tbatchInfo.textureBatchSet.add( texture );\r\n\t\t}\r\n\r\n\t\t// Add the draw order item\r\n\t\tbatchInfo.drawOrder.push( drawOrderItem );\r\n\t\tbatchInfo.currentBatch = batch;\r\n\t}\r\n\r\n\t// Check if need to increase capacity\r\n\tconst requiredCount = batch.count + itemCount;\r\n\tif( requiredCount >= batch.capacity ) {\r\n\r\n\t\t// Make sure we don't exceed max batch size\r\n\t\tif( requiredCount > batch.maxCapacity ) {\r\n\t\t\tif( m_isDebug ) {\r\n\t\t\t\tconsole.log(\r\n\t\t\t\t\t`Batch ${BATCH_TYPES[ batch.type ]} exceeded maxCapacity ` +\r\n\t\t\t\t\t`${batch.maxCapacity}, requested ${requiredCount}.  Flushing batch to reset` +\r\n\t\t\t\t\t` count to 0.`\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t\r\n\t\t\tflushBatches( screenData );\r\n\t\t\treturn prepareBatch( screenData, batchType, itemCount, texture );\r\n\t\t}\r\n\r\n\t\t// Resize to new capacity by doubling current capacity up to maxCapacity\r\n\t\tconst newCapacity = Math.max(\r\n\t\t\trequiredCount, Math.min( batch.capacity * 2, batch.maxCapacity )\r\n\t\t);\r\n\t\tresizeBatch( batch, newCapacity );\r\n\t}\r\n}\r\n\r\n/**\r\n * Flush all batches to FBO\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object|null} blends - Blends data including blend mode, noise, seed or null for default\r\n * @param {Array<Float32Array>|null} noise - Noise values\r\n * @returns {void}\r\n */\r\nexport function flushBatches( screenData, blends = null ) {\r\n\tif( blends === null ) {\r\n\t\tblends = screenData.blends;\r\n\t}\r\n\t\r\n\tconst gl = screenData.gl;\r\n\r\n\tif( screenData.contextLost ) {\r\n\r\n\t\t// TODO-LATER: Maybe add warning here?\r\n\t\t// console.warn( \"WebGL context lost unable to render screen.\" );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Bind FBO\r\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, screenData.FBO );\r\n\t\r\n\t// Set viewport\r\n\tgl.viewport( 0, 0, screenData.width, screenData.height );\r\n\t\r\n\t// Clear FBO on first render only\r\n\tif( screenData.isFirstRender ) {\r\n\t\tgl.clearColor( 0, 0, 0, 0 );\r\n\t\tgl.clear( gl.COLOR_BUFFER_BIT );\r\n\t\tscreenData.isFirstRender = false;\r\n\t}\r\n\r\n\t// Upload batch buffers\r\n\tfor( const batchType in screenData.batches ) {\r\n\t\tconst batch = screenData.batches[ batchType ];\r\n\t\tif( batch.count > 0 ) {\r\n\t\t\tuploadBatch( gl, batch, screenData.width, screenData.height );\r\n\t\t}\r\n\t}\r\n\r\n\t// Draw items\r\n\tfor( const drawOrderItem of screenData.batchInfo.drawOrder ) {\r\n\t\tif( drawOrderItem.endIndex === null ) {\r\n\t\t\tdrawOrderItem.endIndex = drawOrderItem.batch.count;\r\n\t\t}\r\n\r\n\t\t// Only draw the batch if there is something to draw\r\n\t\tif( drawOrderItem.endIndex - drawOrderItem.startIndex > 0 ) {\r\n\r\n\t\t\t// Set blend mode for this item\r\n\t\t\tif( drawOrderItem.overrideGlobalBlend === null ) {\r\n\r\n\t\t\t\t// Other batches use global blend mode\r\n\t\t\t\tif( blends.blend === g_blends.BLEND_REPLACE ) {\r\n\t\t\t\t\tgl.disable( gl.BLEND );\r\n\t\t\t\t} else {\r\n\t\t\t\t\tgl.enable( gl.BLEND );\r\n\t\t\t\t\tgl.blendFuncSeparate(\r\n\t\t\t\t\t\tgl.SRC_ALPHA,           // srcRGBFactor\r\n\t\t\t\t\t\tgl.ONE_MINUS_SRC_ALPHA, // dstRGBFactor\r\n\t\t\t\t\t\tgl.ONE,                 // srcAlphaFactor - src alpha factor 1.0 (no scale)\r\n\t\t\t\t\t\tgl.ONE_MINUS_SRC_ALPHA  // dstAlphaFactor - dst alpha factor (1-src.a)\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\r\n\t\t\t} else if( drawOrderItem.overrideGlobalBlend === true ) {\r\n\r\n\t\t\t\t// IMAGE_BATCH always uses alpha blending\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\t\t\t\tgl.blendFuncSeparate(\r\n\t\t\t\t\tgl.SRC_ALPHA,           // srcRGBFactor\r\n\t\t\t\t\tgl.ONE_MINUS_SRC_ALPHA, // dstRGBFactor\r\n\t\t\t\t\tgl.ONE,                 // srcAlphaFactor - src alpha factor 1.0 (no scale)\r\n\t\t\t\t\tgl.ONE_MINUS_SRC_ALPHA  // dstAlphaFactor - dst alpha factor (1-src.a)\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\tgl.disable( gl.BLEND );\r\n\t\t\t}\r\n\r\n\t\t\tlet texture = null;\r\n\t\t\tif( drawOrderItem.batch.useTexture === true ) {\r\n\t\t\t\ttexture = drawOrderItem.texture;\r\n\t\t\t}\r\n\t\t\tdrawBatch(\r\n\t\t\t\tgl, screenData, drawOrderItem.batch,\r\n\t\t\t\tdrawOrderItem.startIndex, drawOrderItem.endIndex, texture, blends\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t// Reset Batches\r\n\tfor( const batchType in screenData.batches ) {\r\n\t\tconst batch = screenData.batches[ batchType ];\r\n\t\tresetBatch( batch );\r\n\t}\r\n\r\n\t// Reset drawOrder object\r\n\tscreenData.batchInfo.drawOrder = [];\r\n\tscreenData.batchInfo.currentBatch = null;\r\n\tscreenData.batchInfo.textureBatchSet.clear();\r\n\r\n\t// Unbind VAO\r\n\tgl.bindVertexArray( null );\r\n\r\n\t// Unbind FBO\r\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\r\n}\r\n\r\n/**\r\n * Upload batch data to GPU\r\n * \r\n * @param {WebGL2RenderingContext} gl - WebGL2 context\r\n * @param {Object} batch - Batch object\r\n * @param {number} width - Screen width\r\n * @param {number} height - Screen height\r\n * @returns {void}\r\n */\r\nfunction uploadBatch( gl, batch, width, height ) {\r\n\tgl.useProgram( batch.program );\r\n\tgl.uniform2f( batch.locations.resolution, width, height );\r\n\tgl.bindVertexArray( batch.vao );\r\n\t\r\n\t// Allocate or resize buffers on capacity change\r\n\tif( batch.capacityChanged ) {\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.vertexVBO );\r\n\t\tgl.bufferData( gl.ARRAY_BUFFER, batch.vertices.byteLength, gl.STREAM_DRAW );\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.colorVBO );\r\n\t\tgl.bufferData( gl.ARRAY_BUFFER, batch.colors.byteLength, gl.STREAM_DRAW );\r\n\r\n\t\tif( batch.useTexture === true ) {\r\n\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.texCoordVBO );\r\n\t\t\tgl.bufferData( gl.ARRAY_BUFFER, batch.texCoords.byteLength, gl.STREAM_DRAW );\r\n\t\t}\r\n\r\n\t\tbatch.capacityChanged = false;\r\n\t}\r\n\r\n\t// Upload positions\r\n\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.vertexVBO );\r\n\tgl.bufferSubData( \r\n\t\tgl.ARRAY_BUFFER, 0, batch.vertices.subarray( 0, batch.count * batch.vertexComps )\r\n\t);\r\n\t\r\n\t// Upload colors\r\n\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.colorVBO );\r\n\tgl.bufferSubData(\r\n\t\tgl.ARRAY_BUFFER, 0, batch.colors.subarray( 0, batch.count * batch.colorComps )\r\n\t);\r\n\r\n\t// Upload texture coordinates\r\n\tif( batch.useTexture === true ) {\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, batch.texCoordVBO );\r\n\t\tgl.bufferSubData(\r\n\t\t\tgl.ARRAY_BUFFER, 0, batch.texCoords.subarray( 0, batch.count * batch.texCoordComps )\r\n\t\t);\r\n\t}\r\n}\r\n\r\n/**\r\n * Draw batch to FBO\r\n * \r\n * @param {WebGL2RenderingContext} gl - WebGL2 context\r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} batch - Batch object\r\n * @param {number} startIndex - Start index in batch\r\n * @param {number} endIndex - End index in batch\r\n * @param {WebGLTexture|null} texture - Texture for image batches or null\r\n * @param {Object} blends - Blends data including blend mode, noise, seed or null default\r\n * @returns {void}\r\n */\r\nfunction drawBatch( gl, screenData, batch, startIndex, endIndex, texture = null, blends = null ) {\r\n\r\n\tgl.useProgram( batch.program );\r\n\tgl.bindVertexArray( batch.vao );\r\n\r\n\t// For image batches, bind the texture and set uniform\r\n\tif( batch.useTexture === true && texture ) {\r\n\t\tgl.activeTexture( gl.TEXTURE0 );\r\n\t\tgl.bindTexture( gl.TEXTURE_2D, texture );\r\n\t\tgl.uniform1i( batch.locations.texture, 0 );\r\n\t}\r\n\r\n\t// Set noise uniforms for batches that use point shaders\r\n\tif( batch.locations.noiseMin !== undefined ) {\r\n\t\tif( blends === null ) {\r\n\t\t\tblends = screenData.blends;\r\n\t\t}\r\n\t\tconst noise = blends.noise;\r\n\t\tconst noiseSeed = blends.noiseSeed;\r\n\t\t\r\n\t\t// Calculate noise min and max ranges\r\n\t\tlet noiseMin, noiseMax;\r\n\t\tif( noise === null ) {\r\n\r\n\t\t\t// No noise - set both to zero\r\n\t\t\tnoiseMin = new Float32Array( [ 0.0, 0.0, 0.0, 0.0 ] );\r\n\t\t\tnoiseMax = new Float32Array( [ 0.0, 0.0, 0.0, 0.0 ] );\r\n\t\t} else {\r\n\r\n\t\t\tnoiseMin = noise[ 0 ];\r\n\t\t\tnoiseMax = noise[ 1 ];\r\n\t\t}\r\n\t\t\r\n\t\tgl.uniform4fv( batch.locations.noiseMin, noiseMin );\r\n\t\tgl.uniform4fv( batch.locations.noiseMax, noiseMax );\r\n\t\t\r\n\t\t// Set time for animated noise\r\n\t\t// Use seed if available, otherwise use current time\r\n\t\tlet timeValue;\r\n\t\tif( noiseSeed !== null ) {\r\n\t\t\ttimeValue = noiseSeed / 1000.0;\r\n\t\t} else {\r\n\t\t\ttimeValue = performance.now() / 1000.0;\r\n\t\t}\r\n\t\tgl.uniform1f( batch.locations.time, timeValue );\r\n\t}\r\n\r\n\t// Draw based on batch mode\r\n\tgl.drawArrays( batch.mode, startIndex, endIndex - startIndex );\r\n}\r\n\r\n\r\n/**\r\n * Reset batches and draw order items\r\n * \r\n * @param {Object} batch - Batch object\r\n * @returns {void}\r\n */\r\nexport function resetBatches( screenData ) {\r\n\r\n\t// Reset Batches\r\n\tfor( const batchType in screenData.batches ) {\r\n\t\tconst batch = screenData.batches[ batchType ];\r\n\t\tresetBatch( batch );\r\n\t}\r\n\r\n\t// Reset drawOrder object\r\n\tscreenData.batchInfo.drawOrder = [];\r\n\tscreenData.batchInfo.currentBatch = null;\r\n\tscreenData.batchInfo.textureBatchSet.clear();\r\n}\r\n\r\n/**\r\n * Reset batch after flush\r\n * \r\n * @param {Object} batch - Batch object\r\n * @returns {void}\r\n */\r\nfunction resetBatch( batch ) {\r\n\r\n\t// Update the batch local max\r\n\tbatch.capacityLocalMax = Math.max( batch.count, batch.capacityLocalMax );\r\n\r\n\t// Reset batch count\r\n\tbatch.count = 0;\r\n\r\n\tif( batch.useTexture === true ) {\r\n\t\tbatch.texture = null;\r\n\t\tbatch.image = null;\r\n\t}\r\n\r\n\t// Check if should shrink capacity\r\n\tif( Date.now() > batch.capacityShrinkCheckTime ) {\r\n\r\n\t\t// This will resize the batch slowly over time - cutting in half every 5 seconds\r\n\t\tif( batch.capacity > batch.minCapacity && batch.capacityLocalMax < batch.capacity * 0.5 ) {\r\n\r\n\t\t\t// Resize the batch\r\n\t\t\tresizeBatch( batch, Math.max( batch.capacity * 0.5, batch.minCapacity ) );\r\n\t\t}\r\n\r\n\t\tbatch.capacityShrinkCheckTime = Date.now() + BATCH_CAPACITY_SHRINK_INTERVAL;\r\n\t\tbatch.capacityLocalMax = 0;\r\n\t}\r\n}\r\n\r\n/**\r\n * Display FBO texture to canvas\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {void}\r\n */\r\nexport function displayToCanvas( screenData ) {\r\n\t\r\n\tconst gl = screenData.gl;\r\n\tconst program = screenData.displayProgram;\r\n\tconst locations = screenData.displayLocations;\r\n\r\n\t// Bind default framebuffer (screen)\r\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\r\n\t\r\n\t// Set viewport to full canvas\r\n\tgl.viewport( 0, 0, screenData.canvas.width, screenData.canvas.height );\r\n\t\r\n\t// Clear the canvas before drawing the FBO texture\r\n\tgl.clearColor( 0, 0, 0, 0 );\r\n\tgl.clear( gl.COLOR_BUFFER_BIT );\r\n\t\r\n\t// Disable blend for render to display\r\n\tgl.disable( gl.BLEND );\r\n\r\n\t// Use display shader\r\n\tgl.useProgram( program );\r\n\t\r\n\t// Enable position attribute\r\n\tgl.enableVertexAttribArray( locations.position );\r\n\t\r\n\t// Bind position buffer\r\n\tgl.bindBuffer( gl.ARRAY_BUFFER, screenData.displayPositionBuffer );\r\n\tgl.vertexAttribPointer( locations.position, 2, gl.FLOAT, false, 0, 0 );\r\n\t\r\n\t// Bind FBO texture\r\n\tgl.activeTexture( gl.TEXTURE0 );\r\n\tgl.bindTexture( gl.TEXTURE_2D, screenData.fboTexture );\r\n\tgl.uniform1i( locations.texture, 0 );\r\n\t\r\n\t// Draw fullscreen quad\r\n\tgl.drawArrays( gl.TRIANGLES, 0, 6 );\r\n\t\r\n\t// Cleanup\r\n\tgl.disableVertexAttribArray( locations.position );\r\n}\r\n\r\n/**\r\n * Cleanup batch resources for screen\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {void}\r\n */\r\nexport function cleanup( screenData ) {\r\n\tconst gl = screenData.gl;\r\n\r\n\t// Cleanup batches\r\n\tfor( const batchType in screenData.batches ) {\r\n\r\n\t\t// Get the batch\r\n\t\tconst batch = screenData.batches[ batchType ];\r\n\r\n\t\t// Delete texCoord items\r\n\t\tif( batch.texCoordVBO ) {\r\n\t\t\tgl.deleteBuffer( batch.texCoordVBO );\r\n\t\t}\r\n\r\n\t\tgl.deleteBuffer( batch.vertexVBO );\r\n\t\tgl.deleteBuffer( batch.colorVBO );\r\n\t\tgl.deleteVertexArray( batch.vao );\r\n\t\tgl.deleteProgram( batch.program );\r\n\r\n\t\tif( batch.texture ) {\r\n\t\t\tgl.deleteTexture( batch.texture );\r\n\t\t}\r\n\t}\r\n\r\n\t// Clear references for GC and signal uninitialized state\r\n\tscreenData.batches = null;\r\n\tscreenData.batchInfo = null;\r\n}\r\n", "/**\r\n * Pi.js - Batch Drawing Helpers Module\r\n * \r\n * Shared helper functions for adding geometry to batches.\r\n * Provides common operations like adding vertices, quads, and triangles.\r\n * \r\n * @module renderer/draw/batch-helpers\r\n */\r\n\r\n\"use strict\";\r\n\r\nimport * as g_batches from \"../batches.js\";\r\n\r\n\r\n/***************************************************************************************************\r\n * Vertex Helpers\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Add a single vertex to a geometry or points batch\r\n * \r\n * @param {Object} batch - Batch object (GEOMETRY_BATCH or POINTS_BATCH)\r\n * @param {number} x - X coordinate\r\n * @param {number} y - Y coordinate\r\n * @param {Object} color - Color Object with array [ r, g, b, a ] values (0-255)\r\n * @returns {void}\r\n */\r\nexport function addVertexToBatch( batch, x, y, color ) {\r\n\tconst idx = batch.count * batch.vertexComps;\r\n\tconst cidx = batch.count * batch.colorComps;\r\n\tbatch.vertices[ idx     ] = x;\r\n\tbatch.vertices[ idx + 1 ] = y;\r\n\tbatch.colors[ cidx     ] = color.r;\r\n\tbatch.colors[ cidx + 1 ] = color.g;\r\n\tbatch.colors[ cidx + 2 ] = color.b;\r\n\tbatch.colors[ cidx + 3 ] = color.a;\r\n\r\n\tbatch.count++;\r\n}\r\n\r\n/**\r\n * Add a triangle (3 vertices) to a geometry batch\r\n * \r\n * @param {Object} batch - Geometry batch object\r\n * @param {number} x1 - First vertex X coordinate\r\n * @param {number} y1 - First vertex Y coordinate\r\n * @param {number} x2 - Second vertex X coordinate\r\n * @param {number} y2 - Second vertex Y coordinate\r\n * @param {number} x3 - Third vertex X coordinate\r\n * @param {number} y3 - Third vertex Y coordinate\r\n * @param {Object} color - Color object with [ r, g, b, a ] values (0-255)\r\n * @returns {void}\r\n */\r\nexport function addTriangleToBatch( batch, x1, y1, x2, y2, x3, y3, color ) {\r\n\taddVertexToBatch( batch, x1, y1, color );\r\n\taddVertexToBatch( batch, x2, y2, color );\r\n\taddVertexToBatch( batch, x3, y3, color );\r\n}\r\n\r\n/**\r\n * Add a quad (rectangle as two triangles) to a geometry batch\r\n * The quad is defined by two corner points (x1,y1) and (x2,y2) forming a rectangle\r\n * \r\n * TODO-LATER: Improve efficiency, this should work more similiarly to addTexturedQuadToBatch\r\n * \r\n * @param {Object} batch - Geometry batch object\r\n * @param {number} x1 - Left/bottom-left X coordinate\r\n * @param {number} y1 - Left/bottom-left Y coordinate\r\n * @param {number} x2 - Right/top-right X coordinate\r\n * @param {number} y2 - Right/top-right Y coordinate\r\n * @param {Object} color - Color object with [ r, g, b, a ] values (0-255)\r\n * @returns {void}\r\n */\r\nexport function addQuadToBatch( batch, x1, y1, x2, y2, color ) {\r\n\r\n\t// Truncate coordinates for pixel-perfect rendering\r\n\tconst vx1 = x1 | 0;\r\n\tconst vy1 = y1 | 0;\r\n\tconst vx2 = x2 | 0;\r\n\tconst vy2 = y2 | 0;\r\n\r\n\t// First triangle: (x1,y1), (x2,y1), (x1,y2)\r\n\taddVertexToBatch( batch, vx1, vy1, color );\r\n\taddVertexToBatch( batch, vx2, vy1, color );\r\n\taddVertexToBatch( batch, vx1, vy2, color );\r\n\r\n\t// Second triangle: (x2,y1), (x2,y2), (x1,y2)\r\n\taddVertexToBatch( batch, vx2, vy1, color );\r\n\taddVertexToBatch( batch, vx2, vy2, color );\r\n\taddVertexToBatch( batch, vx1, vy2, color );\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Curves Helpers - TODO-LATER Get out of here\r\n ***************************************************************************************************/\r\n\r\n/**\r\n * Tessellate a cubic Bezier curve into a polyline using an adaptive flatness criterion.\r\n * Returns an array of points [x0, y0, x1, y1, ..., xn, yn] including endpoints.\r\n * \r\n * TODO-LATER: Move this function to bezier module\r\n * \r\n * @param {number} x0\r\n * @param {number} y0\r\n * @param {number} x1\r\n * @param {number} y1\r\n * @param {number} x2\r\n * @param {number} y2\r\n * @param {number} x3\r\n * @param {number} y3\r\n * @param {number} maxError - Max perpendicular error in pixels\r\n * @returns {number[]}\r\n */\r\nexport function tessellateCubicBezier( x0, y0, x1, y1, x2, y2, x3, y3, maxError ) {\r\n\r\n\tconst out = [];\r\n\r\n\t// Distance from point to line segment (squared)\r\n\tfunction pointLineDistanceSq( px, py, ax, ay, bx, by ) {\r\n\t\tconst abx = bx - ax;\r\n\t\tconst aby = by - ay;\r\n\t\tconst apx = px - ax;\r\n\t\tconst apy = py - ay;\r\n\t\tconst abLenSq = abx * abx + aby * aby;\r\n\t\tif( abLenSq === 0 ) return apx * apx + apy * apy;\r\n\t\tlet t = ( apx * abx + apy * aby ) / abLenSq;\r\n\t\tif( t < 0 ) t = 0; else if( t > 1 ) t = 1;\r\n\t\tconst cx = ax + t * abx;\r\n\t\tconst cy = ay + t * aby;\r\n\t\tconst dx = px - cx;\r\n\t\tconst dy = py - cy;\r\n\t\treturn dx * dx + dy * dy;\r\n\t}\r\n\r\n\tconst maxErrorSq = maxError * maxError;\r\n\tconst maxDepth = 12;\r\n\r\n\tfunction subdivide( ax, ay, bx, by, cx, cy, dx, dy, depth ) {\r\n\r\n\t\t// Flatness test: max distance of control points to chord (a-d)\r\n\t\tconst d1 = pointLineDistanceSq( bx, by, ax, ay, dx, dy );\r\n\t\tconst d2 = pointLineDistanceSq( cx, cy, ax, ay, dx, dy );\r\n\t\tif( depth >= maxDepth || ( d1 <= maxErrorSq && d2 <= maxErrorSq ) ) {\r\n\t\t\t// Accept segment\r\n\t\t\tif( out.length === 0 ) {\r\n\t\t\t\tout.push( ax, ay );\r\n\t\t\t}\r\n\t\t\tout.push( dx, dy );\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// De Casteljau subdivision at t=0.5\r\n\t\tconst abx = ( ax + bx ) * 0.5; const aby = ( ay + by ) * 0.5;\r\n\t\tconst bcx = ( bx + cx ) * 0.5; const bcy = ( by + cy ) * 0.5;\r\n\t\tconst cdx = ( cx + dx ) * 0.5; const cdy = ( cy + dy ) * 0.5;\r\n\r\n\t\tconst abbcx = ( abx + bcx ) * 0.5; const abbcy = ( aby + bcy ) * 0.5;\r\n\t\tconst bccdx = ( bcx + cdx ) * 0.5; const bccdy = ( bcy + cdy ) * 0.5;\r\n\r\n\t\tconst midx = ( abbcx + bccdx ) * 0.5; const midy = ( abbcy + bccdy ) * 0.5;\r\n\r\n\t\tsubdivide( ax, ay, abx, aby, abbcx, abbcy, midx, midy, depth + 1 );\r\n\t\tsubdivide( midx, midy, bccdx, bccdy, cdx, cdy, dx, dy, depth + 1 );\r\n\t}\r\n\r\n\tsubdivide( x0, y0, x1, y1, x2, y2, x3, y3, 0 );\r\n\treturn out;\r\n}\r\n\r\n", "/**\r\n * Pi.js - Geometry Cache Module\r\n * \r\n * Cached geometry for commonly used shapes.\r\n * Stores pre-computed vertex data for efficient rendering.\r\n * \r\n * @module renderer/draw/geometry\r\n */\r\n\r\n\"use strict\";\r\n\r\nimport * as g_batches from \"../batches.js\";\r\nimport * as g_batchHelpers from \"./batch-helpers.js\";\r\n\r\nexport const FILLED_CIRCLE = 0;\r\nexport const FILLED_ELLIPSE = 1;\r\n\r\n/***************************************************************************************************\r\n * Geometry Cache\r\n ***************************************************************************************************/\r\n\r\n\r\n// Cache key format: \"type:radius\"\r\n// Example: \"circle:32\" for a circle of radius 32\r\nconst m_geometryCache = new Map();\r\n\r\n// Cached vertex data structure:\r\n// {\r\n//   \"vertexCount\": number,\r\n//   \"vertices\": Float32Array,  // Raw x,y positions\r\n// }\r\n\r\n\r\n/***************************************************************************************************\r\n * Module Initialization\r\n ***************************************************************************************************/\r\n\r\nexport { m_geometryCache as geometryCache };\r\n\r\n/**\r\n * Initialize geometry module\r\n * \r\n * @returns {void}\r\n */\r\nexport function init() {\r\n\r\n\t// Pre-populate cache with a couple circles\r\n\tprepopulateCache();\r\n}\r\n\r\n/**\r\n * Pre-populate cache with commonly used geometry\r\n * \r\n * @returns {void}\r\n */\r\nfunction prepopulateCache() {\r\n\r\n\t// Special geometries for small circle radius\r\n\t// radius 1: single pixel as 1x1 quad centered at origin covering [0,0]-[1,1]\r\n\tconst circle1 = generateSinglePixelGeometry();\r\n\tm_geometryCache.set( `${FILLED_CIRCLE}:1`, circle1 );\r\n\r\n\t// Pre-generate circles for sizes 1-10\r\n\tfor( let radius = 1; radius <= 10; radius++ ) {\r\n\t\tconst cacheKey = `${FILLED_CIRCLE}:${radius}`;\r\n\t\t\r\n\t\t// Use Alpha 2's radius threshold: (half - 0.5)^2\r\n\t\tconst geometry = generateCircleGeometry( radius );\r\n\t\tm_geometryCache.set( cacheKey, geometry );\r\n\t}\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Geometry Building Helpers\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Add a single vertex to a geometry vertices array\r\n * \r\n * @param {Float32Array} vertices - Vertices array\r\n * @param {number} vIdx - Current index into vertices array (will be modified)\r\n * @param {number} x - X coordinate\r\n * @param {number} y - Y coordinate\r\n * @returns {number} New index after adding vertex\r\n */\r\nfunction addVertex( vertices, vIdx, x, y ) {\r\n\r\n\tvertices[ vIdx++ ] = x;\r\n\tvertices[ vIdx++ ] = y;\r\n\treturn vIdx;\r\n}\r\n\r\n/**\r\n * Add a triangle (3 vertices) to a geometry vertices array\r\n * \r\n * @param {Float32Array} vertices - Vertices array\r\n * @param {number} vIdx - Current index into vertices array (will be modified)\r\n * @param {number} x1 - First vertex X coordinate\r\n * @param {number} y1 - First vertex Y coordinate\r\n * @param {number} x2 - Second vertex X coordinate\r\n * @param {number} y2 - Second vertex Y coordinate\r\n * @param {number} x3 - Third vertex X coordinate\r\n * @param {number} y3 - Third vertex Y coordinate\r\n * @returns {number} New index after adding triangle\r\n */\r\nfunction addTriangle( vertices, vIdx, x1, y1, x2, y2, x3, y3 ) {\r\n\r\n\tvIdx = addVertex( vertices, vIdx, x1, y1 );\r\n\tvIdx = addVertex( vertices, vIdx, x2, y2 );\r\n\tvIdx = addVertex( vertices, vIdx, x3, y3 );\r\n\treturn vIdx;\r\n}\r\n\r\n/**\r\n * Add a quad (rectangle as two triangles) to a geometry vertices array\r\n * The quad is defined by two corner points (x1,y1) and (x2,y2) forming a rectangle\r\n * \r\n * @param {Float32Array} vertices - Vertices array\r\n * @param {number} vIdx - Current index into vertices array (will be modified)\r\n * @param {number} x1 - Left/bottom-left X coordinate\r\n * @param {number} y1 - Left/bottom-left Y coordinate\r\n * @param {number} x2 - Right/top-right X coordinate\r\n * @param {number} y2 - Right/top-right Y coordinate\r\n * @returns {number} New index after adding quad\r\n */\r\nfunction addQuad( vertices, vIdx, x1, y1, x2, y2 ) {\r\n\r\n\t// First triangle: (x1,y1), (x2,y1), (x1,y2)\r\n\tvIdx = addTriangle( vertices, vIdx, x1, y1, x2, y1, x1, y2 );\r\n\r\n\t// Second triangle: (x2,y1), (x2,y2), (x1,y2)\r\n\tvIdx = addTriangle( vertices, vIdx, x2, y1, x2, y2, x1, y2 );\r\n\treturn vIdx;\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Geometry Generation\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Fill points in an array first, then generate scanlines for pixel-perfect results\r\n * \r\n * @param {number} radius - Radius of the circle\r\n * @returns {Object} Geometry data with vertexCount and vertices array\r\n */\r\nfunction generateCircleGeometry( radius ) {\r\n\r\n\tif( radius <= 0 ) {\r\n\t\treturn { \"vertexCount\": 0, \"vertices\": null };\r\n\t}\r\n\t\r\n\t// Store min/max X for each Y scanline as we discover them during MCA\r\n\tconst scanlineMinMax = new Map(); // Map<y, {min: x, max: x}>\r\n\r\n\t// --- Midpoint Circle Algorithm to find outline pixels ---\r\n\tlet x = radius - 1;  // Radius adjustment - due to integer rounding it looks better this way\r\n\tlet y = 0;\r\n\tlet err = 1 - x;\r\n\r\n\t// Helper to update min/max X for a specific Y scanline\r\n\tconst updateScanline = ( px, py ) => {\r\n\r\n\t\tconst pixelY = py | 0; // Fast Math.floor\r\n\t\tconst pixelX = px | 0;\r\n\r\n\t\tif( !scanlineMinMax.has( pixelY ) ) {\r\n\t\t\tif( pixelX < 0 ) {\r\n\t\t\t\tscanlineMinMax.set( pixelY, { \"left\": pixelX, \"right\": Infinity } );\r\n\t\t\t} else if( pixelX > 0 ) {\r\n\t\t\t\tscanlineMinMax.set( pixelY, { \"left\": -Infinity, \"right\": pixelX } );\t\r\n\t\t\t} else {\r\n\t\t\t\tscanlineMinMax.set( pixelY, { \"left\": pixelX, \"right\": pixelX } );\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst limits = scanlineMinMax.get( pixelY );\r\n\r\n\t\t\t// We want to find interior pixels only not border pixels so we are looking for the\r\n\t\t\t// closest interior pixel. We need to account for two horizontal border pixels in a row.\r\n\r\n\t\t\tif( pixelX < 0 && pixelX > limits.left ) {\r\n\t\t\t\tlimits.left = pixelX;\r\n\t\t\t}\r\n\t\t\tif( pixelX > 0 && pixelX < limits.right ) {\r\n\t\t\t\tlimits.right = pixelX;\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\twhile( x >= y ) {\r\n\r\n\t\t// Apply 8-way symmetry to update scanlines\r\n\t\tupdateScanline(  x,  y ); // Quadrant 1\r\n\t\tupdateScanline(  y,  x ); // Quadrant 2\r\n\t\tupdateScanline( -y,  x ); // Quadrant 3\r\n\t\tupdateScanline( -x,  y ); // Quadrant 4\r\n\t\tupdateScanline( -x, -y ); // Quadrant 5\r\n\t\tupdateScanline( -y, -x ); // Quadrant 6\r\n\t\tupdateScanline(  y, -x ); // Quadrant 7\r\n\t\tupdateScanline(  x, -y ); // Quadrant 8\r\n\r\n\t\ty++;\r\n\t\tif( err < 0 ) {\r\n\t\t\terr += 2 * y + 1;\r\n\t\t} else {\r\n\t\t\tx--;\r\n\t\t\terr += 2 * ( y - x ) + 1;\r\n\t\t}\r\n\t}\r\n\r\n\t// Count valid scanlines for batch preparation\r\n\tlet vertexCount = 0;\r\n\tconst sortedYCoords = [];\r\n\tfor( const [ currentY, mm ] of scanlineMinMax.entries() ) {\r\n\t\tvertexCount += 6;\r\n\t\tsortedYCoords.push( currentY );\r\n\t}\r\n\r\n\tsortedYCoords.sort( ( a, b ) => a - b );\r\n\r\n\tconst vertices = new Float32Array( vertexCount * 2 );\r\n\tlet vIdx = 0;\r\n\r\n\t// Generate quads for each scanline -- skip the top row as it's border\r\n\tfor(let row = 1; row < sortedYCoords.length - 1; row += 1 ) {\r\n\t\tconst currentY = sortedYCoords[ row ];\r\n\t\tconst limits = scanlineMinMax.get( currentY );\r\n\r\n\t\t// Get the interior starts by moving over 1 pixel from border\r\n\t\tconst xStart = limits.left + 1;\r\n\t\tconst xEnd = limits.right - 1;\r\n\r\n\t\t// Quad from (xStart, currentY) to (xEnd+1, currentY+1)\r\n\t\tvIdx = addQuad( vertices, vIdx, xStart, currentY, xEnd + 1, currentY + 1 );\r\n\t}\r\n\r\n\treturn { \"vertexCount\": vertexCount, \"vertices\": vertices };\r\n}\r\n\r\n\r\n/**\r\n * Generate geometry for a single pixel 1x1 quad at origin.\r\n * @returns {Object}\r\n */\r\nfunction generateSinglePixelGeometry() {\r\n\r\n\t// Two triangles forming a 1x1 quad with corners (0,0)-(1,1)\r\n\tconst vertexCount = 6;\r\n\tconst vertices = new Float32Array( vertexCount * 2 );\r\n\tlet vIdx = 0;\r\n\r\n\t// Quad from (0,0) to (1,1)\r\n\tvIdx = addQuad( vertices, vIdx, 0, 0, 1, 1 );\r\n\r\n\treturn { \"vertexCount\": vertexCount, \"vertices\": vertices };\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Cache Management\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Get cached geometry or generate and cache it\r\n * \r\n * @param {string} cacheKey - Geometry cache key (e.g., \"circle:32\")\r\n * @returns {Object} Geometry data with vertexCount and vertices array\r\n */\r\nfunction getCachedGeometry( cacheType, unit ) {\r\n\r\n\tconst cacheKey = `${cacheType}:${unit}`;\r\n\tif( m_geometryCache.has( cacheKey ) ) {\r\n\t\treturn m_geometryCache.get( cacheKey );\r\n\t}\r\n\r\n\t// Parse cache key to determine what to generate\r\n\tlet geometry;\r\n\r\n\tif( cacheType === FILLED_CIRCLE ) {\r\n\t\tgeometry = generateCircleGeometry( unit );\r\n\t} else {\r\n\t\tthrow new Error( `Unknown geometry cache type: ${cacheType}` );\r\n\t}\r\n\r\n\t// Cache the geometry\r\n\tm_geometryCache.set( cacheKey, geometry );\r\n\r\n\treturn geometry;\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Drawing Functions\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Draw cached geometry with specified color\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {string} cacheKey - Geometry cache key (e.g., \"circle:32\")\r\n * @param {number} x - X coordinate\r\n * @param {number} y - Y coordinate\r\n * @param {Object} color - Color object with [ r, g, b, a ] values (0-255)\r\n * @returns {void}\r\n */\r\nexport function drawCachedGeometry( screenData, cacheType, unit, x, y, color ) {\r\n\r\n\t// Get cached geometry\r\n\tconst geometry = getCachedGeometry( cacheType, unit );\r\n\tconst batch = screenData.batches[ g_batches.GEOMETRY_BATCH ];\r\n\r\n\t// Prepare batch for vertices\r\n\tg_batches.prepareBatch( screenData, g_batches.GEOMETRY_BATCH, geometry.vertexCount );\r\n\r\n\t// Copy vertices to batch with offset and generate colors\r\n\tconst vertices = geometry.vertices;\r\n\tlet vIdx = 0;\r\n\r\n\tfor( let i = 0; i < geometry.vertexCount; i++ ) {\r\n\r\n\t\tconst vx = vertices[ vIdx++ ] + x;\r\n\t\tconst vy = vertices[ vIdx++ ] + y;\r\n\t\tg_batchHelpers.addVertexToBatch( batch, vx, vy, color );\r\n\t}\r\n}\r\n\r\n", "/**\n * Pi.js - Textures Module\n * \n * Texture cache management and WebGL2 texture operations.\n * \n * @module renderer/textures\n */\n\n\"use strict\";\n\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_batches from \"./batches.js\";\n\n\n/***************************************************************************************************\n * Module Initialization\n ***************************************************************************************************/\n\n\n/**\n * Initialize textures module\n * \n * @returns {void}\n */\nexport function init() {\n\n\t// Nested Map for WebGL2 texture storage\n\t// Outer Map: Image element -> Inner Map: GL context -> WebGL texture\n\t// This allows efficient lookup by image and cleanup when image is removed\n\tg_screenManager.addScreenDataItem( \"imageContextMap\", new Map() );\n}\n\n\n/***************************************************************************************************\n * Texture Cache Management\n ***************************************************************************************************/\n\n\n/**\n * Copy image data to currently bound texture, handling mock canvases by copying from FBO\n * Handles cross-context copying when mock canvas uses a different WebGL context\n * \n * @param {WebGL2RenderingContext} gl - WebGL2 context (destination context)\n * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} img - Image or Canvas element\n * @returns {void}\n */\nfunction copyImageToTexture( gl, img ) {\n\t\n\t// If img is a mock canvas, copy from the FBO instead of the mock canvas\n\tif( img.isMock ) {\n\t\tconst imgScreenData = g_screenManager.screenCanvasMap.get( img );\n\t\tif( imgScreenData ) {\n\n\t\t\t// Make sure the other screen is up to date\n\t\t\tg_batches.flushBatches( imgScreenData );\n\t\t\t\n\t\t\t// Check if contexts are different (cross-context copy needed)\n\t\t\tif( imgScreenData.gl !== gl ) {\n\t\t\t\t\n\t\t\t\t// Cross-context copy: read pixels from source FBO, upload to destination texture\n\t\t\t\tconst srcGl = imgScreenData.gl;\n\t\t\t\tconst width = imgScreenData.width;\n\t\t\t\tconst height = imgScreenData.height;\n\t\t\t\t\n\t\t\t\t// Allocate buffer for pixel data\n\t\t\t\tconst pixelData = new Uint8Array( width * height * 4 );\n\t\t\t\t\n\t\t\t\t// Read pixels from source FBO in source context\n\t\t\t\tsrcGl.bindFramebuffer( srcGl.FRAMEBUFFER, imgScreenData.FBO );\n\t\t\t\tsrcGl.readPixels( 0, 0, width, height, srcGl.RGBA, srcGl.UNSIGNED_BYTE, pixelData );\n\t\t\t\tsrcGl.bindFramebuffer( srcGl.FRAMEBUFFER, null );\n\t\t\t\t\n\t\t\t\t// Flip Y-axis (WebGL reads bottom-to-top, but texImage2D expects top-to-bottom)\n\t\t\t\t// Flip rows in place\n\t\t\t\tconst rowSize = width * 4;\n\t\t\t\tconst tempRow = new Uint8Array( rowSize );\n\t\t\t\tfor( let y = 0; y < Math.floor( height / 2 ); y++ ) {\n\t\t\t\t\tconst topRow = y * rowSize;\n\t\t\t\t\tconst bottomRow = ( height - 1 - y ) * rowSize;\n\t\t\t\t\t\n\t\t\t\t\t// Swap rows\n\t\t\t\t\ttempRow.set( pixelData.subarray( topRow, topRow + rowSize ) );\n\t\t\t\t\tpixelData.set( pixelData.subarray( bottomRow, bottomRow + rowSize ), topRow );\n\t\t\t\t\tpixelData.set( tempRow, bottomRow );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Upload pixel data to destination texture in destination context\n\t\t\t\tgl.texImage2D(\n\t\t\t\t\tgl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,\n\t\t\t\t\tpixelData\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t\n\t\t\t\t// Same context: can use copyTexImage2D directly\n\t\t\t\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, imgScreenData.FBO );\n\t\t\t\tgl.copyTexImage2D(\n\t\t\t\t\tgl.TEXTURE_2D, 0, gl.RGBA, 0, 0, imgScreenData.width, imgScreenData.height, 0\n\t\t\t\t);\n\t\t\t\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );\n\t\t\t}\n\t\t} else {\n\n\t\t\t// Fallback to regular canvas copy if screenData not found\n\t\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img );\n\t\t}\n\t} else {\n\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img );\n\t}\n}\n\n/**\n * Get or create WebGL2 texture for image\n * Creates and caches texture if it doesn't exist for this GL context.\n * \n * @param {Object} screenData - Screen data object\n * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} img - Image or Canvas element\n * @returns {WebGLTexture|null} WebGL texture or null on error\n */\nexport function getWebGL2Texture( screenData, img ) {\n\n\t// imageContextMap is a map (image -> context) containing a map (context -> texture)\n\t// Get or create inner Map for this image\n\tlet contextTextureMap = screenData.imageContextMap.get( img );\n\tif( !contextTextureMap ) {\n\t\tcontextTextureMap = new Map();\n\t\tscreenData.imageContextMap.set( img, contextTextureMap );\n\t}\n\n\t// Check if texture is another screen\n\tconst otherScreenData = g_screenManager.screenCanvasMap.get( img );\n\tif( otherScreenData ) {\n\n\t\t// Make sure the other screen is up to date\n\t\tg_batches.flushBatches( otherScreenData );\n\t\tg_batches.displayToCanvas( otherScreenData );\n\t}\n\n\t// Check if texture already exists for this screen's context\n\tconst gl = screenData.gl;\n\tlet texture = contextTextureMap.get( gl );\n\tif( texture ) {\n\n\t\t// If image is a canvas, update the texture so that it has the latest data\n\t\tif(\n\t\t\timg instanceof HTMLCanvasElement ||\n\t\t\t( typeof OffscreenCanvas !== \"undefined\" && img instanceof OffscreenCanvas ) ||\n\t\t\timg.isMock\n\t\t) {\n\n\t\t\t// If the img.isDirty is not defined then assume it's dirty, otherwise only if it's\n\t\t\t// explicitly set to false then we don't perform the copy, this makes it so that the \n\t\t\t// default behavior is to copy the texture.\n\t\t\tif( img.isDirty !== undefined && img.isDirty === false ) {\n\t\t\t\treturn texture;\n\t\t\t}\n\n\t\t\t// If a texture is currently scheduled to be drawn we need to flush the batch so that\n\t\t\t// the texture will appear as it was when the draw command was issued\n\t\t\tif( screenData.batchInfo.textureBatchSet.has( texture ) ) {\n\t\t\t\tg_batches.flushBatches( screenData );\n\t\t\t}\n\n\t\t\t// Copy the content of the source canvas to the texture\n\t\t\tgl.bindTexture( gl.TEXTURE_2D, texture );\n\t\t\tcopyImageToTexture( gl, img );\n\t\t\tgl.bindTexture( gl.TEXTURE_2D, null );\n\t\t}\n\t\treturn texture;\n\t}\n\n\t// Create the texture\n\ttexture = gl.createTexture();\n\tif( !texture ) {\n\t\tconst error = new Error( \"Failed to create WebGL2 texture for image.\" );\n\t\terror.code = \"WEBGL2_ERROR\";\n\t\tthrow error;\n\t}\n\n\t// Upload image data to texture\n\tgl.bindTexture( gl.TEXTURE_2D, texture );\n\tcopyImageToTexture( gl, img );\n\n\t// Set texture parameters for pixel-perfect rendering\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\n\t// Unbind the texture\n\tgl.bindTexture( gl.TEXTURE_2D, null );\n\n\t// Store texture in nested Map\n\tcontextTextureMap.set( gl, texture );\n\n\treturn texture;\n}\n\n/**\n * Delete WebGL2 texture for an image on all screens\n * Must be called explicitly to free GPU memory - textures are not automatically\n * garbage collected by the browser.\n * \n * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} img - Image or Canvas element\n * @returns {void}\n */\nexport function deleteWebGL2Texture( screenData, img ) {\n\n\t// Get the context Map for this image\n\tconst contextMap = screenData.imageContextMap.get( img );\n\tif( !contextMap ) {\n\t\treturn;\n\t}\n\n\t// Remove the context Map if empty\n\tif( contextMap.size === 0 ) {\n\t\tscreenData.imageContextMap.delete( img );\n\t}\n}\n\n/**\n * Update a sub-rectangle of an existing WebGL2 texture using pixel data.\n * Creates the texture on-demand if it doesn't yet exist for this context.\n * If imgKey is null, uses screenData.fboTexture directly (for FBO updates).\n * \n * @param {Object} screenData - Screen data object\n * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|null} imgKey - Image cache key\n * @param {Uint8ClampedArray|Uint8Array} pixelData - RGBA pixel data array\n * @param {number} width - Width of the pixel data\n * @param {number} height - Height of the pixel data\n * @param {number} dstX - Destination X in the texture\n * @param {number} dstY - Destination Y in the texture\n * @returns {WebGLTexture|null} Updated WebGL texture or null on error\n */\nexport function updateWebGL2TextureSubImage(\n\tscreenData, imgKey, pixelData, width, height, dstX, dstY\n) {\n\n\tif( !screenData.gl ) {\n\t\treturn null;\n\t}\n\n\tconst gl = screenData.gl;\n\tlet texture;\n\n\t// If imgKey is null, use FBO texture directly\n\tif( imgKey === null ) {\n\t\ttexture = screenData.fboTexture;\n\t\tif( !texture ) {\n\t\t\treturn null;\n\t\t}\n\t} else {\n\t\t\n\t\t// Ensure texture exists for the image key\n\t\ttexture = getWebGL2Texture( screenData, imgKey );\n\t}\n\n\t// If a texture is currently scheduled to be drawn we need to flush the batch so that\n\t// the texture will appear as it was when the draw command was issued\n\tif( screenData.batchInfo.textureBatchSet.has( texture ) ) {\n\t\tg_batches.flushBatches( screenData );\n\t}\n\n\tgl.bindTexture( gl.TEXTURE_2D, texture );\n\n\t// Upload only the updated region using pixel data\n\tgl.texSubImage2D( \n\t\tgl.TEXTURE_2D, 0, dstX, dstY,\n\t\twidth, height,\n\t\tgl.RGBA, gl.UNSIGNED_BYTE, pixelData \n\t);\n\n\t// Keep texture parameters consistent\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\n\tgl.bindTexture( gl.TEXTURE_2D, null );\n\n\treturn texture;\n}\n\n/**\n * Update an entire WebGL2 texture using pixel data.\n * Creates the texture on-demand if it doesn't yet exist for this context.\n * \n * @param {Object} screenData - Screen data object\n * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} imgKey - Image cache key\n * @param {Uint8ClampedArray} pixelData - RGBA pixel data array\n * @param {number} width - Width of the pixel data\n * @param {number} height - Height of the pixel data\n * @returns {WebGLTexture|null} Updated WebGL texture or null on error\n */\nexport function updateWebGL2TextureImage( screenData, imgKey, pixelData, width, height ) {\n\n\t// Get the texture\n\tlet texture = getWebGL2Texture( screenData, imgKey );\n\n\t// If a texture is currently scheduled to be drawn we need to flush the batch so that\n\t// the texture will appear as it was when the draw command was issued\n\tif( screenData.batchInfo.textureBatchSets.has( texture ) ) {\n\t\tg_batches.flushBatches( screenData );\n\t}\n\t\n\tconst gl = screenData.gl;\n\tgl.bindTexture( gl.TEXTURE_2D, texture );\n\n\t// Upload the entire texture using pixel data\n\tgl.texImage2D( \n\t\tgl.TEXTURE_2D, 0, gl.RGBA,\n\t\twidth, height, 0,\n\t\tgl.RGBA, gl.UNSIGNED_BYTE, pixelData \n\t);\n\n\t// Keep texture parameters consistent\n\t// gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\t// gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\t// gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\t// gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\n\tgl.bindTexture( gl.TEXTURE_2D, null );\n\n\treturn texture;\n}\n", "/**\n * Pi.js - Pixel Readback Module\n * \n * Pixel readback operations: single pixel and rectangular regions.\n * \n * @module renderer/readback\n */\n\n\"use strict\";\n\n// Import required modules\nimport * as g_batches from \"./batches.js\";\nimport * as g_utils from \"../core/utils.js\";\n\n\n/***************************************************************************************************\n * Module Initialization\n ***************************************************************************************************/\n\n\n/**\n * Initialize readback module\n * \n * @returns {void}\n */\nexport function init() {\n\t// No initialization needed\n}\n\n/**\n * Read single pixel (synchronous)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @returns {Object|null} Color object with r, g, b, a or null on error\n */\nexport function readPixel( screenData, x, y ) {\n\n\t// Ensure latest contents are in the FBO\n\tg_batches.flushBatches( screenData );\n\n\tconst gl = screenData.gl;\n\tconst screenHeight = screenData.height;\n\n\t// WebGL uses bottom-left origin; flip Y\n\tconst glY = ( screenHeight - 1 ) - y;\n\tconst buf = new Uint8Array( 4 );\n\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, screenData.FBO );\n\tgl.readPixels( x, glY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf );\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n\n\treturn g_utils.rgbToColor( buf[ 0 ], buf[ 1 ], buf[ 2 ], buf[ 3 ] );\n}\n\n/**\n * Read single pixel (asynchronous)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @returns {Promise<Object|null>} Promise resolving to color object or null\n */\nexport function readPixelAsync( screenData, x, y ) {\n\n\t// TODO-LATER: Instead of queueing a microtask make this a part of the batch system, that way \n\t// the user will get a result that reflects the state of the FBO when they make the call rather\n\t// than the state at the end of the frame.\n\t// If I make this change I should rename the API functions to something like getPixelQueued\n\t// instead of getPixelAsync.\n\treturn new Promise( ( resolve ) => {\n\t\tg_utils.queueMicrotask( () => {\n\t\t\tresolve( readPixel( screenData, x, y ) );\n\t\t} );\n\t} );\n}\n\n/**\n * Read pixel rectangle (synchronous)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @param {number} width - Rectangle width\n * @param {number} height - Rectangle height\n * @returns {Array<Array<Object>>} 2D array of color objects [height][width]\n */\nexport function readPixels( screenData, x, y, width, height ) {\n\tconst gl = screenData.gl;\n\tconst screenWidth = screenData.width;\n\tconst screenHeight = screenData.height;\n\n\t// Clamp to screen bounds for robustness if not fully clipped by pixels.js\n\tconst clampedX = Math.max( 0, x );\n\tconst clampedY = Math.max( 0, y );\n\tconst clampedWidth = Math.min( width, screenWidth - clampedX );\n\tconst clampedHeight = Math.min( height, screenHeight - clampedY );\n\n\t// If after clamping, nothing left to read\n\tif( clampedWidth <= 0 || clampedHeight <= 0 ) {\n\t\treturn [];\n\t}\n\n\t// Flush batches before reading\n\tg_batches.flushBatches( screenData );\n\n\t// Allocate buffer for the exact rectangle to read\n\tconst buf = new Uint8Array( clampedWidth * clampedHeight * 4 );\n\n\t// WebGL origin is bottom-left; convert to top-left for `gl.readPixels`\n\t// The Y coordinate for `gl.readPixels` is the bottom edge of the rectangle.\n\t// Bottom-left corner Y of the rectangle\n\tconst glReadY = ( screenHeight - ( clampedY + clampedHeight ) );\n\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, screenData.FBO );\n\tgl.readPixels( clampedX, glReadY, clampedWidth, clampedHeight, gl.RGBA, gl.UNSIGNED_BYTE, buf );\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n\n\t// Map back to output structure expected by api/pixels.js\n\t// This function will return a flat array of color objects\n\tconst resultColors = new Array( clampedHeight );\n\tfor( let row = 0; row < clampedHeight; row++ ) {\n\n\t\tconst resultsRow = new Array( clampedWidth );\n\t\tfor( let col = 0; col < clampedWidth; col++ ) {\n\n\t\t\t// Convert gl.readPixels' bottom-origin Y to top-origin Y for the buffer index\n\t\t\t// `buf` itself is ordered from glReadY up to glReadY + clampedHeight - 1\n\t\t\t// Flip row index\n\t\t\tconst bufRow = ( clampedHeight - 1 ) - row;\n\t\t\tconst i = ( ( clampedWidth * bufRow ) + col ) * 4;\n\t\t\tresultsRow[ col ] = g_utils.rgbToColor(\n\t\t\t\tbuf[ i ], buf[ i + 1 ], buf[ i + 2 ], buf[ i + 3 ]\n\t\t\t);\n\t\t}\n\t\tresultColors[ row ] = resultsRow;\n\t}\n\n\treturn resultColors;\n}\n\n/**\n * Read pixel rectangle (asynchronous)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @param {number} width - Rectangle width\n * @param {number} height - Rectangle height\n * @returns {Promise<Array<Array<Object>>>} Promise resolving to 2D array of color objects\n */\nexport function readPixelsAsync( screenData, x, y, width, height ) {\n\treturn new Promise( ( resolve ) => {\n\t\tg_utils.queueMicrotask( () => {\n\t\t\tresolve( readPixels( screenData, x, y, width, height ) );\n\t\t} );\n\t} );\n}\n\n/**\n * Read pixel rectangle as raw Uint8Array (synchronous)\n * Returns RGBA data in a Uint8Array with WebGL bottom-left origin ordering.\n * Format: [r0, g0, b0, a0, r1, g1, b1, a1, ...] where pixels are ordered\n * row by row from bottom to top, left to right (WebGL native format).\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @param {number} width - Rectangle width\n * @param {number} height - Rectangle height\n * @returns {Uint8Array|null} Raw RGBA pixel data (width * height * 4 bytes) or null if invalid\n */\nexport function readPixelsRaw( screenData, x, y, width, height ) {\n\tconst gl = screenData.gl;\n\tconst screenWidth = screenData.width;\n\tconst screenHeight = screenData.height;\n\n\t// Clamp to screen bounds for robustness\n\tconst clampedX = Math.max( 0, x );\n\tconst clampedY = Math.max( 0, y );\n\tconst clampedWidth = Math.min( width, screenWidth - clampedX );\n\tconst clampedHeight = Math.min( height, screenHeight - clampedY );\n\n\t// If after clamping, nothing left to read\n\tif( clampedWidth <= 0 || clampedHeight <= 0 ) {\n\t\treturn null;\n\t}\n\n\t// Flush batches before reading\n\tg_batches.flushBatches( screenData );\n\n\t// Allocate buffer for the exact rectangle to read\n\tconst buf = new Uint8Array( clampedWidth * clampedHeight * 4 );\n\n\t// WebGL origin is bottom-left; convert to top-left for `gl.readPixels`\n\t// The Y coordinate for `gl.readPixels` is the bottom edge of the rectangle.\n\t// Bottom-left corner Y of the rectangle\n\tconst glReadY = ( screenHeight - ( clampedY + clampedHeight ) );\n\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, screenData.FBO );\n\tgl.readPixels( clampedX, glReadY, clampedWidth, clampedHeight, gl.RGBA, gl.UNSIGNED_BYTE, buf );\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n\n\t// Return raw WebGL data (bottom-left origin) - flipping will be done in applyFilter\n\treturn buf;\n}\n\n", "/**\n * Pi.js - Images Drawing Module\n * \n * Low-level drawing operations: image drawing.\n * \n * @module renderer/draw/images\n */\n\n\"use strict\";\n\nimport * as g_batches from \"../batches.js\";\nimport * as g_textures from \"../textures.js\";\n\n// Color array map to speed up copying of colors to vertices\nconst MAX_QUAD_COLOR_MAP_SIZE = 1000;\nconst m_quadColorMap = new Map();\n\n/**\n * Calculate transformed corner positions for a quad\n * \n * @param {number} width - Quad width\n * @param {number} height - Quad height\n * @param {number} anchorX - Anchor point X (0-1)\n * @param {number} anchorY - Anchor point Y (0-1)\n * @param {number} scaleX - Scale X factor\n * @param {number} scaleY - Scale Y factor\n * @param {number} angleRad - Rotation angle in radians\n * @param {number} x - Translation X\n * @param {number} y - Translation Y\n * @returns {Array<Object>} Array of 4 corner objects with x, y properties\n */\nfunction calculateTransformedCorners(\n\twidth, height, anchorX, anchorY, scaleX, scaleY, angleRad, x, y\n) {\n\n\t// Calculate scaled dimensions first\n\tconst scaledWidth = width * scaleX;\n\tconst scaledHeight = height * scaleY;\n\n\t// Calculate anchor position in pixels from scaled dimensions\n\tconst anchorXPx = Math.round( scaledWidth * anchorX );\n\tconst anchorYPx = Math.round( scaledHeight * anchorY );\n\n\t// Calculate corner positions relative to anchor point\n\tconst corners = [\n\t\t{ \"x\": -anchorXPx, \"y\": -anchorYPx },\t\t\t\t\t\t\t\t// Top-left\n\t\t{ \"x\": scaledWidth - anchorXPx, \"y\": -anchorYPx },\t\t\t\t\t// Top-right\n\t\t{ \"x\": -anchorXPx, \"y\": scaledHeight - anchorYPx },\t\t\t\t\t// Bottom-left\n\t\t{ \"x\": scaledWidth - anchorXPx, \"y\": scaledHeight - anchorYPx }\t\t// Bottom-right\n\t];\n\n\t// Rotate corners around (0,0) then translate to (x,y)\n\tif( angleRad !== 0 ) {\n\t\tconst cos = Math.cos( angleRad );\n\t\tconst sin = Math.sin( angleRad );\n\t\tfor( let i = 0; i < corners.length; i++ ) {\n\t\t\tconst corner = corners[ i ];\n\t\t\tconst rx = corner.x * cos - corner.y * sin;\n\t\t\tconst ry = corner.x * sin + corner.y * cos;\n\t\t\tcorner.x = rx + x;\n\t\t\tcorner.y = ry + y;\n\t\t}\n\t} else {\n\t\t\n\t\t// No rotation, just translate\n\t\tfor( let i = 0; i < corners.length; i++ ) {\n\t\t\tcorners[ i ].x += x;\n\t\t\tcorners[ i ].y += y;\n\t\t}\n\t}\n\n\treturn corners;\n}\n\n/**\n * Add a textured quad (2 triangles, 6 vertices) to IMAGE_BATCH\n * \n * TODO-LATER: Move to batch helpers and call addQuadToBatch\n * \n * @param {Object} screenData - Screen data object\n * @param {WebGLTexture} texture - WebGL texture\n * @param {Array<Object>} corners - Array of 4 corner objects with x, y properties\n * @param {Array<number>} texCoords - Array of 12 texture coordinates (2 per vertex for 6 vertices)\n * @param {Uint8Array} colorQuadArray - Color array with 6 sets of 4 color values (24 values)\n * @returns {void}\n */\nfunction addTexturedQuadToBatch(\n\tscreenData, texture, corners, texCoords, colorQuadArray, batchType\n) {\n\n\t// Prepare batch for 6 vertices (2 triangles)\n\tconst batch = screenData.batches[ batchType ];\n\tg_batches.prepareBatch( screenData, batchType, 6, texture );\n\n\tconst batchVertices = batch.vertices;\n\tconst batchTexCoords = batch.texCoords;\n\tconst batchColors = batch.colors;\n\n\t// Add two triangles (6 vertices)\n\tconst baseIdx = batch.count;\n\tconst vertexBase = baseIdx * batch.vertexComps;\n\tconst texBase = baseIdx * batch.texCoordComps;\n\tconst colorBase = baseIdx * batch.colorComps;\n\n\t// Triangle 1: Top-left, Top-right, Bottom-left\n\tlet vIdx = vertexBase;\n\tlet tIdx = texBase;\n\n\t// Vertex 0: Top-left\n\tbatchVertices[ vIdx++ ] = corners[ 0 ].x;\n\tbatchVertices[ vIdx++ ] = corners[ 0 ].y;\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 0 ];\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 1 ];\n\n\t// Vertex 1: Top-right\n\tbatchVertices[ vIdx++ ] = corners[ 1 ].x;\n\tbatchVertices[ vIdx++ ] = corners[ 1 ].y;\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 2 ];\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 3 ];\n\n\t// Vertex 2: Bottom-left\n\tbatchVertices[ vIdx++ ] = corners[ 2 ].x;\n\tbatchVertices[ vIdx++ ] = corners[ 2 ].y;\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 4 ];\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 5 ];\n\n\t// Triangle 2: Top-right, Bottom-right, Bottom-left\n\t// Vertex 3: Top-right\n\tbatchVertices[ vIdx++ ] = corners[ 1 ].x;\n\tbatchVertices[ vIdx++ ] = corners[ 1 ].y;\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 6 ];\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 7 ];\n\n\t// Vertex 4: Bottom-right\n\tbatchVertices[ vIdx++ ] = corners[ 3 ].x;\n\tbatchVertices[ vIdx++ ] = corners[ 3 ].y;\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 8 ];\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 9 ];\n\n\t// Vertex 5: Bottom-left\n\tbatchVertices[ vIdx++ ] = corners[ 2 ].x;\n\tbatchVertices[ vIdx++ ] = corners[ 2 ].y;\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 10 ];\n\tbatchTexCoords[ tIdx++ ] = texCoords[ 11 ];\n\n\tbatchColors.set( colorQuadArray, colorBase );\n\n\t// Update batch count\n\tbatch.count += 6;\n}\n\nfunction getQuadColorArray( color ) {\n\tlet quadColorArray = m_quadColorMap.get( color.key );\n\n\tif( quadColorArray === undefined ) {\n\n\t\t// Simple approach: Clear the entire map. Aggressive but easy.\n\t\tif( m_quadColorMap.size >= MAX_QUAD_COLOR_MAP_SIZE ) {\n\t\t\tm_quadColorMap.clear();\n\t\t}\n\t\t\n\t\tconst r = color.r;\n\t\tconst g = color.g;\n\t\tconst b = color.b;\n\t\tconst a = color.a;\n\n\t\t// Create the quad color array\n\t\tquadColorArray = new Uint8Array( 24 );\n\t\tquadColorArray[ 0 ] = r;\n\t\tquadColorArray[ 1 ] = g;\n\t\tquadColorArray[ 2 ] = b;\n\t\tquadColorArray[ 3 ] = a;\n\t\tquadColorArray[ 4 ] = r;\n\t\tquadColorArray[ 5 ] = g;\n\t\tquadColorArray[ 6 ] = b;\n\t\tquadColorArray[ 7 ] = a;\n\t\tquadColorArray[ 8 ] = r;\n\t\tquadColorArray[ 9 ] = g;\n\t\tquadColorArray[ 10 ] = b;\n\t\tquadColorArray[ 11 ] = a;\n\t\tquadColorArray[ 12 ] = r;\n\t\tquadColorArray[ 13 ] = g;\n\t\tquadColorArray[ 14 ] = b;\n\t\tquadColorArray[ 15 ] = a;\n\t\tquadColorArray[ 16 ] = r;\n\t\tquadColorArray[ 17 ] = g;\n\t\tquadColorArray[ 18 ] = b;\n\t\tquadColorArray[ 19 ] = a;\n\t\tquadColorArray[ 20 ] = r;\n\t\tquadColorArray[ 21 ] = g;\n\t\tquadColorArray[ 22 ] = b;\n\t\tquadColorArray[ 23 ] = a;\n\n\t\t// Add the key to map\n\t\tm_quadColorMap.set( color.key, quadColorArray );\n\t}\n\treturn quadColorArray;\n}\n\n/**\n * Draw image as textured quad with optional transform\n * \n * @param {Object} screenData - Screen data object\n * @param {Image|Canvas|WebGLTexture} img - Image, Canvas, or Texture\n * @param {number} x - X position\n * @param {number} y - Y position\n * @param {number} anchorX - Anchor point X (0-1)\n * @param {number} anchorY - Anchor point Y (0-1)\n * @param {Object} color - Color value object with rgba and key for map lookups\n * @param {number} scaleX - Scale X factor\n * @param {number} scaleY - Scale Y factor\n * @param {number} angleRad - Rotation angle in radians\n * @returns {void}\n */\nexport function drawImage( \n\tscreenData, img, x, y, color, anchorX, anchorY, scaleX, scaleY, angleRad,\n\tbatchType = g_batches.IMAGE_BATCH\n) {\n\n\t// Get or create texture\n\tconst texture = g_textures.getWebGL2Texture( screenData, img );\n\n\t// Calculate image dimensions\n\tconst imgWidth = img.width;\n\tconst imgHeight = img.height;\n\n\t// Calculate transformed corners\n\tconst corners = calculateTransformedCorners(\n\t\timgWidth, imgHeight, anchorX, anchorY, scaleX, scaleY, angleRad, x, y\n\t);\n\n\t// Texture coordinates (full image)\n\tconst texCoords = [\n\t\t0, 0,  // Top-left\n\t\t1, 0,  // Top-right\n\t\t0, 1,  // Bottom-left\n\t\t1, 0,  // Top-right (repeat for second triangle)\n\t\t1, 1,  // Bottom-right\n\t\t0, 1   // Bottom-left (repeat for second triangle)\n\t];\n\n\t// Add textured quad to batch\n\taddTexturedQuadToBatch(\n\t\tscreenData, texture, corners, texCoords, getQuadColorArray( color ), batchType\n\t);\n}\n\n/**\n * Draw sprite (sub-region) from texture atlas\n * \n * @param {Object} screenData - Screen data object\n * @param {Image|Canvas|WebGLTexture} img - Image, Canvas, or Texture\n * @param {number} sx - Source X in texture\n * @param {number} sy - Source Y in texture\n * @param {number} sw - Source width\n * @param {number} sh - Source height\n * @param {number} x - Destination X position\n * @param {number} y - Destination Y position\n * @param {number} width - Destination width\n * @param {number} height - Destination height\n * @param {Object} color - Color object with rgba and key for map lookups\n * @param {number} [anchorX=0] - Anchor point X (0-1)\n * @param {number} [anchorY=0] - Anchor point Y (0-1)\n * @param {number} [scaleX=1] - Scale X factor\n * @param {number} [scaleY=1] - Scale Y factor\n * @param {number} [angleRad=0] - Rotation angle in radians\n * @returns {void}\n */\nexport function drawSprite(\n\tscreenData, img, sx, sy, sw, sh, x, y, width, height, color,\n\tanchorX = 0, anchorY = 0, scaleX = 1, scaleY = 1, angleRad = 0,\n\tbatchType = g_batches.IMAGE_BATCH\n) {\n\n\t// Get or create texture\n\tconst texture = g_textures.getWebGL2Texture( screenData, img );\n\n\t// Get texture dimensions for coordinate conversion\n\tconst texWidth = img.width;\n\tconst texHeight = img.height;\n\n\t// Convert pixel coordinates to normalized texture coordinates (0-1)\n\tconst u0 = sx / texWidth;\n\tconst v0 = sy / texHeight;\n\tconst u1 = ( sx + sw ) / texWidth;\n\tconst v1 = ( sy + sh ) / texHeight;\n\n\t// Calculate transformed corners\n\tconst corners = calculateTransformedCorners(\n\t\twidth, height, anchorX, anchorY, scaleX, scaleY, angleRad, x, y\n\t);\n\n\t// Texture coordinates for sub-region\n\tconst texCoords = [\n\t\tu0, v0,  // Top-left\n\t\tu1, v0,  // Top-right\n\t\tu0, v1,  // Bottom-left\n\t\tu1, v0,  // Top-right (repeat for second triangle)\n\t\tu1, v1,  // Bottom-right\n\t\tu0, v1   // Bottom-left (repeat for second triangle)\n\t];\n\n\t// Add textured quad to batch\n\taddTexturedQuadToBatch(\n\t\tscreenData, texture, corners, texCoords, getQuadColorArray( color ), batchType\n\t);\n}\n\n", "/**\n * Pi.js - Low-Level Drawing Module\n * \n * Low-level drawing operations: pixel writes\n * \n * @module renderer/draw/primitives\n */\n\n\"use strict\";\n\nimport * as g_batchHelpers from \"./batch-helpers.js\";\nimport * as g_batches from \"../batches.js\";\n\n\n/**\n * Fast path for single pixel write (safe - prepares batch)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @returns {void}\n */\nexport function drawPixel( screenData, x, y, batchType ) {\n\n\t// Prep for 1 pixel\n\tg_batches.prepareBatch( screenData, batchType, 1, null, null );\n\n\t// Add directly to point batch\n\tconst batch = screenData.batches[ batchType ];\n\tg_batchHelpers.addVertexToBatch( batch, x, y, screenData.color );\n}\n\n/**\n * Fast path for single pixel write (unsafe - does not prepare batch)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @param {Object} color - Color color with [ r, g, b, a ] values (0-255)\n * @returns {void}\n */\nexport function drawPixelUnsafe( screenData, x, y, color, batchType ) {\n\n\t// Add directly to point batch\n\tconst batch = screenData.batches[ batchType ];\n\tg_batchHelpers.addVertexToBatch( batch, x, y, color );\n}\n", "/**\r\n * Pi.js - Arcs Drawing Module\r\n * \r\n * Low-level drawing operations: arcs drawing.\r\n * \r\n * drawArc, drawArcSquare, drawArcCircle\r\n * \r\n * @module renderer/draw/arcs\r\n */\r\n\r\n\"use strict\";\r\n\r\nimport * as g_batches from \"../batches.js\";\r\nimport * as g_batchHelpers from \"./batch-helpers.js\";\r\n\r\nconst TWO_PI = 2 * Math.PI;\r\nconst FULL_CIRCLE_EPSILON = 0.0001;\r\n\r\n/**\r\n * Draw arc outline using midpoint circle algorithm\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {number} cx - Center X coordinate\r\n * @param {number} cy - Center Y coordinate\r\n * @param {number} radius - Arc radius\r\n * @param {number} angle1 - Start angle in radians\r\n * @param {number} angle2 - End angle in radians\r\n * @returns {void}\r\n */\r\nexport function drawArc( screenData, cx, cy, radius, angle1, angle2 ) {\r\n\tconst color = screenData.color;\r\n\r\n\t// Normalize angles to [0, 2\u03C0)\r\n\tlet a1 = normalizeAngle( angle1 );\r\n\tlet a2 = normalizeAngle( angle2 );\r\n\r\n\t// CCW span from a1 to a2 in [0, 2\u03C0)\r\n\tlet span = a2 - a1;\r\n\tif( span < 0 ) {\r\n\t\tspan += TWO_PI;\r\n\t}\r\n\r\n\tconst isFullCircle = span >= TWO_PI - FULL_CIRCLE_EPSILON;\r\n\tconst isLargeArc = !isFullCircle && span > Math.PI;\r\n\r\n\t// Estimate pixel count based on span\r\n\tconst estimatedPixels = Math.max(\r\n\t\t4,\r\n\t\tMath.ceil( radius * ( isFullCircle ? TWO_PI : span ) )\r\n\t);\r\n\r\n\t// Prepare batch\r\n\tconst batchIndex = g_batches.POINTS_BATCH;\r\n\tg_batches.prepareBatch( screenData, batchIndex, estimatedPixels );\r\n\tconst batch = screenData.batches[ batchIndex ];\r\n\r\n\t// Precompute start/end direction vectors for angle tests\r\n\tlet startX = 0;\r\n\tlet startY = 0;\r\n\tlet endX = 0;\r\n\tlet endY = 0;\r\n\r\n\tif( !isFullCircle ) {\r\n\t\tstartX = Math.cos( a1 );\r\n\t\tstartY = Math.sin( a1 );\r\n\t\tendX = Math.cos( a2 );\r\n\t\tendY = Math.sin( a2 );\r\n\t}\r\n\r\n\t// Per-pixel plot helper with arc angle filtering (no atan2)\r\n\tlet setPixel;\r\n\r\n\tif( isFullCircle ) {\r\n\t\tsetPixel = function( px, py ) {\r\n\t\t\tg_batchHelpers.addVertexToBatch( batch, px, py, color );\r\n\t\t};\r\n\t} else if( !isLargeArc ) {\r\n\r\n\t\t// Small arc: span <= \u03C0\r\n\t\t// Inside if: cross( startDir, w ) >= 0 && cross( endDir, w ) <= 0\r\n\t\tsetPixel = function( px, py ) {\r\n\t\t\tconst dx = px - cx;\r\n\t\t\tconst dy = py - cy;\r\n\r\n\t\t\tif( dx === 0 && dy === 0 ) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst cuw = startX * dy - startY * dx;\r\n\t\t\tconst cvw = endX * dy - endY * dx;\r\n\r\n\t\t\tif( cuw >= 0 && cvw <= 0 ) {\r\n\t\t\t\tg_batchHelpers.addVertexToBatch( batch, px, py, color );\r\n\t\t\t}\r\n\t\t};\r\n\t} else {\r\n\r\n\t\t// Large arc: span > \u03C0\r\n\t\t// The gap is the small arc from endDir to startDir.\r\n\t\t// w is inside arc if it is NOT in the gap:\r\n\t\t// gap if: cross( endDir, w ) >= 0 && cross( startDir, w ) <= 0\r\n\t\tsetPixel = function( px, py ) {\r\n\t\t\tconst dx = px - cx;\r\n\t\t\tconst dy = py - cy;\r\n\r\n\t\t\tif( dx === 0 && dy === 0 ) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst cuw = startX * dy - startY * dx;\r\n\t\t\tconst cvw = endX * dy - endY * dx;\r\n\r\n\t\t\tif( !( cvw >= 0 && cuw <= 0 ) ) {\r\n\t\t\t\tg_batchHelpers.addVertexToBatch( batch, px, py, color );\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\t// Adjust radius (consistent with filled circle implementation)\r\n\tconst finalRadius = radius - 1;\r\n\r\n\t// Handle special cases\r\n\tif( finalRadius < 1 ) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif( finalRadius === 1 ) {\r\n\r\n\t\t// Draw 4 cardinal points\r\n\t\tsetPixel( cx + 1, cy );\r\n\t\tsetPixel( cx - 1, cy );\r\n\t\tsetPixel( cx, cy + 1 );\r\n\t\tsetPixel( cx, cy - 1 );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Midpoint circle algorithm\r\n\tlet x = finalRadius;\r\n\tlet y = 0;\r\n\tlet err = 1 - x;\r\n\r\n\t// Initial symmetrical points (no duplicates here)\r\n\tsetPixel( cx + x, cy + y );\r\n\tsetPixel( cx - x, cy + y );\r\n\tsetPixel( cx + y, cy + x );\r\n\tsetPixel( cx + y, cy - x );\r\n\r\n\twhile( x >= y ) {\r\n\t\ty++;\r\n\r\n\t\tif( err < 0 ) {\r\n\t\t\terr += 2 * y + 1;\r\n\t\t} else {\r\n\t\t\tx--;\r\n\t\t\terr += 2 * ( y - x ) + 1;\r\n\t\t}\r\n\r\n\t\tif( x === y ) {\r\n\r\n\t\t\t// Diagonal: 8-way symmetry collapses to 4 unique pixels\r\n\t\t\tsetPixel( cx + x, cy + y );\r\n\t\t\tsetPixel( cx - x, cy + y );\r\n\t\t\tsetPixel( cx - x, cy - y );\r\n\t\t\tsetPixel( cx + x, cy - y );\r\n\t\t} else {\r\n\r\n\t\t\t// 8-way symmetry, all distinct when x !== y\r\n\t\t\tsetPixel( cx + x, cy + y );\r\n\t\t\tsetPixel( cx + y, cy + x );\r\n\t\t\tsetPixel( cx - y, cy + x );\r\n\t\t\tsetPixel( cx - x, cy + y );\r\n\t\t\tsetPixel( cx - x, cy - y );\r\n\t\t\tsetPixel( cx - y, cy - x );\r\n\t\t\tsetPixel( cx + y, cy - x );\r\n\t\t\tsetPixel( cx + x, cy - y );\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction normalizeAngle( angle ) {\r\n\tlet normalized = angle % TWO_PI;\r\n\tif( normalized < 0 ) {\r\n\t\tnormalized += TWO_PI;\r\n\t}\r\n\treturn normalized;\r\n}\r\n", "/**\n * Pi.js - Bezier Drawing Module\n * \n * Low-level drawing operations: bezier drawing.\n * \n * drawBezier, drawBezierSquare, drawBezierCircle\n * \n * @module renderer/draw/bezier\n */\n\n\"use strict\";\n\nimport * as g_batches from \"../batches.js\";\nimport * as g_batchHelpers from \"./batch-helpers.js\";\n\n/**\n * Draw cubic Bezier with pixel pen by tessellating into short line segments.\n * Uses adaptive subdivision for smoothness and deduplicates pixels at junctions.\n * \n * @param {Object} screenData\n * @param {number} p0x\n * @param {number} p0y\n * @param {number} p1x\n * @param {number} p1y\n * @param {number} p2x\n * @param {number} p2y\n * @param {number} p3x\n * @param {number} p3y\n * @param {Object} color\n * @returns {void}\n */\nexport function drawBezier( screenData, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y ) {\n\tconst color = screenData.color;\n\n\t// Tessellate curve into points with ~0.75px max error\n\tconst maxError = 0.75;\n\tconst pts = g_batchHelpers.tessellateCubicBezier(\n\t\tp0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, maxError\n\t);\n\n\tif( pts.length < 4 ) {\n\t\t\n\t\t// Degenerate: plot a single pixel\n\t\tconst batch = screenData.batches[ g_batches.POINTS_BATCH ];\n\t\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, 1 );\n\t\tg_batchHelpers.addVertexToBatch( batch, p0x | 0, p0y | 0, color );\n\t\treturn;\n\t}\n\n\t// Track drawn pixels to avoid duplicates at segment junctions\n\tconst drawn = new Set();\n\tconst batch = screenData.batches[ g_batches.POINTS_BATCH ];\n\n\t// Draw consecutive segments, skipping duplicate pixels\n\tfor( let i = 0; i + 3 < pts.length; i += 2 ) {\n\t\tconst x1 = pts[ i ] | 0;\n\t\tconst y1 = pts[ i + 1 ] | 0;\n\t\tconst x2 = pts[ i + 2 ] | 0;\n\t\tconst y2 = pts[ i + 3 ] | 0;\n\t\tif( x1 === x2 && y1 === y2 ) continue;\n\n\t\tconst dx = Math.abs( x2 - x1 );\n\t\tconst dy = Math.abs( y2 - y1 );\n\t\tconst pointCount = Math.max( dx, dy ) + 1;\n\t\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, pointCount );\n\n\t\tconst sx = x1 < x2 ? 1 : -1;\n\t\tconst sy = y1 < y2 ? 1 : -1;\n\t\tlet err = dx - dy;\n\t\tlet x = x1;\n\t\tlet y = y1;\n\n\t\twhile( true ) {\n\t\t\tconst key = x + \",\" + y;\n\t\t\tif( !drawn.has( key ) ) {\n\t\t\t\tdrawn.add( key );\n\t\t\t\tg_batchHelpers.addVertexToBatch( batch, x, y, color );\n\t\t\t}\n\n\t\t\tif( x === x2 && y === y2 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst e2 = err * 2;\n\t\t\tif( e2 > -dy ) {\n\t\t\t\terr -= dy;\n\t\t\t\tx += sx;\n\t\t\t}\n\t\t\tif( e2 < dx ) {\n\t\t\t\terr += dx;\n\t\t\t\ty += sy;\n\t\t\t}\n\t\t}\n\t}\n}\n", "/**\n * Pi.js - Lines Drawing Module\n * \n * High-level primitive drawing operations: lines\n * \n * drawLine, drawLineSquare, drawLineCircle\n * \n * @module renderer/draw/lines\n */\n\n\"use strict\";\n\n// Import required modules\nimport * as g_batches from \"../batches.js\";\nimport * as g_batchHelpers from \"./batch-helpers.js\";\n\n\n/***************************************************************************************************\n * Module Initialization\n ***************************************************************************************************/\n\n/**\n * Draw line using WebGL2 LINES or geometry based on pen size\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x1 - Start X coordinate\n * @param {number} y1 - Start Y coordinate\n * @param {number} x2 - End X coordinate\n * @param {number} y2 - End Y coordinate\n * @returns {void}\n */\nexport function drawLine( screenData, x1, y1, x2, y2 ) {\n\tconst color = screenData.color;\n\n\t// Estimate number of points needed (Manhattan distance)\n\tconst dx = Math.abs( x2 - x1 );\n\tconst dy = Math.abs( y2 - y1 );\n\tconst pointCount = Math.max( dx, dy ) + 1;\n\n\t// Prepare batch for points\n\tconst batch = screenData.batches[ g_batches.POINTS_BATCH ];\n\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, pointCount );\n\n\t// Add a line using Bresenham's algorithm (as individual points)\n\tconst sx = x1 < x2 ? 1 : -1;\n\tconst sy = y1 < y2 ? 1 : -1;\n\tlet err = dx - dy;\n\n\tlet x = x1;\n\tlet y = y1;\n\n\twhile( true ) {\n\n\t\t// Add current point\n\t\tg_batchHelpers.addVertexToBatch( batch, x, y, color );\n\n\t\t// Check if we've reached the end\n\t\tif( x === x2 && y === y2 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// Bresenham error calculation\n\t\tconst e2 = err * 2;\n\t\tif( e2 > -dy ) {\n\t\t\terr -= dy;\n\t\t\tx += sx;\n\t\t}\n\t\tif( e2 < dx ) {\n\t\t\terr += dx;\n\t\t\ty += sy;\n\t\t}\n\t}\n}\n", "/**\n * Pi.js - Rects Drawing Module\n * \n * High-level primitive drawing operations: rects\n * \n * drawRectPenPixel, drawRectSquare, drawRectCircle\n * \n * @module renderer/draw/rects\n */\n\n\"use strict\";\n\n// Import required modules\nimport { drawLine } from \"./lines.js\";\nimport { GEOMETRY_BATCH  } from \"../renderer.js\";\nimport * as g_batches from \"../batches.js\";\nimport * as g_batchHelpers from \"./batch-helpers.js\";\n\n/***************************************************************************************************\n * Public API\n ***************************************************************************************************/\n\n\n/**\n * Draw a rectangle (outline and optional fill) using the pixel pen.\n *\n * @param {Object} screenData - Screen data object\n * @param {number} x - Left coordinate\n * @param {number} y - Top coordinate\n * @param {number} width - Rectangle width (pixels)\n * @param {number} height - Rectangle height (pixels)\n * @returns {void}\n */\nexport function drawRect( screenData, x, y, width, height ) {\n\tconst x2 = x + width - 1;\n\tconst y2 = y + height - 1;\n\tconst color = screenData.color;\n\t\n\t// Outline only for pixel pen rectangles\n\n\t// Top edge\n\tdrawRectFilled( screenData, x, y, width, 1, color );\n\n\t// Bottom edge\n\tif( height > 1 ) {\n\t\tdrawRectFilled( screenData, x, y + height - 1, width, 1, color );\n\t}\n\n\t// Left edge\n\tif( width > 1 && height > 2 ) {\n\t\tdrawRectFilled( screenData, x + width - 1, y + 1, 1, height - 2, color );\n\t}\n\t\n\t// Right edge\n\tif( height > 2 ) {\n\t\tdrawRectFilled( screenData, x, y + 1, 1, height - 2, color );\n\t}\n}\n\n\n/**\n * Draw filled rectangle (unsafe - no bounds checking, GPU clipping)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @param {number} width - Rectangle width\n * @param {number} height - Rectangle height\n * @param {Object} color - Color object with r/g/b/a components (0-255)\n * @returns {void}\n */\nexport function drawRectFilled( screenData, x, y, width, height, color ) {\n\n\t// Get geometry batch\n\tconst batch = screenData.batches[ GEOMETRY_BATCH ];\n\n\t// Prepare batch for 6 vertices (2 triangles)\n\tg_batches.prepareBatch( screenData, GEOMETRY_BATCH, 6 );\n\n\tconst x1 = x;\n\tconst y1 = y;\n\tconst x2 = x + width;\n\tconst y2 = y + height;\n\n\t// First triangle: (x,y), (x+width,y), (x,y+height)\n\tg_batchHelpers.addTriangleToBatch( batch, x1, y1, x2, y1, x1, y2, color );\n\n\t// Second triangle: (x+width,y), (x+width,y+height), (x,y+height)\n\tg_batchHelpers.addTriangleToBatch( batch, x2, y1, x2, y2, x1, y2, color );\n}\n", "/**\r\n * Pi.js - Circles Drawing Module\r\n * \r\n * Low-level drawing operations: circle drawing.\r\n * \r\n * drawCircle, drawCirclePenSquare, drawCircleCircle\r\n * \r\n * @module renderer/draw/circles\r\n */\r\n\r\n\"use strict\";\r\n\r\nimport * as g_batches from \"../batches.js\";\r\nimport * as g_geometry from \"./geometry.js\";\r\nimport { drawPixelUnsafe } from \"./primitives.js\";\r\n\r\n\r\n/**\r\n * Draw circle outline using pixel drawing (no bounds checking, GPU clipping)\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {number} cx - Center X coordinate\r\n * @param {number} cy - Center Y coordinate\r\n * @param {number} radius - Circle radius\r\n * @returns {void}\r\n */\r\nexport function drawCircle( screenData, cx, cy, radius ) {\r\n\tconst color = screenData.color;\r\n\r\n\t// Nothing to draw\r\n\tif( radius <= 0 ) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif( radius === 1 ) {\r\n\t\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, 1 );\r\n\t\tdrawPixelUnsafe( screenData, cx + 1, cy, color, g_batches.POINTS_BATCH );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Radius adjustment\r\n\tradius -= 1;\r\n\r\n\t// Single point\r\n\tif( radius === 1 ) {\r\n\t\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, 4 );\r\n\t\tdrawPixelUnsafe( screenData, cx + 1, cy, color, g_batches.POINTS_BATCH );\r\n\t\tdrawPixelUnsafe( screenData, cx - 1, cy, color, g_batches.POINTS_BATCH );\r\n\t\tdrawPixelUnsafe( screenData, cx, cy + 1, color, g_batches.POINTS_BATCH );\r\n\t\tdrawPixelUnsafe( screenData, cx, cy - 1, color, g_batches.POINTS_BATCH );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Estimate batch size based on circumference\r\n\tconst perimeterPixels = Math.round( 2 * Math.PI * radius );\r\n\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, perimeterPixels );\r\n\r\n\t// Midpoint circle algorithm (8-way symmetry)\r\n\tlet x = radius;\r\n\tlet y = 0;\r\n\tlet err = 1 - x;\r\n\r\n\t// Initial symmetrical points (no duplicates here)\r\n\tdrawPixelUnsafe( screenData, cx + x, cy + y, color, g_batches.POINTS_BATCH );\r\n\tdrawPixelUnsafe( screenData, cx - x, cy + y, color, g_batches.POINTS_BATCH );\r\n\tdrawPixelUnsafe( screenData, cx + y, cy + x, color, g_batches.POINTS_BATCH );\r\n\tdrawPixelUnsafe( screenData, cx + y, cy - x, color, g_batches.POINTS_BATCH );\r\n\r\n\twhile( x >= y ) {\r\n\t\ty++;\r\n\t\tif( err < 0 ) {\r\n\t\t\terr += 2 * y + 1;\r\n\t\t} else {\r\n\t\t\tx--;\r\n\t\t\terr += 2 * ( y - x ) + 1;\r\n\t\t}\r\n\r\n\t\tif( x === y ) {\r\n\r\n\t\t\t// On the diagonal, 8-way symmetry collapses to 4 distinct pixels.\r\n\t\t\t// Emit each unique coordinate only once so there are no overlaps.\r\n\t\t\tdrawPixelUnsafe( screenData, cx + x, cy + y, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx - x, cy + y, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx - x, cy - y, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx + x, cy - y, color, g_batches.POINTS_BATCH );\r\n\t\t} else {\r\n\r\n\t\t\t// 8-way symmetry, all distinct when x !== y\r\n\t\t\tdrawPixelUnsafe( screenData, cx + x, cy + y, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx + y, cy + x, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx - y, cy + x, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx - x, cy + y, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx - x, cy - y, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx - y, cy - x, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx + y, cy - x, color, g_batches.POINTS_BATCH );\r\n\t\t\tdrawPixelUnsafe( screenData, cx + x, cy - y, color, g_batches.POINTS_BATCH );\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\n/**\r\n * Draw filled circle (no bounds checking, GPU clipping)\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {number} cx - Center X coordinate\r\n * @param {number} cy - Center Y coordinate\r\n * @param {number} radius - Circle radius\r\n * @param {Object} color - Color object with r/g/b/a components (0-255)\r\n * @returns {void}\r\n */\r\nexport function drawCircleFilled( screenData, cx, cy, radius, color ) {\r\n\r\n\t// Apply input adjustments for MCA consistency\r\n\treturn g_geometry.drawCachedGeometry(\r\n\t\tscreenData, g_geometry.FILLED_CIRCLE, radius, cx, cy, color\r\n\t);\r\n}\r\n", "/**\n * Pi.js - Ellipses Drawing Module\n * \n * Low-level drawing operations: ellipse drawing.\n * \n * drawEllipse, drawEllipseSquare, drawEllipseCircle\n * \n * @module renderer/draw/ellipses\n */\n\n\"use strict\";\n\nimport * as g_batches from \"../batches.js\";\nimport * as g_batchHelpers from \"./batch-helpers.js\";\n\n/**\n * Draw ellipse outline or filled\n * \n * @param {Object} screenData - Screen data object\n * @param {number} cx - Center X coordinate\n * @param {number} cy - Center Y coordinate\n * @param {number} rx - Radius X\n * @param {number} ry - Radius Y\n * @param {Object} fillColor - Fill color object (or null for outline only)\n * @returns {void}\n */\nexport function drawEllipse( screenData, cx, cy, rx, ry, fillColor ) {\n\tconst color = screenData.color;\n\n\t// Validate radii\n\tif( rx < 0 || ry < 0 ) {\n\t\treturn;\n\t}\n\n\t// Handle trivial cases\n\tif( rx === 0 && ry === 0 ) {\n\t\tg_batches.prepareBatch( screenData, g_batches.POINTS_BATCH, 1 );\n\t\tconst singleBatch = screenData.batches[ g_batches.POINTS_BATCH ];\n\t\tg_batchHelpers.addVertexToBatch( singleBatch, cx, cy, color );\n\t\treturn;\n\t}\n\n\t// Estimate pixel count using Ramanujan perimeter approximation\n\t// P \u2248 \u03C0[ 3(a+b) \u2212 sqrt{ (3a+b)(a+3b) } ] where a=rx, b=ry\n\tconst a = rx;\n\tconst b = ry;\n\tconst perimeter = Math.PI * ( 3 * ( a + b ) - Math.sqrt( ( 3 * a + b ) * ( a + 3 * b ) ) );\n\tconst estimatedPixels = Math.max( 8, Math.ceil( perimeter ) );\n\n\t// Prepare outline batch\n\tconst pointsBatchIndex = g_batches.POINTS_BATCH;\n\tg_batches.prepareBatch( screenData, pointsBatchIndex, estimatedPixels );\n\tconst pointsBatch = screenData.batches[ pointsBatchIndex ];\n\n\tconst plotPoint = function( px, py ) {\n\t\tconst ix = px | 0;\n\t\tconst iy = py | 0;\n\t\tg_batchHelpers.addVertexToBatch( pointsBatch, ix, iy, color );\n\t};\n\n\t// Symmetric plotting for the four quadrants (no duplicate pixels)\n\tconst plotSymmetric = function( x, y ) {\n\t\t\n\t\t// x, y are integers from the midpoint algorithm\n\t\tif( x === 0 ) {\n\n\t\t\t// Vertical axis: top and bottom only\n\t\t\tplotPoint( cx, cy + y );\n\t\t\tif( y !== 0 ) {\n\t\t\t\tplotPoint( cx, cy - y );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif( y === 0 ) {\n\n\t\t\t// Horizontal axis: left and right only\n\t\t\tplotPoint( cx + x, cy );\n\t\t\tplotPoint( cx - x, cy );\n\t\t\treturn;\n\t\t}\n\n\t\t// General case: four distinct points\n\t\tplotPoint( cx + x, cy + y );\n\t\tplotPoint( cx - x, cy + y );\n\t\tplotPoint( cx - x, cy - y );\n\t\tplotPoint( cx + x, cy - y );\n\t};\n\n\t// Midpoint ellipse algorithm\n\tlet x = 0;\n\tlet y = ry;\n\n\tconst rx2 = rx * rx;\n\tconst ry2 = ry * ry;\n\tlet dx = 2 * ry2 * x;\n\tlet dy = 2 * rx2 * y;\n\n\t// Decision parameter for region 1\n\tlet d1 = ry2 - rx2 * ry + 0.25 * rx2;\n\tplotSymmetric( x, y );\n\n\t// Optional: collect scanlines for fill (no caching)\n\tconst doFill = fillColor !== null && rx >= 1 && ry >= 1;\n\tlet scanlineMinMax = null;\n\tlet updateScanlineSym = null;\n\n\tif( doFill ) {\n\n\t\t// Map<y, {left: x, right: x}>\n\t\tscanlineMinMax = new Map();\n\n\t\tconst updateScanline = function( px, py ) {\n\t\t\tconst pixelY = py | 0;\n\t\t\tconst pixelX = px | 0;\n\n\t\t\tif( !scanlineMinMax.has( pixelY ) ) {\n\t\t\t\tif( pixelX < 0 ) {\n\t\t\t\t\tscanlineMinMax.set( pixelY, { \"left\": pixelX, \"right\": Infinity } );\n\t\t\t\t} else if( pixelX > 0 ) {\n\t\t\t\t\tscanlineMinMax.set( pixelY, { \"left\": -Infinity, \"right\": pixelX } );\n\t\t\t\t} else {\n\t\t\t\t\tscanlineMinMax.set( pixelY, { \"left\": pixelX, \"right\": pixelX } );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst limits = scanlineMinMax.get( pixelY );\n\n\t\t\t\t// Find innermost border pixels (closest to center)\n\t\t\t\tif( pixelX < 0 && pixelX > limits.left ) {\n\t\t\t\t\tlimits.left = pixelX;\n\t\t\t\t}\n\t\t\t\tif( pixelX > 0 && pixelX < limits.right ) {\n\t\t\t\t\tlimits.right = pixelX;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Seed\n\t\tupdateScanline(  x,  y );\n\t\tupdateScanline( -x,  y );\n\t\tupdateScanline( -x, -y );\n\t\tupdateScanline(  x, -y );\n\n\t\t// Symmetric updater for scanlines (can accept any x,y pair)\n\t\tupdateScanlineSym = function( sx, sy ) {\n\t\t\tupdateScanline(  sx,  sy );\n\t\t\tupdateScanline( -sx,  sy );\n\t\t\tupdateScanline( -sx, -sy );\n\t\t\tupdateScanline(  sx, -sy );\n\t\t};\n\t}\n\n\t// Region 1\n\twhile( dx < dy ) {\n\t\tif( d1 < 0 ) {\n\t\t\tx += 1;\n\t\t\tdx = dx + 2 * ry2;\n\t\t\td1 = d1 + dx + ry2;\n\t\t} else {\n\t\t\tx += 1;\n\t\t\ty -= 1;\n\t\t\tdx = dx + 2 * ry2;\n\t\t\tdy = dy - 2 * rx2;\n\t\t\td1 = d1 + dx - dy + ry2;\n\t\t}\n\n\t\tplotSymmetric( x, y );\n\n\t\t// Update fill scanlines\n\t\tif( doFill ) {\n\t\t\tupdateScanlineSym( x, y );\n\t\t}\n\t}\n\n\t// Decision parameter for region 2\n\tlet d2 = ry2 * ( x + 0.5 ) * ( x + 0.5 ) + rx2 * ( y - 1 ) * ( y - 1 ) - rx2 * ry2;\n\n\t// Region 2\n\twhile( y >= 0 ) {\n\t\tif( d2 > 0 ) {\n\t\t\ty -= 1;\n\t\t\tdy = dy - 2 * rx2;\n\t\t\td2 = d2 + rx2 - dy;\n\t\t} else {\n\t\t\ty -= 1;\n\t\t\tx += 1;\n\t\t\tdx = dx + 2 * ry2;\n\t\t\tdy = dy - 2 * rx2;\n\t\t\td2 = d2 + dx - dy + rx2;\n\t\t}\n\n\t\tplotSymmetric( x, y );\n\n\t\t// Update fill scanlines\n\t\tif( doFill ) {\n\t\t\tupdateScanlineSym( x, y );\n\t\t}\n\t}\n\n\t// Emit fill geometry if requested\n\tif( doFill ) {\n\t\tconst sortedYCoords = [];\n\t\tfor( const [ currentY ] of scanlineMinMax.entries() ) {\n\t\t\tsortedYCoords.push( currentY );\n\t\t}\n\t\tsortedYCoords.sort( function( a, b ) { return a - b; } );\n\n\t\tif( sortedYCoords.length >= 3 ) {\n\t\t\tconst interiorRowCount = sortedYCoords.length - 2;\n\t\t\tconst vertexCount = interiorRowCount * 6;\n\t\t\tg_batches.prepareBatch( screenData, g_batches.GEOMETRY_BATCH, vertexCount );\n\t\t\tconst geoBatch = screenData.batches[ g_batches.GEOMETRY_BATCH ];\n\n\t\t\tfor( let row = 1; row < sortedYCoords.length - 1; row++ ) {\n\t\t\t\tconst currentY = sortedYCoords[ row ];\n\t\t\t\tconst limits = scanlineMinMax.get( currentY );\n\n\t\t\t\t// Skip if we don't have valid limits (safety)\n\t\t\t\tif( limits.left === -Infinity || limits.right === Infinity ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Get the interior span by moving 1 pixel inward from innermost border pixels\n\t\t\t\tconst xStart = limits.left + 1;\n\t\t\t\tconst xEnd = limits.right - 1;\n\t\t\t\tif( xEnd < xStart ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Adjust Y to align fill with outline\n\t\t\t\tconst yWorld = cy + currentY;\n\t\t\t\tconst x1 = cx + xStart;\n\t\t\t\tconst x2 = cx + xEnd + 1;\n\n\t\t\t\tg_batchHelpers.addVertexToBatch( geoBatch, x1, yWorld, fillColor );\n\t\t\t\tg_batchHelpers.addVertexToBatch( geoBatch, x2, yWorld, fillColor );\n\t\t\t\tg_batchHelpers.addVertexToBatch( geoBatch, x1, yWorld + 1, fillColor );\n\t\t\t\tg_batchHelpers.addVertexToBatch( geoBatch, x2, yWorld, fillColor );\n\t\t\t\tg_batchHelpers.addVertexToBatch( geoBatch, x2, yWorld + 1, fillColor );\n\t\t\t\tg_batchHelpers.addVertexToBatch( geoBatch, x1, yWorld + 1, fillColor );\n\t\t\t}\n\t\t}\n\t}\n}\n", "/**\n * Pi.js - Render Effects Module\n * \n * Screen-space post operations that manipulate the off-screen render target (FBO),\n * such as scrolling and simple blits.\n * \n * @module renderer/draw/effects\n */\n\n\"use strict\";\n\nimport * as g_batches from \"./batches.js\";\n\n/**\n * Shift screen image up by yOffset pixels using ping-pong FBO blit\n * \n * @param {Object} screenData - Screen data object\n * @param {number} yOffset - Number of pixels to shift up\n * @returns {void}\n */\nexport function shiftImageUp( screenData, yOffset ) {\n\n\tif( yOffset <= 0 ) {\n\t\treturn;\n\t}\n\n\tconst gl = screenData.gl;\n\tconst width = screenData.width;\n\tconst height = screenData.height;\n\n\t// Ensure the latest content is in screenData.fboTexture\n\tg_batches.flushBatches( screenData );\n\n\t// NOTE ABOUT COORDINATES:\n\t// WebGL framebuffer coordinates are bottom-left origin. When we say\n\t// \"shift image up\" in the on-screen sense, we mean the visible content moves\n\t// toward the top of the window, leaving a newly blank area at the bottom.\n\t// The blit rectangles below are chosen to achieve exactly that effect.\n\n\t// Pass 1: Copy the portion that will remain on screen after the shift\n\t// from main FBO source [0, 0, width, height - yOffset] (bottom part)\n\t// into buffer FBO destination [0, yOffset, width, height] (moved up).\n\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, screenData.FBO );\n\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, screenData.bufferFBO );\n\tgl.clearColor( 0, 0, 0, 0 );\n\tgl.clear( gl.COLOR_BUFFER_BIT );\n\tgl.blitFramebuffer(\n\t\t0, 0, width, Math.max( 0, height - yOffset ),\n\t\t0, yOffset, width, height,\n\t\tgl.COLOR_BUFFER_BIT, gl.NEAREST\n\t);\n\n\t// Pass 2: Copy the entire buffer back to the main FBO. This leaves the\n\t// bottom yOffset pixels blank (transparent), which is the desired outcome\n\t// when we say \"shift up\" (blank area appears at the bottom).\n\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, screenData.FBO );\n\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, screenData.bufferFBO );\n\tgl.blitFramebuffer(\n\t\t0, 0, width, height,\n\t\t0, 0, width, height,\n\t\tgl.COLOR_BUFFER_BIT, gl.NEAREST\n\t);\n\n\t// Unbind framebuffers\n\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );\n\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );\n\n\t// No need to call g_batches.displayToCanvas as caller should setImageDirty. \n}\n\n\n/**\n * Clear a region of the screen framebuffer\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - Left coordinate\n * @param {number} y - Top coordinate\n * @param {number} width - Region width\n * @param {number} height - Region height\n * @returns {void}\n */\nexport function cls( screenData, x, y, width, height ) {\n\n\t// If clearing entire screen remove all batches, if not flush before clearing area\n\tif( x === 0 && y === 0 && width === screenData.width && height === screenData.height ) {\n\t\tg_batches.resetBatches( screenData );\n\t} else {\n\t\tg_batches.flushBatches( screenData );\n\t}\n\n\tconst gl = screenData.gl;\n\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, screenData.FBO );\n\tgl.viewport( 0, 0, screenData.width, screenData.height );\n\n\tif(\n\t\tx === 0 &&\n\t\ty === 0 &&\n\t\twidth === screenData.width &&\n\t\theight === screenData.height\n\t) {\n\t\tgl.clearColor( 0, 0, 0, 0 );\n\t\tgl.clear( gl.COLOR_BUFFER_BIT );\n\t} else {\n\t\tgl.enable( gl.SCISSOR_TEST );\n\t\tconst scissorY = screenData.height - ( y + height );\n\t\tgl.scissor( x, scissorY, width, height );\n\t\tgl.clearColor( 0, 0, 0, 0 );\n\t\tgl.clear( gl.COLOR_BUFFER_BIT );\n\t\tgl.disable( gl.SCISSOR_TEST );\n\t}\n\n\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n}", "/**\r\n * Pi.js - Graphics API Module\r\n * \r\n * Thin wrapper layer for graphics commands.\r\n * Handles input parsing, validation, and builds optimized drawing functions.\r\n * \r\n * @module api/graphics\r\n */\r\n\r\n\"use strict\";\r\n\r\n// Import modules\r\nimport * as g_commands from \"../core/commands.js\";\r\nimport * as g_screenManager from \"../core/screen-manager.js\";\r\nimport * as g_utils from \"../core/utils.js\";\r\nimport * as g_renderer from \"../renderer/renderer.js\";\r\nimport * as g_colors from \"./colors.js\";\r\nimport * as g_images from \"./images.js\";\r\n\r\nconst DEFAULT_BLIT_COLOR = g_utils.rgbToColor( 255, 255, 255, 255 );\r\nlet m_api = null;\r\n\r\n\r\n/***************************************************************************************************\r\n * Module Commands\r\n ***************************************************************************************************/\r\n\r\n\r\n// Initialize graphics module - only gets called on script load\r\nexport function init( api ) {\r\n\tm_api = api;\r\n\r\n\t// Build the null graphics commands - basically will throw an error since no screen is available\r\n\tbuildApi( null );\r\n\r\n\t// CLS doesn't need to be a hot-path item so just use addCommand\r\n\tg_commands.addCommand( \"cls\", cls, true, [ \"x\", \"y\", \"width\", \"height\" ] );\r\n\r\n\t// Register screen init function to rebuild API when screen is created\r\n\tg_screenManager.addScreenInitFunction( ( screenData ) => buildApi( screenData ) );\r\n}\r\n\r\n// Function to build the external API drawing commands (e.g., pset, line, etc...) for the current\r\n// active screen. This creates specialized API wrappers that handle input parsing/validation, then\r\n// call optimized internal drawing routines. By closing over specific, already-optimized functions\r\n// and screen configuration, it provides highly performant, monomorphic call sites in hot loops.\r\nexport function buildApi( s_screenData ) {\r\n\r\n\t// Set error functions for when no screen is available\r\n\tif( s_screenData === null ) {\r\n\t\tm_api.arc = () => g_utils.errFn( \"arc\" );\r\n\t\tm_api.bezier = () => g_utils.errFn( \"bezier\" );\r\n\t\tm_api.circle = () => g_utils.errFn( \"circle\" );\r\n\t\tm_api.ellipse = () => g_utils.errFn( \"ellipse\" );\r\n\t\tm_api.line = () => g_utils.errFn( \"line\" );\r\n\t\tm_api.pset = () => g_utils.errFn( \"pset\" );\r\n\t\tm_api.rect = () => g_utils.errFn( \"rect\" );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Draw commands\r\n\tconst s_drawArc = g_renderer.drawArc;\r\n\tconst s_drawBezier = g_renderer.drawBezier;\r\n\tconst s_drawCircle = g_renderer.drawCircle;\r\n\tconst s_drawCircleFilled = g_renderer.drawCircleFilled;\r\n\tconst s_drawEllipse = g_renderer.drawEllipse;\r\n\tconst s_drawLine = g_renderer.drawLine;\r\n\tconst s_drawPixel = g_renderer.drawPixel;\r\n\tconst s_drawRect = g_renderer.drawRect;\r\n\tconst s_drawRectFilled = g_renderer.drawRectFilled;\r\n\tconst s_drawImage = g_renderer.drawImage;\r\n\tconst s_drawSprite = g_renderer.drawSprite;\r\n\t\r\n\t// Other API Commands\r\n\tconst s_getImageFromRawInput = g_images.getImageFromRawInput;\r\n\tconst s_getStoredImage = g_images.getStoredImage;\r\n\r\n\t// Utility commands\r\n\tconst s_isObjectLiteral = g_utils.isObjectLiteral;\r\n\tconst s_setImageDirty = g_renderer.setImageDirty;\r\n\tconst s_getInt = g_utils.getInt;\r\n\tconst s_getFloat = g_utils.getFloat;\r\n\tconst s_degreesToRadian = g_utils.degreesToRadian;\r\n\tconst s_getColorValueByRawInput = g_colors.getColorValueByRawInput;\r\n\r\n\t// Constants\r\n\tconst s_pointsBatch = g_renderer.POINTS_BATCH;\r\n\tconst s_imageReplaceBatch = g_renderer.IMAGE_REPLACE_BATCH;\r\n\r\n\t/**********************************************************************************************\r\n\t * ARC Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst arcFn = ( x, y, radius, angle1, angle2 ) => {\r\n\t\tconst pX = s_getInt( x, null );\r\n\t\tconst pY = s_getInt( y, null );\r\n\t\tconst pRadius = s_getInt( radius, null );\r\n\r\n\t\t// Validate integer parameters\r\n\t\tif( pX === null || pY === null || pRadius === null ) {\r\n\t\t\tconst error = new TypeError( \"arc: Parameters x, y, and radius must be integers.\" );\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Validate angle parameters (numbers in radians)\r\n\t\tif(\r\n\t\t\ttypeof angle1 !== \"number\" || isNaN( angle1 ) ||\r\n\t\t\ttypeof angle2 !== \"number\" || isNaN( angle2 )\r\n\t\t) {\r\n\t\t\tconst error = new TypeError(\r\n\t\t\t\t\"arc: Parameters angle1 and angle2 must be numbers (in radians).\"\r\n\t\t\t);\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Draw Arc\r\n\t\ts_drawArc(\r\n\t\t\ts_screenData, pX, pY, pRadius, s_degreesToRadian( angle1 ),\r\n\t\t\ts_degreesToRadian( angle2 )\r\n\t\t);\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\tconst arcFnWrapper = ( x, y, radius, angle1, angle2 ) => {\r\n\t\tif( s_isObjectLiteral( x ) ) {\r\n\t\t\tarcFn( x.x, x.y, x.radius, x.angle1, x.angle2 );\r\n\t\t} else {\r\n\t\t\tarcFn( x, y, radius, angle1, angle2 );\r\n\t\t}\r\n\t};\r\n\tm_api.arc = arcFnWrapper;\r\n\ts_screenData.api.arc = arcFnWrapper;\r\n\t\r\n\t/**********************************************************************************************\r\n\t * BEZIER Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst bezierFn = ( x1, y1, x2, y2, x3, y3, x4, y4 ) => {\r\n\t\tconst pX1 = s_getInt( x1, null );\r\n\t\tconst pY1 = s_getInt( y1, null );\r\n\t\tconst pX2 = s_getInt( x2, null );\r\n\t\tconst pY2 = s_getInt( y2, null );\r\n\t\tconst pX3 = s_getInt( x3, null );\r\n\t\tconst pY3 = s_getInt( y3, null );\r\n\t\tconst pX4 = s_getInt( x4, null );\r\n\t\tconst pY4 = s_getInt( y4, null );\r\n\r\n\t\tif(\r\n\t\t\tpX1 === null || pY1 === null || pX2 === null || pY2 === null ||\r\n\t\t\tpX3 === null || pY3 === null || pX4 === null || pY4 === null\r\n\t\t) {\r\n\t\t\tconst error = new TypeError(\r\n\t\t\t\t\"bezier: All control point coordinates must be integers.\"\r\n\t\t\t);\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Draw Bezier\r\n\t\ts_drawBezier( s_screenData, pX1, pY1, pX2, pY2, pX3, pY3, pX4, pY4 );\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\tconst bezierFnWrapper = ( x1, y1, x2, y2, x3, y3, x4, y4 ) => {\r\n\t\tif( s_isObjectLiteral( x1 ) ) {\r\n\t\t\tbezierFn( x1.x1, x1.y1, x1.x2, x1.y2, x1.x3, x1.y3, x1.x4, x1.y4 );\r\n\t\t} else {\r\n\t\t\tbezierFn( x1, y1, x2, y2, x3, y3, x4, y4 );\r\n\t\t}\r\n\t};\r\n\tm_api.bezier = bezierFnWrapper;\r\n\ts_screenData.api.bezier = bezierFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * Circle Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst circleFn = ( x, y, radius, fillColor ) => {\r\n\t\tconst pX = s_getInt( x, null );\r\n\t\tconst pY = s_getInt( y, null );\r\n\t\tconst pRadius = s_getInt( radius, null );\r\n\r\n\t\tif( pX === null || pY === null || pRadius === null ) {\r\n\t\t\tconst error = new TypeError(\r\n\t\t\t\t\"circle: Parameters x, y, and radius must be integers.\"\r\n\t\t\t);\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Parse and validate fillColor here (single source of truth)\r\n\t\tlet fillColorValue = null;\r\n\t\tif( fillColor != null ) {\r\n\t\t\tfillColorValue = s_getColorValueByRawInput( s_screenData, fillColor );\r\n\t\t\tif( fillColorValue === null ) {\r\n\t\t\t\tconst error = new TypeError( \"rect: Parameter 'fillColor' must be a valid color.\" );\r\n\t\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\t\tthrow error;\r\n\t\t\t}\r\n\r\n\t\t\t// Fill in the circle\r\n\t\t\tif( pRadius > 0 ) {\r\n\t\t\t\ts_drawCircleFilled( s_screenData, pX, pY, pRadius, fillColorValue );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Draw the circle border\r\n\t\ts_drawCircle( s_screenData, pX, pY, pRadius );\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\tconst circleFnWrapper = ( x, y, radius, fillColor ) => {\r\n\t\tif( s_isObjectLiteral( x ) ) {\r\n\t\t\tcircleFn( x.x, x.y, x.radius, x.fillColor );\r\n\t\t} else {\r\n\t\t\tcircleFn( x, y, radius, fillColor);\r\n\t\t}\r\n\t};\r\n\r\n\tm_api.circle = circleFnWrapper;\r\n\ts_screenData.api.circle = circleFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * Ellipse Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst ellipseFn = ( x, y, radiusX, radiusY, fillColor ) => {\r\n\t\tconst pX = s_getInt( x, null );\r\n\t\tconst pY = s_getInt( y, null );\r\n\t\tconst pRx = s_getInt( radiusX, null );\r\n\t\tconst pRy = s_getInt( radiusY, null );\r\n\r\n\t\tif( pX === null || pY === null || pRx === null || pRy === null ) {\r\n\t\t\tconst error = new TypeError( \"ellipse: Parameters x, y, rx, and ry must be integers.\" );\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Parse and validate fillColor here (single source of truth)\r\n\t\tlet fillColorValue = null;\r\n\t\tif( fillColor != null ) {\r\n\t\t\tfillColorValue = s_getColorValueByRawInput( s_screenData, fillColor );\r\n\t\t\tif( fillColorValue === null ) {\r\n\t\t\t\tconst error = new TypeError(\r\n\t\t\t\t\t\"ellipse: Parameter 'fillColor' must be a valid color.\"\r\n\t\t\t\t);\r\n\t\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\t\tthrow error;\r\n\t\t\t}\r\n\r\n\t\t\t// Filled handled inside drawEllipse\r\n\t\t}\r\n\r\n\t\t// Draw the ellipse border\r\n\t\ts_drawEllipse( s_screenData, pX, pY, pRx, pRy, fillColorValue );\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\tconst ellipseFnWrapper = ( x, y, radiusX, radiusY, fillColor ) => {\r\n\t\tif( s_isObjectLiteral( x ) ) {\r\n\t\t\tellipseFn( x.x, x.y, x.radiusX, x.radiusY, x.fillColor );\r\n\t\t} else {\r\n\t\t\tellipseFn( x, y, radiusX, radiusY, fillColor);\r\n\t\t}\r\n\t};\r\n\r\n\tm_api.ellipse = ellipseFnWrapper;\r\n\ts_screenData.api.ellipse = ellipseFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * LINE Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst lineFn = ( x1, y1, x2, y2 ) => {\r\n\t\tconst pX1 = s_getInt( x1, null );\r\n\t\tconst pY1 = s_getInt( y1, null );\r\n\t\tconst pX2 = s_getInt( x2, null );\r\n\t\tconst pY2 = s_getInt( y2, null );\r\n\r\n\t\t// Make sure x1, y1, x2, y2 are integers\r\n\t\tif( pX1 === null || pY1 === null || pX2 === null || pY2 === null ) {\r\n\t\t\tconst error = new TypeError( \"line: Parameters x1, y1, x2, y2 must be integers.\" );\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Draw Line\r\n\t\ts_drawLine( s_screenData, pX1, pY1, pX2, pY2 );\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\tconst lineFnWrapper = ( x1, y1, x2, y2 ) => {\r\n\t\tif( s_isObjectLiteral( x1 ) ) {\r\n\t\t\tlineFn( x1.x1 , x1.y1, x1.x2, x1.y2 );\r\n\t\t} else {\r\n\t\t\tlineFn( x1, y1, x2, y2 );\r\n\t\t}\r\n\t};\r\n\r\n\tm_api.line = lineFnWrapper;\r\n\ts_screenData.api.line = lineFnWrapper;\r\n\t\r\n\t/**********************************************************************************************\r\n\t * PSET Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst psetFn = ( x, y ) => {\r\n\t\tconst pX = s_getInt( x, null );\r\n\t\tconst pY = s_getInt( y, null );\r\n\r\n\t\t// Make sure x and y are integers\r\n\t\tif( pX === null || pY === null ) {\r\n\t\t\tconst error = new TypeError( \"pset: Parameters x and y must be integers.\" );\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Draw the pixel\r\n\t\ts_drawPixel( s_screenData, pX, pY, s_pointsBatch );\r\n\t\ts_setImageDirty( s_screenData );\r\n\r\n\t\t// Set the cursor after drawing\r\n\t\ts_screenData.cursor.x = x;\r\n\t\ts_screenData.cursor.y = y;\r\n\t};\r\n\tconst psetFnWrapper = ( x, y ) => {\r\n\t\tif( s_isObjectLiteral( x ) ) {\r\n\t\t\tpsetFn( x.x , x.y );\r\n\t\t} else {\r\n\t\t\tpsetFn( x, y );\r\n\t\t}\r\n\t};\r\n\tm_api.pset = psetFnWrapper;\r\n\ts_screenData.api.pset = psetFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * RECT Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst rectFn = ( x, y, width, height, fillColor ) => {\r\n\t\tconst pX = s_getInt( x, null );\r\n\t\tconst pY = s_getInt( y, null );\r\n\t\tconst pWidth = s_getInt( width, null );\r\n\t\tconst pHeight = s_getInt( height, null );\r\n\r\n\t\tif( pX === null || pY === null || pWidth === null || pHeight === null ) {\r\n\t\t\tconst error = new TypeError( \"rect: Parameters x, y, width, height must be integers.\" );\r\n\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tif( pWidth < 1 || pHeight < 1 ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Parse and validate fillColor here (single source of truth)\r\n\t\tlet fillColorValue = null;\r\n\t\tif( fillColor != null ) {\r\n\t\t\tfillColorValue = s_getColorValueByRawInput( s_screenData, fillColor );\r\n\t\t\tif( fillColorValue === null ) {\r\n\t\t\t\tconst error = new TypeError( \"rect: Parameter 'fillColor' must be a valid color.\" );\r\n\t\t\t\terror.code = \"INVALID_PARAMETER\";\r\n\t\t\t\tthrow error;\r\n\t\t\t}\r\n\r\n\t\t\t// Fill in the rectangle\r\n\t\t\tconst fWidth = pWidth - 2;\r\n\t\t\tconst fHeight = pHeight - 2;\r\n\t\t\tif( fWidth > 0 && fHeight > 0 ) {\r\n\t\t\t\ts_drawRectFilled( s_screenData, pX + 1, pY + 1, fWidth, fHeight, fillColorValue );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Draw the rect border\r\n\t\ts_drawRect( s_screenData, pX, pY, pWidth, pHeight );\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\tconst rectFnWrapper = ( x, y, width, height, fillColor ) => {\r\n\t\tif( s_isObjectLiteral( x ) ) {\r\n\t\t\trectFn( x.x , x.y, x.width, x.height, x.fillColor );\r\n\t\t} else {\r\n\t\t\trectFn( x, y, width, height, fillColor );\r\n\t\t}\r\n\t};\r\n\r\n\tm_api.rect = rectFnWrapper;\r\n\ts_screenData.api.rect = rectFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * BLIT IMAGE Command\r\n\t **********************************************************************************************/\r\n\r\n\t// Draw image with blending disabled\r\n\tconst blitImageFn = ( img, x, y, color, anchorX, anchorY, scaleX, scaleY, angleRad ) => {\r\n\t\tconst pAnchorX = anchorX ?? s_screenData.defaultAnchorX;\r\n\t\tconst pAnchorY = anchorY ?? s_screenData.defaultAnchorY;\r\n\t\tconst pColor = color ?? DEFAULT_BLIT_COLOR;\r\n\t\ts_drawImage(\r\n\t\t\ts_screenData, img, x, y, pColor, pAnchorX, pAnchorY, scaleX, scaleY, angleRad,\r\n\t\t\ts_imageReplaceBatch\r\n\t\t);\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\r\n\tconst blitImageFnWrapper = (\r\n\t\timg,\r\n\t\tx = 0,\r\n\t\ty = 0,\r\n\t\tcolor,\r\n\t\tanchorX,\r\n\t\tanchorY,\r\n\t\tscaleX = 1,\r\n\t\tscaleY = 1,\r\n\t\tangleRad = 0\r\n\t) => {\r\n\t\tif( s_isObjectLiteral( img ) ) {\r\n\t\t\tblitImageFn(\r\n\t\t\t\timg.img, img.x, img.y, img.color, img.anchorX, img.anchorY, img.scaleX, img.scaleY,\r\n\t\t\t\timg.angleRad\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tblitImageFn( img, x, y, color, anchorX, anchorY, scaleX, scaleY, angleRad );\r\n\t\t}\r\n\t};\r\n\tm_api.blitImage = blitImageFnWrapper;\r\n\ts_screenData.api.blitImage = blitImageFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * BLIT SPRITE Command\r\n\t **********************************************************************************************/\r\n\r\n\t// Draw image with blending disabled\r\n\tconst blitSpriteFn = (\r\n\t\tname, frame, x, y, color, anchorX, anchorY, scaleX, scaleY, angleRad\r\n\t) => {\r\n\t\tconst spriteData = s_getStoredImage( name );\r\n\t\tconst frameData = spriteData.frames[ frame ];\r\n\t\tconst img = spriteData.image;\r\n\t\tconst pAnchorX = anchorX ?? s_screenData.defaultAnchorX;\r\n\t\tconst pAnchorY = anchorY ?? s_screenData.defaultAnchorY;\r\n\t\tconst pColor = color ?? DEFAULT_BLIT_COLOR;\r\n\t\ts_drawSprite(\r\n\t\t\ts_screenData, img,\r\n\t\t\tframeData.x, frameData.y, frameData.width, frameData.height,\r\n\t\t\tx, y, frameData.width, frameData.height,\r\n\t\t\tpColor, pAnchorX, pAnchorY, scaleX, scaleY, angleRad,\r\n\t\t\ts_imageReplaceBatch\r\n\t\t);\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\r\n\tconst blitSpriteFnWrapper = (\r\n\t\tname,\r\n\t\tframe = 0,\r\n\t\tx = 0,\r\n\t\ty = 0,\r\n\t\tcolor,\r\n\t\tanchorX,\r\n\t\tanchorY,\r\n\t\tscaleX = 1,\r\n\t\tscaleY = 1,\r\n\t\tangleRad = 0\r\n\t) => {\r\n\t\tif( s_isObjectLiteral( name ) ) {\r\n\t\t\tblitSpriteFn(\r\n\t\t\t\tname.name, name.frame, name.x, name.y, name.color, name.anchorX, name.anchorY,\r\n\t\t\t\tname.scaleX, name.scaleY, name.angleRad\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tblitSpriteFn( name, frame, x, y, color, anchorX, anchorY, scaleX, scaleY, angleRad );\r\n\t\t}\r\n\t};\r\n\tm_api.blitSprite = blitSpriteFnWrapper;\r\n\ts_screenData.api.blitSprite = blitSpriteFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * DRAW IMAGE Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst drawImageFn = ( image, x, y, color, anchorX, anchorY, scaleX, scaleY, angle ) => {\r\n\t\tx = s_getInt( x, null );\r\n\t\ty = s_getInt( y, null );\r\n\t\tcolor = color ?? DEFAULT_BLIT_COLOR;\r\n\t\tanchorX = s_getFloat( anchorX, s_screenData.defaultAnchorX );\r\n\t\tanchorY = s_getFloat( anchorY, s_screenData.defaultAnchorY );\r\n\t\tscaleX = s_getFloat( scaleX, 1 );\r\n\t\tscaleY = s_getFloat( scaleY, 1 );\r\n\t\tangle = s_getFloat( angle, 0 );\r\n\t\timage = s_getImageFromRawInput( image, \"drawImage\" );\r\n\t\r\n\t\t// Validate coordinates\r\n\t\tif( x === null || y === null ) {\r\n\t\t\tconst error = new TypeError( \"drawImage: Parameters x and y must be numbers.\" );\r\n\t\t\terror.code = \"INVALID_COORDINATES\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\t\r\n\t\t// Parses the color and makes sure it's in a valid format\r\n\t\tcolor = s_getColorValueByRawInput( s_screenData, color );\r\n\t\tif( color === null ) {\r\n\t\t\tcolor = DEFAULT_BLIT_COLOR;\r\n\t\t}\r\n\t\t\t\r\n\t\t// Convert angle from degrees to radians\r\n\t\tconst angleRad = s_degreesToRadian( angle );\r\n\t\r\n\t\t// Draw using renderer-specific implementation\r\n\t\ts_drawImage(\r\n\t\t\ts_screenData, image, x, y, color, anchorX, anchorY, scaleX, scaleY, angleRad\r\n\t\t);\r\n\t\r\n\t\t// Mark screen as dirty\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\r\n\tconst drawImageFnWrapper = ( image, x, y, color, anchorX, anchorY, scaleX, scaleY, angle ) => {\r\n\t\tif( s_isObjectLiteral( image ) ) {\r\n\t\t\tdrawImageFn(\r\n\t\t\t\timage.image, image.x, image.y, image.color, image.anchorX, image.anchorY,\r\n\t\t\t\timage.scaleX, image.scaleY, image.angle\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tdrawImageFn( image, x, y, color, anchorX, anchorY, scaleX, scaleY, angle );\r\n\t\t}\r\n\t};\r\n\r\n\tm_api.drawImage = drawImageFnWrapper;\r\n\ts_screenData.api.drawImage = drawImageFnWrapper;\r\n\r\n\t/**********************************************************************************************\r\n\t * DRAW SPRITE Command\r\n\t **********************************************************************************************/\r\n\r\n\tconst drawSpriteFn = ( name, frame, x, y, color, anchorX, anchorY, scaleX, scaleY, angle ) => {\r\n\t\tframe = frame ?? 0;\r\n\t\tx = s_getInt( x, null );\r\n\t\ty = s_getInt( y, null );\r\n\t\tcolor = color ?? DEFAULT_BLIT_COLOR;\r\n\t\tanchorX = s_getFloat( anchorX, s_screenData.defaultAnchorX );\r\n\t\tanchorY = s_getFloat( anchorY, s_screenData.defaultAnchorY );\r\n\t\tscaleX = s_getFloat( scaleX, 1 );\r\n\t\tscaleY = s_getFloat( scaleY, 1 );\r\n\t\tangle = s_getFloat( angle, 0 );\r\n\r\n\t\t// Validate name\r\n\t\tif( typeof name !== \"string\" ) {\r\n\t\t\tconst error = new TypeError( \"drawSprite: Parameter name must be a string.\" );\r\n\t\t\terror.code = \"INVALID_NAME\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tconst spriteData = s_getStoredImage( name );\r\n\t\tif( !spriteData ) {\r\n\t\t\tconst error = new Error( `drawSprite: Spritesheet \"${name}\" not found.` );\r\n\t\t\terror.code = \"IMAGE_NOT_FOUND\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Validate it's a spritesheet\r\n\t\tif( spriteData.type !== \"spritesheet\" ) {\r\n\t\t\tconst error = new Error( `drawSprite: Image \"${name}\" is not a spritesheet.` );\r\n\t\t\terror.code = \"NOT_A_SPRITESHEET\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tif( spriteData.status !== \"ready\" ) {\r\n\t\t\tconst imgName = `Spritesheet \"${name}\"`;\r\n\t\t\tif( spriteData.status === \"loading\" ) {\r\n\t\t\t\tconst error = new Error(\r\n\t\t\t\t\t`drawSprite: ${imgName} is still loading. Use $.ready() to wait for it.`\r\n\t\t\t\t);\r\n\t\t\t\terror.code = \"IMAGE_NOT_READY\";\r\n\t\t\t\tthrow error;\r\n\t\t\t}\r\n\r\n\t\t\tif( spriteData.status === \"error\" ) {\r\n\t\t\t\tconst error = new Error( `drawSprite: ${imgName} failed to load.` );\r\n\t\t\t\terror.code = \"IMAGE_LOAD_FAILED\";\r\n\t\t\t\tthrow error;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Validate frame\r\n\t\tif( !Number.isInteger( frame ) || frame >= spriteData.frames.length || frame < 0 ) {\r\n\t\t\tconst error = new RangeError(\r\n\t\t\t\t`drawSprite: Frame ${frame} is not valid. Spritesheet has ` +\r\n\t\t\t\t`${spriteData.frames.length} frames.`\r\n\t\t\t);\r\n\t\t\terror.code = \"INVALID_FRAME\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Validate coordinates\r\n\t\tif( x === null || y === null ) {\r\n\t\t\tconst error = new TypeError( \"drawSprite: Parameters x and y must be numbers.\" );\r\n\t\t\terror.code = \"INVALID_COORDINATES\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\t// Parses the color and makes sure it's in a valid format\r\n\t\tcolor = s_getColorValueByRawInput( s_screenData, color );\r\n\t\tif( color === null ) {\r\n\t\t\tcolor = DEFAULT_BLIT_COLOR;\r\n\t\t}\r\n\r\n\t\t// Convert angle from degrees to radians\r\n\t\tconst angleRad = s_degreesToRadian( angle );\r\n\r\n\t\t// Get frame data\r\n\t\tconst frameData = spriteData.frames[ frame ];\r\n\t\tconst img = spriteData.image;\r\n\r\n\t\t// Draw using renderer-specific implementation\r\n\t\tg_renderer.drawSprite(\r\n\t\t\ts_screenData, img,\r\n\t\t\tframeData.x, frameData.y, frameData.width, frameData.height,\r\n\t\t\tx, y, frameData.width, frameData.height,\r\n\t\t\tcolor, anchorX, anchorY, scaleX, scaleY, angleRad\r\n\t\t);\r\n\r\n\t\t// Mark screen as dirty\r\n\t\ts_setImageDirty( s_screenData );\r\n\t};\r\n\r\n\tconst drawSpriteFnWrapper = (\r\n\t\tname, frame, x, y, color, anchorX, anchorY, scaleX, scaleY, angle\r\n\t) => {\r\n\t\tif( s_isObjectLiteral( name ) ) {\r\n\t\t\tdrawSpriteFn(\r\n\t\t\t\tname.name, name.frame, name.x, name.y, name.color, name.anchorX, name.anchorY,\r\n\t\t\t\tname.scaleX, name.scaleY, name.angle\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tdrawSpriteFn( name, frame, x, y, color, anchorX, anchorY, scaleX, scaleY, angle );\r\n\t\t}\r\n\t};\r\n\r\n\tm_api.drawSprite = drawSpriteFnWrapper;\r\n\ts_screenData.api.drawSprite = drawSpriteFnWrapper;\r\n}\r\n\r\n/**\r\n * Clear the screen or a rectangular region\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Options containing x, y, width, height\r\n * @returns {void}\r\n */\r\nfunction cls( screenData, options ) {\r\n\tconst x = g_utils.clamp( g_utils.getInt( options.x, 0 ), 0, screenData.width );\r\n\tconst y = g_utils.clamp( g_utils.getInt( options.y, 0 ), 0, screenData.height );\r\n\tconst width = g_utils.clamp(\r\n\t\tg_utils.getInt( options.width, screenData.width - x ), 0, screenData.width\r\n\t);\r\n\tconst height = g_utils.clamp(\r\n\t\tg_utils.getInt( options.height, screenData.height - y ), 0, screenData.height\r\n\t);\r\n\r\n\tif( width <= 0 || height <= 0 ) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tg_renderer.cls( screenData, x, y, width, height );\r\n\tg_renderer.setImageDirty( screenData );\r\n\r\n\t// Reset the cursor position if clearing the full screen\r\n\tif( x === 0 && y === 0 && width === screenData.width && height === screenData.height ) {\r\n\t\tscreenData.api.setPos( 0, 0 );\r\n\t}\r\n}\r\n", "/**\n * Pi.js - Colors Module\n * \n * Manages the color palettes and color values.\n * Simplified version focused on WebGL2 rendering.\n * \n * @module api/colors\n */\n\n\"use strict\";\n\n// Import modules directly\nimport * as g_commands from \"../core/commands.js\";\nimport * as g_utils from \"../core/utils.js\";\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_images from \"./images.js\";\n\n// Max color difference used in find color by index\nconst MAX_DIFFERENCE = ( 255 * 255 ) * 3.25;\n\nlet m_defaultPal = [];\nlet m_defaultPalMap = new Map();\nlet m_defaultColor = -1;\n\n\n/***************************************************************************************************\n * Module Commands\n **************************************************************************************************/\n\n\n// Initialize color defaults\nexport function init( api ) {\n\n\t// Default 256-color palette (CGA + extended colors) - raw hex strings\n\tconst defaultPaletteHex = [\n\t\t\"#0000AA\", \"#00AA00\", \"#00AAAA\", \"#AA0000\", \"#AA00AA\", \"#AA5500\", \"#AAAAAA\", \"#555555\",\n\t\t\"#5555FF\", \"#55FF55\", \"#55FFFF\", \"#FF5555\", \"#FF55FF\", \"#FFFF55\", \"#FFFFFF\", \"#000000\",\n\t\t\"#141414\", \"#202020\", \"#2D2D2D\", \"#393939\", \"#454545\", \"#515151\", \"#616161\", \"#717171\",\n\t\t\"#828282\", \"#929292\", \"#A2A2A2\", \"#B6B6B6\", \"#CACACA\", \"#E3E3E3\", \"#FFFFFF\", \"#0000FF\",\n\t\t\"#4100FF\", \"#7D00FF\", \"#BE00FF\", \"#FF00FF\", \"#FF00BE\", \"#FF007D\", \"#FF0041\", \"#FF0000\",\n\t\t\"#FF4100\", \"#FF7D00\", \"#FFBE00\", \"#FFFF00\", \"#BEFF00\", \"#7DFF00\", \"#41FF00\", \"#00FF00\",\n\t\t\"#00FF41\", \"#00FF7D\", \"#00FFBE\", \"#00FFFF\", \"#00BEFF\", \"#007DFF\", \"#0041FF\", \"#7D7DFF\",\n\t\t\"#9E7DFF\", \"#BE7DFF\", \"#DF7DFF\", \"#FF7DFF\", \"#FF7DDF\", \"#FF7DBE\", \"#FF7D9E\", \"#FF7D7D\",\n\t\t\"#FF9E7D\", \"#FFBE7D\", \"#FFDF7D\", \"#FFFF7D\", \"#DFFF7D\", \"#BEFF7D\", \"#9EFF7D\", \"#7DFF7D\",\n\t\t\"#7DFF9E\", \"#7DFFBE\", \"#7DFFDF\", \"#7DFFFF\", \"#7DDFFF\", \"#7DBEFF\", \"#7D9EFF\", \"#B6B6FF\",\n\t\t\"#C6B6FF\", \"#DBB6FF\", \"#EBB6FF\", \"#FFB6FF\", \"#FFB6EB\", \"#FFB6DB\", \"#FFB6C6\", \"#FFB6B6\",\n\t\t\"#FFC6B6\", \"#FFDBB6\", \"#FFEBB6\", \"#FFFFB6\", \"#EBFFB6\", \"#DBFFB6\", \"#C6FFB6\", \"#B6FFB6\",\n\t\t\"#B6FFC6\", \"#B6FFDB\", \"#B6FFEB\", \"#B6FFFF\", \"#B6EBFF\", \"#B6DBFF\", \"#B6C6FF\", \"#000071\",\n\t\t\"#1C0071\", \"#390071\", \"#550071\", \"#710071\", \"#710055\", \"#710039\", \"#71001C\", \"#710000\",\n\t\t\"#711C00\", \"#713900\", \"#715500\", \"#717100\", \"#557100\", \"#397100\", \"#1C7100\", \"#007100\",\n\t\t\"#00711C\", \"#007139\", \"#007155\", \"#007171\", \"#005571\", \"#003971\", \"#001C71\", \"#393971\",\n\t\t\"#453971\", \"#553971\", \"#613971\", \"#713971\", \"#713961\", \"#713955\", \"#713945\", \"#713939\",\n\t\t\"#714539\", \"#715539\", \"#716139\", \"#717139\", \"#617139\", \"#557139\", \"#457139\", \"#397139\",\n\t\t\"#397145\", \"#397155\", \"#397161\", \"#397171\", \"#396171\", \"#395571\", \"#394571\", \"#515171\",\n\t\t\"#595171\", \"#615171\", \"#695171\", \"#715171\", \"#715169\", \"#715161\", \"#715159\", \"#715151\",\n\t\t\"#715951\", \"#716151\", \"#716951\", \"#717151\", \"#697151\", \"#617151\", \"#597151\", \"#517151\",\n\t\t\"#517159\", \"#517161\", \"#517169\", \"#517171\", \"#516971\", \"#516171\", \"#515971\", \"#000041\",\n\t\t\"#100041\", \"#200041\", \"#310041\", \"#410041\", \"#410031\", \"#410020\", \"#410010\", \"#410000\",\n\t\t\"#411000\", \"#412000\", \"#413100\", \"#414100\", \"#314100\", \"#204100\", \"#104100\", \"#004100\",\n\t\t\"#004110\", \"#004120\", \"#004131\", \"#004141\", \"#003141\", \"#002041\", \"#001041\", \"#202041\",\n\t\t\"#282041\", \"#312041\", \"#392041\", \"#412041\", \"#412039\", \"#412031\", \"#412028\", \"#412020\",\n\t\t\"#412820\", \"#413120\", \"#413920\", \"#414120\", \"#394120\", \"#314120\", \"#284120\", \"#204120\",\n\t\t\"#204128\", \"#204131\", \"#204139\", \"#204141\", \"#203941\", \"#203141\", \"#202841\", \"#2D2D41\",\n\t\t\"#312D41\", \"#352D41\", \"#3D2D41\", \"#412D41\", \"#412D3D\", \"#412D35\", \"#412D31\", \"#412D2D\",\n\t\t\"#41312D\", \"#41352D\", \"#413D2D\", \"#41412D\", \"#3D412D\", \"#35412D\", \"#31412D\", \"#2D412D\",\n\t\t\"#2D4131\", \"#2D4135\", \"#2D413D\", \"#2D4141\", \"#2D3D41\", \"#2D3541\", \"#2D3141\", \"#000000\",\n\t\t\"#000000\", \"#000000\", \"#000000\", \"#000000\", \"#000000\", \"#000000\"\n\t];\n\n\t// Set the default pal and color\n\tsetDefaultPal( { \"pal\": defaultPaletteHex } );\n\tsetDefaultColor( { \"color\": 7 } );\n\n\t// Add getters for screen manager to get defaults for dynamic items\n\tg_screenManager.addScreenDataItemGetter( \"pal\", () => m_defaultPal );\n\tg_screenManager.addScreenDataItemGetter( \"color\", () => m_defaultColor );\n\tg_screenManager.addScreenDataItemGetter( \"palMap\", () => m_defaultPalMap );\n\n\t// Add external API commands\n\tregisterCommands( api );\n}\n\n\n/***************************************************************************************************\n * External API Commands\n **************************************************************************************************/\n\nfunction registerCommands() {\n\n\t// Register non-screen commands\n\tg_commands.addCommand( \"setDefaultPal\", setDefaultPal, false, [ \"pal\" ] );\n\tg_commands.addCommand( \"getDefaultPal\", getDefaultPal, false, [ \"include0\" ] );\n\tg_commands.addCommand( \"setDefaultColor\", setDefaultColor, false, [ \"color\" ] );\n\tg_commands.addCommand( \"getDefaultColor\", getDefaultColor, false, [ \"asIndex\" ] );\n\tg_commands.addCommand( \"createColor\", createColor, false, [ \"color\" ] );\n\n\t// Register screen commands\n\tg_commands.addCommand( \"setColor\", setColor, true, [ \"color\" ] );\n\tg_commands.addCommand( \"getColor\", getColor, true, [ \"asIndex\" ] );\n\tg_commands.addCommand( \"getPal\", getPal, true, [ \"include0\" ] );\n\tg_commands.addCommand( \"setPal\", setPal, true, [ \"pal\" ] );\n\tg_commands.addCommand( \"getPalIndex\", getPalIndex, true, [ \"color\", \"tolerance\" ] );\n\tg_commands.addCommand( \"setBgColor\", setBgColor, true, [ \"color\" ] );\n\tg_commands.addCommand( \"setContainerBgColor\", setContainerBgColor, true, [ \"color\" ] );\n\tg_commands.addCommand( \"setPalColors\", setPalColors, true, [ \"indices\", \"colors\" ] );\n\tg_commands.addCommand( \"addPalColors\", addPalColors, true, [ \"colors\" ] );\n\tg_commands.addCommand( \"getPalColor\", getPalColor, true, [ \"index\" ] );\n}\n\n// Set default pal\nfunction setDefaultPal( options ) {\n\tconst pal = options.pal;\n\n\tif( !Array.isArray( pal ) ) {\n\t\tconst error = new TypeError( \"setDefaultPal: Parameter pal must be an array.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\tif( pal.length === 0 ) {\n\t\tconst error = new RangeError(\n\t\t\t\"setDefaultPal: Parameter pal must have at least one color value.\"\n\t\t);\n\t\terror.code = \"EMPTY_PALETTE\";\n\t\tthrow error;\n\t}\n\n\t// Create default pal with the 0'th item set as a black transparent color\n\tm_defaultPal = [ g_utils.convertToColor( [ 0, 0, 0, 0 ] ) ];\n\n\t// Convert palette to color format\n\tfor( let i = 0; i < pal.length; i++ ) {\n\t\tconst c = g_utils.convertToColor( pal[ i ] );\n\t\tif( c === null ) {\n\t\t\tconsole.warn( `setDefaultPal: Invalid color value inside array pal at index: ${i}.` );\n\t\t\tm_defaultPal.push( g_utils.convertToColor( \"#000000\" ) );\n\t\t} else {\n\t\t\tm_defaultPal.push( c );\n\t\t}\n\t}\n\n\t// Set the default pal map\n\tm_defaultPalMap = new Map();\n\tfor( let i = 0; i < m_defaultPal.length; i++ ) {\n\t\tm_defaultPalMap.set( m_defaultPal[ i ].key, i );\n\t}\n\n\t// Make sure default color is in the new palette\n\tif( !m_defaultPalMap.has( m_defaultColor.key ) ) {\n\t\tm_defaultColor = m_defaultPal[ 1 ];\n\t}\n}\n\n// Get default pal\nfunction getDefaultPal( options ) {\n\tconst include0 = options.include0 ?? null;\n\tconst filteredPal = [];\n\t\n\t// Set the start index to 0 if including 0 which is the transparent black color\n\tlet startIndex = 0;\n\tif( include0 === null ) {\n\t\tstartIndex = 1;\n\t}\n\n\t// Need to explicitly convert each color because I don't want the default pal to be modified\n\t// outside.\n\tfor( let i = startIndex; i < m_defaultPal.length; i += 1 ) {\n\t\tfilteredPal.push( g_utils.rgbToColor(\n\t\t\tm_defaultPal[ i ].r,\n\t\t\tm_defaultPal[ i ].g,\n\t\t\tm_defaultPal[ i ].b,\n\t\t\tm_defaultPal[ i ].a\n\t\t) );\n\t}\n\treturn filteredPal;\n}\n\n// Set default color\nfunction setDefaultColor( options ) {\n\tlet c = options.color;\n\n\tif( !isNaN( Number( c ) ) && m_defaultPal.length > c ) {\n\t\tm_defaultColor = m_defaultPal[ c ];\n\t} else {\n\t\tc = g_utils.convertToColor( c );\n\t\tif( c === null ) {\n\t\t\tconst error = new TypeError(\n\t\t\t\t\"setDefaultColor: Parameter color is not a valid color format.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_PARAMETER\";\n\t\t\tthrow error;\n\t\t}\n\t\tm_defaultColor = c;\n\t}\n}\n\n// Get default color\nfunction getDefaultColor( options ) {\n\tconst asIndex = options.asIndex ?? true;\n\tif( asIndex ) {\n\t\tconst fakeScreenData = { \"pal\": m_defaultPal, \"palMap\": m_defaultPalMap };\n\t\treturn findColorIndexByColorValue( fakeScreenData, m_defaultColor );\n\t}\n\treturn g_utils.createColor( m_defaultColor.array );\n}\n\nfunction createColor( options ) {\n\tconst color = g_utils.convertToColor( options.color );\n\tif( color === null ) {\n\t\tconst error = new TypeError(\n\t\t\t`createColor: Parameter color is not a valid color format.`\n\t\t);\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\treturn color\n}\n\n// Set color\nfunction setColor( screenData, options ) {\n\tconst colorInput = options.color;\n\n\tlet colorValue;\n\n\t// If colorInput is an number then get colorValue for pal\n\tif( typeof colorInput === \"number\" ) {\n\t\tif( colorInput >= screenData.pal.length ) {\n\t\t\tconst error = new TypeError(\n\t\t\t\t`setColor: Parameter color index is not in pal.`\n\t\t\t);\n\t\t\terror.code = \"INVALID_PARAMETER\";\n\t\t\tthrow error;\n\t\t}\n\t\tcolorValue = screenData.pal[ colorInput ];\n\t} else {\n\n\t\t// Convert the color to a colorValue\n\t\tcolorValue = g_utils.convertToColor( colorInput );\n\n\t\t// If we were unable to convert this color than it is not a valid color format\n\t\tif( colorValue === null ) {\n\t\t\tconst error = new TypeError(\n\t\t\t\t`setColor: Parameter color is not a valid color format.`\n\t\t\t);\n\t\t\terror.code = \"INVALID_PARAMETER\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Update the color values\n\tscreenData.color = colorValue;\n}\n\nfunction getColor( screenData, options ) {\n\tconst asIndex = !!options.asIndex;\n\tif( asIndex ) {\n\t\treturn findColorIndexByColorValue( screenData, screenData.color );\n\t}\n\treturn g_utils.createColor( screenData.color.array );\n}\n\n\n// Get palette\nfunction getPal( screenData, options ) {\n\tconst include0 = options.include0 ?? null;\n\tconst filteredPal = [];\n\t\n\t// Set the start index to 0 if including 0 which is the transparent black color\n\tlet startIndex = 0;\n\tif( include0 === null ) {\n\t\tstartIndex = 1;\n\t}\n\n\t// Need to explicitly convert each color because I don't want the pal to be modified\n\t// outside.\n\tfor( let i = startIndex; i < screenData.pal.length; i += 1 ) {\n\t\tfilteredPal.push( g_utils.rgbToColor(\n\t\t\tscreenData.pal[ i ].r,\n\t\t\tscreenData.pal[ i ].g,\n\t\t\tscreenData.pal[ i ].b,\n\t\t\tscreenData.pal[ i ].a\n\t\t) );\n\t}\n\treturn filteredPal;\n}\n\n// Set entire palette\nfunction setPal( screenData, options ) {\n\tconst pal = options.pal;\n\n\tif( !Array.isArray( pal ) ) {\n\t\tconst error = new TypeError( \"setPal: Parameter pal is must be an array.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\tif( pal.length === 0 ) {\n\t\tconst error = new RangeError(\n\t\t\t\"setPal: Parameter pal must have at least one color value.\"\n\t\t);\n\t\terror.code = \"EMPTY_PALETTE\";\n\t\tthrow error;\n\t}\n\n\t// Create a new pal with 0'th color set to black transparent\n\tconst newPal = [ g_utils.rgbToColor( 0, 0, 0, 0 ) ];\n\n\t// Convert all colors and validate\n\tfor( let i = 0; i < pal.length; i++ ) {\n\t\tconst c = g_utils.convertToColor( pal[ i ] );\n\t\tif( c === null ) {\n\t\t\tconsole.warn( `setPal: Invalid color value inside array pal at index: ${i}.` );\n\t\t\tnewPal.push( g_utils.convertToColor( \"#000000\" ) );\n\t\t} else {\n\t\t\tnewPal.push( c );\n\t\t}\n\t}\n\n\t// Set the new palette\n\tscreenData.pal = newPal;\n\n\t// Clear the palMap since we've replaced the entire palette\n\tscreenData.palMap = new Map();\n\n\t// Rebuild palMap for new palette colors\n\tfor( let i = 0; i < newPal.length; i++ ) {\n\t\tscreenData.palMap.set( newPal[ i ].key, i );\n\t}\n\n\t// Check if current drawing color needs to be updated\n\t// Find the new palette index that best matches the current color\n\tconst currentColor = screenData.color;\n\tconst newIndex = findColorIndexByColorValue( screenData, currentColor );\n\tif( newIndex !== null ) {\n\t\tscreenData.color = newPal[ newIndex ];\n\t} else {\n\n\t\t// If current color not found, default to palette index 1\n\t\tscreenData.color = newPal[ 1 ];\n\t}\n\n\t// Trigger images to update color palletes\n\tg_images.palettizeImages( screenData );\n}\n\n// Get palette index for a color\nfunction getPalIndex( screenData, options ) {\n\tlet color = options.color;\n\tlet tolerance = g_utils.getFloat( options.tolerance, 0 );\n\n\t// Validate tolerance variable\n\tif( tolerance < 0 || tolerance > 1 ) {\n\t\tconst error = new RangeError(\n\t\t\t\"getPalIndex: Parameter tolerance must be a number between 0 and 1 (0 = exact match, 1 = any color).\"\n\t\t);\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\t// Convert to color value\n\tconst colorValue = g_utils.convertToColor( color );\n\tif( colorValue === null ) {\n\t\tconst error = new TypeError(\n\t\t\t`getPalIndex: Parameter color is not a valid color format.`\n\t\t);\n\t\terror.code = \"INVALID_COLOR\";\n\t\tthrow error;\n\t}\n\n\tconst index = findColorIndexByColorValue( screenData, colorValue, tolerance );\n\treturn index;\n}\n\n// Set the background color of the canvas\nfunction setBgColor( screenData, options ) {\n\tconst colorRaw = options.color;\n\tconst color = getColorValueByRawInput( screenData, colorRaw );\n\tif( color !== null ) {\n\t\tscreenData.canvas.style.backgroundColor = g_utils.colorToHex( color );\n\t} else {\n\t\tconst error = new TypeError( \"setBgColor: invalid color value for parameter color.\" );\n\t\terror.code = \"INVALID_COLOR\";\n\t\tthrow error;\n\t}\n}\n\n// Set the background color of the container\nfunction setContainerBgColor( screenData, options ) {\n\tif( !screenData.container ) {\n\t\treturn;\n\t}\n\n\tconst colorRaw = options.color;\n\tconst color = getColorValueByRawInput( screenData, colorRaw );\n\t\n\tif( color !== null ) {\n\t\tscreenData.container.style.backgroundColor = g_utils.colorToHex( color );\n\t} else {\n\t\tconst error = new TypeError(\n\t\t\t\"setContainerBgColor: invalid color value for parameter color.\"\n\t\t);\n\t\terror.code = \"INVALID_COLOR\";\n\t\tthrow error;\n\t}\n}\n\n// Set palette colors\nfunction setPalColors( screenData, options ) {\n\tconst indices = options.indices;\n\tconst colors = options.colors;\n\n\t// Validate indices array\n\tif( !Array.isArray( indices ) ) {\n\t\tconst error = new TypeError( \"setPalColors: Parameter indices must be an array.\" );\n\t\terror.code = \"INVALID_INDICES\";\n\t\tthrow error;\n\t}\n\n\t// Validate colors array\n\tif( !Array.isArray( colors ) ) {\n\t\tconst error = new TypeError( \"setPalColors: Parameter colors must be an array.\" );\n\t\terror.code = \"INVALID_COLORS\";\n\t\tthrow error;\n\t}\n\n\t// Arrays must have the same length\n\tif( indices.length !== colors.length ) {\n\t\tconst error = new RangeError(\n\t\t\t\"setPalColors: Parameters indices and colors must have the same length.\"\n\t\t);\n\t\terror.code = \"LENGTH_MISMATCH\";\n\t\tthrow error;\n\t}\n\n\t// Arrays must not be empty\n\tif( indices.length === 0 ) {\n\t\treturn;\n\t}\n\n\tlet colorSwapped = false;\n\n\t// Validate each index and color\n\tfor( let i = 0; i < indices.length; i += 1 ) {\n\t\tconst index = indices[ i ];\n\t\tconst color = colors[ i ];\n\n\t\t// index must be an integer\n\t\tif(\n\t\t\t!Number.isInteger( index ) ||\n\t\t\tindex < 0 ||\n\t\t\tindex >= screenData.pal.length\n\t\t) {\n\t\t\tconsole.warn(\n\t\t\t\t`setPalColors: Parameter indices[${i}] must be an integer value between 0 and ` +\n\t\t\t\t`${screenData.pal.length - 1}.`\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// index cannot be 0\n\t\tif( index === 0 ) {\n\t\t\tconsole.warn(\n\t\t\t\t`setPalColors: Parameter indices[${i}] cannot be 0, this is reserved for ` +\n\t\t\t\t\"transparency. To set background color of the screen use the setBgColor command.\"\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get the color value\n\t\tconst colorValue = g_utils.convertToColor( color );\n\t\tif( colorValue === null ) {\n\t\t\tconsole.warn(\n\t\t\t\t`setPalColors: Parameter colors[${i}] is not a valid color format.`\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Store the old color before replacing\n\t\tconst oldColor = screenData.pal[ index ];\n\n\t\t// Skip if color is not changing\n\t\tif( colorValue.key === oldColor.key ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if we are changing the current selected fore color\n\t\tif( screenData.color.key === oldColor.key ) {\n\t\t\tscreenData.color = colorValue;\n\t\t}\n\n\t\t// Set the new palette color\n\t\tscreenData.pal[ index ] = colorValue;\n\n\t\t// Update the palMap - remove old color entry and add new one\n\t\tscreenData.palMap.delete( oldColor.key );\n\t\tscreenData.palMap.set( colorValue.key, index );\n\n\t\t// Set color swapped to true indicated a palette color has been changed\n\t\tcolorSwapped = true;\n\t}\n\n\t// Trigger images to update color palletes\n\tif( colorSwapped ) {\n\t\tg_images.palettizeImages( screenData );\n\t}\n}\n\n// Add palette colors\nfunction addPalColors( screenData, options ) {\n\tconst colors = options.colors;\n\n\t// Validate colors array\n\tif( !Array.isArray( colors ) ) {\n\t\tconst error = new TypeError( \"addPalColors: Parameter colors must be an array.\" );\n\t\terror.code = \"INVALID_COLORS\";\n\t\tthrow error;\n\t}\n\n\t// Array must not be empty\n\tif( colors.length === 0 ) {\n\t\treturn [];\n\t}\n\n\tconst newIndices = [];\n\tlet colorsAdded = false;\n\n\t// Convert and add each color to the palette\n\tfor( let i = 0; i < colors.length; i += 1 ) {\n\t\tconst color = colors[ i ];\n\n\t\t// Get the color value\n\t\tconst colorValue = g_utils.convertToColor( color );\n\t\tif( colorValue === null ) {\n\t\t\tconsole.warn( `addPalColors: Parameter colors[${i}] is not a valid color format.` );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if color already exists in palette\n\t\tconst existingIndex = screenData.palMap.get( colorValue.key );\n\t\tif( existingIndex !== undefined ) {\n\t\t\t// Color already exists, skip it\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Add the new color to the palette\n\t\tconst newIndex = screenData.pal.length;\n\t\tscreenData.pal.push( colorValue );\n\t\tscreenData.palMap.set( colorValue.key, newIndex );\n\t\tnewIndices.push( newIndex );\n\n\t\tcolorsAdded = true;\n\t}\n\n\t// Trigger images to update color palletes\n\tif( colorsAdded ) {\n\t\tg_images.palettizeImages( screenData );\n\t}\n\n\treturn newIndices;\n}\n\nfunction getPalColor( screenData, options ) {\n\tconst index = options.index;\n\n\tif( screenData.pal[ index ] ) {\n\t\tconst color = screenData.pal[ index ];\n\t\treturn g_utils.createColor( color.array );\n\t}\n\treturn null;\n}\n\n\n/***************************************************************************************************\n * Internal Commands\n **************************************************************************************************/\n\n\nexport function getColorValueByRawInput( screenData, rawInput ) {\n\tlet colorValue;\n\n\t// If it is an integer than get from pal array\n\tif( Number.isInteger( rawInput ) ) {\n\t\tif( rawInput >= screenData.pal.length ) {\n\t\t\treturn null;\n\t\t}\n\t\treturn screenData.pal[ rawInput ];\n\t}\n\t\n\t// Convert to a color value\n\tcolorValue = g_utils.convertToColor( rawInput );\n\n\treturn colorValue;\n}\n\n// Finds a color index without adding it to palette\n// @param {Object} screenData - The screen data object\n// @param {Object} color - Color object to find\n// @param {number} tolerance - Color matching tolerance (0 = exact match, 1 = any color)\nexport function findColorIndexByColorValue( screenData, color, tolerance = 0 ) {\n\n\t// First check by key - fastest lookup\n\tif( screenData.palMap.has( color.key ) ) {\n\t\treturn screenData.palMap.get( color.key );\n\t}\n\n\t// Calculate minimum similarity threshold for color comparison\n\t// Tolerance: 0 = exact match only, 1 = any color\n\tconst minSimularity = ( 1 - tolerance * tolerance ) * MAX_DIFFERENCE;\n\n\t// Collect all matches meeting the target similarity, then return the most similar\n\tlet bestMatchIndex = null;\n\tlet bestMatchSimularity = 0;\n\tfor( let i = 0; i < screenData.pal.length; i++ ) {\n\t\tconst palColor = screenData.pal[ i ];\n\t\tif( palColor.key === color.key ) {\n\n\t\t\t// Exact match found; this is the best possible\n\t\t\treturn i;\n\t\t}\n\n\t\tlet difference;\n\n\t\t// Special case for color 0: weight alpha higher for transparent color\n\t\tif( i === 0 ) {\n\t\t\tdifference = g_utils.calcColorDifference( palColor, color, [ 0.2, 0.2, 0.2, 0.4 ] );\n\t\t} else {\n\t\t\tdifference = g_utils.calcColorDifference( palColor, color );\n\t\t}\n\n\t\tconst similarity = MAX_DIFFERENCE - difference;\n\t\tif( similarity >= minSimularity ) {\n\t\t\tif( similarity > bestMatchSimularity ) {\n\t\t\t\tbestMatchIndex = i;\n\t\t\t\tbestMatchSimularity = similarity;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn bestMatchIndex;\n}\n\nexport function getColorValueByIndex( screenData, palIndex ) {\n\tif( palIndex >= screenData.pal.length ) {\n\t\treturn null;\n\t}\n\treturn screenData.pal[ palIndex ];\n}\n", "/**\n * Pi.js - Images Module\n * \n * Image loading, storage, and management for WebGL2 renderer.\n * \n * @module api/images\n */\n\n\"use strict\";\n\nimport * as g_utils from \"../core/utils.js\";\nimport * as g_commands from \"../core/commands.js\";\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_renderer from \"../renderer/renderer.js\";\nimport * as g_colors from \"./colors.js\";\n\n// Image storage by name\nconst m_images = {};\nconst m_paletteImages = [];\nlet m_imageCount = 0;\n\n\n/**************************************************************************************************\n * Module Initialization\n **************************************************************************************************/\n\n\n/**\n * Initialize images module\n * \n * @param {Object} api - The main Pi.js API object\n * @returns {void}\n */\nexport function init( api ) {\n\tregisterCommands( api );\n\n\tg_screenManager.addScreenDataItem( \"defaultAnchorX\", 0 );\n\tg_screenManager.addScreenDataItem( \"defaultAnchorY\", 0 );\n\tg_screenManager.addScreenDataItem( \"palImagesData\", {} );\n\n\t// Palettize all images when screen is loaded\n\tg_screenManager.addScreenInitFunction( palettizeImages );\n}\n\n/**\n * Register image commands\n * \n * @returns {void}\n */\nfunction registerCommands( api ) {\n\tg_commands.addCommand(\n\t\t\"loadImage\", loadImage, false,\n\t\t[ \"src\", \"name\", \"usePalette\", \"paletteKeys\", \"onLoad\", \"onError\" ]\n\t);\n\tg_commands.addCommand(\n\t\t\"loadSpritesheet\", loadSpritesheet, false,\n\t\t[\n\t\t\t\"src\", \"name\", \"width\", \"height\", \"margin\", \"usePalette\", \"paletteKeys\", \"onLoad\",\n\t\t\t\"onError\"\n\t\t]\n\t);\n\tg_commands.addCommand( \"getImage\", getImage, false, [ \"name\" ] );\n\tg_commands.addCommand( \"getSpritesheetData\", getSpritesheetData, true, [ \"name\" ], true );\n\tg_commands.addCommand( \"removeImage\", removeImage, false, [ \"name\" ] );\n\tg_commands.addCommand(\n\t\t\"createImageFromScreen\", createImageFromScreen, true,\n\t\t[ \"name\", \"x1\", \"y1\", \"x2\", \"y2\" ]\n\t);\n\tg_commands.addCommand( \"setDefaultAnchor\", setDefaultAnchor, true, [ \"x\", \"y\" ] );\n}\n\n\n/**************************************************************************************************\n * External API Commands\n **************************************************************************************************/\n\n\n/**\n * Load an image from URL or use provided Image/Canvas element\n * \n * @param {Object} options - Load options\n * @param {string|HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} options.src - Image source\n * @param {string} [options.name] - Optional name for the image\n * @param {boolean} [options.usePalette] - Set image colors to be linked to screen canvas\n * @param {Array} [options.paletteKeys] - An array of colors used as key colors from the image to\n * \t\t\t\t\t\t\t\t\t\t  use as indices to look up palette colors\n * @param {Function} [options.onLoad] - Callback when image loads\n * @param {Function} [options.onError] - Callback when image fails to load\n * @returns {string} Image name\n */\nfunction loadImage( options ) {\n\tconst src = options.src;\n\tlet name = options.name;\n\tconst usePalette = !!options.usePalette;\n\tconst paletteKeys = options.paletteKeys;\n\tconst onLoadCallback = options.onLoad;\n\tconst onErrorCallback = options.onError;\n\tconst srcErrMsg = \"loadImage: Parameter src must be a string URL, Image element, or Canvas \" +\n\t\t\"element.\";\n\n\t// Validate src parameter - can be string URL, Image element, or Canvas element\n\tif( typeof src === \"string\" ) {\n\t\tif( src === \"\" ) {\n\t\t\tconst error = new TypeError( srcErrMsg );\n\t\t\terror.code = \"INVALID_SRC\";\n\t\t\tthrow error;\n\t\t}\n\t} else if( src && typeof src === \"object\" ) {\n\t\tif( src.tagName !== \"IMG\" && src.tagName !== \"CANVAS\" ) {\n\t\t\tconst error = new TypeError( srcErrMsg );\n\t\t\terror.code = \"INVALID_SRC\";\n\t\t\tthrow error;\n\t\t}\n\t} else {\n\t\tconst error = new TypeError( srcErrMsg );\n\t\terror.code = \"INVALID_SRC\";\n\t\tthrow error;\n\t}\n\n\t// Validate name\n\tif( name && typeof name !== \"string\" ) {\n\t\tconst error = new TypeError( \"loadImage: Parameter name must be a string.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\t// Generate a name if none is provided\n\tif( !name || name === \"\" ) {\n\t\tm_imageCount += 1;\n\t\tname = \"\" + m_imageCount;\n\t}\n\tif( m_images[ name ] ) {\n\t\tconst error = new TypeError( \"loadImage: Parameter name must be unique.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\n\t// Validate callbacks if provided\n\tif( onLoadCallback != null && !g_utils.isFunction( onLoadCallback ) ) {\n\t\tconst error = new TypeError( \"loadImage: Parameter onLoad must be a function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\tif( onErrorCallback != null && !g_utils.isFunction( onErrorCallback ) ) {\n\t\tconst error = new TypeError( \"loadImage: Parameter onError must be a function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\n\t// Validate paletteKeys\n\tlet palColors = null;\n\tlet palColorMap = null;\n\tif( usePalette ) {\n\t\tif( !Array.isArray( paletteKeys ) || paletteKeys.length === 0 ) {\n\t\t\tconst error = new TypeError(\n\t\t\t\t\"loadImage: Parameter paletteKeys must be non empty Array when usePalette is set.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_PALETTE\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Create a color map\n\t\tpalColorMap = new Map();\n\n\t\t// Initialize palColors with 0 for transparent black\n\t\tpalColors = [ g_utils.convertToColor( \"rgba(0, 0, 0, 0)\" ) ];\n\t\tpalColorMap.set( palColors[ 0 ].key, 0 );\n\n\t\tfor( let i = 0; i < paletteKeys.length; i += 1 ) {\n\t\t\tconst palColorRaw = paletteKeys[ i ];\n\t\t\tconst palColor = g_utils.convertToColor( palColorRaw );\n\t\t\tpalColors.push( palColor );\n\t\t\tpalColorMap.set( palColor.key, i + 1 );\n\t\t}\n\t}\n\n\t// Create blank image object\n\tm_images[ name ] = {\n\t\t\"status\": \"loading\",\n\t\t\"image\": null,\n\t\t\"width\": null,\n\t\t\"height\": null,\n\t\t\"usePalette\": usePalette,\n\t\t\"palColors\": palColors,\n\t\t\"palColorMap\": palColorMap\n\t};\n\n\t// Update function for when image is loaded to update the image object\n\tconst updateImageFn = ( img ) => {\n\n\t\t// Use the element directly\n\t\tconst imageObj = m_images[ name ];\n\t\timageObj.image = img;\n\t\timageObj.status = \"ready\";\n\t\timageObj.width = img.width;\n\t\timageObj.height = img.height;\n\n\t\t// If using palette then push the image to the use palette array\n\t\tif( imageObj.usePalette ) {\n\t\t\taddPaletteImage( name );\n\t\t}\n\n\t\t// Call user callback if provided\n\t\tif( onLoadCallback ) {\n\t\t\tonLoadCallback( name );\n\t\t}\n\t};\n\n\t// Handle Image or Canvas element passed directly\n\tif( typeof src !== \"string\" ) {\n\n\t\t// Use the element directly\n\t\tupdateImageFn( src );\n\t\treturn name;\n\t}\n\n\t// Create the new image\n\tconst img = new Image();\n\t\n\t// Increment wait count for ready() - will be decremented in onload/onerror\n\tg_commands.wait();\n\n\t// Setup onload handler\n\timg.onload = function() {\n\t\tupdateImageFn( img );\n\n\t\t// Decrement wait count\n\t\tg_commands.done();\n\t};\n\n\t// Setup onerror handler\n\timg.onerror = function( error ) {\n\n\t\t// Mark image as failed\n\t\tm_images[ name ] = {\n\t\t\t\"status\": \"error\",\n\t\t\t\"error\": error\n\t\t};\n\n\t\t// Call user error callback if provided\n\t\tif( onErrorCallback ) {\n\t\t\tonErrorCallback( error );\n\t\t}\n\n\t\t// Decrement wait count even on error\n\t\tg_commands.done();\n\t};\n\n\t// Set source - may trigger onload synchronously if cached\n\timg.src = src;\n\n\treturn name;\n}\n\n\n/**\n * Remove an image from storage\n * \n * @param {Object} options - Load options\n * @param {string} [options.name] - Name of the image to remove\n */\nfunction removeImage( options ) {\n\tconst name = options.name;\n\tif( typeof name !== \"string\" ) {\n\t\tconst error = new TypeError( \"removeImage: Parameter name must be a string.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\n\tconst imageObj = m_images[ name ];\n\tif( imageObj && imageObj.image ) {\n\n\t\tconst img = imageObj.image;\n\n\t\t// Explicitly delete WebGL2 textures to free GPU memory\n\t\t// WebGLTextures hold GPU memory that is NOT automatically freed by JS garbage collection\n\t\t// Must call gl.deleteTexture() explicitly to prevent memory leaks\n\t\tfor( const screenData of g_screenManager.getAllScreensData() ) {\n\t\t\tg_renderer.deleteWebGL2Texture( screenData, img );\n\t\t}\n\n\t\t// Remove from paletteImages\n\t\tif( imageObj.usePalette ) {\n\n\t\t\t// Since name is guaranteed to be unique we can assume there are no duplicate names in\n\t\t\t// the array\n\t\t\tm_paletteImages.splice( m_paletteImages.indexOf( name ), 1 );\n\t\t}\n\n\t\t// Delete the image object\n\t\tdelete m_images[ name ];\n\t}\n}\n\n/**\n * Load a spritesheet from URL or use provided Image/Canvas element\n * \n * @param {Object} options - Load options\n * @param {string|HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} options.src - Image source\n * @param {string} [options.name] - Optional name for the spritesheet\n * @param {number} [options.width] - Sprite width (required for fixed grid mode)\n * @param {number} [options.height] - Sprite height (required for fixed grid mode)\n * @param {number} [options.margin] - Margin between sprites (default: 0)\n * @param {boolean} [options.usePalette] - Set image colors to be linked to screen canvas\n * @param {Array} [options.paletteKeys] - An array of colors used as key colors from the image to\n * \t\t\t\t\t\t\t\t\t\t  use as indices to look up palette colors\n * @param {Function} [options.onLoad] - Callback when spritesheet loads\n * @param {Function} [options.onError] - Callback when spritesheet fails to load\n * @returns {string} Spritesheet name\n */\nfunction loadSpritesheet( options ) {\n\tconst src = options.src;\n\tlet name = options.name;\n\tlet spriteWidth = options.width;\n\tlet spriteHeight = options.height;\n\tlet margin = options.margin;\n\tconst usePalette = !!options.usePalette;\n\tconst paletteKeys = options.paletteKeys;\n\tconst onLoadCallback = options.onLoad;\n\tconst onErrorCallback = options.onError;\n\tlet isAuto = false;\n\n\tif( margin === null ) {\n\t\tmargin = 0;\n\t}\n\n\tif( spriteWidth === null && spriteHeight === null ) {\n\t\tisAuto = true;\n\t\tspriteWidth = 0;\n\t\tspriteHeight = 0;\n\t\tmargin = 0;\n\t} else {\n\t\tspriteWidth = Math.round( spriteWidth );\n\t\tspriteHeight = Math.round( spriteHeight );\n\t\tmargin = Math.round( margin );\n\t}\n\n\t// Validate spriteWidth and spriteHeight for fixed mode\n\tif( !isAuto && ( !Number.isInteger( spriteWidth ) || !Number.isInteger( spriteHeight ) ) ) {\n\t\tconst error = new TypeError( \"loadSpritesheet: width and height must be integers.\" );\n\t\terror.code = \"INVALID_DIMENSIONS\";\n\t\tthrow error;\n\t}\n\n\t// Size cannot be less than 1\n\tif( !isAuto && ( spriteWidth < 1 || spriteHeight < 1 ) ) {\n\t\tconst error = new RangeError(\n\t\t\t\"loadSpritesheet: width and height must be greater than 0.\"\n\t\t);\n\t\terror.code = \"INVALID_DIMENSIONS\";\n\t\tthrow error;\n\t}\n\n\t// Validate margin\n\tif( !Number.isInteger( margin ) ) {\n\t\tconst error = new TypeError( \"loadSpritesheet: margin must be an integer.\" );\n\t\terror.code = \"INVALID_MARGIN\";\n\t\tthrow error;\n\t}\n\n\t// Generate a name if none is provided\n\tif( !name || name === \"\" ) {\n\t\tm_imageCount += 1;\n\t\tname = \"\" + m_imageCount;\n\t}\n\n\t// Validate name\n\tif( typeof name !== \"string\" ) {\n\t\tconst error = new TypeError( \"loadSpritesheet: Parameter name must be a string.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\tif( m_images[ name ] ) {\n\t\tconst error = new TypeError( \"loadSpritesheet: Parameter name must be unique.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\n\t// Validate callbacks if provided\n\tif( onLoadCallback != null && !g_utils.isFunction( onLoadCallback ) ) {\n\t\tconst error = new TypeError( \"loadSpritesheet: Parameter onLoad must be a function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\tif( onErrorCallback != null && !g_utils.isFunction( onErrorCallback ) ) {\n\t\tconst error = new TypeError( \"loadSpritesheet: Parameter onError must be a function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\n\t// Validate paletteKeys\n\tlet palColors = null;\n\tlet palColorMap = null;\n\tif( usePalette ) {\n\t\tif( !Array.isArray( paletteKeys ) || paletteKeys.length === 0 ) {\n\t\t\tconst error = new TypeError(\n\t\t\t\t\"loadSpritesheet: Parameter paletteKeys must be non empty Array when usePalette \" +\n\t\t\t\t\"is set.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_PALETTE\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Create a color map\n\t\tpalColorMap = new Map();\n\n\t\t// Initialize palColors with 0 for transparent black\n\t\tpalColors = [ g_utils.convertToColor( \"rgba(0, 0, 0, 0)\" ) ];\n\t\tpalColorMap.set( palColors[ 0 ].key, 0 );\n\n\t\tfor( let i = 0; i < paletteKeys.length; i += 1 ) {\n\t\t\tconst palColorRaw = paletteKeys[ i ];\n\t\t\tconst palColor = g_utils.convertToColor( palColorRaw );\n\t\t\tpalColors.push( palColor );\n\t\t\tpalColorMap.set( palColor.key, i + 1 );\n\t\t}\n\t}\n\n\t// Load the image first, then process frames in callback\n\tloadImage( {\n\t\t\"src\": src,\n\t\t\"name\": name,\n\t\t\"usePalette\": usePalette,\n\t\t\"paletteKeys\": paletteKeys,\n\t\t\"onLoad\": function( imageName ) {\n\n\t\t\t// Update the image data to spritesheet type\n\t\t\tconst imageData = m_images[ imageName ];\n\t\t\timageData.type = \"spritesheet\";\n\t\t\timageData.spriteWidth = spriteWidth;\n\t\t\timageData.spriteHeight = spriteHeight;\n\t\t\timageData.margin = margin;\n\t\t\timageData.frames = [];\n\t\t\timageData.isAuto = isAuto;\n\n\t\t\tconst width = imageData.width;\n\t\t\tconst height = imageData.height;\n\n\t\t\tif( isAuto ) {\n\n\t\t\t\t// Auto-detect sprites using connected component analysis\n\t\t\t\tprocessSpriteSheetAuto( imageData, width, height );\n\t\t\t} else {\n\n\t\t\t\t// Fixed grid of sprites\n\t\t\t\tprocessSpriteSheetFixed( imageData, width, height );\n\t\t\t}\n\n\t\t\t// Call user callback if provided\n\t\t\tif( onLoadCallback ) {\n\t\t\t\tonLoadCallback( imageName );\n\t\t\t}\n\t\t},\n\t\t\"onError\": onErrorCallback\n\t} );\n\n\treturn name;\n}\n\n/**\n * Gets the image by name and returns the DOM element (Image or Canvas).\n * \n * @param {Object} options - Options\n * @param {string} [options.name] - Optional name for the image\n * @returns {Object} Actual image\n */\nfunction getImage( options ) {\n\tconst img = getImageFromRawInput( options.name, \"getImage\" );\n\n\t// For offscreen screens then call createImageFromScreen\n\tif( img.isMock ) {\n\t\tconst imgScreenData = g_screenManager.getScreenData( \"getImage\", img.dataset.screenId );\n\t\treturn createImageFromScreen( imgScreenData );\n\t}\n\treturn img;\n}\n\n/**\n * Create an image from a region of the screen (FBO)\n * Defaults to fullscreen if no coordinates are provided\n * \n * @param {Object} screenData - Screen data object\n * @param {Object} options - Options\n * @param {string} [options.name] - Optional name for the image\n * @param {number} [options.x1] - Left coordinate (defaults to 0)\n * @param {number} [options.y1] - Top coordinate (defaults to 0)\n * @param {number} [options.x2] - Right coordinate (defaults to screen width)\n * @param {number} [options.y2] - Bottom coordinate (defaults to screen height)\n * @returns {string} Image name\n */\nfunction createImageFromScreen( screenData, options ) {\n\tlet name = options.name;\n\tlet x1 = g_utils.getInt( options.x1, 0 );\n\tlet y1 = g_utils.getInt( options.y1, 0 );\n\tlet x2 = g_utils.getInt( options.x2, screenData.width - 1 );\n\tlet y2 = g_utils.getInt( options.y2, screenData.height - 1 );\n\n\t// Validate and clamp bounds to screen dimensions\n\tx1 = g_utils.clamp( x1, 0, screenData.width - 1 );\n\ty1 = g_utils.clamp( y1, 0, screenData.height - 1 );\n\tx2 = g_utils.clamp( x2, 0, screenData.width - 1 );\n\ty2 = g_utils.clamp( y2, 0, screenData.height - 1 );\n\n\t// Calculate dimensions -- x2, y2 are inclusive so add 1 to width & height here\n\tconst width = Math.abs( x2 - x1 ) + 1;\n\tconst height = Math.abs( y2 - y1 ) + 1;\n\n\tif( width === 0 || height === 0 ) {\n\t\tconst error = new RangeError(\n\t\t\t\"createImageFromScreen: Region width and height must be greater than 0.\"\n\t\t);\n\t\terror.code = \"INVALID_DIMENSIONS\";\n\t\tthrow error;\n\t}\n\n\t// Calculate actual coordinates (top-left corner)\n\tconst actualX = Math.min( x1, x2 );\n\tconst actualY = Math.min( y1, y2 );\n\n\t// Generate a name if none is provided\n\tif( !name || name === \"\" ) {\n\t\tm_imageCount += 1;\n\t\tname = \"\" + m_imageCount;\n\t} else if( typeof name !== \"string\" ) {\n\t\tconst error = new TypeError( \"createImageFromScreen: Parameter name must be a string.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t} else if( m_images[ name ] ) {\n\t\tconst error = new Error(\n\t\t\t`createImageFromScreen: name \"${name}\" is already used; name must be unique.`\n\t\t);\n\t\terror.code = \"DUPLICATE_NAME\";\n\t\tthrow error;\n\t}\n\n\t// Create canvas copy using helper function\n\tconst canvas = createCanvasFromScreenRegion( screenData, actualX, actualY, width, height );\n\n\t// Store in m_images\n\tm_images[ name ] = {\n\t\t\"status\": \"ready\",\n\t\t\"image\": canvas,\n\t\t\"width\": width,\n\t\t\"height\": height,\n\t\t\"usePalette\": false,\n\t\t\"palColors\": null,\n\t\t\"palColorMap\": null\n\t};\n\n\treturn name;\n}\n\n/**\n * Set the default anchor point for images on this screen\n * \n * @param {Object} screenData - Screen data object\n * @param {Object} options - Options\n * @param {number} options.anchorX - Anchor point X (0-1)\n * @param {number} options.anchorY - Anchor point Y (0-1)\n * @returns {void}\n */\nfunction setDefaultAnchor( screenData, options ) {\n\tconst anchorX = g_utils.getFloat( options.x, null );\n\tconst anchorY = g_utils.getFloat( options.y, null );\n\n\t// Validate anchorX\n\tif( anchorX === null || anchorX < 0 || anchorX > 1 ) {\n\t\tconst error = new TypeError(\n\t\t\t\"setDefaultAnchor: Parameter x must be a number between 0 and 1.\"\n\t\t);\n\t\terror.code = \"INVALID_ANCHOR\";\n\t\tthrow error;\n\t}\n\n\t// Validate anchorY\n\tif( anchorY === null || anchorY < 0 || anchorY > 1 ) {\n\t\tconst error = new TypeError(\n\t\t\t\"setDefaultAnchor: Parameter y must be a number between 0 and 1.\"\n\t\t);\n\t\terror.code = \"INVALID_ANCHOR\";\n\t\tthrow error;\n\t}\n\n\t// Update default anchor values\n\tscreenData.defaultAnchorX = anchorX;\n\tscreenData.defaultAnchorY = anchorY;\n}\n\n/**\n * Get spritesheet data including frame information\n * \n * @param {Object} screenData - Screen data object\n * @param {Object} options - Options\n * @param {string} options.name - Spritesheet name\n * @returns {Object} Spritesheet data with frameCount and frames array\n */\nfunction getSpritesheetData( screenData, options ) {\n\tconst name = options.name;\n\n\t// Validate name\n\tif( typeof name !== \"string\" ) {\n\t\tconst error = new TypeError( \"getSpritesheetData: Parameter name must be a string.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\n\tconst spriteData = getStoredImage( name );\n\tif( !spriteData ) {\n\t\tconst error = new Error( `getSpritesheetData: Spritesheet \"${name}\" not found.` );\n\t\terror.code = \"IMAGE_NOT_FOUND\";\n\t\tthrow error;\n\t}\n\n\tif( spriteData.type !== \"spritesheet\" ) {\n\t\tconst error = new Error( `getSpritesheetData: Image \"${name}\" is not a spritesheet.` );\n\t\terror.code = \"NOT_A_SPRITESHEET\";\n\t\tthrow error;\n\t}\n\n\tconst spriteDataResult = {\n\t\t\"frameCount\": spriteData.frames.length,\n\t\t\"frames\": []\n\t};\n\n\tfor( let i = 0; i < spriteData.frames.length; i++ ) {\n\t\tspriteDataResult.frames.push( {\n\t\t\t\"index\": i,\n\t\t\t\"x\": spriteData.frames[ i ].x,\n\t\t\t\"y\": spriteData.frames[ i ].y,\n\t\t\t\"width\": spriteData.frames[ i ].width,\n\t\t\t\"height\": spriteData.frames[ i ].height,\n\t\t\t\"left\": spriteData.frames[ i ].x,\n\t\t\t\"top\": spriteData.frames[ i ].y,\n\t\t\t\"right\": spriteData.frames[ i ].right,\n\t\t\t\"bottom\": spriteData.frames[ i ].bottom\n\t\t} );\n\t}\n\n\treturn spriteDataResult;\n}\n\n\n/**************************************************************************************************\n * Internal Helper Functions\n **************************************************************************************************/\n\n\n/**\n * Create a canvas copy from a region of the screen (FBO)\n * \n * @param {Object} screenData - Screen data object\n * @param {number} x - X coordinate of region\n * @param {number} y - Y coordinate of region\n * @param {number} width - Width of region\n * @param {number} height - Height of region\n * @returns {HTMLCanvasElement} Canvas element with copy of screen region\n */\nfunction createCanvasFromScreenRegion( screenData, x, y, width, height ) {\n\n\t// TODO-LATER: Research if it's possible to use blitFrameBuffer or another faster method than\n\t// readPixels.\n\t\n\t// Read pixel data from FBO using readPixelsRaw\n\tconst pixelData = g_renderer.readPixelsRaw( screenData, x, y, width, height );\n\n\tif( !pixelData ) {\n\t\tconst error = new Error(\n\t\t\t\"createCanvasFromScreenRegion: Failed to read pixel data from screen.\"\n\t\t);\n\t\terror.code = \"READ_FAILED\";\n\t\tthrow error;\n\t}\n\n\t// Create canvas\n\tconst canvas = document.createElement( \"canvas\" );\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tconst context = canvas.getContext( \"2d\" );\n\n\t// Create ImageData for canvas (top-left origin)\n\tconst imageData = context.createImageData( width, height );\n\tconst canvasData = imageData.data;\n\n\t// Convert from bottom-left origin (WebGL) to top-left origin (Canvas)\n\t// pixelData is ordered from bottom row to top row\n\t// canvasData needs to be ordered from top row to bottom row\n\tfor( let row = 0; row < height; row++ ) {\n\t\tfor( let col = 0; col < width; col++ ) {\n\n\t\t\t// Source row in bottom-left origin (pixelData)\n\t\t\tconst srcRow = ( height - 1 ) - row;\n\t\t\tconst srcIndex = ( srcRow * width + col ) * 4;\n\n\t\t\t// Destination row in top-left origin (canvasData)\n\t\t\tconst dstIndex = ( row * width + col ) * 4;\n\n\t\t\t// Copy RGBA values\n\t\t\tcanvasData[ dstIndex     ] = pixelData[ srcIndex     ];\n\t\t\tcanvasData[ dstIndex + 1 ] = pixelData[ srcIndex + 1 ];\n\t\t\tcanvasData[ dstIndex + 2 ] = pixelData[ srcIndex + 2 ];\n\t\t\tcanvasData[ dstIndex + 3 ] = pixelData[ srcIndex + 3 ];\n\t\t}\n\t}\n\n\t// Put image data into canvas\n\tcontext.putImageData( imageData, 0, 0 );\n\n\treturn canvas;\n}\n\nexport function getImageFromRawInput( imageOrName, fnName ) {\n\tlet img = null;\n\n\t// Resolve image from name parameter\n\tif( typeof imageOrName === \"string\" ) {\n\n\t\t// Handle string image name\n\t\tconst imageData = getStoredImage( imageOrName );\n\t\tif( !imageData ) {\n\t\t\tconst error = new Error( `${fnName}: Image \"${imageOrName}\" not found.` );\n\t\t\terror.code = \"IMAGE_NOT_FOUND\"\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Make sure image is ready\n\t\tif( imageData.status !== \"ready\" ) {\n\t\t\tconst imgName = `Image \"${imageOrName}\"`;\n\t\t\tif( imageData.status === \"loading\" ) {\n\t\t\t\tconst error = new Error(\n\t\t\t\t\t`${fnName}: \"${imgName}\" is still loading. Use $.ready() to wait for it.`\n\t\t\t\t);\n\t\t\t\terror.code = \"IMAGE_NOT_READY\";\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif( imageData.status === \"error\" ) {\n\t\t\t\tconst error = new Error( `${fnName}: \"${imgName}\" failed to load.` );\n\t\t\t\terror.code = \"IMAGE_LOAD_FAILED\";\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// Set the image\n\t\timg = imageData.image;\n\t} else if( imageOrName && typeof imageOrName === \"object\" ) {\n\t\tif( isTexImageCompatible( imageOrName ) ) {\n\t\t\timg = imageOrName;\n\t\t} else if( imageOrName.screen === true ) {\n\t\t\tconst imgScreenData = g_screenManager.getScreenData( fnName, imageOrName.id );\n\t\t\timg = imgScreenData.canvas;\n\t\t}\n\t}\n\n\tif( img === null ) {\n\t\tconst error = new TypeError(\n\t\t\t`${fnName}: Parameter name must be a string, canvas element, or image element.`\n\t\t);\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\n\treturn img;\n}\n\nfunction isTexImageCompatible( img ) {\n\treturn (\n\t\timg instanceof HTMLImageElement ||\n\t\timg instanceof HTMLVideoElement ||\n\t\timg instanceof HTMLCanvasElement ||\n\t\timg instanceof ImageBitmap ||\n\t\timg instanceof ImageData ||\n\t\t( typeof OffscreenCanvas !== \"undefined\" && img instanceof OffscreenCanvas )\n\t);\n}\n\n/**\n * Get stored image by name\n * \n * @param {string} name - Image name\n * @returns {Object|null} Image data object or null if not found\n */\nexport function getStoredImage( name ) {\n\tif( typeof name !== \"string\" ) {\n\t\treturn null;\n\t}\n\treturn m_images[ name ] || null;\n}\n\nfunction addPaletteImage( name ) {\n\tm_paletteImages.push( name );\n\n\t// Get the color object data\n\tconst imageObj = m_images[ name ];\n\n\tlet context;\n\n\t// Create a canvas for manipulating color data of original image\n\tif( imageObj.image.tagName !== \"CANVAS\" ) {\n\t\tconst canvas = document.createElement( \"canvas\" );\n\t\tcanvas.width = imageObj.width;\n\t\tcanvas.height = imageObj.height;\n\t\tcontext = canvas.getContext( \"2d\" );\n\t\tcontext.drawImage( imageObj.image, 0, 0 );\n\t\timageObj.image = canvas;\n\t} else {\n\t\tconst canvas = imageObj.image;\n\t\tcontext = canvas.getContext( \"2d\" );\n\t}\n\n\t// Create a fake screen data object so we can use the findColorIndexByColorValue function\n\tconst fakeScreenData = { \"pal\": imageObj.palColors, \"palMap\": imageObj.palColorMap };\n\n\t// Quantize image colors to color keys - Makes sure image only uses colors provided in key map\n\tconst imageData = context.getImageData( 0, 0, imageObj.width, imageObj.height );\n\tconst data = imageData.data;\n\tfor( let i = 0; i < data.length; i += 4 ) {\n\t\tconst color = g_utils.rgbToColor( data[ i ], data[ i + 1 ], data[ i + 2 ], data[ i + 3 ] );\n\t\tconst index = g_colors.findColorIndexByColorValue( fakeScreenData, color, 1 );\n\t\tconst newColor = fakeScreenData.pal[ index ];\n\t\tif( newColor.key !== color.key ) {\n\t\t\tdata[ i ] = newColor.r;\n\t\t\tdata[ i + 1 ] = newColor.g;\n\t\t\tdata[ i + 2 ] = newColor.b;\n\t\t\tdata[ i + 3 ] = newColor.a;\n\t\t}\n\t}\n\tcontext.putImageData( imageData, 0, 0 );\n\n\t// Store the imageData.data onto the object so we don't need to call getImageData when palette\n\t// swaps. The base canvas never changes after this so we can just store the image data here.\n\timageObj.data = data;\n\n\t// Palettize image on all created screens\n\tfor( const screenData of g_screenManager.getAllScreensData() ) {\n\t\tpalettizeImage( screenData, name );\n\t}\n}\n\n// Palettizes all images for a screen\nexport function palettizeImages( screenData ) {\n\n\t// Loop through all palette images\n\tfor( const name of m_paletteImages ) {\n\t\tpalettizeImage( screenData, name );\n\t}\n}\n\nfunction palettizeImage( screenData, name ) {\n\n\t// Get the global image object\n\tconst imageObj = m_images[ name ];\n\n\t// Make sure there are enough colors in the screen palette for this image\n\tif( imageObj.palColors.length > screenData.pal.length ) {\n\t\tconsole.warn(\n\t\t\t`There are too many palette colors in image: ${name}. Unable to swap colors for this ` +\n\t\t\t\"palette.\"\n\t\t);\n\t\treturn;\n\t}\n\n\t// Cache the array length\n\tconst len = imageObj.width * imageObj.height * 4;\n\n\t// Create a \n\tconst palettizedImageData = new Uint8ClampedArray( len );\n\tconst data = imageObj.data;\n\t\n\t// Swap canvas colors. Should have enough indices for screen palette.\n\tfor( let i = 0; i < len; i += 4 ) {\n\n\t\t// Get the pal index from the original image data\n\t\tconst key = g_utils.generateColorKey(\n\t\t\tdata[ i ], data[ i + 1 ], data[ i + 2 ], data[i + 3 ]\n\t\t);\n\t\tconst palIndex = imageObj.palColorMap.get( key );\n\n\t\t// Set the new color\n\t\tconst newColor = screenData.pal[ palIndex ];\n\t\tpalettizedImageData[ i ] = newColor.r;\n\t\tpalettizedImageData[ i + 1 ] = newColor.g;\n\t\tpalettizedImageData[ i + 2 ] = newColor.b;\n\t\tpalettizedImageData[ i + 3 ] = newColor.a;\n\t}\n\n\t// Update the texture with the palettized imageData\n\tg_renderer.updateWebGL2TextureImage(\n\t\tscreenData, imageObj.image, palettizedImageData, imageObj.width, imageObj.height\n\t);\n}\n\n/**\n * Process spritesheet with fixed grid dimensions\n * \n * @param {Object} imageData - Image data object\n * @param {number} width - Image width\n * @param {number} height - Image height\n * @returns {void}\n */\nfunction processSpriteSheetFixed( imageData, width, height ) {\n\tlet x1 = imageData.margin;\n\tlet y1 = imageData.margin;\n\tlet x2 = x1 + imageData.spriteWidth;\n\tlet y2 = y1 + imageData.spriteHeight;\n\n\t// Loop through all the frames in a grid pattern\n\twhile( y2 <= height - imageData.margin ) {\n\t\twhile( x2 <= width - imageData.margin ) {\n\t\t\timageData.frames.push( {\n\t\t\t\t\"x\": x1,\n\t\t\t\t\"y\": y1,\n\t\t\t\t\"width\": imageData.spriteWidth,\n\t\t\t\t\"height\": imageData.spriteHeight,\n\t\t\t\t\"right\": x1 + imageData.spriteWidth - 1,\n\t\t\t\t\"bottom\": y1 + imageData.spriteHeight - 1\n\t\t\t} );\n\t\t\tx1 += imageData.spriteWidth + imageData.margin;\n\t\t\tx2 = x1 + imageData.spriteWidth;\n\t\t}\n\t\tx1 = imageData.margin;\n\t\tx2 = x1 + imageData.spriteWidth;\n\t\ty1 += imageData.spriteHeight + imageData.margin;\n\t\ty2 = y1 + imageData.spriteHeight;\n\t}\n}\n\n/**\n * Process spritesheet with auto-detection (finds connected pixel clusters)\n * \n * @param {Object} imageData - Image data object\n * @param {number} width - Image width\n * @param {number} height - Image height\n * @returns {void}\n */\nfunction processSpriteSheetAuto( imageData, width, height ) {\n\n\t// Create canvas to read pixel data\n\tconst canvas = document.createElement( \"canvas\" );\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tconst context = canvas.getContext( \"2d\", { \"willReadFrequently\": true } );\n\tcontext.drawImage( imageData.image, 0, 0 );\n\n\tconst data = context.getImageData( 0, 0, width, height ).data;\n\tconst searched = new Uint8Array( width * height );\n\n\t// 8-directional neighbors\n\tconst dirs = [\n\t\t[ -1, -1 ], [ 0, -1 ], [ 1, -1 ],\n\t\t[ -1,  0 ],            [ 1,  0 ],\n\t\t[ -1,  1 ], [ 0,  1 ], [ 1,  1 ]\n\t];\n\n\t// Find clusters of non-transparent pixels\n\tfor( let i = 3; i < data.length; i += 4 ) {\n\t\tif( data[ i ] > 0 ) {\n\t\t\tconst index = ( i - 3 ) / 4;\n\t\t\tconst x1 = index % width;\n\t\t\tconst y1 = Math.floor( index / width );\n\t\t\tconst pixelIndex = y1 * width + x1;\n\n\t\t\t// Skip if already searched\n\t\t\tif( searched[ pixelIndex ] ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Find bounding box of this cluster\n\t\t\tconst frameData = {\n\t\t\t\t\"x\": width,\n\t\t\t\t\"y\": height,\n\t\t\t\t\"width\": 0,\n\t\t\t\t\"height\": 0,\n\t\t\t\t\"right\": 0,\n\t\t\t\t\"bottom\": 0\n\t\t\t};\n\n\t\t\t// BFS to find all connected pixels\n\t\t\tconst queue = [];\n\t\t\tqueue.push( { \"x\": x1, \"y\": y1 } );\n\t\t\tsearched[ pixelIndex ] = 1;\n\n\t\t\tlet head = 0;\n\t\t\twhile( head < queue.length ) {\n\t\t\t\tconst pixel = queue[ head++ ];\n\t\t\t\tconst px = pixel.x;\n\t\t\t\tconst py = pixel.y;\n\n\t\t\t\t// Update bounding box\n\t\t\t\tframeData.x = Math.min( frameData.x, px );\n\t\t\t\tframeData.y = Math.min( frameData.y, py );\n\t\t\t\tframeData.right = Math.max( frameData.right, px );\n\t\t\t\tframeData.bottom = Math.max( frameData.bottom, py );\n\n\t\t\t\t// Check all 8 neighbors\n\t\t\t\tfor( const dir of dirs ) {\n\t\t\t\t\tconst nx = px + dir[ 0 ];\n\t\t\t\t\tconst ny = py + dir[ 1 ];\n\n\t\t\t\t\t// Skip if out of bounds\n\t\t\t\t\tif( nx < 0 || nx >= width || ny < 0 || ny >= height ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst nIndex = ny * width + nx;\n\n\t\t\t\t\t// Skip if already searched\n\t\t\t\t\tif( searched[ nIndex ] ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if pixel is non-transparent\n\t\t\t\t\tconst dataIndex = nIndex * 4;\n\t\t\t\t\tif( data[ dataIndex + 3 ] > 0 ) {\n\t\t\t\t\t\tsearched[ nIndex ] = 1;\n\t\t\t\t\t\tqueue.push( { \"x\": nx, \"y\": ny } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Calculate final dimensions\n\t\t\tframeData.width = frameData.right - frameData.x + 1;\n\t\t\tframeData.height = frameData.bottom - frameData.y + 1;\n\n\t\t\t// Only add frames larger than 4 pixels (filters out noise)\n\t\t\tif( ( frameData.width + frameData.height ) > 4 ) {\n\t\t\t\timageData.frames.push( frameData );\n\t\t\t}\n\t\t}\n\t}\n}\n", "/**\n * Pi.js - Plugin System Core Module\n * \n * Plugin registration and management for extending Pi.js functionality.\n * \n * @module core/plugins\n */\n\n\"use strict\";\n\n// Import modules directly\nimport * as g_commands from \"./commands.js\";\nimport * as g_screenManager from \"./screen-manager.js\";\nimport * as g_utils from \"./utils.js\";\n\nconst m_plugins = [];\nconst m_waitingForDependencies = [];\nconst m_clearEventsHandlers = {};\nlet m_api = null;\n\n\n/***************************************************************************************************\n * Module Commands\n **************************************************************************************************/\n\n\nexport function init( api ) {\n\tm_api = api;\n\n\t// Register external API commands\n\tg_commands.addCommand(\n\t\t\"registerPlugin\", registerPlugin, false,\n\t\t[ \"name\", \"init\", \"version\", \"description\", \"dependencies\" ]\n\t);\n\tg_commands.addCommand(\n\t\t\"getPlugins\", getPlugins, false, []\n\t);\n\tg_commands.addCommand(\n\t\t\"clearEvents\", clearEvents, true, [ \"type\" ], true\n\t);\n\n\t// Resolve plugins waiting on dependencies at end of frame\n\tqueueMicrotask( () => {\n\t\tfor( const pluginInfo of m_waitingForDependencies ) {\n\t\t\tlet missingDependencies = [];\n\t\t\tfor( const dependency of pluginInfo.dependencies ) {\n\t\t\t\tif( !m_plugins.some( pi => pi.name === dependency ) ) {\n\t\t\t\t\tmissingDependencies.push( dependency );\n\t\t\t\t}\n\t\t\t}\n\t\t\tif( missingDependencies.length > 0 ) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Unable to initialize plugin \"${pluginInfo.name}\". Missing the following ` +\n\t\t\t\t\t`dependencies: ` + missingDependencies.join( \", \" ) + \".\"\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tinitializePlugin( pluginInfo );\n\t\t\t}\n\t\t}\n\t} );\n}\n\n\n/***************************************************************************************************\n * External API Commands\n **************************************************************************************************/\n\n\n/**\n * Register a plugin with Pi.js\n * \n * @param {Object} options - Plugin configuration\n * @param {string} options.name - Unique name for the plugin\n * @param {Function} options.init - Initialization function that receives pluginApi\n * @param {string} [options.version] - Optional version string\n * @param {string} [options.description] - Optional description\n * @param {string} [options.dependencies] - Optional list of dependencies\n * @returns {void}\n * \n * @example\n * pi.registerPlugin( {\n *   \"name\": \"my-plugin\",\n *   \"version\": \"1.0.0\",\n *   \"description\": \"My custom plugin\",\n *   \"init\": ( pluginApi ) => {\n *     pluginApi.addCommand( \"myCommand\", myFn, [ \"param1\" ] );\n *   }\n * } );\n */\nfunction registerPlugin( options ) {\n\n\t// Validate required parameters\n\tif( !options.name || typeof options.name !== \"string\" ) {\n\t\tconst error = new TypeError( \"registerPlugin: Plugin must have a 'name' property.\" );\n\t\terror.code = \"INVALID_PLUGIN_NAME\";\n\t\tthrow error;\n\t}\n\n\tif( !options.init || typeof options.init !== \"function\" ) {\n\t\tconst error = new TypeError(\n\t\t\t`registerPlugin: Plugin '${options.name}' must have an 'init' function.`\n\t\t);\n\t\terror.code = \"INVALID_PLUGIN_INIT\";\n\t\tthrow error;\n\t}\n\n\t// If dependencies is not defined then create empty array\n\tif( options.dependencies === null ) {\n\t\toptions.dependencies = [];\n\t}\n\n\t// Check for duplicate\n\tif( m_plugins.some( p => p.name === options.name ) ) {\n\t\tconst error = new Error(\n\t\t\t`registerPlugin: Plugin '${options.name}' is already registered.`\n\t\t);\n\t\terror.code = \"DUPLICATE_PLUGIN\";\n\t\tthrow error;\n\t}\n\n\t// Store plugin info\n\tconst pluginInfo = {\n\t\t\"name\": options.name,\n\t\t\"version\": options.version || \"unknown\",\n\t\t\"description\": options.description || \"\",\n\t\t\"config\": options,\n\t\t\"initialized\": false\n\t};\n\n\tm_plugins.push( pluginInfo );\n\n\t// If all dependencies loaded then process immediately\n\tlet isWaitingForDependencies = false;\n\tfor( const dependency of pluginInfo.config.dependencies ) {\n\t\tif( !m_plugins.some( pi => pi.name === dependency ) ) {\n\t\t\tisWaitingForDependencies = true;\n\t\t}\n\t}\n\tif( isWaitingForDependencies ) {\n\t\tm_waitingForDependencies.push( pluginInfo );\n\t} else {\n\t\tinitializePlugin( pluginInfo );\n\t}\n}\n\n/**\n * Get list of registered plugins\n * \n * @returns {Array<Object>} Array of plugin info objects with name, version, description\n * \n * @example\n * const plugins = pi.getPlugins();\n * console.log( plugins ); // [{ name: \"my-plugin\", version: \"1.0.0\", ... }]\n */\nfunction getPlugins() {\n\treturn m_plugins.map( p => ( {\n\t\t\"name\": p.name,\n\t\t\"version\": p.version,\n\t\t\"description\": p.description,\n\t\t\"initialized\": p.initialized\n\t} ) );\n}\n\n/**\n * Clear all events from all plugins or a specific plugin type\n * \n * @param {Object} screenData - Screen data object (may be null)\n * @param {Object} options - Options object\n * @param {string} [options.type] - Optional type to clear (e.g., \"keyboard\", \"mouse\", \"touch\", \"press\")\n * @returns {void}\n * \n * @example\n * $.clearEvents(); // Clear all events from all plugins\n * $.clearEvents( { \"type\": \"keyboard\" } ); // Clear only keyboard events\n */\nfunction clearEvents( screenData, options ) {\n\tconst type = options?.type;\n\t\n\tif( type ) {\n\n\t\t// Clear events for specific type\n\t\tconst lowerType = String( type ).toLowerCase();\n\t\tconst handler = m_clearEventsHandlers[ lowerType ];\n\t\t\n\t\tif( !handler ) {\n\t\t\tconst validTypes = Object.keys( m_clearEventsHandlers );\n\t\t\tlet errorMessage = `clearEvents: Invalid type \"${type}\".`;\n\t\t\tif( validTypes.length > 0 ) {\n\t\t\t\terrorMessage += ` Valid types are: ${validTypes.join( \", \" )}.`;\n\t\t\t} else {\n\t\t\t\terrorMessage += \" No event handlers are registered.\";\n\t\t\t}\n\t\t\tconst error = new Error( errorMessage );\n\t\t\terror.code = \"INVALID_TYPE\";\n\t\t\tthrow error;\n\t\t}\n\t\t\n\t\ttry {\n\t\t\thandler( screenData );\n\t\t} catch( error ) {\n\t\t\tconsole.error(\n\t\t\t\t`clearEvents: Error calling clearEvents handler for type \"${type}\": ` +\n\t\t\t\t`${error.message}`\n\t\t\t);\n\t\t}\n\t} else {\n\n\t\t// Clear events for all registered types\n\t\tfor( const handlerName in m_clearEventsHandlers ) {\n\t\t\tconst handler = m_clearEventsHandlers[ handlerName ];\n\t\t\ttry {\n\t\t\t\thandler( screenData );\n\t\t\t} catch( error ) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`clearEvents: Error calling clearEvents handler for type \"${handlerName}\": ` +\n\t\t\t\t\t`${error.message}`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/***************************************************************************************************\n * Internal Commands\n **************************************************************************************************/\n\n\n/**\n * Register a clearEvents handler function with a name\n * \n * @param {string} name - Name of the event type (e.g., \"keyboard\", \"mouse\", \"touch\", \"press\")\n * @param {Function} handler - Function to call when clearEvents is invoked for this type\n * @param {Object} [handler.screenData] - Screen data passed from clearEvents (may be null)\n * @returns {void}\n * \n * @example\n * pluginApi.registerClearEvents( \"keyboard\", ( screenData ) => {\n *   // Clear keyboard events for this plugin\n * } );\n */\nfunction registerClearEvents( name, handler ) {\n\tif( !name || typeof name !== \"string\" ) {\n\t\tconst error = new TypeError( \"registerClearEvents: name must be a non-empty string.\" );\n\t\terror.code = \"INVALID_NAME\";\n\t\tthrow error;\n\t}\n\t\n\tif( typeof handler !== \"function\" ) {\n\t\tconst error = new TypeError( \"registerClearEvents: handler must be a function.\" );\n\t\terror.code = \"INVALID_HANDLER\";\n\t\tthrow error;\n\t}\n\t\n\tconst lowerName = name.toLowerCase();\n\t\n\tif( m_clearEventsHandlers[ lowerName ] ) {\n\t\tconst error = new Error(\n\t\t\t`registerClearEvents: Handler with name \"${name}\" is already registered.`\n\t\t);\n\t\terror.code = \"DUPLICATE_HANDLER\";\n\t\tthrow error;\n\t}\n\t\n\tm_clearEventsHandlers[ lowerName ] = handler;\n}\n\n// Initialize a plugin\nfunction initializePlugin( pluginInfo ) {\n\tif( pluginInfo.initialized ) {\n\t\treturn;\n\t}\n\n\t// Create plugin API\n\tconst pluginApi = {\n\t\t\"addCommand\": g_commands.addCommand,\n\t\t\"addScreenDataItem\": g_screenManager.addScreenDataItem,\n\t\t\"addScreenDataItemGetter\": g_screenManager.addScreenDataItemGetter,\n\t\t\"addScreenInitFunction\": g_screenManager.addScreenInitFunction,\n\t\t\"addScreenCleanupFunction\": g_screenManager.addScreenCleanupFunction,\n\t\t\"getScreenData\": g_screenManager.getScreenData,\n\t\t\"getAllScreensData\": g_screenManager.getAllScreensData,\n\t\t\"getApi\": () => m_api,\n\t\t\"utils\": g_utils,\n\t\t\"wait\": g_commands.wait,\n\t\t\"done\": g_commands.done,\n\t\t\"registerClearEvents\": registerClearEvents\n\t};\n\n\t// Initialize plugin\n\ttry {\n\t\tpluginInfo.config.init( pluginApi );\n\t\tg_commands.processCommands( m_api );\n\t\tpluginInfo.initialized = true;\n\t} catch( error ) {\n\t\tconst pluginError = new Error(\n\t\t\t`registerPlugin: Failed to initialize plugin '${pluginInfo.name}': ${error.message}`\n\t\t);\n\t\tpluginError.code = \"PLUGIN_INIT_FAILED\";\n\t\tpluginError.originalError = error;\n\t\tthrow pluginError;\n\t}\n}\n\n", "/**\n * Pi.js - Graphics Pixels Module\n * \n * Commands to read and write pixels from the screen.\n * \n * @module api/pixels\n */\n\n\"use strict\";\n\n// Imports\nimport * as g_utils from \"../core/utils.js\";\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_colors from \"./colors.js\";\nimport * as g_commands from \"../core/commands.js\";\nimport * as g_renderer from \"../renderer/renderer.js\";\nimport * as g_textures from \"../renderer/textures.js\";\n\n\n/***************************************************************************************************\n * Module Commands\n **************************************************************************************************/\n\n\nexport function init( api ) {\n\tregisterCommands();\n\n\t// Stable API - do not route through addCommand for hot path put\n\tapi.put = ( data, x, y, include0 ) => {\n\t\treturn putWrapper( g_screenManager.getActiveScreen( \"put\" ), data, x, y, include0 );\n\t};\n\n\t// Also add to each screen's api when screen is created\n\tg_screenManager.addScreenInitFunction( ( screenData ) => {\n\t\tscreenData.api.put = ( data, x, y, include0 ) => {\n\t\t\treturn putWrapper( screenData, data, x, y, include0 );\n\t\t};\n\t} );\n}\n\n\nfunction registerCommands() {\n\t\n\t// Register screen commands\n\tg_commands.addCommand( \"getPixel\", getPixel, true, [ \"x\", \"y\", \"asIndex\" ] );\n\tg_commands.addCommand( \"getPixelAsync\", getPixelAsync, true, [ \"x\", \"y\", \"asIndex\" ] );\n\tg_commands.addCommand(\n\t\t\"get\", get, true, [ \"x\", \"y\", \"width\", \"height\", \"tolerance\", \"asIndex\" ]\n\t);\n\tg_commands.addCommand(\n\t\t\"getAsync\", getAsync, true, [ \"x\", \"y\", \"width\", \"height\", \"tolerance\", \"asIndex\" ]\n\t);\n\tg_commands.addCommand(\n\t\t\"filterImg\", filterImg, true, [ \"filter\", \"x1\", \"y1\", \"x2\", \"y2\" ]\n\t);\n}\n\n\n/***************************************************************************************************\n * Get Pixel and Get Pixel Async\n **************************************************************************************************/\n\n\n// getPixel: Returns RGBA color object by default; if asIndex===true, returns palette index\nfunction getPixel( screenData, options ) {\n\tconst px = g_utils.getInt( options.x, null );\n\tconst py = g_utils.getInt( options.y, null );\n\tif( px === null || py === null ) {\n\t\tconst error = new TypeError( \"getPixel: Parameters x and y must be integers.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\tconst asIndex = options.asIndex ?? false;\n\tconst colorValue = g_renderer.readPixel( screenData, px, py );\n\tif( asIndex ) {\n\t\treturn g_colors.findColorIndexByColorValue( screenData, colorValue );\n\t}\n\treturn colorValue;\n}\n\nfunction getPixelAsync( screenData, options ) {\n\tconst px = g_utils.getInt( options.x, null );\n\tconst py = g_utils.getInt( options.y, null );\n\tif( px === null || py === null ) {\n\t\tconst error = new TypeError( \"getPixelAsync: Parameters x and y must be integers.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\tconst asIndex = options.asIndex ?? false;\n\treturn g_renderer.readPixelAsync( screenData, px, py ).then( ( colorValue ) => {\n\t\tif( asIndex ) {\n\t\t\treturn g_colors.findColorIndexByColorValue( screenData, colorValue );\n\t\t}\n\t\treturn colorValue;\n\t} );\n}\n\n\n/***************************************************************************************************\n * Get and Get Async\n **************************************************************************************************/\n\n\n// get: Returns a 2D array [height][width] of palette indices by default.\n// Set asIndex=false to return colorValue objects instead.\n// Optional tolerance passed to findColorIndexByColorValue.\nfunction get( screenData, options ) {\n\tconst pX = g_utils.getInt( options.x, null );\n\tconst pY = g_utils.getInt( options.y, null );\n\tconst pWidth = g_utils.getInt( options.width, null );\n\tconst pHeight = g_utils.getInt( options.height, null );\n\tconst tolerance = g_utils.getFloat( options.tolerance, 1 );\n\tconst asIndex = options.asIndex ?? true;\n\n\tif( pX === null || pY === null || pWidth === null || pHeight === null ) {\n\t\tconst error = new TypeError(\n\t\t\t\"get: Parameters x, y, width and height must be integers.\"\n\t\t);\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\t\n\tif( pWidth <= 0 || pHeight <= 0 ) {\n\t\treturn [];\n\t}\n\n\tconst colors = g_renderer.readPixels( screenData, pX, pY, pWidth, pHeight );\n\treturn convertColorsToIndices( screenData, colors, pWidth, asIndex, tolerance );\n}\n\nfunction getAsync( screenData, options ) {\n\tconst pX = g_utils.getInt( options.x, null );\n\tconst pY = g_utils.getInt( options.y, null );\n\tconst pWidth = g_utils.getInt( options.width, null );\n\tconst pHeight = g_utils.getInt( options.height, null );\n\tconst tolerance = g_utils.getFloat( options.tolerance, 1 );\n\tconst asIndex = options.asIndex ?? true;\n\n\tif( pX === null || pY === null || pWidth === null || pHeight === null ) {\n\t\tconst error = new TypeError(\n\t\t\t\"getAsync: Parameters x, y, width and height must be integers.\"\n\t\t);\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\tif( pWidth <= 0 || pHeight <= 0 ) {\n\t\treturn Promise.resolve( [] );\n\t}\n\n\treturn g_renderer.readPixelsAsync( screenData, pX, pY, pWidth, pHeight ).then( ( colors ) => {\n\t\treturn convertColorsToIndices( screenData, colors, pWidth, asIndex, tolerance );\n\t} );\n}\n\n/**\n * Convert colors array to indices array if needed\n * \n * @param {Object} screenData - Screen data object\n * @param {Array} colors - 2D array of color values [height][width]\n * @param {number} width - Width of the region\n * @param {boolean} asIndex - Whether to convert to indices\n * @param {number|undefined} tolerance - Tolerance for color matching\n * @returns {Array} 2D array of colors or indices\n */\nfunction convertColorsToIndices( screenData, colors, width, asIndex, tolerance ) {\n\tif( !asIndex ) {\n\t\treturn colors;\n\t}\n\n\tconst results = new Array( colors.length );\n\tfor( let row = 0; row < colors.length; row++ ) {\n\t\tconst resultsRow = new Array( width );\n\t\tconst rowLength = colors[ row ] ? colors[ row ].length : 0;\n\t\t\n\t\tfor( let col = 0; col < width; col++ ) {\n\t\t\tif( col < rowLength ) {\n\t\t\t\tconst colorValue = colors[ row ][ col ];\n\t\t\t\tconst idx = g_colors.findColorIndexByColorValue(\n\t\t\t\t\tscreenData, colorValue, tolerance\n\t\t\t\t);\n\t\t\t\tresultsRow[ col ] = ( idx === null ? 0 : idx );\n\t\t\t} else {\n\t\t\t\tresultsRow[ col ] = 0;\n\t\t\t}\n\t\t}\n\t\tresults[ row ] = resultsRow;\n\t}\n\treturn results;\n}\n\n\n/***************************************************************************************************\n * Filter Image\n **************************************************************************************************/\n\n\n/**\n * Apply a filter function to a region of the screen\n * \n * @param {Object} screenData - Screen data object\n * @param {Object} options - Options object with filter, x1, y1, x2, y2\n * @returns {void}\n */\nfunction filterImg( screenData, options ) {\n\tconst filter = options.filter;\n\n\t// Get optional clipping bounds (default to full screen)\n\tlet x1 = g_utils.getInt( options.x1, 0 );\n\tlet y1 = g_utils.getInt( options.y1, 0 );\n\tlet x2 = g_utils.getInt( options.x2, screenData.width - 1 );\n\tlet y2 = g_utils.getInt( options.y2, screenData.height - 1 );\n\n\tif( !g_utils.isFunction( filter ) ) {\n\t\tconst error = new TypeError( \"filterImg: Argument filter must be a callback function.\" );\n\t\terror.code = \"INVALID_CALLBACK\";\n\t\tthrow error;\n\t}\n\n\t// Validate and clamp bounds to screen dimensions\n\tx1 = g_utils.clamp( x1, 0, screenData.width - 1 );\n\ty1 = g_utils.clamp( y1, 0, screenData.height - 1 );\n\tx2 = g_utils.clamp( x2, 0, screenData.width - 1 );\n\ty2 = g_utils.clamp( y2, 0, screenData.height - 1 );\n\n\t// Ensure x1 <= x2 and y1 <= y2\n\tif( x1 > x2 ) {\n\t\tconst temp = x1;\n\t\tx1 = x2;\n\t\tx2 = temp;\n\t}\n\tif( y1 > y2 ) {\n\t\tconst temp = y1;\n\t\ty1 = y2;\n\t\ty2 = temp;\n\t}\n\n\tconst width = x2 - x1 + 1;\n\tconst height = y2 - y1 + 1;\n\n\t// Queue filter operation to run at end of frame\n\t// Use double microtask to ensure it runs after any current render operations\n\tg_utils.queueMicrotask( () => {\n\t\tg_utils.queueMicrotask( () => {\n\t\t\tapplyFilter( screenData, filter, x1, y1, width, height );\n\t\t} );\n\t} );\n}\n\n/**\n * Apply filter to pixel region (called at end of frame)\n * \n * @param {Object} screenData - Screen data object\n * @param {Function} filter - Filter callback function (pixelData, x, y) => boolean\n * \t\t\t\t\t\t\t  pixelData is a Uint8ClampedArray with [r, g, b, a] at indices 0-3\n * @param {number} x1 - Left coordinate\n * @param {number} y1 - Top coordinate\n * @param {number} width - Region width\n * @param {number} height - Region height\n * @returns {void}\n */\nfunction applyFilter( screenData, filter, x1, y1, width, height ) {\n\n\t// Ensure batches are flushed before reading\n\tg_renderer.flushBatches( screenData );\n\n\t// Read pixels as raw Uint8Array (bottom-left origin from WebGL)\n\tconst imageData = g_renderer.readPixelsRaw( screenData, x1, y1, width, height );\n\n\tif( !imageData ) {\n\t\treturn;\n\t}\n\n\tconst screenHeight = screenData.height;\n\n\t// Build filtered pixel data in bottom-left origin format (for WebGL texSubImage2D)\n\t// The input pixelData is in bottom-left origin, so we need to flip Y when accessing\n\t// for the filter callback (which expects top-left coordinates), then flip back for output\n\tconst filteredData = new Uint8Array( width * height * 4 );\n\tconst pixelData = new Uint8ClampedArray( 4 );\n\n\tfor( let y = 0; y < height; y++ ) {\n\t\tfor( let x = 0; x < width; x++ ) {\n\n\t\t\t// Convert top-left y to bottom-left y for reading from pixelData\n\t\t\t// pixelData is ordered from bottom row to top row\n\t\t\tconst srcRow = ( height - 1 ) - y;\n\t\t\tconst srcIndex = ( srcRow * width + x ) * 4;\n\n\t\t\t// Populate the temporary buffer with current pixel's RGBA\n\t\t\tpixelData[ 0 ] = imageData[ srcIndex ];\n\t\t\tpixelData[ 1 ] = imageData[ srcIndex + 1 ];\n\t\t\tpixelData[ 2 ] = imageData[ srcIndex + 2 ];\n\t\t\tpixelData[ 3 ] = imageData[ srcIndex + 3 ];\n\n\t\t\t// Output index is in bottom-left origin format (same as pixelData)\n\t\t\tconst dstIndex = ( srcRow * width + x ) * 4;\n\n\t\t\t// Call filter with pixelData array\n\t\t\t// x and y are in top-left coordinate system for the filter callback\n\t\t\tif( filter( pixelData, x1 + x, y1 + y ) ) {\n\n\t\t\t\t// Update the pixeldata \n\t\t\t\tfilteredData[ dstIndex     ] = pixelData[ 0 ];\n\t\t\t\tfilteredData[ dstIndex + 1 ] = pixelData[ 1 ];\n\t\t\t\tfilteredData[ dstIndex + 2 ] = pixelData[ 2 ];\n\t\t\t\tfilteredData[ dstIndex + 3 ] = pixelData[ 3 ];\n\t\t\t} else {\n\n\t\t\t\t// Invalid color format, keep original pixel\n\t\t\t\tfilteredData[ dstIndex     ] = 0;\n\t\t\t\tfilteredData[ dstIndex + 1 ] = 0;\n\t\t\t\tfilteredData[ dstIndex + 2 ] = 0;\n\t\t\t\tfilteredData[ dstIndex + 3 ] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Calculate destination Y in WebGL texture coordinates (bottom-left origin)\n\t// The texture Y coordinate is the bottom edge of the region\n\tconst dstY = screenHeight - ( y1 + height );\n\n\t// Update FBO texture directly using texSubImage2D\n\t// Pass null as imgKey to use screenData.fboTexture directly\n\tg_textures.updateWebGL2TextureSubImage(\n\t\tscreenData, null, filteredData, width, height, x1, dstY\n\t);\n\n\t// Mark image as dirty to trigger render\n\tg_renderer.setImageDirty( screenData );\n}\n\n\n/***************************************************************************************************\n * Write API\n **************************************************************************************************/\n\n\n// Wrapper for the put commands handles all parsing and data validation\nfunction putWrapper( screenData, data, x, y, include0 = false ) {\n\n\t// Accept either object-literal or positional params without using parseOptions\n\tlet pData, pX, pY, pInclude0;\n\tif( g_utils.isObjectLiteral( data ) ) {\n\t\tpData = data.data;\n\t\tpX = g_utils.getInt( data.x, null );\n\t\tpY = g_utils.getInt( data.y, null );\n\t\tpInclude0 = !!data.include0;\n\t} else {\n\t\tpData = data;\n\t\tpX = g_utils.getInt( x, null );\n\t\tpY = g_utils.getInt( y, null );\n\t\tpInclude0 = !!include0;\n\t}\n\n\t// Fast bail if no data\n\tif( !pData || pData.length < 1 ) {\n\t\treturn null;\n\t}\n\n\t// Validate coordinates\n\tif( pX === null || pY === null ) {\n\t\tconst error = new TypeError( \"put: Parameters x and y must be integers.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\t// Validate and clip data\n\tconst screenW = screenData.width;\n\tconst screenH = screenData.height;\n\n\t// Clip starting offsets when x/y are negative\n\tlet startX = ( pX < 0 ? -pX : 0 );\n\tlet startY = ( pY < 0 ? -pY : 0 );\n\n\t// Calculate width/height available from data starting at the clipped offsets\n\tlet width = pData[ 0 ] ? ( pData[ 0 ].length - startX ) : 0;\n\tlet height = pData.length - startY;\n\n\t// Clamp to screen bounds\n\tif( pX + startX + width > screenW ) {\n\t\twidth = screenW - pX - startX;\n\t}\n\tif( pY + startY + height > screenH ) {\n\t\theight = screenH - pY - startY;\n\t}\n\n\t// If nothing to draw after clipping, exit\n\tif( width <= 0 || height <= 0 ) {\n\t\treturn null;\n\t}\n\n\t// Prepare the batch by making sure there are enough memory in the batch\n\tlet pixelCount = 0;\n\n\t// Use the already calculated loop bounds\n\tfor( let i = startY; i < startY + height; i++ ) {\n\t\tconst row = pData[ i ];\n\n\t\t// Check if row exists\n\t\tif( row ) {\n\n\t\t\t// The actual number of pixels drawn from this row will be `width`\n\t\t\tpixelCount += width;\n\t\t}\n\t}\n\n\tg_renderer.prepareBatch( screenData, g_renderer.POINTS_REPLACE_BATCH, pixelCount );\n\n\tput( screenData, pData, pX, pY, pInclude0, startY, startX, width, height );\n\n\t// Mark image as dirty\n\tg_renderer.setImageDirty( screenData );\n}\n\n// put: Hot path inner function. Assumes x/y are integers and data is a 2D array.\nfunction put( screenData, data, x, y, include0, startY, startX, width, height ) {\n\t\n\tconst endY = startY + height;\n\tconst endX = startX + width;\n\n\t// Draw\n\tfor( let dataY = startY; dataY < endY; dataY++ ) {\n\t\tconst row = data[ dataY ];\n\t\tif( !row ) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor( let dataX = startX; dataX < endX; dataX++ ) {\n\n\t\t\t// Double bitwise NOT - fast convert to int function\n\t\t\tconst colorIndex = ~~row[ dataX ];\n\n\t\t\t// Skip transparent unless include0 is true\n\t\t\tif( colorIndex === 0 && include0 === false ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst colorValue = g_colors.getColorValueByIndex( screenData, colorIndex );\n\t\t\tconst sx = x + dataX;\n\t\t\tconst sy = y + dataY;\n\n\t\t\tg_renderer.drawPixelUnsafe(\n\t\t\t\tscreenData, sx, sy, colorValue, g_renderer.POINTS_REPLACE_BATCH\n\t\t\t);\n\t\t}\n\t}\n}\n\n", "/**\n * Pi.js - Paint Module\n * \n * Flood fill algorithm with tolerance support\n * \n * @module api/paint\n */\n\n\"use strict\";\n\nimport * as g_colors from \"./colors.js\";\nimport * as g_utils from \"../core/utils.js\";\nimport * as g_renderer from \"../renderer/renderer.js\";\nimport * as g_commands from \"../core/commands.js\";\n\n\n/***************************************************************************************************\n * Module Commands\n **************************************************************************************************/\n\n\n/**\n * Initialize paint module\n * \n * @param {Object} api - The main Pi.js API object\n * @returns {void}\n */\nexport function init( api ) {\n\tregisterCommands();\n}\n\n\n/***************************************************************************************************\n * External API Commands\n **************************************************************************************************/\n\n\nfunction registerCommands() {\n\tg_commands.addCommand(\n\t\t\"paint\", paint, true, [ \"x\", \"y\", \"fillColor\", \"tolerance\", \"boundaryColor\" ]\n\t);\n}\n\n\n/**\n * Paint command - flood fill algorithm with tolerance support\n * \n * @param {Object} screenData - The screen data object\n * @param {Object} options - Options object with x, y, fillColor, tolerance, boundaryColor\n * @param {number} options.tolerance - Color matching tolerance (0 = exact match, 1 = any color)\n * @returns {void}\n */\nfunction paint( screenData, options ) {\n\tconst x = g_utils.getInt( options.x, null );\n\tconst y = g_utils.getInt( options.y, null );\n\tlet fillColor = options.fillColor;\n\tlet tolerance = g_utils.getFloat( options.tolerance, 0 );\n\tlet boundaryColor = options.boundaryColor;\n\n\tif( x === null || y === null ) {\n\t\tconst error = new TypeError( \"paint: Parameters x and y must be integers\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\tif( tolerance < 0 || tolerance > 1 ) {\n\t\tconst error = new RangeError(\n\t\t\t\"paint: Parameter tolerance must be a number between 0 and 1 \" +\n\t\t\t\"(0 = exact match, 1 = any color).\"\n\t\t);\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\t// Get fill color\n\tfillColor = g_colors.getColorValueByRawInput( screenData, fillColor );\n\tif( fillColor === null ) {\n\t\tconst error = new RangeError( \"paint: Parameter fillColor is not a valid color format.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\tconst width = screenData.width;\n\tconst height = screenData.height;\n\n\t// Check if starting point is in bounds\n\tif( x < 0 || x >= width || y < 0 || y >= height ) {\n\t\treturn;\n\t}\n\n\t// Optimization: if tolerance is 1 (any color), just fill the entire screen\n\tif( tolerance === 1 ) {\n\t\tg_renderer.drawRectFilled( screenData, 0, 0, width, height, fillColor );\n\t\tg_renderer.setImageDirty( screenData );\n\t\treturn;\n\t}\n\n\t// Read all pixels from screen as 2D array\n\tconst pixels2D = g_renderer.readPixels( screenData, 0, 0, width, height );\n\n\t// Get the starting pixel color\n\tconst startColor = pixels2D[ y ][ x ];\n\n\t// Don't fill if the color is the same\n\tif( startColor.key === fillColor.key ) {\n\t\treturn;\n\t}\n\n\t// Calculate tolerance threshold for color comparison\n\t// Using perceptual weights: [0.2, 0.68, 0.07, 0.05] for R, G, B, A\n\t// Tolerance: 0 = exact match only, 1 = any color\n\tconst weights = [ 0.2, 0.68, 0.07, 0.05 ];\n\tconst maxDifference = ( 255 * 255 ) * weights.reduce( ( a, b ) => a + b );\n\tconst toleranceThreshold = ( 1 - tolerance * tolerance ) * maxDifference;\n\n\t// Use Uint8Array for efficient visited pixel tracking\n\tconst visited = new Uint8Array( width * height );\n\n\t// BFS queue for flood fill - using head pointer for O(1) dequeue\n\tconst queue = [];\n\tqueue.push( { \"x\": x, \"y\": y } );\n\n\t// Mark starting pixel as visited\n\tvisited[ y * width + x ] = 1;\n\n\t// Define color comparison function based on fill mode (no conditionals in hot loop)\n\tlet shouldSkipPixel;\n\tif( boundaryColor !== null ) {\n\n\t\t// Boundary fill mode: skip pixels that match boundary color\n\t\tboundaryColor = g_colors.getColorValueByRawInput( screenData, boundaryColor );\n\t\tif( boundaryColor === null ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"paint: Parameter boundaryColor is not a valid color format.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_PARAMETER\";\n\t\t\tthrow error;\n\t\t}\n\t\tshouldSkipPixel = ( pixelColor ) => {\n\t\t\tconst difference = g_utils.calcColorDifference( boundaryColor, pixelColor, weights );\n\t\t\tconst similarity = maxDifference - difference;\n\t\t\treturn similarity >= toleranceThreshold;\n\t\t};\n\n\t} else {\n\n\t\t// Flood fill mode: skip pixels that don't match start color\n\t\tshouldSkipPixel = ( pixelColor ) => {\n\t\t\tconst difference = g_utils.calcColorDifference( startColor, pixelColor, weights );\n\t\t\tconst similarity = maxDifference - difference;\n\t\t\treturn similarity < toleranceThreshold;\n\t\t};\n\t}\n\n\t// Prepare batch for drawing pixels\n\tconst pixelCount = width * height;\n\tg_renderer.prepareBatch( screenData, g_renderer.POINTS_BATCH, pixelCount );\n\n\tlet head = 0;\n\twhile( head < queue.length ) {\n\n\t\t// Dequeue using head pointer (O(1) instead of O(n) with shift)\n\t\tconst pixel = queue[ head++ ];\n\t\tconst px = pixel.x;\n\t\tconst py = pixel.y;\n\n\t\t// Get pixel color\n\t\tconst pixelColor = pixels2D[ py ][ px ];\n\n\t\t// Skip if color comparison fails\n\t\tif( shouldSkipPixel( pixelColor ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Fill this pixel using drawPixelUnsafe\n\t\tg_renderer.drawPixelUnsafe(\n\t\t\tscreenData, pixel.x, pixel.y, fillColor, g_renderer.POINTS_BATCH\n\t\t);\n\n\t\t// Add adjacent pixels to queue if not visited and in bounds\n\t\taddToQueue( queue, visited, px + 1, py, width, height );\n\t\taddToQueue( queue, visited, px - 1, py, width, height );\n\t\taddToQueue( queue, visited, px, py + 1, width, height );\n\t\taddToQueue( queue, visited, px, py - 1, width, height );\n\t}\n\n\t// Mark image as dirty to trigger render\n\tg_renderer.setImageDirty( screenData );\n}\n\n\n/***************************************************************************************************\n * Internal Commands\n **************************************************************************************************/\n\n\n/**\n * Add pixel to queue if valid and not visited\n * \n * @param {Array} queue - BFS queue\n * @param {Uint8Array} visited - Visited pixel tracking array\n * @param {number} x - X coordinate\n * @param {number} y - Y coordinate\n * @param {number} width - Screen width\n * @param {number} height - Screen height\n * @returns {void}\n */\nfunction addToQueue( queue, visited, x, y, width, height ) {\n\tif( x < 0 || x >= width || y < 0 || y >= height ) {\n\t\treturn;\n\t}\n\n\tconst index = y * width + x;\n\tif( visited[ index ] === 0 ) {\n\t\tvisited[ index ] = 1;\n\t\tqueue.push( { \"x\": x, \"y\": y } );\n\t}\n}\n\n", "/**\n * Pi.js - Draw Module\n * \n * BASIC-style draw command with string syntax for procedural drawing\n * \n * @module api/draw\n */\n\n\"use strict\";\n\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_utils from \"../core/utils.js\";\nimport * as g_commands from \"../core/commands.js\";\n\n\n/***************************************************************************************************\n * Module Commands\n **************************************************************************************************/\n\n\n/**\n * Initialize draw module\n * \n * @param {Object} api - The main Pi.js API object\n * @returns {void}\n */\nexport function init( api ) {\n\tg_screenManager.addScreenDataItem( \"cursor\", { \"x\": 0, \"y\": 0 } );\n\tg_screenManager.addScreenDataItem( \"angle\", 0 );\n\n\tregisterCommands();\n}\n\n\n/***************************************************************************************************\n * External API Commands\n **************************************************************************************************/\n\n\nfunction registerCommands() {\n\tg_commands.addCommand( \"draw\", draw, true, [ \"drawString\" ] );\n}\n\n\n/**\n * Draw command - BASIC-style draw command with string syntax\n * \n * @param {Object} screenData - The screen data object\n * @param {Object} options - Options object with drawString\n * @param {string} options.drawString - The draw command string\n * @returns {void}\n */\nfunction draw( screenData, options ) {\n\tlet drawString = options.drawString;\n\n\tif( typeof drawString !== \"string\" ) {\n\t\tconst error = new TypeError( \"draw: Parameter drawString must be a string.\" );\n\t\terror.code = \"INVALID_PARAMETER\";\n\t\tthrow error;\n\t}\n\n\t// Convert to uppercase\n\tdrawString = drawString.toUpperCase();\n\n\t// Get colors\n\tconst tempColors = drawString.match( /(#[A-Z0-9]+)/g );\n\tif( tempColors ) {\n\t\tfor( let i = 0; i < tempColors.length; i++ ) {\n\t\t\tdrawString = drawString.replace( \"C\" + tempColors[ i ], \"O\" + i );\n\t\t}\n\t}\n\n\t// Remove spaces and invalid characters (keep only valid commands, numbers, #, and commas)\n\t// Note: Z is not included because Z is a replacement character and not allowed in original\n\t// string\n\tdrawString = drawString.replace( /[^CRBFGLATDHUENMPSO0-9#,]/g, \"\" );\n\t\n\t// Convert TA to T\n\tdrawString = drawString.replace( /(TA)/gi, \"T\" );\n\n\t// Convert ARC to Z\n\tdrawString = drawString.replace( /(ARC)/gi, \"Z\" );\n\t\n\t// Regular expression for the draw commands\n\tconst reg = /(?=C|O|R|B|F|G|L|A|T|D|G|H|U|E|N|M|P|S|Z)/;\n\n\t// Run the regular expression and split into separate commands\n\tconst parts = drawString.split( reg );\n\n\t// This triggers a move back after drawing the next command\n\tlet isReturn = false;\n\n\t// Store the last cursor - use current angle, not 0\n\tlet lastCursor = {\n\t\t\"x\": screenData.cursor.x,\n\t\t\"y\": screenData.cursor.y,\n\t\t\"angle\": screenData.angle\n\t};\n\n\t// Move without drawing\n\tlet isBlind = false;\n\n\tlet isArc = false;\n\tlet arcRadius, arcAngle1, arcAngle2;\n\tlet scale = 1;\n\n\tfor( let i = 0; i < parts.length; i++ ) {\n\t\tconst drawArgs = parts[ i ].split( /(\\d+)/ );\n\n\t\tswitch( drawArgs[ 0 ] ) {\n\n\t\t\t// C - Change Color - Using integer\n\t\t\tcase \"C\": {\n\t\t\t\tconst colorNum = Number( drawArgs[ 1 ] );\n\t\t\t\tscreenData.api.setColor( colorNum );\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// O - Change Color - Using string\n\t\t\tcase \"O\": {\n\t\t\t\tconst colorStr = tempColors[ drawArgs[ 1 ] ];\n\t\t\t\tscreenData.api.setColor( colorStr );\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// D - Down\n\t\t\tcase \"D\": {\n\t\t\t\tconst len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tconst angle = g_utils.degreesToRadian( 90 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// E - Up and Right\n\t\t\tcase \"E\": {\n\t\t\t\tlet len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tlen = Math.sqrt( len * len + len * len );\n\t\t\t\tconst angle = g_utils.degreesToRadian( 315 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// F - Down and Right\n\t\t\tcase \"F\": {\n\t\t\t\tlet len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tlen = Math.sqrt( len * len + len * len );\n\t\t\t\tconst angle = g_utils.degreesToRadian( 45 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// G - Down and Left\n\t\t\tcase \"G\": {\n\t\t\t\tlet len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tlen = Math.sqrt( len * len + len * len );\n\t\t\t\tconst angle = g_utils.degreesToRadian( 135 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// H - Up and Left\n\t\t\tcase \"H\": {\n\t\t\t\tlet len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tlen = Math.sqrt( len * len + len * len );\n\t\t\t\tconst angle = g_utils.degreesToRadian( 225 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// L - Left\n\t\t\tcase \"L\": {\n\t\t\t\tconst len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tconst angle = g_utils.degreesToRadian( 180 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// R - Right\n\t\t\tcase \"R\": {\n\t\t\t\tconst len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tconst angle = g_utils.degreesToRadian( 0 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// U - Up\n\t\t\tcase \"U\": {\n\t\t\t\tconst len = g_utils.getInt( drawArgs[ 1 ], 1 ) * scale;\n\t\t\t\tconst angle = g_utils.degreesToRadian( 270 ) + screenData.angle;\n\t\t\t\tscreenData.cursor.x += Math.round( Math.cos( angle ) * len );\n\t\t\t\tscreenData.cursor.y += Math.round( Math.sin( angle ) * len );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// P - Paint Exact Match\n\t\t\tcase \"P\": {\n\t\t\t\tconst colorNum = g_utils.getInt( drawArgs[ 1 ], 0 );\n\t\t\t\tconst boundryNumber = g_utils.getInt( drawArgs[ 3 ], null );\n\t\t\t\tscreenData.api.paint(\n\t\t\t\t\tscreenData.cursor.x, screenData.cursor.y, colorNum, 0, boundryNumber\n\t\t\t\t);\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// S - Scale\n\t\t\t/*\n\t\t\t\tSet scale factor. n may range from 1 to 255. n is divided by 4 to derive the scale \n\t\t\t\tfactor. The scale factor is multiplied by the distances given with U, D, L, R, E, \n\t\t\t\tF, G, H, or relative M commands to get the actual distance traveled. The default \n\t\t\t\tfor S is 4.\n\t\t\t*/\n\t\t\tcase \"S\": {\n\t\t\t\tconst scaleNum = g_utils.getInt( drawArgs[ 1 ], 4 );\n\t\t\t\tscale = scaleNum / 4;\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Z - Arc Line\n\t\t\tcase \"Z\":\n\t\t\t\tarcRadius = g_utils.getInt( drawArgs[ 1 ], 1 );\n\t\t\t\tarcAngle1 = g_utils.getInt( drawArgs[ 3 ], 1 );\n\t\t\t\tarcAngle2 = g_utils.getInt( drawArgs[ 5 ], 1 );\n\t\t\t\tisArc = true;\n\t\t\t\tbreak;\n\n\t\t\t// A - Angle\n\t\t\t/*\n\t\t\t\tSet angle n. n may range from 0 to 3, where 0 is 0\u00B0, 1 is 90\u00B0, 2 is 180\u00B0, and 3 is\n\t\t\t\t270\u00B0. Figures rotated 90\u00B0 or 270\u00B0 are scaled so that they will appear the same size\n\t\t\t\tas with 0\u00B0 or 180\u00B0 on a monitor screen with the standard aspect ratio of 4:3.\n\t\t\t*/\n\t\t\tcase \"A\":\n\t\t\t\tscreenData.angle = g_utils.degreesToRadian(\n\t\t\t\t\tg_utils.clamp( g_utils.getInt( drawArgs[ 1 ], 0 ), 0, 3 ) * 90\n\t\t\t\t);\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\n\t\t\t// TA - T - Turn Angle\n\t\t\tcase \"T\":\n\t\t\t\tscreenData.angle = g_utils.degreesToRadian(\n\t\t\t\t\tg_utils.clamp( g_utils.getInt( drawArgs[ 1 ], 0 ), -360, 360 )\n\t\t\t\t);\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\n\t\t\t// M - Move\n\t\t\tcase \"M\":\n\t\t\t\tscreenData.cursor.x = g_utils.getInt( drawArgs[ 1 ], 1 );\n\t\t\t\tscreenData.cursor.y = g_utils.getInt( drawArgs[ 3 ], 1 );\n\t\t\t\tisBlind = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tisBlind = true;\n\t\t}\n\n\t\tif( !isBlind ) {\n\t\t\tif( isArc ) {\n\t\t\t\tscreenData.api.arc(\n\t\t\t\t\tscreenData.cursor.x,\n\t\t\t\t\tscreenData.cursor.y,\n\t\t\t\t\tarcRadius,\n\t\t\t\t\tarcAngle1,\n\t\t\t\t\tarcAngle2\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tscreenData.api.line(\n\t\t\t\t\tlastCursor.x,\n\t\t\t\t\tlastCursor.y,\n\t\t\t\t\tscreenData.cursor.x,\n\t\t\t\t\tscreenData.cursor.y\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tisBlind = false;\n\t\tisArc = false;\n\n\t\tif( isReturn ) {\n\t\t\tisReturn = false;\n\t\t\tscreenData.cursor.x = lastCursor.x;\n\t\t\tscreenData.cursor.y = lastCursor.y;\n\t\t\tscreenData.angle = lastCursor.angle;\n\t\t}\n\n\t\tif( drawArgs[ 0 ] === \"N\" ) {\n\t\t\tisReturn = true;\n\t\t} else {\n\t\t\tlastCursor = {\n\t\t\t\t\"x\": screenData.cursor.x,\n\t\t\t\t\"y\": screenData.cursor.y,\n\t\t\t\t\"angle\": screenData.angle\n\t\t\t};\n\t\t}\n\n\t\tif( drawArgs[ 0 ] === \"B\" ) {\n\t\t\tisBlind = true;\n\t\t}\n\t}\n}\n\n", "/**\n * Pi.js - Font Module\n * \n * Font loading, management, and character data for text rendering.\n * Supports bitmap fonts from images only (no base32-encoded data).\n * \n * @module text/fonts\n */\n\n// TODO-LATER: Add remove font command that removes the font and deletes any WebGL textures\n\n\"use strict\";\n\nimport * as g_utils from \"../core/utils.js\";\nimport * as g_commands from \"../core/commands.js\";\nimport * as g_screenManager from \"../core/screen-manager.js\";\nimport * as g_renderer from \"../renderer/renderer.js\";\nimport * as g_print from \"./print.js\";\n\nimport g_fnt6x6 from \"./fonts/font-6x6.webp\";\nimport * as g_fnt6x8 from \"./fonts/font-6x8.js\";\nimport g_fnt8x8 from \"./fonts/font-8x8.webp\";\nimport g_fnt8x14 from \"./fonts/font-8x14.webp\";\nimport g_fnt8x16 from \"./fonts/font-8x16.webp\";\n\nconst m_fontMap = new Map();\nlet m_defaultFontId = null;\nlet m_nextFontId = 0;\n\n\n/***************************************************************************************************\n * Module Initialization\n ***************************************************************************************************/\n\n\n/**\n * Initialize font module\n * \n * @param {Object} api - The main Pi.js API object\n * @returns {void}\n */\nexport function init( api ) {\n\tg_screenManager.addScreenDataItem( \"font\", null );\n\t\n\tregisterCommands( api );\n\tloadDefaultFonts();\n\n\t// Set the font when a screen is initialized\n\tg_screenManager.addScreenInitFunction(\n\t\t( screenData ) => setFont( screenData, { \"fontId\": m_defaultFontId } )\n\t);\n}\n\n/**\n * Register font commands\n * \n * @param {Object} api - The main Pi.js API object\n * @returns {void}\n */\nfunction registerCommands( api ) {\n\n\t// Register non-screen commands\n\tg_commands.addCommand(\n\t\t\"loadFont\", loadFont, false,\n\t\t[ \"src\", \"width\", \"height\", \"margin\", \"charset\" ]\n\t);\n\tg_commands.addCommand( \"setDefaultFont\", setDefaultFont, false, [ \"fontId\" ] );\n\tg_commands.addCommand( \"getAvailableFonts\", getAvailableFonts, false, [] );\n\n\t// Register screen commands\n\tg_commands.addCommand( \"setChar\", setChar, true, [ \"charCode\", \"data\" ] );\n\tg_commands.addCommand( \"setFont\", setFont, true, [ \"fontId\" ] );\n}\n\n\n\n// Load the default fonts\nfunction loadDefaultFonts() {\n\n\t// 6x6 font\n\tloadFont( {\n\t\t\"src\": g_fnt6x6.data,\n\t\t\"width\": 6,\n\t\t\"height\": 6,\n\t\t\"margin\": 0,\n\t\t\"charset\": null\n\t} );\n\tg_fnt6x6.data = \"\";\n\n\t// 6x8 font - default font\n\tm_defaultFontId = loadFont( {\n\t\t\"src\": g_fnt6x8.getFontImage(),\n\t\t\"width\": 6,\n\t\t\"height\": 8,\n\t\t\"margin\": 0,\n\t\t\"charset\": null\n\t} );\n\n\t// 8x8 font\n\tloadFont( {\n\t\t\"src\": g_fnt8x8.data,\n\t\t\"width\": 8,\n\t\t\"height\": 8,\n\t\t\"margin\": 0,\n\t\t\"charset\": null\n\t} );\n\tg_fnt8x8.data = \"\";\n\n\t// 8x14 font\n\tloadFont( {\n\t\t\"src\": g_fnt8x14.data,\n\t\t\"width\": 8,\n\t\t\"height\": 14,\n\t\t\"margin\": 0,\n\t\t\"charset\": null\n\t} );\n\tg_fnt8x14.data = \"\";\n\n\t// 8x16 font\n\tloadFont( {\n\t\t\"src\": g_fnt8x16.data,\n\t\t\"width\": 8,\n\t\t\"height\": 16,\n\t\t\"margin\": 0,\n\t\t\"charset\": null\n\t} );\n\tg_fnt8x16.data = \"\";\n}\n\n\n/**************************************************************************************************\n * Load Font Command\n **************************************************************************************************/\n\n\n/**\n * Load font from image source\n * \n * @param {Object} options - Load options\n * @param {string|HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} options.src - Font image\n * @param {number} options.width - Character width in pixels\n * @param {number} options.height - Character height in pixels\n * @param {number} options.margin - Individual character cell width in pixels\n * @param {Array<number>|string} [options.charset] - Character set array or string\n * @returns {number} Font ID\n */\nfunction loadFont( options ) {\n\tconst fontSrc = options.src;\n\tconst width = g_utils.getInt( options.width, null );\n\tconst height = g_utils.getInt( options.height, null );\n\tconst margin = g_utils.getInt( options.margin, 0 );\n\tconst cellWidth = width + margin * 2;\n\tconst cellHeight = height + margin * 2;\n\tlet charset = options.charset;\n\n\tif( width === null || height === null ) {\n\t\tconst error = new TypeError( \"loadFont: width and height must be integers.\" );\n\t\terror.code = \"INVALID_DIMENSIONS\";\n\t\tthrow error;\n\t}\n\n\t// Default charset to 0 to 255\n\tif( !charset ) {\n\t\tcharset = [];\n\t\tfor( let i = 0; i < 256; i += 1 ) {\n\t\t\tcharset.push( i );\n\t\t}\n\t}\n\n\tif( !( Array.isArray( charset ) || typeof charset === \"string\" ) ) {\n\t\tconst error = new TypeError( \"loadFont: charset must be an array or a string.\" );\n\t\terror.code = \"INVALID_CHARSET\";\n\t\tthrow error;\n\t}\n\n\t// Convert charset to array of integers (character codes)\n\tif( typeof charset === \"string\" ) {\n\t\tconst temp = [];\n\t\tfor( let i = 0; i < charset.length; i += 1 ) {\n\t\t\ttemp.push( charset.charCodeAt( i ) );\n\t\t}\n\t\tcharset = temp;\n\t}\n\n\t// Build chars lookup map\n\tconst chars = {};\n\tfor( let i = 0; i < charset.length; i += 1 ) {\n\t\tchars[ charset[ i ] ] = i;\n\t}\n\n\t// Create font object\n\tconst font = {\n\t\t\"id\": m_nextFontId,\n\t\t\"width\": width,\n\t\t\"height\": height,\n\t\t\"margin\": margin,\n\t\t\"cellWidth\": cellWidth,\n\t\t\"cellHeight\": cellHeight,\n\t\t\"chars\": chars,\n\t\t\"charset\": charset,\n\t\t\"image\": null,\n\t\t\"atlasWidth\": null,\n\t\t\"atlasHeight\": null\n\t};\n\n\t// Add to fonts array\n\tm_fontMap.set( font.id, font );\n\tm_nextFontId += 1;\n\n\t// Load from image source\n\tloadFontFromImage( fontSrc, font );\n\n\treturn font.id;\n}\n\n/**\n * Load font from image source\n * \n * @param {string|HTMLImageElement} fontSrc - Font image source\n * @param {Object} font - Font object to populate\n * @returns {void}\n */\nfunction loadFontFromImage( fontSrc, font ) {\n\tlet img;\n\n\tif( typeof fontSrc === \"string\" ) {\n\n\t\t// Create a new image\n\t\timg = new Image();\n\n\t\t// Increment wait count\n\t\tg_commands.wait();\n\n\t\timg.onload = function() {\n\t\t\tfont.image = img;\n\t\t\tfont.atlasWidth = img.width;\n\t\t\tfont.atlasHeight = img.height;\n\t\t\tg_commands.done();\n\t\t};\n\n\t\timg.onerror = function( err ) {\n\t\t\tconsole.error( \"loadFont: Unable to load image for font.\" );\n\t\t\tg_commands.done();\n\t\t};\n\n\t\t// Set source after handlers\n\t\timg.src = fontSrc;\n\t} else if(\n\t\tfontSrc instanceof HTMLImageElement || fontSrc instanceof HTMLCanvasElement ||\n\t\t( typeof OffscreenCanvas !== \"undefined\" && fontSrc instanceof OffscreenCanvas )\n\t) {\n\n\t\t// Use image element directly\n\t\tfont.image = fontSrc;\n\t\tfont.atlasWidth = fontSrc.width;\n\t\tfont.atlasHeight = fontSrc.height;\n\t} else {\n\t\tconst error = new TypeError( \"loadFont: fontSrc must be a string or Image element.\" );\n\t\terror.code = \"INVALID_FONT_SRC\";\n\t\tthrow error;\n\t}\n}\n\n\n/**************************************************************************************************\n * Set Defaault Font Commands\n **************************************************************************************************/\n\n\n/**\n * Set default font\n * \n * @param {Object} options - Options\n * @param {number} options.fontId - Font ID\n * @returns {void}\n */\nfunction setDefaultFont( options ) {\n\tconst fontId = g_utils.getInt( options.fontId, null );\n\n\tif( fontId === null || !m_fontMap.has( fontId ) ) {\n\t\tconst error = new RangeError( \"setDefaultFont: invalid fontId\" );\n\t\terror.code = \"INVALID_FONT_ID\";\n\t\tthrow error;\n\t}\n\n\tm_defaultFontId = fontId;\n}\n\n/**\n * Set font for screen\n * \n * @param {Object} screenData - Screen data object\n * @param {Object} options - Options\n * @param {number} options.fontId - Font ID or CSS font string\n * @returns {void}\n */\nexport function setFont( screenData, options ) {\n\tconst fontId = g_utils.getInt( options.fontId, null );\n\n\t// TODO-LATER: setFont should also accept a font object returned by getAvailableFonts\n\t\n\tif( fontId === null || !m_fontMap.has( fontId ) ) {\n\t\tconst error = new RangeError(\n\t\t\t\"setFont: Parameter fontId must be an integer and an index in the available fonts.\"\n\t\t);\n\t\terror.code = \"INVALID_FONT_ID\";\n\t\tthrow error;\n\t}\n\n\tconst font = m_fontMap.get( fontId );\n\n\t// Get or create texture for font image if it's loaded\n\tif( font.image ) {\n\t\tg_renderer.getWebGL2Texture( screenData, font.image );\n\t}\n\n\t// Set the screenData font\n\tscreenData.font = font;\n\n\t// Update print cursor dimensions\n\tg_print.updatePrintCursorDimensions( screenData );\n}\n\n\n/**************************************************************************************************\n * Get Available Font Command\n **************************************************************************************************/\n\n\n/**\n * Get available fonts\n * \n * @returns {Array<Object>} Array of font info objects\n */\nfunction getAvailableFonts() {\n\tconst fonts = [];\n\tfor( const [ fontId, font ] of m_fontMap ) {\n\t\tfonts.push( {\n\t\t\t\"id\": font.id,\n\t\t\t\"width\": font.width,\n\t\t\t\"height\": font.height\n\t\t} );\n\t}\n\treturn fonts;\n}\n\n\n/**************************************************************************************************\n * Get Available Font Command\n **************************************************************************************************/\n\n\n/**\n * Set custom character bitmap by drawing into a temporary Canvas2D copy of the\n * font atlas, then updating the existing WebGL texture.\n * \n * @param {Object} screenData - Screen data object\n * @param {Object} options - Options\n * @param {number|string} options.charCode - Character code or single-character string\n * @param {Array<Array<number>>|string} options.data - Character bitmap (2D array or hex string)\n * @returns {void}\n */\nfunction setChar( screenData, options ) {\n\tlet charCode = options.charCode;\n\tlet data = options.data;\n\n\tconst font = screenData.font;\n\tif( !font || !font.image ) {\n\t\tconst error = new Error( \"setChar: No font image loaded on this screen.\" );\n\t\terror.code = \"NO_FONT_IMAGE\";\n\t\tthrow error;\n\t}\n\n\t// Convert string to char code\n\tif( typeof charCode === \"string\" ) {\n\t\tcharCode = charCode.charCodeAt( 0 );\n\t} else {\n\t\tcharCode = g_utils.getInt( charCode, null );\n\t\tif( charCode === null ) {\n\t\t\tconst error = new TypeError( \"setChar: charCode must be an integer or a string\" );\n\t\t\terror.code = \"INVALID_CHAR_CODE\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Normalize data to 2D array\n\tif( !Array.isArray( data ) ) {\n\t\tif( typeof data === \"string\" ) {\n\t\t\tdata = g_utils.hexToData( data, font.width, font.height );\n\t\t} else {\n\t\t\tconst error = new TypeError( \"setChar: data must be a 2D array or an encoded string\" );\n\t\t\terror.code = \"INVALID_DATA\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Validate dimensions\n\tif( data.length !== font.height ) {\n\t\tconst error = new RangeError(\n\t\t\t`setChar: data height (${data.length}) must match font height (${font.height})`\n\t\t);\n\t\terror.code = \"INVALID_DATA_HEIGHT\";\n\t\tthrow error;\n\t}\n\n\tfor( let i = 0; i < data.length; i++ ) {\n\t\tif( !Array.isArray( data[ i ] ) || data[ i ].length !== font.width ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t`setChar: data width at row ${i} must match font width (${font.width})`\n\t\t\t);\n\t\t\terror.code = \"INVALID_DATA_WIDTH\";\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Locate character cell in atlas\n\tconst charIndex = font.chars[ charCode ];\n\tif( charIndex === undefined ) {\n\t\tconst error = new RangeError( \"setChar: character not in font character set\" );\n\t\terror.code = \"CHAR_NOT_IN_FONT\";\n\t\tthrow error;\n\t}\n\n\tconst columns = Math.floor( font.atlasWidth / font.cellWidth );\n\tconst cellX = ( charIndex % columns ) * font.cellWidth;\n\tconst cellY = Math.floor( charIndex / columns ) * font.cellHeight;\n\n\t// Inner glyph bounds\n\tconst sx = cellX + font.margin;\n\tconst sy = cellY + font.margin;\n\tconst sw = font.width;\n\tconst sh = font.height;\n\n\t// Create a Uint8ClampedArray for the glyph sub-image pixel data\n\tconst buf = new Uint8ClampedArray( sw * sh * 4 );\n\tfor( let y = 0; y < sh; y += 1 ) {\n\t\tfor( let x = 0; x < sw; x += 1 ) {\n\t\t\tconst on = data[ y ][ x ] ? 1 : 0;\n\t\t\tif( on ) {\n\t\t\t\tconst i = ( y * sw + x ) * 4;\n\t\t\t\tbuf[ i + 0 ] = 255;\n\t\t\t\tbuf[ i + 1 ] = 255;\n\t\t\t\tbuf[ i + 2 ] = 255;\n\t\t\t\tbuf[ i + 3 ] = 255;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Update only the glyph region in the GPU texture\n\tg_renderer.updateWebGL2TextureSubImage( screenData, font.image, buf, sw, sh, sx, sy );\n}\n", "/**\r\n * Pi.js - Print Module\r\n * \r\n * Text printing, cursor positioning, and word wrapping for bitmap fonts.\r\n * \r\n * @module text/print\r\n */\r\n\r\n// Maybe move setFont to print.js from fonts.js?\r\n\r\n\"use strict\";\r\n\r\nimport * as g_utils from \"../core/utils.js\";\r\nimport * as g_commands from \"../core/commands.js\";\r\nimport * as g_screenManager from \"../core/screen-manager.js\";\r\nimport * as g_renderer from \"../renderer/renderer.js\";\r\nimport * as g_textures from \"../renderer/textures.js\";\r\nimport * as g_sprites from \"../renderer/draw/sprites.js\";\r\n\r\n\r\n/***************************************************************************************************\r\n * Module Initialization\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Initialize print module\r\n * \r\n * @param {Object} api - The main Pi.js API object\r\n * @returns {void}\r\n */\r\nexport function init( api ) {\r\n\tg_screenManager.addScreenDataItem( \"printCursor\", {\r\n\t\t\"x\": 0,\r\n\t\t\"y\": 0,\r\n\t\t\"cols\": 0,\r\n\t\t\"rows\": 0,\r\n\t\t\"scaleWidth\": 1,\r\n\t\t\"scaleHeight\": 1,\r\n\t\t\"width\": 0,\r\n\t\t\"height\": 0,\r\n\t\t\"breakWord\": true,\r\n\t\t\"padX\": 0,\r\n\t\t\"padY\": 0\r\n\t} );\r\n\r\n\tregisterCommands();\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Command Registration\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Register print commands\r\n * \r\n * @returns {void}\r\n */\r\nfunction registerCommands() {\r\n\r\n\t// Register screen commands\r\n\tg_commands.addCommand( \"print\", print, true, [ \"msg\", \"isInline\", \"isCentered\" ] );\r\n\tg_commands.addCommand( \"setPos\", setPos, true, [ \"col\", \"row\" ] );\r\n\tg_commands.addCommand( \"setPosPx\", setPosPx, true, [ \"x\", \"y\" ] );\r\n\tg_commands.addCommand( \"getPos\", getPos, true, [] );\r\n\tg_commands.addCommand( \"getPosPx\", getPosPx, true, [] );\r\n\tg_commands.addCommand( \"getCols\", getCols, true, [] );\r\n\tg_commands.addCommand( \"getRows\", getRows, true, [] );\r\n\tg_commands.addCommand( \"setWordBreak\", setWordBreak, true, [ \"isEnabled\" ] );\r\n\tg_commands.addCommand( \"setPrintSize\", setPrintSize, true, [ \"scaleWidth\", \"scaleHeight\", \"padX\", \"padY\" ] );\r\n\tg_commands.addCommand( \"calcWidth\", calcWidth, true, [ \"msg\" ] );\r\n}\r\n\r\n\r\n/**************************************************************************************************\r\n * External API Commands\r\n **************************************************************************************************/\r\n\r\n\r\n/**\r\n * Print text to screen\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Print options\r\n * @param {string} [options.msg] - Message to print\r\n * @param {boolean} [options.isInline] - If true, don't advance to next line\r\n * @param {boolean} [options.isCentered] - If true, center the text\r\n * @returns {void}\r\n */\r\nfunction print( screenData, options ) {\r\n\tlet msg = options.msg;\r\n\tconst isInline = !!options.isInline;\r\n\tconst isCentered = !!options.isCentered;\r\n\r\n\t// Check if font is set\r\n\tif( !screenData.font ) {\r\n\t\tconst error = new Error( \"print: No font set. Call setFont() first.\" );\r\n\t\terror.code = \"NO_FONT_SET\";\r\n\t\tthrow error;\r\n\t}\r\n\r\n\t// Bail if not possible to print an entire line on screen\r\n\tif( screenData.printCursor.height > screenData.height ) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif( msg === undefined || msg === null ) {\r\n\t\tmsg = \"\";\r\n\t} else if( typeof msg !== \"string\" ) {\r\n\t\tmsg = \"\" + msg;\r\n\t}\r\n\r\n\t// Replace tabs with spaces\r\n\tmsg = msg.replace( /\\t/g, \"    \" );\r\n\r\n\t// Split messages by newlines\r\n\tconst parts = msg.split( /\\n/ );\r\n\tfor( let i = 0; i < parts.length; i++ ) {\r\n\t\tstartPrint( screenData, parts[ i ], isInline, isCentered );\r\n\t}\r\n}\r\n\r\n/**\r\n * Set cursor position by row/column\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Position options\r\n * @param {number} [options.col] - Column position\r\n * @param {number} [options.row] - Row position\r\n * @returns {void}\r\n */\r\nfunction setPos( screenData, options ) {\r\n\tconst col = options.col;\r\n\tconst row = options.row;\r\n\r\n\tconst font = screenData.font;\r\n\tif( !font ) {\r\n\t\tconst error = new Error( \"setPos: No font set. Call setFont() first.\" );\r\n\t\terror.code = \"NO_FONT_SET\";\r\n\t\tthrow error;\r\n\t}\r\n\tconst printCursor = screenData.printCursor;\r\n\r\n\t// Set the x value\r\n\tif( col !== null ) {\r\n\t\tif( isNaN( col ) ) {\r\n\t\t\tconst error = new TypeError( \"setPos: parameter col must be a number\" );\r\n\t\t\terror.code = \"INVALID_COL\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\t\tlet x = Math.floor( col * printCursor.width );\r\n\t\tif( x > screenData.width ) {\r\n\t\t\tx = screenData.width - printCursor.height;\r\n\t\t}\r\n\t\tscreenData.printCursor.x = x;\r\n\t}\r\n\r\n\t// Set the y value\r\n\tif( row !== null ) {\r\n\t\tif( isNaN( row ) ) {\r\n\t\t\tconst error = new TypeError( \"setPos: parameter row must be a number\" );\r\n\t\t\terror.code = \"INVALID_ROW\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\t\tlet y = Math.floor( row * screenData.printCursor.height );\r\n\t\tif( y > screenData.height ) {\r\n\t\t\ty = screenData.height - screenData.printCursor.height;\r\n\t\t}\r\n\t\tscreenData.printCursor.y = y;\r\n\t}\r\n}\r\n\r\n/**\r\n * Set cursor position by pixels\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Position options\r\n * @param {number} [options.x] - X position in pixels\r\n * @param {number} [options.y] - Y position in pixels\r\n * @returns {void}\r\n */\r\nfunction setPosPx( screenData, options ) {\r\n\tconst x = options.x;\r\n\tconst y = options.y;\r\n\r\n\tif( x != null ) {\r\n\t\tif( isNaN( x ) ) {\r\n\t\t\tconst error = new TypeError( \"setPosPx: parameter x must be a number\" );\r\n\t\t\terror.code = \"INVALID_X\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\t\tscreenData.printCursor.x = Math.round( x );\r\n\t}\r\n\r\n\tif( y != null ) {\r\n\t\tif( isNaN( y ) ) {\r\n\t\t\tconst error = new TypeError( \"setPosPx: parameter y must be a number\" );\r\n\t\t\terror.code = \"INVALID_Y\";\r\n\t\t\tthrow error;\r\n\t\t}\r\n\t\tscreenData.printCursor.y = Math.round( y );\r\n\t}\r\n}\r\n\r\n/**\r\n * Get cursor position as row/column\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {Object} Object with col and row properties\r\n */\r\nfunction getPos( screenData ) {\r\n\tconst font = screenData.font;\r\n\tif( !font ) {\r\n\t\treturn { \"col\": 0, \"row\": 0 };\r\n\t}\r\n\tconst printCursor = screenData.printCursor;\r\n\r\n\treturn {\r\n\t\t\"col\": Math.floor( printCursor.x / printCursor.width ),\r\n\t\t\"row\": Math.floor( printCursor.y / printCursor.height )\r\n\t};\r\n}\r\n\r\n/**\r\n * Get cursor position in pixels\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {Object} Object with x and y properties\r\n */\r\nfunction getPosPx( screenData ) {\r\n\treturn {\r\n\t\t\"x\": screenData.printCursor.x,\r\n\t\t\"y\": screenData.printCursor.y\r\n\t};\r\n}\r\n\r\n/**\r\n * Get number of columns\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {number} Number of columns\r\n */\r\nfunction getCols( screenData ) {\r\n\treturn screenData.printCursor.cols;\r\n}\r\n\r\n/**\r\n * Get number of rows\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {number} Number of rows\r\n */\r\nfunction getRows( screenData ) {\r\n\treturn screenData.printCursor.rows;\r\n}\r\n\r\n/**\r\n * Enable/disable word breaking\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Options\r\n * @param {boolean} options.isEnabled - Enable word breaking\r\n * @returns {void}\r\n */\r\nfunction setWordBreak( screenData, options ) {\r\n\tscreenData.printCursor.breakWord = !!options.isEnabled;\r\n}\r\n\r\n/**\r\n * Set font size for bitmap fonts\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Options\r\n * @param {number} options.scaleWidth - Font scale width\r\n * @param {number} options.scaleHeight - Font scale height\r\n * @param {number} [options.padX] - Horizontal padding between characters\r\n * @param {number} [options.padY] - Vertical padding between lines\r\n * @returns {void}\r\n */\r\nfunction setPrintSize( screenData, options ) {\r\n\tconst scaleWidth = g_utils.getFloat( options.scaleWidth, null );\r\n\tconst scaleHeight = g_utils.getFloat( options.scaleHeight, null );\r\n\tconst padX = g_utils.getInt( options.padX, null );\r\n\tconst padY = g_utils.getInt( options.padY, null );\r\n\r\n\tif(\r\n\t\t( scaleWidth !== null && scaleWidth <= 0 ) || ( scaleHeight !== null && scaleHeight <= 0 )\r\n\t) {\r\n\t\tconst error = new RangeError(\r\n\t\t\t\"setPrintSize: Parameters scaleWidth and scaleHeight must be a number greater than 0.\"\r\n\t\t);\r\n\t\terror.code = \"INVALID_SIZE\";\r\n\t\tthrow error;\r\n\t}\r\n\r\n\tif( scaleWidth !== null ) {\r\n\t\tscreenData.printCursor.scaleWidth = scaleWidth;\r\n\t}\r\n\r\n\tif( scaleHeight !== null ) {\r\n\t\tscreenData.printCursor.scaleHeight = scaleHeight;\r\n\t}\r\n\r\n\t// Update padding if provided\r\n\tif( padX !== null ) {\r\n\t\tscreenData.printCursor.padX = padX;\r\n\t}\r\n\tif( padY !== null ) {\r\n\t\tscreenData.printCursor.padY = padY;\r\n\t}\r\n\r\n\t// Update print cursor dimensions\r\n\tupdatePrintCursorDimensions( screenData );\r\n}\r\n\r\n/**\r\n * Calculate text width\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {Object} options - Options\r\n * @param {string} [options.msg] - Message to calculate width for\r\n * @returns {number} Text width in pixels\r\n */\r\nfunction calcWidth( screenData, options ) {\r\n\tconst msg = options.msg || \"\";\r\n\tconst printCursor = screenData.printCursor;\r\n\t\r\n\treturn printCursor.width * msg.length;\r\n}\r\n\r\n\r\n/***************************************************************************************************\r\n * Internal Functions\r\n ***************************************************************************************************/\r\n\r\n\r\n/**\r\n * Start printing text\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {string} msg - Message to print\r\n * @param {boolean} isInline - If true, don't advance to next line\r\n * @param {boolean} isCentered - If true, center the text\r\n * @returns {void}\r\n */\r\nfunction startPrint( screenData, msg, isInline, isCentered ) {\r\n\tconst printCursor = screenData.printCursor;\r\n\tconst font = screenData.font;\r\n\r\n\t// Calculate text width\r\n\tconst width = calcWidth( screenData, { \"msg\": msg } );\r\n\r\n\t// Handle centering\r\n\tif( isCentered ) {\r\n\t\tprintCursor.x = Math.floor( ( printCursor.cols - msg.length ) / 2 ) * printCursor.width;\r\n\t}\r\n\r\n\t// Handle text wrapping if text is too wide\r\n\tif(\r\n\t\t!isInline &&\r\n\t\t!isCentered &&\r\n\t\twidth + printCursor.x > screenData.width &&\r\n\t\tmsg.length > 1\r\n\t) {\r\n\t\tconst overlap = ( width + printCursor.x ) - screenData.width;\r\n\t\tconst onScreen = width - overlap;\r\n\t\tconst onScreenPct = onScreen / width;\r\n\t\tlet msgSplit = Math.floor( msg.length * onScreenPct );\r\n\t\tlet msg1 = msg.substring( 0, msgSplit );\r\n\t\tlet msg2 = msg.substring( msgSplit, msg.length );\r\n\r\n\t\t// Word breaking\r\n\t\tif( printCursor.breakWord ) {\r\n\t\t\tconst index = msg1.lastIndexOf( \" \" );\r\n\t\t\tif( index > -1 ) {\r\n\t\t\t\tmsg2 = msg1.substring( index ).trim() + msg2;\r\n\t\t\t\tmsg1 = msg1.substring( 0, index );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstartPrint( screenData, msg1, isInline, isCentered );\r\n\t\tstartPrint( screenData, msg2, isInline, isCentered );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Handle auto-scroll if text is too tall\r\n\tif( printCursor.y + printCursor.height > screenData.height ) {\r\n\r\n\t\t// Shift image up by font height\r\n\t\tg_renderer.shiftImageUp( screenData, printCursor.height );\r\n\r\n\t\t// Move cursor up\r\n\t\tprintCursor.y -= printCursor.height;\r\n\t}\r\n\r\n\t// Print the text using bitmap font\r\n\tbitmapPrint( screenData, msg, printCursor.x, printCursor.y );\r\n\r\n\t// Advance cursor position\r\n\tif( !isInline ) {\r\n\t\tprintCursor.y += printCursor.height;\r\n\t\tprintCursor.x = 0;\r\n\t} else {\r\n\t\tprintCursor.x += printCursor.width * msg.length;\r\n\t\tif( printCursor.x > screenData.width - printCursor.width ) {\r\n\t\t\tprintCursor.x = 0;\r\n\t\t\tprintCursor.y += printCursor.height;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * Print using bitmap font image\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @param {string} msg - Message to print\r\n * @param {number} x - X position\r\n * @param {number} y - Y position\r\n * @returns {void}\r\n */\r\nfunction bitmapPrint( screenData, msg, x, y ) {\r\n\tconst font = screenData.font;\r\n\r\n\tif( !font.image ) {\r\n\t\tconsole.warn( \"bitmapPrint: Font image not loaded yet.\" );\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Get or create texture for font image\r\n\tg_textures.getWebGL2Texture( screenData, font.image );\r\n\r\n\tconst atlasWidth = font.atlasWidth;\r\n\tconst fontWidth = font.width;\r\n\tconst fontHeight = font.height;\r\n\tconst printWidth = screenData.printCursor.width;\r\n\tconst scaleX = screenData.printCursor.scaleWidth;\r\n\tconst scaleY = screenData.printCursor.scaleHeight;\r\n\tconst margin = font.margin;\r\n\tconst cellWidth = font.cellWidth;\r\n\tconst cellHeight = font.cellHeight;\r\n\tconst columns = Math.floor( atlasWidth / cellWidth );\r\n\r\n\t// Loop through each character in the message\r\n\tfor( let i = 0; i < msg.length; i++ ) {\r\n\r\n\t\t// Get the character index for the character data\r\n\t\tconst charIndex = font.chars[ msg.charCodeAt( i ) ];\r\n\r\n\t\tif( charIndex !== undefined ) {\r\n\r\n\t\t\t// Get the source x & y coordinates in the atlas\r\n\t\t\tconst sx = ( charIndex % columns ) * cellWidth + margin;\r\n\t\t\tconst sy = Math.floor( charIndex / columns ) * cellHeight + margin;\r\n\r\n\t\t\t// Get the destination x coordinate\r\n\t\t\tconst dx = x + printWidth * i;\r\n\r\n\t\t\t// Draw the character using drawSprite\r\n\t\t\tconst color = screenData.color;\r\n\t\t\tg_sprites.drawSprite(\r\n\t\t\t\tscreenData, font.image,\r\n\t\t\t\tsx, sy, fontWidth, fontHeight,\r\n\t\t\t\tdx, y, fontWidth, fontHeight,\r\n\t\t\t\tcolor, 0, 0, scaleX, scaleY, 0\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t// Mark screen as dirty\r\n\tg_renderer.setImageDirty( screenData );\r\n}\r\n\r\n/**\r\n * Update print cursor rows and columns based on font and size\r\n * \r\n * @param {Object} screenData - Screen data object\r\n * @returns {void}\r\n */\r\nexport function updatePrintCursorDimensions( screenData ) {\r\n\tconst font = screenData.font;\r\n\tif( !font ) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst printCursor = screenData.printCursor;\r\n\r\n\tprintCursor.width = printCursor.scaleWidth * ( font.width + printCursor.padX );\r\n\tprintCursor.height = printCursor.scaleHeight * ( font.height + printCursor.padY );\r\n\tprintCursor.cols = Math.floor( screenData.width / printCursor.width );\r\n\tprintCursor.rows = Math.floor( screenData.height / printCursor.height );\r\n}\r\n", "export default { \"data\": \"data:image/webp;base64,UklGRs4EAABXRUJQVlA4WAoAAAAYAAAAfwEAFwAAVlA4TNIDAAAvf8EFEA8w//M///Mf8KA+///atl3fR/IvyS+ZrpU99are+RzJUZnkMltW7CVl+fpsWO6j3MnDwEB1DCoFyoxjZgbTmJnR3rxHZSbfwXqL6L/Ctm0bZnT3EOAHLgk/TKsYd1xe4qlTaR2Qugw97NaclAWQcmd9O9/v4LKgmmkpFzwZZiKWWtLcuqPhbfXt7ihvFa5Av7D+QRBFBpZO8Aa2StrmnBTr1YDz73w+XcY0K3/lwOfGIFads3lX6lgHWMOjg+RMq04dFTU355dxdWAhVxybKSNoSRXbr3TZpVKm4rx4iCE5CRCH6docxefKIdYLK2d6io6JCKYqC0a4OJHu2NVzugswenKgXoZa1F309WWdXFaimoQmeePnjB/TUs9Wrkw6V3JHeRyfCBbVQXCN4AG482ZP8YQruSU24nZ3funbyvrD//ocCXAaeAsEPL0WSdTl7Ur9Zom62HCsbf2DitNWHhdqnLVBxm42+eZn3VGe/q1yD0dsYm/NXS8+aO4u0MPFDz2sL3Zs/ZsFtYxmeI4AufqdhVYFhj1+rhAasld53CZDwNnR4eXW5/KGY49viA0L2MGI4OVFAqulYWtzuxJV7VFzuRtMO3iBJnmR2HsLZs/wpa73+98ccQcZHaHdhvcvH18LfBwRWzTlsGGP8JFgO91gCLkmkT2P/xuXAQDToFV9UvWh5QCAvTHpcNoMepUeWUkw7VzfPM/XE/b+pZKoFCuaAGEYbP7JS3UGIUaIg9UMZGiDBqcmvvfCUFfe99S5rge9YTbARwsmhVKjzdPONH3QzHweum/wGURz03ryNLFMTCxT5i4dvvFB9p1vGgb8KdamW3tqAAgOuf/B12WqMzQU4OPYqwR4Epm7mScB5cMV/s0vdr5w7rrYEZXIczf/02EXR3KBSht4+31lXyRnicfa9xfT70fKZi3+Y6jr1MSnvumc9Oeg2jKCPgS4qu0PmsOfh25pPC65U8+N+Xh5T35aT175sGk4x08ofaLuPyL2ZNUyN5ZSoNyoHqahMCBRVkLUEDRG0GQBBoVB2cvW2isoMo2AJ38BOcYP0CC4qo+rLJn0QOn0A6VvBhrTBhj+Kn0K48SrG4WG/WtUBHiBGC4s5Ug1gzAgQKWx/2mfDT8fbWnbPLizbWTrO90SKYzgWEnIMOdL+VLvF9X8x0/RTOmD7tI7a5mPFCOWkTcLN+4vzkWAJwRISUKagVVZzLrye3mRWsxMWxT2W5fLPhtubNaljcrc1NJW/x/TSMgARmx9v5qBmsoT6Az0MK3SJ6FRljwTu5CaazlA2BGACgBFWElG1gAAAElJKgAIAAAABgASAQMAAQAAAAEAAAAaAQUAAQAAAFYAAAAbAQUAAQAAAF4AAAAoAQMAAQAAAAIAAAAxAQIAEAAAAGYAAABphwQAAQAAAHYAAAAAAAAAYAAAAAEAAABgAAAAAQAAAFBhaW50Lk5FVCA1LjEuOQAFAACQBwAEAAAAMDIzMAGgAwABAAAAAQAAAAKgBAABAAAAgAEAAAOgBAABAAAAGAAAAAWgBAABAAAAuAAAAAAAAAACAAEAAgAEAAAAUjk4AAIABwAEAAAAMDEwMAAAAAA=\" };", "/**\n * Pi.js - Font 6x8 Module\n * \n * Default bitmap font for Pi.js with 6x8 pixel character glyphs in 8x10 character cells.\n * Uses a custom base32-encoded format for synchronous font loading, enabling immediate text\n * rendering without requiring the $.ready() command to wait for font assets to load.\n * \n * This font is unique among Pi.js fonts in that it uses base32 encoding instead of Base64\n * WebP encoding. While WebP offers better compression and ease of use, the base32 encoding\n * allows the font data to be embedded directly in JavaScript, enabling synchronous loading\n * and making it ideal for simple \"Hello World\" examples that don't require async asset\n * management.\n * \n * The font provides a complete ASCII character set (0-255) with retro-style bitmap glyphs.\n * Characters are 6 pixels wide and 8 pixels tall, with each character occupying an 8x10\n * pixel cell to provide spacing between characters.\n * \n * @module text/fonts/font-6x8\n * @see /tools/fonts/gen-fonts.js - Font encoding script\n * \n * @example\n * // Font is automatically loaded as the default font on initialization\n * $.print( \"Hello, World!\" );\n */\n\n// Font 6x8\n// String length: 2431\n// Compression: 48x36\nconst m_font6x8 = {\n\t\"byteSize\": 48,\n\t\"byteBase\": 36,\n\t\"width\": 6,\n\t\"height\": 8,\n\t\"margin\": 0,\n\t\"str\": \"0,1blc8udu8u,1cbkhzwsm6,wpp1xfvgg,coebolreo,d5nukh2cc,coe2eccv0,65jplhc,2rrpnxyccf,0,0,azkg0jpqw,j5ihd7hxo,nly3soshc,nly42td40,dkvajkdak,1f2tcd2lts,39po4vukg,d6e29q3uw,voa3n9udc,1dd8ay5r40,majymyen0,4r8g0,d6e2i2i4f,d6ebp7j7k,co4b4mebk,7307h2ww,78xcoo3k,80mu96o,g90j3o5c,74q25kao,1j83fxkao,0,d5xai464g,vo9y0dkao,voutnk5q8,d7qk1tfr4,18caako74,cyn4y7kow,co7x9kqgw,cvgmd4740,p51ihjmyo,hnt6v75s,3khmlszk,pow,8bnthc,pog,wl5log0,18hslmrwg0,d2kxm9lkw,18halx058g,18haltkhkw,6japxtny8,2pg5ex9zwg,j3ykqif40,2phicbtjpc,18hqina874,18hqj26t4w,74i0nugw,74i0nuhc,6fqfmdlog,ukzeakg,p51hxkg74,18hajmifpc,18hwjobyf4,cyzwjl3ls,2lzffaao74,j5phy2vpc,2lzfcieqdc,2p3nb23s74,2p3nb23lkw,j5phz0lfk,1huhdyxjsw,17ukqfasqo,lxadcq0ow,26fz67fm4g,2fp5guls3k,1ic4kdfc74,1i8m9a9g8w,18hqkb7shs,2lzff9z94w,18hqkb8hs3,2lzffb8jnk,18hpizqeio,2pokva2znk,1huh678wsg,1huh677nk0,1huh8gfaww,1hi03e73pc,1hua29iwow,2phicbv6v4,2g3ele8o3k,1eo82xhoow,2fi0wks268,cyzw9tpmo,1r,co2068kjk,dtwj5q8,23860tetq8,e2shedc,9eixrx874,e2x5s74,j5hseuwhs,d3a881o,23881h7i4g,chbdmk9hc,34buepwv0,23870bnr7k,11m2zty1vk,pz8ndz4,m3d2d8g,e2ssmww,tqjd4qg,d3uih3i,qu79kao,f1qczy8,pcts9aups,h1ch2f4,h1cfgn4,h3ln400,gxcj3i8,h1cgbzw,um4hny8,9jvh9ef7k,co3z8madc,2311eu3da8,t4svfdzi8,7aoozlhc,18hpkro330,vkry6glc,ipvap80sg,18hleduav4,1h0inglklc,11faaz7pfk,chbclspz4,e28hnkc,18hnlvwutc,1h0kuyo4jk,11fciha9ds,1k4rjs1hj4,18hlfeludc,11fabzz8xs,1h7hguv81s,co0929o5c,9dlbfia9s,orcjkhs,mbrplsz28,cyj2ztqm8,ttkqcjcw,p4zq8wp34,cyj4nraww,p4zrwu9ds,ttme9pr0,1h7hgqgmww,1h0ntdz280,cof2w6djc,j5hsewhkw,1hikteekn4,2m32k36f3m,iyd2l9grc,ipt375gu8,ipt47x0cg,6fiigughs,3mhmfvgg,15lstet6kg,15gjbpd9xc,18jink6l1c,12b0vaw3k0,ch3jttxc0,hcdfk0,h7m8lc,tc5on8j33,tc4p4v62q,e18f6vi8,91vaa29s,zcpsr7r4,rdwjrp3dw,xrpq1jqei,2cwu2vechn,co41gj1fs,co41o0qh4,corq1de6g,fu5215hu2,9p8y2,row8vm0,fuso6leh6,fu51tnssq,ulsat8q,fuso76zgg,fu521r2tc,corq1cohs,8rcw8,co41hlnnk,co41p3cow,9uoso,co41hmdc8,9tz40,co41p42dk,co7hskgso,fu51ttf2i,fu5j1pts0,7gmtnka,fut5enfgg,v2zr98q,fu5j148sq,v30cu80,fut5e1uh6,cov45hcsg,fu521wp34,v30djwo,9uv7u,fu51uf01s,co7hsjr40,7gnfy88,2d66i,fu521xl6y,cov6detjc,co41o00sg,2czrc,2rrvthnxtr,9zldr,2gosa7pa2g,b33j9ynrb,2rrvt7ocg0,cnr79s0,p16ep15s,1iubfwjy8,rrfz0t4w,2phoaj5qbk,f408g74,g19nt3xc,mg0a7ocg,2ov1ky6o8u,j5q8b5xc0,j5pzx5vpc,m7xcjszuo,geqgaku8,1mantcco0,j3ykq5kw0,18hqkb7ssg,r6vxlclc,couodj5hc,ckirtofwg,cvghtiikg,9kr8exk3s,co41glw60,j00j709hc,mfz9m9s0,j5ifndeyo,3dqjuo,1vf9c,b0fboebd8,2g6yvj277k,12an04etc0,e13wsn4,0\"\n};\n\nexport function getFontImage() {\n\tconst charWidth = m_font6x8.width;\n\tconst charHeight = m_font6x8.height;\n\tconst margin = m_font6x8.margin;\n\tconst cellWidth = m_font6x8.width + margin * 2;\n\tconst cellHeight = m_font6x8.height + margin * 2;\n\tconst width = cellWidth * 64;\n\tconst height = cellHeight * 4;\n\tconst chars = decompressFont( m_font6x8 );\n\t\n\t// Clear memory\n\tm_font6x8.str = \"\";\n\n\t// Create a Uint8ClampedArray for pixel data\n\tconst data = new Uint8ClampedArray( width * height * 4 );\n\n\tlet x = margin;\n\tlet y = margin;\n\tfor( const char of chars ) {\n\n\t\t// Write the char data to the screen\n\t\tfor( let dataY = 0; dataY < charHeight; dataY += 1 ) {\n\t\t\tfor( let dataX = 0; dataX < charWidth; dataX += 1 ) {\n\t\t\t\tconst bit = char[ dataY ][ dataX ];\n\t\t\t\tif( bit === 1 ) {\n\t\t\t\t\tconst i = ( ( width * ( y + dataY ) ) + ( x + dataX ) ) * 4;\n\t\t\t\t\tdata[ i ] = 255;\n\t\t\t\t\tdata[ i + 1 ] = 255;\n\t\t\t\t\tdata[ i + 2 ] = 255;\n\t\t\t\t\tdata[ i + 3 ] = 255;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Increment to next character\n\t\tx += cellWidth;\n\t\tif( x >= width ) {\n\t\t\tx = margin;\n\t\t\ty += cellHeight;\n\t\t}\n\t}\n\n\t// Create ImageData from the array\n\tconst imageData = new ImageData( data, width, height );\n\n\t// Create the canvas and draw the image data\n\tconst canvas = document.createElement( \"canvas\" );\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tconst context = canvas.getContext( \"2d\" );\n\tcontext.putImageData( imageData, 0, 0 );\n\n\treturn canvas;\n}\n\nfunction decompressFont( fontData ) {\n\tlet numStr = fontData.str;\n\tconst width = fontData.width;\n\tconst height = fontData.height;\n\tconst byteSize = fontData.byteSize;\n\tconst byteBase = fontData.byteBase;\n\tlet bin = \"\";\n\tconst data = [];\n\t\n\tnumStr = \"\" + numStr;\n\tconst nums = numStr.split( \",\" );\n\n\t// Loop through all the base-32 numbers\n\tfor( let i = 0; i < nums.length; i++ ) {\n\n\t\t// Convert base-32 string to binary string\n\t\tlet num = parseInt( nums[ i ], byteBase ).toString( 2 );\n\n\t\t// Pad the front with 0's so that num has length of 32\n\t\twhile( num.length < byteSize ) {\n\t\t\tnum = \"0\" + num;\n\t\t}\n\n\t\t// Add to the binary string\n\t\tbin += num;\n\t}\n\n\t// Loop through all the bits and build character data\n\tlet i = 0;\n\tif( bin.length % byteSize > 0 ) {\n\t\tconsole.warn( \"loadFont: Invalid font data.\" );\n\t\treturn data;\n\t}\n\n\twhile( i < bin.length ) {\n\n\t\t// Push a new character onto data\n\t\tdata.push( [] );\n\n\t\t// Store the index of the font character\n\t\tconst index = data.length - 1;\n\n\t\t// Loop through all rows\n\t\tfor( let y = 0; y < height; y += 1 ) {\n\n\t\t\t// Push a new row onto the character data\n\t\t\tdata[ index ].push( [] );\n\n\t\t\t// Loop through columns in this row\n\t\t\tfor( let x = 0; x < width; x += 1 ) {\n\n\t\t\t\tlet num;\n\t\t\t\tif( i >= bin.length ) {\n\t\t\t\t\tnum = 0;\n\t\t\t\t} else {\n\t\t\t\t\tnum = parseInt( bin[ i ] );\n\t\t\t\t\tif( isNaN( num ) ) {\n\t\t\t\t\t\tnum = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Push the bit onto the character\n\t\t\t\tdata[ index ][ y ].push( num );\n\n\t\t\t\t// Increment the bit position\n\t\t\t\ti += 1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn data;\n}", "export default { \"data\": \"data:image/webp;base64,UklGRpQFAABXRUJQVlA4WAoAAAAYAAAA/wEAHwAAVlA4TJcEAAAv/8EHEA8w//M///Mf8LCs/p8bSdK3EUTW4U+On/kPJf5af3Kx/CEmoYRi/Wmv3hYIop3I6vWmCol+jH6Ate/g25z6AQrWezfem6K0Rm2fIKL/CtO2YRQ6T2Ec0069wwzPtyenV858SMvpEarKMpKSUAcNAOx3YrbJdTYDJRiX56nuFv5Qbt74/OpSW359g7ZVFd6lM5ZS16cgUgSI/dq9rYK7iwjifP/XU1fX+nd4vpycts3RWH5dM44aQ1XaGUtT5XUVtBVAvy4xpqaK7iIha+TyPE1T116FnxW58fdp0vK7hKpOUzWPI0Iy3RJ0zmTkUOraY6PWQUVUfnq166apvQreyo2/N0dajtM46hhDVeYWYYqyxy0tHEiIU3TxCAEVrvy9rrtO/w6u67+1q0sjx/XYaqsyvWtWIDXFESkiSHVW3KO7uIpIFrg87+zUNTP4+MDZz5/5UFuOfVRVlhGS9Fs0gCBnupztO2ZiaxElCOMIXccMpqvqCigYM3eVwB0SADrJbTNNrdt3zj7Q93W2bNm9732yynYQVmyoWUlcrW+xs7TR1ZbeSkmf+ERxiSV8+2wqXvx9C30IWiMEIokAQW4hS6Kyt3PopSqPP165xBSmg754WYl7n/yDQTShFixa2KZ1LOKN7W33us697z2LCvWhd1Uxq7JEC9Nh33m3FveLtWlQ7SF23vkDvpWYZHIvvq3E/WLyJ1dsSId50b7u4ukTF7/eh720Efeplk+GqEBXKs/Bi0RbKibuU+0iKvSVl5I+EYqLl9L3KVhxcft2khL2FfDiXoWuiCe56N51Ib7XbUrdexbMc9tMDxy52dmp7+sHNmfNsvS9TfYhA7Z7trUH4lnzs9a7hfhAo1tJfcwbXTFxr5lZpgED4IHvsEwDAMZm9JUw+sq7VS8bjgwMrrrW3lza1EBua4GrVxU+9pNfq+oAw8AwKO5cBeEq0FMLJPeVr1zR5H4Mm01DSkDf601/6FPP3kGFtWZmrdm6XifyqQNA6+N7zNXWgKck4E4pi9YMNAfDdDA0uPt+jLEq7qLSW4iTmbl78eqB/JU2innz1FEdcj78tfrNhz717UXT/WF/f1DM81HXddWYs6hMbqfu7ktBeu3E3TNUVbz5tC5b0xxMzcFwME1No14Vd7dQVaLS53BLda2PZ/NL6uLue2PnVSyv3u496DAMgMbRTsZxjK2ZtdZ7Pv26mY1jVNMs/e5oNrqDgb+k8L/3HRgA1NwxDSjy5zW3y/O/AP7/vj1VFNVhYNF1gEFhUGXmgedngAzkut6wXxsS9JIKNTxva7gPLE9O2UpKQgyeReRYZZsgJr3V68PTJ8/NT8/PzcPM8PrrDPMttu4pjGXP+l7HsXKyhmNlb0Ha2zQREGDR9HZtr6mS7Bb1qe9+/etm0VQztRJTaHl9nl+f59efPnl6fu7p+bl5nueT118/mefm9Xl+4Hke8SqF3aLeJ//1rytHgqqyRfWpZC2gi8bAMDCALv6Dogt7TZV8t1NLyccxeAZ0V/aABPfDtqpSXgeV+ttGqJ2cs+4KLD/3ARVARQaoAEDXAGwAAABFWElG1gAAAElJKgAIAAAABgASAQMAAQAAAAEAAAAaAQUAAQAAAFYAAAAbAQUAAQAAAF4AAAAoAQMAAQAAAAIAAAAxAQIAEAAAAGYAAABphwQAAQAAAHYAAAAAAAAAYAAAAAEAAABgAAAAAQAAAFBhaW50Lk5FVCA1LjEuOQAFAACQBwAEAAAAMDIzMAGgAwABAAAAAQAAAAKgBAABAAAAAAIAAAOgBAABAAAAIAAAAAWgBAABAAAAuAAAAAAAAAACAAEAAgAEAAAAUjk4AAIABwAEAAAAMDEwMAAAAAA=\" };", "export default { \"data\": \"data:image/webp;base64,UklGRpYGAABXRUJQVlA4WAoAAAAYAAAA/wEANwAAVlA4TJoFAAAv/8ENEA8w//M///Mf8LCs/n8jSdKvV6DKg8jxMz9Ikbn+rEWgKUihbHCnvXobwx/+7YKohPFTRYi+7SvsA/hX8P7krgVtjjveHF3RsSYyKztnHiCi/wzbtg1DAW67fYKNBjxMxEN3vrKdgoB7CH0PkBiAV/LZA164SH0gILn5VVOBd2F8uVhYSqi+lgI0sAW3hzTJGQOw1r//jabJesci55FJRdYkSI4EADTiRQ6NFREywAl+eqf63GMAvq1nD+4crHu949H3pMOTviJ/uV66lKwLSgDh+XnTZGMaEZKg4PZQy+sDXwe+ru5veXFCvZNAMliTfEFGMuLhQiYAHjM0yZggArg+BNwean19yH8G5tn97fVaqfcFJGs1tRQQqYQOLgw9KtwRmeNqxdIDFg3x2z/X8nqf/wxEbsypYGOKB5EaLjfHXqNraiNOGsAhED95vXiSrwOxn/77zsG6x2mqPXu6+mT1AOpzLsIFJQEjtE0YIdkTuD34CYkBiHzkdZom66mvmRkA6gREEo0gAYIXhCJBxEkgAxzR9xPkjAGY8+AaL1yknoZKEuOIVKRDcCMofS2vlOLKHK6BJTYaAAAGAABBj60R4xwepgFbKzgnYh8N+Gw2gfuU+T0ok1Ve1Jolv3LtERG/KqvSi4hozRdyAnGAQ3gcsDnwGyZja047iFdNqioMal++llRUxsSZIAAsAhIsG8sNbozkEpL0kl69ekkYkq1HoqLyXRFJ+jV3ELDhq7DATjA5FjX69NNmrIqKWoqIV7ppADCfl1xsl/xa+eyyLLtlWUUVkUoS/liK0fncVIa5vXUsRYqnyC2fnfMBQEiS5JHYsUmsKho7cVElSZxijXRcR3M8Gnle7K0URmjdYQBQ1MRqo7KZ85aKRp26qLe8kCRkKXpJr1oRxnRVROyxCiXVxEtuHQBENdGMpDF7OOZGjKgmtSqMqiLJFhWKL0JxzZhEsUXZKG+plGKljbmmXkmiFlnlRX3k+5Ln16qIfyRcK7lMkuSaL2YAXSldeSRcy3otixYbHimHHZM0dc0pdmmN3YqAAgBswLiA/TRsmAMZAPDIKxsW+GzmuZtumx//6tckW6Bt0bYEECawHhNY0EpywATWWYjQY7FmILHMHoAxAL74jffOkSN9dAk+Os1OvMWJFzd3IsKk8dTRuQ4pOcAY7jIaXYr0SJGqnABISRgpHvmrGmmdtUsZEeEucwkAgLzxx9cYAQBIojYvCAC4duIBxIh2dv6YWObz+VxLKd77lLSLpZQYRcQ+wi9x7ktcHgEOmM2Y0mgWLRZHbT1qFzBRQgjBighJEdtWERmzfewDJWrti6vVOc7azWHTNk1LXIq1lFK01jpS+rhJLY9ZKFGPAWsaq3k8i8VRXRy1R7UuFhpNjDFmYwzJWu1si2z7yEiJ+jwgplk+n7d8btm2LQDmKDHGGDYfuqFPwmvcICPPvZqB/30+R+hK13VdU0rJOYvUl54vpXRd4wtXFHa5dCpAAcIJgfOnAQAg49wCAAAzbIsNdpmCXZuPTbc6abDLYL/tNCQIsm0xWrZAS6AlMeCRDwbsFrGlT48HPphN96OiAui9fwV/OATgwppAAkKa7YdAADAlh8aVSvKUHHN7UaRaaJdFiN4KGNwp2XkgJFs2fNi+c/b+8M7w/tAOaD/8EO2woROTXK9LFQn9HSvoG0tiCSCkJzaxdQ5wAEbDbbNcmcSZUquc3LlTpDI4sgeIkBYFHw7Dh8Pw4Ttn7wzvvzO8PwzDcPbhh2fDsPhwGB75ADMxyc2UKknv/MsKSJLoQD4LFAAcDVq0LVqAo+8twS3srDBL0r63ArjAGZcA0n4sVybJzJIpKayTCoAzAkDej86YVKeWvX85wxwKhr7nFABwCGAPYADAYHvElvbhczivvduhcwFFWElG1gAAAElJKgAIAAAABgASAQMAAQAAAAEAAAAaAQUAAQAAAFYAAAAbAQUAAQAAAF4AAAAoAQMAAQAAAAIAAAAxAQIAEAAAAGYAAABphwQAAQAAAHYAAAAAAAAAYAAAAAEAAABgAAAAAQAAAFBhaW50Lk5FVCA1LjEuOQAFAACQBwAEAAAAMDIzMAGgAwABAAAAAQAAAAKgBAABAAAAAAIAAAOgBAABAAAAOAAAAAWgBAABAAAAuAAAAAAAAAACAAEAAgAEAAAAUjk4AAIABwAEAAAAMDEwMAAAAAA=\" };", "export default { \"data\": \"data:image/webp;base64,UklGRq4GAABXRUJQVlA4WAoAAAAYAAAA/wEAPwAAVlA4TLEFAAAv/8EPEA8w//M///Mf8AwFbdswCX/Y+0MQERPAU60igEq0rP5/JEnOrxGoehE1+8wPUmR5PwsEckEK9VJQT+Elmj/8Z49J8FZQRcjLU8wD+DH2gLnOtUwaH10345PxqeMQiqzs9HKO6P8EwGm1vW72APgv67tZMifvAfBKgZDVWEzBlCKn473fVCVtCUT0P7A44XUSx7j04BmAsp/O3GsYhr1ewXTUVwKSC1QUeBdcK7OUUH0tpVHwqwkgF77iyTbrziLnpaxJkBzZUi9ybqyIAB2s4Le79DDnhVd842rQnccw7PGddHGRrAuNZ+O667IxnQgZ4AS/mqrPw8JXu7Mb6i6BJF0L1YiHC0oA3cjQpQUODLNyN+GulWul/k1mwTaIVEIPF/Is7Mgcnz4NZQAcAvG7sda7CWPr7uyGetuodanjBi5MAyq4o+tqJ5QOsOiIL+9quRuW8htXg96mOpDB7uEiXMgE4EbaLnTiZm4IxK+m4kncNf6+O9lm3PqaOdA1gPrSzpQE7EizQBIEfjX5hySmxh1NR70NlcxoE0kkggQIGqVIEHESyABHDMND5LzwIR88g95KHch9yssewTUe5KGWq1JcWcN1sMRiy6BZcE+i7fA6W4deer2v5zj/8w79EO4/zB/Dw6f5rNYs+erDN0YpT8vTMsk4juOUkROIE5zD44TdiV942NrytEfxqklVhUHt3YeiorJrjO5BEAAWAQmWneWCa5HcQJJe6OXlRWP6ovGljKOOL50JWPgeLHAQPBRRo++/b4Qh2anOLGUcswZ3MluvSy62T36r/HBTNv2mPI3jOEqd+WspRtdrUxnWdnctRYqfMdOdzkKSJG/Enl3ipKKxFxfHUSWeYot0XdXo++9fy2z8iVhJgTLuSOf8rKiJ1UZlt+ZupnaWhSQh16JGrRVhTHYUsaLdLNO681lUE81+1rs47iiusRG90MuGXs4+VaHopPyN294nLQQXdZfFNoyoJrU609n1LOvI0XUtidLQBfks5klFZrXI03xW3/iB5PWHdZTyRvmw5EId85SfZQB9KX15o3yYuw/zTkspb5TznjoOdctTHDLgsAFQzG1Au8Oht/eYFuIBwsEOvQZy442rhbMjO17Pw/T71NYlGWxsAYSHsB4PYUEryQEPYZ2FCD2ebhlIbLIHYAyAXMZOjvTRJXhxmh28xY0Xt3YCMI166+hcj5TcjEBtfUfhEuiRQCgfAkgJjESR4XuqtM7ajTQuLgjkMnYu0Mxoel8R0RQZbS7E/MMbD0AEQG19x8SyXq/XWkrx3qekP4+llBhFxLzBS659iZsvAAfEyM9WuQwpmTR7mZ0wUUIIwYoISRH71yoiLTvpEChR61BcrSRTqq1LMpo8TRYm1lJKsbXWRrmN+/BfLLNrwJrOOa4+y2UopXlJs+dlSekimhhjVGMMyVrtsMdoJ2Wc/QQwprOaU6qtS7JlG5C2ckvErvYYLBcEENP95Cf5s1UuYydHmQURaehmD354n798nIHa+k7oS9/3fVdKyTmL1H/8pJTS90MpfMqv2efSzwrQ3RDIZex0aGbcu0NzhX1DB6C2vlNaBwyt073+Pctl7ODg69YBa+sfOnwuY0dCSDbGWAYLLBH8n+J+TWLP73ngn6vTo1jXBX8FnDe2BBIQ0uoooqACGHxy+KMrgAu3S+5IqkB7JiE6K5XkLQk/s2Xh7PW+xRpbOPD5jOOljybZQTdZJAyDFTA4kj1m7yzJPz/wAxgsYb1sVia5lVJFbna7Ihg6S2LTOCs4R5wjzut9jW2NLSLifj7fI9I54v/EKprEWU2621mpDI4cAOL7QAFISMbYGGSQTbAlJrmZJN19bQUkuUIPMh2PXRVmSToMVgAXuOIGwJFsxCRZWTIlhXVSAXBFAMjH0UeT6qnl4H+RYc4F0zDwFPNzNN9tG+xP7P+Z+/5/AQBFWElG1gAAAElJKgAIAAAABgASAQMAAQAAAAEAAAAaAQUAAQAAAFYAAAAbAQUAAQAAAF4AAAAoAQMAAQAAAAIAAAAxAQIAEAAAAGYAAABphwQAAQAAAHYAAAAAAAAAYAAAAAEAAABgAAAAAQAAAFBhaW50Lk5FVCA1LjEuOQAFAACQBwAEAAAAMDIzMAGgAwABAAAAAQAAAAKgBAABAAAAAAIAAAOgBAABAAAAQAAAAAWgBAABAAAAuAAAAAAAAAACAAEAAgAEAAAAUjk4AAIABwAEAAAAMDEwMAAAAAA=\" };", "/**\n * Pi.js - Main Entry Point\n * \n * Graphics library for retro-style games and demos.\n * \n * @module pi.js\n * @author Andy Stubbs\n * @license Apache-2.0\n */\n\n\"use strict\";\n\n// This is the lite version entry point (core only, no plugins).\n// The full version with plugins is in index-full.js.\n\n// Core Modules\nimport * as g_utils from \"./core/utils.js\";\nimport * as g_commands from \"./core/commands.js\";\nimport * as g_screenManager from \"./core/screen-manager.js\";\nimport * as g_plugins from \"./core/plugins.js\";\n\n// Renderer\nimport * as g_renderer from \"./renderer/renderer.js\";\n\n// API\nimport * as g_colors from \"./api/colors.js\";\nimport * as g_graphicsApi from \"./api/graphics.js\";\nimport * as g_images from \"./api/images.js\";\nimport * as g_pixels from \"./api/pixels.js\";\nimport * as g_paint from \"./api/paint.js\";\nimport * as g_blends from \"./api/blends.js\";\nimport * as g_draw from \"./api/draw.js\";\n\n// Text\nimport * as g_fonts from \"./text/fonts.js\";\nimport * as g_print from \"./text/print.js\";\n\n// Version injected during build from package.json\nconst VERSION = \"2.0.1\";\n\n// Create the main api for all external commands later assinged to globals pi or $\nconst api = {\n\t\"version\": VERSION\n};\n\n// Store modules in array for ordered initialization\nconst mods = [\n\tg_utils, g_commands, g_screenManager, g_plugins, g_renderer, g_colors, g_graphicsApi, g_images,\n\tg_blends, g_pixels, g_paint, g_draw, g_fonts, g_print\n];\n\n// Initialize the modules\nfor( const mod of mods ) {\n\tif( mod.init ) {\n\t\tmod.init( api );\n\t}\n}\n\n// Process API commands\ng_commands.processCommands( api );\n\n// Set window.pi for browser environments\nif( typeof window !== \"undefined\" ) {\n\twindow.pi = api;\n\n\t// Set $ alias only if not already defined (avoid jQuery conflicts)\n\tif( window.$ === undefined ) {\n\t\twindow.$ = api;\n\t}\n}\n\n// Export for different module systems\nexport default api;\nexport { api as pi };\n"],
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAAA;AAAA,IAAA;AAAA;AAAA;AAAA;AAgBO,MAAM,QAAQ,CAAE,gBAAiB;AACvC,UAAM,QAAQ,IAAI;AAAA,MACjB,GAAG,WAAW;AAAA,IAEf;AACA,UAAM,OAAO;AACb,UAAM;AAAA,EACP;AAUO,WAAS,aAAc,MAAM,gBAAiB;AACpD,UAAM,gBAAgB,CAAC;AAGvB,eAAW,QAAQ,gBAAiB;AACnC,oBAAe,IAAK,IAAI;AAAA,IACzB;AAEA,QAAI,wBAAwB;AAG5B,QAAI,KAAK,SAAS,KAAK,gBAAiB,KAAM,CAAE,CAAE,GAAI;AACrD,YAAM,eAAe,KAAM,CAAE;AAE7B,iBAAW,QAAQ,gBAAiB;AACnC,YAAI,QAAQ,cAAe;AAC1B,kCAAwB;AACxB,wBAAe,IAAK,IAAI,aAAc,IAAK;AAAA,QAC5C;AAAA,MACD;AAAA,IACD;AAGA,QAAI,CAAC,uBAAwB;AAK5B,eAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAM;AAChD,YAAI,IAAI,KAAK,QAAS;AACrB,wBAAe,eAAgB,CAAE,CAAE,IAAI,KAAM,CAAE;AAAA,QAChD;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAGO,MAAM,aAAa,CAAE,OAAQ,OAAO,OAAO;AAC3C,MAAM,eAAe,CAAE,OAAQ,cAAc;AAC7C,MAAM,kBAAkB,CAAE,QAAS;AACzC,QAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAS,GAAI,GAAI;AACrE,aAAO;AAAA,IACR;AACA,UAAM,QAAQ,OAAO,eAAgB,GAAI;AACzC,WAAO,UAAU,QAAQ,UAAU,OAAO;AAAA,EAC3C;AAYO,WAAS,UAAW,KAAK,OAAO,QAAS;AAC/C,UAAM,IAAI,YAAY;AACtB,UAAM,OAAO,CAAC;AACd,QAAI,IAAI;AACR,QAAI,SAAS;AACb,QAAI,aAAa;AAEjB,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAM;AACjC,WAAK,KAAM,CAAC,CAAE;AACd,eAAS,IAAI,GAAG,IAAI,OAAO,KAAM;AAChC,YAAI,cAAc,OAAO,QAAS;AACjC,cAAI,UAAU,SAAU,IAAK,CAAE,GAAG,EAAG;AACrC,cAAI,MAAO,OAAQ,GAAI;AACtB,sBAAU;AAAA,UACX;AACA,mBAAS,KAAM,QAAQ,SAAU,CAAE,GAAG,GAAG,GAAI;AAC7C,eAAK;AACL,uBAAa;AAAA,QACd;AACA,aAAM,CAAE,EAAE,KAAM,SAAU,OAAQ,UAAW,CAAE,CAAE;AACjD,sBAAc;AAAA,MACf;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAYO,WAAS,MAAO,KAAK,KAAK,KAAM;AACtC,WAAO,KAAK,IAAK,KAAK,IAAK,KAAK,GAAI,GAAG,GAAI;AAAA,EAC5C;AASO,WAAS,QAAS,OAAO,QAAS;AACxC,WAAO,MAAM,KAAK,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI,OAAO,SACzD,MAAM,KAAK,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI,OAAO;AAAA,EACrD;AAaO,WAAS,SAAU,IAAI,IAAI,IAAI,IAAI,OAAO,QAAS;AACzD,WAAO,MAAM,MAAM,KAAK,KAAK,SAC5B,MAAM,MAAM,KAAK,KAAK;AAAA,EACxB;AASO,WAAS,SAAU,KAAK,KAAM;AACpC,WAAO,KAAK,OAAO,KAAM,MAAM,OAAQ;AAAA,EACxC;AAQO,WAAS,gBAAiB,KAAM;AACtC,WAAO,OAAQ,KAAK,KAAK;AAAA,EAC1B;AAQO,WAAS,iBAAkB,KAAM;AACvC,WAAO,OAAQ,MAAM,KAAK;AAAA,EAC3B;AAYO,WAAS,KAAM,KAAK,KAAK,GAAI;AACnC,QAAI,OAAO,MAAM,UAAW;AAC3B,UAAI;AAAA,IACL;AACA,QAAIC,OAAM;AACV,UAAM,MAAM;AACZ,aAAS,IAAI,IAAI,QAAQ,IAAI,KAAK,KAAM;AACvC,MAAAA,QAAO;AAAA,IACR;AACA,WAAOA,OAAM;AAAA,EACd;AAUO,WAAS,IAAK,KAAK,KAAK,GAAI;AAClC,QAAI,OAAO,MAAM,YAAY,EAAE,WAAW,GAAI;AAC7C,UAAI;AAAA,IACL;AACA,UAAM,MAAM;AACZ,WAAO,IAAI,SAAS,KAAM;AACzB,YAAM,IAAI,MAAM;AAAA,IACjB;AACA,QAAI,IAAI,SAAS,KAAM;AACtB,YAAM,IAAI,UAAW,GAAG,GAAI;AAAA,IAC7B;AACA,WAAO;AAAA,EACR;AASO,WAAS,OAAQ,KAAK,KAAM;AAClC,QAAI,QAAQ,QAAQ,QAAQ,QAAY;AACvC,aAAO;AAAA,IACR;AACA,UAAM,SAAS,OAAQ,GAAI;AAC3B,QAAI,CAAC,OAAO,SAAU,MAAO,GAAI;AAChC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,MAAO,MAAO;AAAA,EAC3B;AASO,WAAS,SAAU,KAAK,KAAM;AACpC,QAAI,QAAQ,QAAQ,QAAQ,QAAY;AACvC,aAAO;AAAA,IACR;AACA,UAAM,SAAS,OAAQ,GAAI;AAC3B,QAAI,CAAC,OAAO,SAAU,MAAO,GAAI;AAChC,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR;AAIO,MAAMD,kBAAiB,CAAE,aAAc;AAC7C,QAAI,OAAO,gBAAiB;AAC3B,aAAO,eAAgB,QAAS;AAAA,IACjC,OAAO;AACN,iBAAY,UAAU,CAAE;AAAA,IACzB;AAAA,EACD;AAQA,MAAM,wBAAwB,SAAS,cAAe,QAAS,EAAE;AAAA,IAChE;AAAA,IAAM,EAAE,sBAAsB,KAAK;AAAA,EACpC;AACA,MAAM,cAAc;AAAA,IACnB,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,SAAS;AAAA,EACV;AAQO,WAAS,YAAa,YAAa;AACzC,UAAM,QAAQ,OAAO,OAAQ,WAAY;AACzC,UAAM,QAAQ;AACd,UAAM,IAAI,WAAY,CAAE;AACxB,UAAM,IAAI,WAAY,CAAE;AACxB,UAAM,IAAI,WAAY,CAAE;AACxB,UAAM,IAAI,WAAY,CAAE;AACxB,UAAM,MAAQ,WAAY,CAAE,KAAK,KAC9B,WAAY,CAAE,KAAK,KACnB,WAAY,CAAE,KAAK,IACrB,WAAY,CAAE;AACf,WAAO;AAAA,EACR;AAaO,WAAS,iBAAkB,GAAG,GAAG,GAAG,GAAI;AAC9C,WAAS,KAAK,KAAS,KAAK,KAAS,KAAK,IAAM;AAAA,EACjD;AAWO,WAAS,WAAY,GAAG,GAAG,GAAG,GAAI;AACxC,UAAM,aAAa,IAAI,WAAY,CAAE;AACrC,eAAW,IAAK,CAAE,GAAG,GAAG,GAAG,CAAE,CAAE;AAC/B,WAAO,YAAa,UAAW;AAAA,EAChC;AAQO,WAAS,eAAgB,OAAQ;AACvC,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAK;AAC3D,aAAO;AAAA,IACR;AAGA,QAAI,OAAO,eAAgB,KAAM,MAAM,aAAc;AACpD,aAAO;AAAA,IACR,WAAW,MAAM,QAAS,KAAM,GAAI;AAGnC,UAAI,MAAM,SAAS,GAAI;AACtB,eAAO;AAAA,MACR,WAAW,MAAM,WAAW,GAAI;AAC/B,cAAM,KAAM,GAAI;AAAA,MACjB;AAAA,IACD,WAAW,OAAO,UAAU,UAAW;AAGtC,YAAM,gBAAgB;AACtB,UAAI,cAAc,KAAM,KAAM,GAAI;AACjC,eAAO,WAAY,KAAM;AAAA,MAC1B;AAGA,UAAI,MAAM,QAAS,KAAM,MAAM,GAAI;AAClC,gBAAQ,SAAU,KAAM;AACxB,YAAI,MAAM,SAAS,GAAI;AACtB,iBAAO;AAAA,QACR,WAAW,MAAM,WAAW,GAAI;AAC/B,gBAAM,KAAM,GAAI;AAAA,QACjB;AAAA,MACD,OAAO;AAGN,eAAO,mBAAoB,KAAM;AAAA,MAClC;AAAA,IACD,WACC,MAAM,MAAM,UACZ,MAAM,MAAM,UACZ,MAAM,MAAM,UACZ,MAAM,MAAM,QACX;AACD,cAAQ,CAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAE;AAAA,IAC9C;AAGA,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK,GAAI;AAC/B,YAAO,CAAE,IAAI,OAAQ,MAAO,CAAE,GAAG,CAAE;AAAA,IACpC;AAGA,UAAO,CAAE,IAAI,SAAU,MAAO,CAAE,GAAG,CAAE;AACrC,QAAI,MAAO,CAAE,KAAK,GAAI;AACrB,YAAO,CAAE,IAAI,KAAK,MAAO,MAAO,CAAE,IAAI,GAAI;AAAA,IAC3C,OAAO;AACN,YAAO,CAAE,IAAI,KAAK,MAAO,MAAO,CAAE,CAAE;AAAA,IACrC;AAEA,WAAO,WAAY,MAAO,CAAE,GAAG,MAAO,CAAE,GAAG,MAAO,CAAE,GAAG,MAAO,CAAE,CAAE;AAAA,EACnE;AAEO,WAAS,oBAAqB,IAAI,IAAI,IAAI,CAAE,KAAK,MAAM,MAAM,IAAK,GAAI;AAC5E,UAAM,KAAK,GAAG,MAAO,CAAE,IAAI,GAAG,MAAO,CAAE;AACvC,UAAM,KAAK,GAAG,MAAO,CAAE,IAAI,GAAG,MAAO,CAAE;AACvC,UAAM,KAAK,GAAG,MAAO,CAAE,IAAI,GAAG,MAAO,CAAE;AACvC,UAAM,KAAK,GAAG,MAAO,CAAE,IAAI,GAAG,MAAO,CAAE;AAEvC,WAAS,KAAK,KAAK,EAAG,CAAE,IAAI,KAAK,KAAK,EAAG,CAAE,IAAI,KAAK,KAAK,EAAG,CAAE,IAAI,KAAK,KAAK,EAAG,CAAE;AAAA,EAClF;AAEO,WAAS,UAAW,UAAU,WAAY;AAChD,cAAU,MAAM,SAAS;AACzB,cAAU,MAAO,CAAE,IAAI,SAAS,MAAO,CAAE;AACzC,cAAU,MAAO,CAAE,IAAI,SAAS,MAAO,CAAE;AACzC,cAAU,MAAO,CAAE,IAAI,SAAS,MAAO,CAAE;AACzC,cAAU,MAAO,CAAE,IAAI,SAAS,MAAO,CAAE;AAAA,EAC1C;AAQA,WAAS,WAAY,KAAM;AAC1B,QAAI,GAAG,GAAG,GAAG;AAEb,QAAI,IAAI,WAAW,GAAI;AACtB,UAAI,SAAU,IAAI,OAAQ,CAAE,IAAI,IAAI,OAAQ,CAAE,GAAG,EAAG;AACpD,UAAI,SAAU,IAAI,OAAQ,CAAE,IAAI,IAAI,OAAQ,CAAE,GAAG,EAAG;AACpD,UAAI,SAAU,IAAI,OAAQ,CAAE,IAAI,IAAI,OAAQ,CAAE,GAAG,EAAG;AAAA,IACrD,OAAO;AACN,UAAI,SAAU,IAAI,UAAW,GAAG,CAAE,GAAG,EAAG;AACxC,UAAI,SAAU,IAAI,UAAW,GAAG,CAAE,GAAG,EAAG;AACxC,UAAI,SAAU,IAAI,UAAW,GAAG,CAAE,GAAG,EAAG;AAAA,IACzC;AAEA,QAAI,IAAI,WAAW,GAAI;AACtB,UAAI,SAAU,IAAI,UAAW,GAAG,CAAE,GAAG,EAAG;AAAA,IACzC,OAAO;AACN,UAAI;AAAA,IACL;AAEA,WAAO,WAAY,GAAG,GAAG,GAAG,CAAE;AAAA,EAC/B;AAQA,WAAS,OAAQ,GAAI;AACpB,QAAI,CAAC,OAAO,UAAW,CAAE,GAAI;AAC5B,UAAI,KAAK,MAAO,CAAE;AAAA,IACnB;AACA,QAAI,MAAO,GAAG,GAAG,GAAI;AACrB,UAAM,MAAM,OAAQ,CAAE,EAAE,SAAU,EAAG;AACrC,WAAO,IAAI,SAAS,IAAI,MAAM,MAAM,IAAI,YAAY;AAAA,EACrD;AAQO,WAAS,WAAY,OAAQ;AACnC,WAAO,MAAM,OAAQ,MAAM,CAAE,IAAI,OAAQ,MAAM,CAAE,IAAI,OAAQ,MAAM,CAAE,IAAI,OAAQ,MAAM,CAAE;AAAA,EAC1F;AAQA,WAAS,SAAU,GAAI;AACtB,QAAI,EAAE,MAAO,EAAE,QAAS,GAAI,IAAI,GAAG,EAAE,QAAS,GAAI,CAAE;AACpD,UAAM,QAAQ,EAAE,MAAO,GAAI;AAC3B,UAAM,SAAS,CAAC;AAChB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAM;AACvC,UAAI;AACJ,UAAI,MAAM,GAAI;AACb,cAAM,WAAY,MAAO,CAAE,EAAE,KAAK,CAAE;AACpC,YAAI,OAAO,GAAI;AACd,iBAAO;AAAA,QACR;AAAA,MACD,OAAO;AACN,cAAM,SAAU,MAAO,CAAE,EAAE,KAAK,CAAE;AAAA,MACnC;AACA,aAAO,KAAM,GAAI;AAAA,IAClB;AACA,WAAO;AAAA,EACR;AAQA,WAAS,mBAAoB,UAAW;AACvC,0BAAsB,UAAW,GAAG,GAAG,GAAG,CAAE;AAC5C,0BAAsB,YAAY;AAClC,0BAAsB,SAAU,GAAG,GAAG,GAAG,CAAE;AAC3C,UAAM,OAAO,sBAAsB,aAAc,GAAG,GAAG,GAAG,CAAE,EAAE;AAC9D,WAAO,WAAY,KAAM,CAAE,GAAG,KAAM,CAAE,GAAG,KAAM,CAAE,GAAG,KAAM,CAAE,CAAE;AAAA,EAC/D;;;AC9gBA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAE;AAAA,IAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA,IAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAAC;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;;;ACAA,MAAAC,mBAAA;;;AC2BO,WAAS,OAAO;AAEtB,IAAgB,kBAAmB,kBAAkB,IAAK;AAC1D,IAAgB,kBAAmB,yBAAyB,IAAK;AACjE,IAAgB,kBAAmB,oBAAoB,IAAK;AAAA,EAC7D;AAUO,WAAS,cAAe,IAAI,MAAM,QAAS;AAEjD,UAAM,SAAS,GAAG,aAAc,IAAK;AACrC,OAAG,aAAc,QAAQ,MAAO;AAChC,OAAG,cAAe,MAAO;AAEzB,QAAI,CAAC,GAAG,mBAAoB,QAAQ,GAAG,cAAe,GAAI;AACzD,cAAQ,MAAO,yBAAyB,GAAG,iBAAkB,MAAO,CAAE;AACtE,SAAG,aAAc,MAAO;AACxB,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR;AAUO,WAAS,oBAAqB,IAAI,WAAW,SAAU;AAE7D,UAAM,eAAe,cAAe,IAAI,GAAG,eAAe,SAAU;AACpE,UAAM,iBAAiB,cAAe,IAAI,GAAG,iBAAiB,OAAQ;AAEtE,QAAI,CAAC,gBAAgB,CAAC,gBAAiB;AACtC,YAAM,QAAQ,IAAI,MAAO,oCAAqC;AAC9D,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,UAAM,UAAU,GAAG,cAAc;AACjC,OAAG,aAAc,SAAS,YAAa;AACvC,OAAG,aAAc,SAAS,cAAe;AACzC,OAAG,YAAa,OAAQ;AAGxB,OAAG,aAAc,YAAa;AAC9B,OAAG,aAAc,cAAe;AAEhC,QAAI,CAAC,GAAG,oBAAqB,SAAS,GAAG,WAAY,GAAI;AACxD,YAAM,SAAS,GAAG,kBAAmB,OAAQ;AAC7C,SAAG,cAAe,OAAQ;AAC1B,YAAM,QAAQ,IAAI,MAAO,kCAAkC,MAAM,GAAI;AACrE,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,WAAO;AAAA,EACR;AAQO,WAAS,mBAAoB,YAAa;AAEhD,UAAM,KAAK,WAAW;AAGtB,UAAM,UAAU,oBAAqB,IAAI,iBAAkBC,gBAAiB;AAG5E,UAAM,YAAY,IAAI,aAAc;AAAA,MACnC;AAAA,MAAI;AAAA;AAAA,MACH;AAAA,MAAG;AAAA;AAAA,MACJ;AAAA,MAAK;AAAA;AAAA,MACL;AAAA,MAAK;AAAA;AAAA,MACJ;AAAA,MAAG;AAAA;AAAA,MACH;AAAA,MAAI;AAAA;AAAA,IACN,CAAE;AAGF,UAAM,iBAAiB,GAAG,aAAa;AACvC,OAAG,WAAY,GAAG,cAAc,cAAe;AAC/C,OAAG,WAAY,GAAG,cAAc,WAAW,GAAG,WAAY;AAG1D,UAAM,cAAc,GAAG,kBAAmB,SAAS,YAAa;AAChE,UAAM,aAAa,GAAG,mBAAoB,SAAS,WAAY;AAG/D,eAAW,iBAAiB;AAC5B,eAAW,wBAAwB;AACnC,eAAW,mBAAmB;AAAA,MAC7B,YAAY;AAAA,MACZ,WAAW;AAAA,IACZ;AAAA,EACD;;;ACvIA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA;AAiBO,MAAM,gBAAgB;AACtB,MAAM,cAAc;AACpB,MAAM,SAAS,oBAAI,IAAK,CAAE,eAAe,WAAY,CAAE;AASvD,WAASC,MAAMC,MAAM;AAG3B,IAAgB,kBAAmB,UAAU;AAAA,MAC5C,SAAS;AAAA,MAAe,SAAS;AAAA,MAAM,aAAa;AAAA,MAAM,aAAa,CAAC;AAAA,IACzE,CAAE;AAEF,qBAAiB;AAAA,EAClB;AAGA,WAAS,mBAAmB;AAC3B,IAAW,WAAY,YAAY,UAAU,MAAM,CAAE,OAAQ,CAAE;AAC/D,IAAW,WAAY,YAAY,UAAU,MAAM,CAAE,SAAS,MAAO,CAAE;AAAA,EACxE;AASA,WAAS,SAAU,YAAY,SAAU;AACxC,QAAI,QAAQ,QAAQ,SAAS,WAAW,OAAO;AAE/C,QAAI,CAAC,OAAO,IAAK,KAAM,GAAI;AAC1B,YAAM,QAAQ,IAAI;AAAA,QACjB,qEACG,MAAM,KAAM,MAAO,EAAE,KAAM,IAAK,CAAC;AAAA,MACrC;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,UAAM,gBAAgB,WAAW,OAAO;AACxC,UAAM,iBAAiB,gBAAiB,WAAW,MAAO;AAC1D,eAAW,OAAO,QAAQ;AAG1B,QAAI,kBAAkB,OAAQ;AAC7B,MAAW,iBAAkB,YAAY,cAAe;AAAA,IACzD;AAAA,EACD;AAIA,WAAS,SAAU,YAAY,SAAU;AACxC,QAAI,QAAQ,QAAQ;AACpB,QAAI,OAAO,QAAQ;AAEnB,UAAM,gBAAgB;AAMtB,QAAI,cAAc;AAGlB,QAAI,UAAU,MAAO;AAGpB,YAAM,qBAAqB,CAAE,aAAc;AAC1C,YAAI,aAAa,MAAO;AACvB,gBAAM,QAAQ,IAAI,UAAW,aAAc;AAC3C,gBAAM,OAAO;AACb,gBAAM;AAAA,QACP;AAAA,MACD;AAGA,UAAI,MAAM,QAAS,KAAM,GAAI;AAG5B,sBAAc;AAAA,UACb,IAAI,aAAc,CAAE,GAAG,GAAG,GAAG,CAAE,CAAE;AAAA,UAAG,IAAI,aAAc,CAAE,GAAG,GAAG,GAAG,CAAE,CAAE;AAAA,QACtE;AAGA,iBAAS,IAAI,GAAG,IAAI,MAAM,UAAU,IAAI,GAAG,KAAK,GAAI;AAEnD,gBAAM,WAAW,MAAO,CAAE;AAG1B,cAAI,MAAM,QAAS,QAAS,GAAI;AAG/B,gBAAI,KAAK,GAAI;AACZ;AAAA,YACD;AAGA,qBAAS,IAAI,GAAG,IAAI,SAAS,UAAU,IAAI,GAAG,KAAK,GAAI;AACtD,oBAAM,WAAmB,OAAQ,SAAU,CAAE,GAAG,IAAK;AACrD,iCAAoB,QAAS;AAC7B,0BAAa,CAAE,EAAG,CAAE,IAAI,WAAW;AAAA,YACpC;AAAA,UACD,OAAO;AACN,kBAAM,WAAmB,OAAQ,UAAU,IAAK;AAChD,+BAAoB,QAAS;AAG7B,wBAAa,CAAE,EAAG,CAAE,IAAI,CAAC,WAAW;AACpC,wBAAa,CAAE,EAAG,CAAE,IAAI,WAAW;AAAA,UACpC;AAAA,QACD;AAAA,MACD,OAAO;AAGN,cAAM,WAAmB,OAAQ,OAAO,IAAK;AAG7C,YAAI,aAAa,MAAO;AACvB,gBAAM,MAAM,WAAW;AACvB,wBAAc;AAAA,YACb,IAAI,aAAc,CAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAI,CAAE;AAAA,YAC7C,IAAI,aAAc,CAAG,KAAM,KAAM,KAAM,GAAI,CAAE;AAAA,UAC9C;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,QAAI,YAAoB,SAAU,MAAM,IAAK;AAG7C,UAAM,gBAAgB,WAAW,OAAO;AACxC,UAAM,eAAe,WAAW,OAAO;AACvC,UAAM,iBAAiB,gBAAiB,WAAW,MAAO;AAE1D,eAAW,OAAO,QAAQ;AAC1B,eAAW,OAAO,YAAY;AAG9B,QAAI,iBAAiB;AACrB,QAAI,kBAAkB,QAAQ,gBAAgB,MAAO;AACpD,uBAAiB;AAAA,IAClB,WACC,kBAAkB,QAAQ,gBAAgB,QAC1C,kBAAkB,QAAQ,gBAAgB,MACzC;AACD,uBAAiB;AAAA,IAClB,OAAO;AACN,uBAAiB,KAAK,UAAW,aAAc,MAAM,KAAK,UAAW,WAAY;AAAA,IAClF;AAGA,UAAM,gBAAgB,iBAAiB;AAGvC,QAAI,kBAAkB,eAAgB;AACrC,MAAW,iBAAkB,YAAY,cAAe;AAAA,IACzD;AAAA,EACD;;;ACvLA;;;ACAA,MAAAC,iBAAA;;;ACAA;;;ACAA,MAAAC,iBAAA;;;ACAA;;;AC8BO,MAAM,eAAe;AACrB,MAAM,cAAc;AACpB,MAAM,iBAAiB;AACvB,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAGnC,MAAM,sBAAsB,KAAK,IAAK,GAAG,CAAE;AAG3C,MAAM,2BAA2B;AACjC,MAAM,uBAAuB,2BAA2B;AAGxD,MAAM,2BAA2B;AACjC,MAAM,uBAAuB,2BAA2B;AAGxD,MAAM,8BAA8B;AACpC,MAAM,0BAA0B,8BAA8B;AAG9D,MAAM,iCAAiC;AAGvC,MAAM,cAAc,CAAE,UAAU,SAAS,YAAY,kBAAkB,eAAgB;AAGvF,MAAM,eAAe;AAAA;AAAA,IAGpB,QAAQ;AAAA,IACR,uBAAuB;AAAA;AAAA,IAEvB,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA;AAAA,IAGT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,2BAA2B;AAAA;AAAA,IAG3B,eAAe;AAAA,IACf,cAAc;AAAA,IACd,iBAAiB;AAAA;AAAA,IAGjB,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,OAAO;AAAA;AAAA,IAGP,cAAc;AAAA,IACd,WAAW;AAAA;AAAA,IAGX,QAAQ;AAAA;AAAA,IAGR,aAAa;AAAA,EACd;AAEA,MAAM,YAAY,OAAO,SAAS,OAAO,SAAU,aAAc;AAa1D,WAASC,QAAO;AAGtB,IAAgB,kBAAmB,WAAW,CAAC,CAAE;AACjD,IAAgB,kBAAmB,aAAa;AAAA,MAC/C,gBAAgB;AAAA,MAChB,aAAa,CAAC;AAAA,MACd,mBAAmB,oBAAI,IAAI;AAAA,IAC5B,CAAE;AAAA,EACH;AAOO,WAAS,cAAe,YAAa;AAG3C,eAAW,QAAS,YAAa,IAAI,YAAa,YAAY,YAAa;AAC3E,eAAW,QAAS,WAAY,IAAI,YAAa,YAAY,WAAY;AACzE,eAAW,QAAS,cAAe,IAAI,YAAa,YAAY,cAAe;AAC/E,eAAW,QAAS,oBAAqB,IAAI,YAAa,YAAY,oBAAqB;AAC3F,eAAW,QAAS,mBAAoB,IAAI,YAAa,YAAY,mBAAoB;AAAA,EAC1F;AASO,WAAS,YAAa,YAAY,MAAO;AAE/C,UAAM,KAAK,WAAW;AACtB,UAAM,QAAQ,OAAO,OAAQ,YAAa;AAG1C,QAAI,SAAS;AACb,QAAI,SAAS,cAAe;AAC3B,gBAAU;AACV,gBAAUC;AACV,YAAM,WAAW;AACjB,YAAM,cAAc;AACpB,YAAM,cAAc;AACpB,YAAM,OAAO,GAAG;AAAA,IACjB,WAAW,SAAS,eAAe,SAAS,qBAAsB;AACjE,gBAAU;AACV,gBAAUC;AACV,YAAM,WAAW;AACjB,YAAM,cAAc;AACpB,YAAM,cAAc;AACpB,YAAM,OAAO,GAAG;AAChB,YAAM,aAAa;AACnB,UAAI,SAAS,aAAc;AAC1B,cAAM,sBAAsB;AAAA,MAC7B;AAAA,IACD,WAAW,SAAS,gBAAiB;AACpC,gBAAU;AACV,gBAAUD;AACV,YAAM,WAAW;AACjB,YAAM,cAAc;AACpB,YAAM,cAAc;AACpB,YAAM,OAAO,GAAG;AAAA,IACjB,WAAW,SAAS,sBAAuB;AAC1C,gBAAU;AACV,gBAAUA;AACV,YAAM,WAAW;AACjB,YAAM,cAAc;AACpB,YAAM,cAAc;AACpB,YAAM,OAAO,GAAG;AAChB,YAAM,sBAAsB;AAAA,IAC7B,OAAO;AACN,YAAM,mCAAmC,IAAI;AAAA,IAC9C;AAGA,UAAM,UAAoB,oBAAqB,IAAI,SAAS,OAAQ;AAGpE,UAAM,YAAY;AAAA,MACjB,YAAY,GAAG,kBAAmB,MAAM,SAAS,YAAa;AAAA,MAC9D,SAAS,GAAG,kBAAmB,MAAM,SAAS,SAAU;AAAA,MACxD,cAAc,GAAG,mBAAoB,MAAM,SAAS,cAAe;AAAA,IACpE;AAGA,QACC,SAAS,gBAAgB,SAAS,wBAAwB,SAAS,gBAClE;AACD,YAAM,UAAU,WAAW,GAAG,mBAAoB,MAAM,SAAS,YAAa;AAC9E,YAAM,UAAU,WAAW,GAAG,mBAAoB,MAAM,SAAS,YAAa;AAC9E,YAAM,UAAU,OAAO,GAAG,mBAAoB,MAAM,SAAS,QAAS;AAAA,IACvE;AAGA,UAAM,OAAO;AAGb,QAAI,MAAM,eAAe,MAAO;AAG/B,YAAM,UAAU,WAAW,GAAG,kBAAmB,MAAM,SAAS,YAAa;AAC7E,YAAM,UAAU,UAAU,GAAG,mBAAoB,MAAM,SAAS,WAAY;AAG5E,YAAM,YAAY,IAAI,aAAc,MAAM,WAAW,MAAM,aAAc;AAGzE,YAAM,cAAc,GAAG,aAAa;AAAA,IACrC;AAGA,UAAM,WAAW,IAAI,aAAc,MAAM,WAAW,MAAM,WAAY;AACtE,UAAM,SAAS,IAAI,WAAY,MAAM,WAAW,MAAM,UAAW;AACjE,UAAM,YAAY,GAAG,aAAa;AAClC,UAAM,WAAW,GAAG,aAAa;AAGjC,UAAM,MAAM,GAAG,kBAAkB;AACjC,OAAG,gBAAiB,MAAM,GAAI;AAG9B,OAAG,WAAY,GAAG,cAAc,MAAM,SAAU;AAChD,OAAG,wBAAyB,MAAM,UAAU,QAAS;AACrD,OAAG;AAAA,MACF,MAAM,UAAU;AAAA,MAAU,MAAM;AAAA,MAAa,GAAG;AAAA,MAAO;AAAA,MAAO;AAAA,MAAG;AAAA,IAClE;AAGA,OAAG,WAAY,GAAG,cAAc,MAAM,QAAS;AAC/C,OAAG,wBAAyB,MAAM,UAAU,KAAM;AAClD,OAAG;AAAA,MACF,MAAM,UAAU;AAAA,MAAO,MAAM;AAAA,MAAY,GAAG;AAAA,MAAe;AAAA,MAAM;AAAA,MAAG;AAAA,IACrE;AAGA,QAAI,MAAM,eAAe,MAAO;AAC/B,SAAG,WAAY,GAAG,cAAc,MAAM,WAAY;AAClD,SAAG,wBAAyB,MAAM,UAAU,QAAS;AACrD,SAAG;AAAA,QACF,MAAM,UAAU;AAAA,QAAU,MAAM;AAAA,QAAe,GAAG;AAAA,QAAO;AAAA,QAAO;AAAA,QAAG;AAAA,MACpE;AAAA,IACD;AAEA,OAAG,gBAAiB,IAAK;AAGzB,UAAM,0BAA0B,KAAK,IAAI,IAAI;AAE7C,WAAO;AAAA,EACR;AASA,WAAS,YAAa,OAAO,aAAc;AAG1C,UAAM,cAAc,IAAI,aAAc,cAAc,MAAM,WAAY;AACtE,UAAM,YAAY,IAAI,WAAY,cAAc,MAAM,UAAW;AAIjE,QAAI,MAAM,QAAQ,GAAI;AACrB,kBAAY,IAAK,MAAM,SAAS,SAAU,GAAG,MAAM,QAAQ,MAAM,WAAY,CAAE;AAC/E,gBAAU,IAAK,MAAM,OAAO,SAAU,GAAG,MAAM,QAAQ,MAAM,UAAW,CAAE;AAAA,IAC3E;AAEA,UAAM,WAAW;AACjB,UAAM,SAAS;AAEf,QAAI,MAAM,eAAe,MAAO;AAC/B,YAAM,eAAe,IAAI,aAAc,cAAc,MAAM,aAAc;AAGzE,UAAI,MAAM,QAAQ,GAAI;AACrB,qBAAa,IAAK,MAAM,UAAU,SAAU,GAAG,MAAM,QAAQ,MAAM,aAAc,CAAE;AAAA,MACpF;AAEA,YAAM,YAAY;AAAA,IACnB;AAEA,QAAI,WAAY;AACf,cAAQ;AAAA,QACP,SAAS,YAAa,MAAM,IAAK,CAAC,iBAAiB,MAAM,QAAQ,OAAO,WAAW;AAAA,MACpF;AAAA,IACD;AAGA,UAAM,WAAW;AACjB,UAAM,kBAAkB;AAGxB,UAAM,0BAA0B,KAAK,IAAI,IAAI;AAAA,EAC9C;AAWO,WAAS,aAAc,YAAY,WAAW,WAAW,SAAU;AAGzE,UAAM,QAAQ,WAAW,QAAS,SAAU;AAG5C,UAAM,YAAY,WAAW;AAC7B,UAAM,oBAAoB,UAAU,iBAAiB;AACrD,UAAM,kBAAkB,MAAM,eAAe,QAC5C,UAAU,iBAAiB,SAAS,MAAM,YAAY;AAEvD,QAAI,qBAAqB,iBAAkB;AAG1C,UAAI,UAAU,UAAU,SAAS,GAAI;AACpC,cAAM,oBAAoB,UAAU,UAAW,UAAU,UAAU,SAAS,CAAE;AAC9E,0BAAkB,WAAW,kBAAkB,MAAM;AAAA,MACtD;AAGA,YAAM,gBAAgB;AAAA,QACrB,SAAS;AAAA,QACT,cAAc,MAAM;AAAA,QACpB,YAAY;AAAA,QACZ,uBAAuB,MAAM;AAAA,MAC9B;AAGA,UAAI,MAAM,eAAe,MAAO;AAC/B,cAAM,UAAU;AAChB,sBAAc,UAAU;AACxB,kBAAU,gBAAgB,IAAK,OAAQ;AAAA,MACxC;AAGA,gBAAU,UAAU,KAAM,aAAc;AACxC,gBAAU,eAAe;AAAA,IAC1B;AAGA,UAAM,gBAAgB,MAAM,QAAQ;AACpC,QAAI,iBAAiB,MAAM,UAAW;AAGrC,UAAI,gBAAgB,MAAM,aAAc;AACvC,YAAI,WAAY;AACf,kBAAQ;AAAA,YACP,SAAS,YAAa,MAAM,IAAK,CAAC,yBAC/B,MAAM,WAAW,eAAe,aAAa;AAAA,UAEjD;AAAA,QACD;AAEA,qBAAc,UAAW;AACzB,eAAO,aAAc,YAAY,WAAW,WAAW,OAAQ;AAAA,MAChE;AAGA,YAAM,cAAc,KAAK;AAAA,QACxB;AAAA,QAAe,KAAK,IAAK,MAAM,WAAW,GAAG,MAAM,WAAY;AAAA,MAChE;AACA,kBAAa,OAAO,WAAY;AAAA,IACjC;AAAA,EACD;AAUO,WAAS,aAAc,YAAY,SAAS,MAAO;AACzD,QAAI,WAAW,MAAO;AACrB,eAAS,WAAW;AAAA,IACrB;AAEA,UAAM,KAAK,WAAW;AAEtB,QAAI,WAAW,aAAc;AAI5B;AAAA,IACD;AAGA,OAAG,gBAAiB,GAAG,aAAa,WAAW,GAAI;AAGnD,OAAG,SAAU,GAAG,GAAG,WAAW,OAAO,WAAW,MAAO;AAGvD,QAAI,WAAW,eAAgB;AAC9B,SAAG,WAAY,GAAG,GAAG,GAAG,CAAE;AAC1B,SAAG,MAAO,GAAG,gBAAiB;AAC9B,iBAAW,gBAAgB;AAAA,IAC5B;AAGA,eAAW,aAAa,WAAW,SAAU;AAC5C,YAAM,QAAQ,WAAW,QAAS,SAAU;AAC5C,UAAI,MAAM,QAAQ,GAAI;AACrB,oBAAa,IAAI,OAAO,WAAW,OAAO,WAAW,MAAO;AAAA,MAC7D;AAAA,IACD;AAGA,eAAW,iBAAiB,WAAW,UAAU,WAAY;AAC5D,UAAI,cAAc,aAAa,MAAO;AACrC,sBAAc,WAAW,cAAc,MAAM;AAAA,MAC9C;AAGA,UAAI,cAAc,WAAW,cAAc,aAAa,GAAI;AAG3D,YAAI,cAAc,wBAAwB,MAAO;AAGhD,cAAI,OAAO,UAAmB,eAAgB;AAC7C,eAAG,QAAS,GAAG,KAAM;AAAA,UACtB,OAAO;AACN,eAAG,OAAQ,GAAG,KAAM;AACpB,eAAG;AAAA,cACF,GAAG;AAAA;AAAA,cACH,GAAG;AAAA;AAAA,cACH,GAAG;AAAA;AAAA,cACH,GAAG;AAAA;AAAA,YACJ;AAAA,UACD;AAAA,QAED,WAAW,cAAc,wBAAwB,MAAO;AAGvD,aAAG,OAAQ,GAAG,KAAM;AACpB,aAAG;AAAA,YACF,GAAG;AAAA;AAAA,YACH,GAAG;AAAA;AAAA,YACH,GAAG;AAAA;AAAA,YACH,GAAG;AAAA;AAAA,UACJ;AAAA,QACD,OAAO;AACN,aAAG,QAAS,GAAG,KAAM;AAAA,QACtB;AAEA,YAAI,UAAU;AACd,YAAI,cAAc,MAAM,eAAe,MAAO;AAC7C,oBAAU,cAAc;AAAA,QACzB;AACA;AAAA,UACC;AAAA,UAAI;AAAA,UAAY,cAAc;AAAA,UAC9B,cAAc;AAAA,UAAY,cAAc;AAAA,UAAU;AAAA,UAAS;AAAA,QAC5D;AAAA,MACD;AAAA,IACD;AAGA,eAAW,aAAa,WAAW,SAAU;AAC5C,YAAM,QAAQ,WAAW,QAAS,SAAU;AAC5C,iBAAY,KAAM;AAAA,IACnB;AAGA,eAAW,UAAU,YAAY,CAAC;AAClC,eAAW,UAAU,eAAe;AACpC,eAAW,UAAU,gBAAgB,MAAM;AAG3C,OAAG,gBAAiB,IAAK;AAGzB,OAAG,gBAAiB,GAAG,aAAa,IAAK;AAAA,EAC1C;AAWA,WAAS,YAAa,IAAI,OAAO,OAAO,QAAS;AAChD,OAAG,WAAY,MAAM,OAAQ;AAC7B,OAAG,UAAW,MAAM,UAAU,YAAY,OAAO,MAAO;AACxD,OAAG,gBAAiB,MAAM,GAAI;AAG9B,QAAI,MAAM,iBAAkB;AAC3B,SAAG,WAAY,GAAG,cAAc,MAAM,SAAU;AAChD,SAAG,WAAY,GAAG,cAAc,MAAM,SAAS,YAAY,GAAG,WAAY;AAC1E,SAAG,WAAY,GAAG,cAAc,MAAM,QAAS;AAC/C,SAAG,WAAY,GAAG,cAAc,MAAM,OAAO,YAAY,GAAG,WAAY;AAExE,UAAI,MAAM,eAAe,MAAO;AAC/B,WAAG,WAAY,GAAG,cAAc,MAAM,WAAY;AAClD,WAAG,WAAY,GAAG,cAAc,MAAM,UAAU,YAAY,GAAG,WAAY;AAAA,MAC5E;AAEA,YAAM,kBAAkB;AAAA,IACzB;AAGA,OAAG,WAAY,GAAG,cAAc,MAAM,SAAU;AAChD,OAAG;AAAA,MACF,GAAG;AAAA,MAAc;AAAA,MAAG,MAAM,SAAS,SAAU,GAAG,MAAM,QAAQ,MAAM,WAAY;AAAA,IACjF;AAGA,OAAG,WAAY,GAAG,cAAc,MAAM,QAAS;AAC/C,OAAG;AAAA,MACF,GAAG;AAAA,MAAc;AAAA,MAAG,MAAM,OAAO,SAAU,GAAG,MAAM,QAAQ,MAAM,UAAW;AAAA,IAC9E;AAGA,QAAI,MAAM,eAAe,MAAO;AAC/B,SAAG,WAAY,GAAG,cAAc,MAAM,WAAY;AAClD,SAAG;AAAA,QACF,GAAG;AAAA,QAAc;AAAA,QAAG,MAAM,UAAU,SAAU,GAAG,MAAM,QAAQ,MAAM,aAAc;AAAA,MACpF;AAAA,IACD;AAAA,EACD;AAcA,WAAS,UAAW,IAAI,YAAY,OAAO,YAAY,UAAU,UAAU,MAAM,SAAS,MAAO;AAEhG,OAAG,WAAY,MAAM,OAAQ;AAC7B,OAAG,gBAAiB,MAAM,GAAI;AAG9B,QAAI,MAAM,eAAe,QAAQ,SAAU;AAC1C,SAAG,cAAe,GAAG,QAAS;AAC9B,SAAG,YAAa,GAAG,YAAY,OAAQ;AACvC,SAAG,UAAW,MAAM,UAAU,SAAS,CAAE;AAAA,IAC1C;AAGA,QAAI,MAAM,UAAU,aAAa,QAAY;AAC5C,UAAI,WAAW,MAAO;AACrB,iBAAS,WAAW;AAAA,MACrB;AACA,YAAM,QAAQ,OAAO;AACrB,YAAM,YAAY,OAAO;AAGzB,UAAI,UAAU;AACd,UAAI,UAAU,MAAO;AAGpB,mBAAW,IAAI,aAAc,CAAE,GAAK,GAAK,GAAK,CAAI,CAAE;AACpD,mBAAW,IAAI,aAAc,CAAE,GAAK,GAAK,GAAK,CAAI,CAAE;AAAA,MACrD,OAAO;AAEN,mBAAW,MAAO,CAAE;AACpB,mBAAW,MAAO,CAAE;AAAA,MACrB;AAEA,SAAG,WAAY,MAAM,UAAU,UAAU,QAAS;AAClD,SAAG,WAAY,MAAM,UAAU,UAAU,QAAS;AAIlD,UAAI;AACJ,UAAI,cAAc,MAAO;AACxB,oBAAY,YAAY;AAAA,MACzB,OAAO;AACN,oBAAY,YAAY,IAAI,IAAI;AAAA,MACjC;AACA,SAAG,UAAW,MAAM,UAAU,MAAM,SAAU;AAAA,IAC/C;AAGA,OAAG,WAAY,MAAM,MAAM,YAAY,WAAW,UAAW;AAAA,EAC9D;AASO,WAAS,aAAc,YAAa;AAG1C,eAAW,aAAa,WAAW,SAAU;AAC5C,YAAM,QAAQ,WAAW,QAAS,SAAU;AAC5C,iBAAY,KAAM;AAAA,IACnB;AAGA,eAAW,UAAU,YAAY,CAAC;AAClC,eAAW,UAAU,eAAe;AACpC,eAAW,UAAU,gBAAgB,MAAM;AAAA,EAC5C;AAQA,WAAS,WAAY,OAAQ;AAG5B,UAAM,mBAAmB,KAAK,IAAK,MAAM,OAAO,MAAM,gBAAiB;AAGvE,UAAM,QAAQ;AAEd,QAAI,MAAM,eAAe,MAAO;AAC/B,YAAM,UAAU;AAChB,YAAM,QAAQ;AAAA,IACf;AAGA,QAAI,KAAK,IAAI,IAAI,MAAM,yBAA0B;AAGhD,UAAI,MAAM,WAAW,MAAM,eAAe,MAAM,mBAAmB,MAAM,WAAW,KAAM;AAGzF,oBAAa,OAAO,KAAK,IAAK,MAAM,WAAW,KAAK,MAAM,WAAY,CAAE;AAAA,MACzE;AAEA,YAAM,0BAA0B,KAAK,IAAI,IAAI;AAC7C,YAAM,mBAAmB;AAAA,IAC1B;AAAA,EACD;AAQO,WAAS,gBAAiB,YAAa;AAE7C,UAAM,KAAK,WAAW;AACtB,UAAM,UAAU,WAAW;AAC3B,UAAM,YAAY,WAAW;AAG7B,OAAG,gBAAiB,GAAG,aAAa,IAAK;AAGzC,OAAG,SAAU,GAAG,GAAG,WAAW,OAAO,OAAO,WAAW,OAAO,MAAO;AAGrE,OAAG,WAAY,GAAG,GAAG,GAAG,CAAE;AAC1B,OAAG,MAAO,GAAG,gBAAiB;AAG9B,OAAG,QAAS,GAAG,KAAM;AAGrB,OAAG,WAAY,OAAQ;AAGvB,OAAG,wBAAyB,UAAU,QAAS;AAG/C,OAAG,WAAY,GAAG,cAAc,WAAW,qBAAsB;AACjE,OAAG,oBAAqB,UAAU,UAAU,GAAG,GAAG,OAAO,OAAO,GAAG,CAAE;AAGrE,OAAG,cAAe,GAAG,QAAS;AAC9B,OAAG,YAAa,GAAG,YAAY,WAAW,UAAW;AACrD,OAAG,UAAW,UAAU,SAAS,CAAE;AAGnC,OAAG,WAAY,GAAG,WAAW,GAAG,CAAE;AAGlC,OAAG,yBAA0B,UAAU,QAAS;AAAA,EACjD;AAQO,WAAS,QAAS,YAAa;AACrC,UAAM,KAAK,WAAW;AAGtB,eAAW,aAAa,WAAW,SAAU;AAG5C,YAAM,QAAQ,WAAW,QAAS,SAAU;AAG5C,UAAI,MAAM,aAAc;AACvB,WAAG,aAAc,MAAM,WAAY;AAAA,MACpC;AAEA,SAAG,aAAc,MAAM,SAAU;AACjC,SAAG,aAAc,MAAM,QAAS;AAChC,SAAG,kBAAmB,MAAM,GAAI;AAChC,SAAG,cAAe,MAAM,OAAQ;AAEhC,UAAI,MAAM,SAAU;AACnB,WAAG,cAAe,MAAM,OAAQ;AAAA,MACjC;AAAA,IACD;AAGA,eAAW,UAAU;AACrB,eAAW,YAAY;AAAA,EACxB;;;AC/sBO,WAAS,iBAAkB,OAAO,GAAG,GAAG,OAAQ;AACtD,UAAM,MAAM,MAAM,QAAQ,MAAM;AAChC,UAAM,OAAO,MAAM,QAAQ,MAAM;AACjC,UAAM,SAAU,GAAQ,IAAI;AAC5B,UAAM,SAAU,MAAM,CAAE,IAAI;AAC5B,UAAM,OAAQ,IAAS,IAAI,MAAM;AACjC,UAAM,OAAQ,OAAO,CAAE,IAAI,MAAM;AACjC,UAAM,OAAQ,OAAO,CAAE,IAAI,MAAM;AACjC,UAAM,OAAQ,OAAO,CAAE,IAAI,MAAM;AAEjC,UAAM;AAAA,EACP;AAeO,WAAS,mBAAoB,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,OAAQ;AAC1E,qBAAkB,OAAO,IAAI,IAAI,KAAM;AACvC,qBAAkB,OAAO,IAAI,IAAI,KAAM;AACvC,qBAAkB,OAAO,IAAI,IAAI,KAAM;AAAA,EACxC;AAyDO,WAAS,sBAAuB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,UAAW;AAEjF,UAAM,MAAM,CAAC;AAGb,aAAS,oBAAqB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAK;AACtD,YAAM,MAAM,KAAK;AACjB,YAAM,MAAM,KAAK;AACjB,YAAM,MAAM,KAAK;AACjB,YAAM,MAAM,KAAK;AACjB,YAAM,UAAU,MAAM,MAAM,MAAM;AAClC,UAAI,YAAY,EAAI,QAAO,MAAM,MAAM,MAAM;AAC7C,UAAI,KAAM,MAAM,MAAM,MAAM,OAAQ;AACpC,UAAI,IAAI,EAAI,KAAI;AAAA,eAAY,IAAI,EAAI,KAAI;AACxC,YAAM,KAAK,KAAK,IAAI;AACpB,YAAM,KAAK,KAAK,IAAI;AACpB,YAAM,KAAK,KAAK;AAChB,YAAM,KAAK,KAAK;AAChB,aAAO,KAAK,KAAK,KAAK;AAAA,IACvB;AAEA,UAAM,aAAa,WAAW;AAC9B,UAAM,WAAW;AAEjB,aAAS,UAAW,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,OAAQ;AAG3D,YAAM,KAAK,oBAAqB,IAAI,IAAI,IAAI,IAAI,IAAI,EAAG;AACvD,YAAM,KAAK,oBAAqB,IAAI,IAAI,IAAI,IAAI,IAAI,EAAG;AACvD,UAAI,SAAS,YAAc,MAAM,cAAc,MAAM,YAAe;AAEnE,YAAI,IAAI,WAAW,GAAI;AACtB,cAAI,KAAM,IAAI,EAAG;AAAA,QAClB;AACA,YAAI,KAAM,IAAI,EAAG;AACjB;AAAA,MACD;AAGA,YAAM,OAAQ,KAAK,MAAO;AAAK,YAAM,OAAQ,KAAK,MAAO;AACzD,YAAM,OAAQ,KAAK,MAAO;AAAK,YAAM,OAAQ,KAAK,MAAO;AACzD,YAAM,OAAQ,KAAK,MAAO;AAAK,YAAM,OAAQ,KAAK,MAAO;AAEzD,YAAM,SAAU,MAAM,OAAQ;AAAK,YAAM,SAAU,MAAM,OAAQ;AACjE,YAAM,SAAU,MAAM,OAAQ;AAAK,YAAM,SAAU,MAAM,OAAQ;AAEjE,YAAM,QAAS,QAAQ,SAAU;AAAK,YAAM,QAAS,QAAQ,SAAU;AAEvE,gBAAW,IAAI,IAAI,KAAK,KAAK,OAAO,OAAO,MAAM,MAAM,QAAQ,CAAE;AACjE,gBAAW,MAAM,MAAM,OAAO,OAAO,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAE;AAAA,IAClE;AAEA,cAAW,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAE;AAC7C,WAAO;AAAA,EACR;;;AC3JO,MAAM,gBAAgB;AAU7B,MAAM,kBAAkB,oBAAI,IAAI;AAoBzB,WAASE,QAAO;AAGtB,qBAAiB;AAAA,EAClB;AAOA,WAAS,mBAAmB;AAI3B,UAAM,UAAU,4BAA4B;AAC5C,oBAAgB,IAAK,GAAG,aAAa,MAAM,OAAQ;AAGnD,aAAS,SAAS,GAAG,UAAU,IAAI,UAAW;AAC7C,YAAM,WAAW,GAAG,aAAa,IAAI,MAAM;AAG3C,YAAM,WAAW,uBAAwB,MAAO;AAChD,sBAAgB,IAAK,UAAU,QAAS;AAAA,IACzC;AAAA,EACD;AAiBA,WAAS,UAAW,UAAU,MAAM,GAAG,GAAI;AAE1C,aAAU,MAAO,IAAI;AACrB,aAAU,MAAO,IAAI;AACrB,WAAO;AAAA,EACR;AAeA,WAAS,YAAa,UAAU,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,IAAK;AAE9D,WAAO,UAAW,UAAU,MAAM,IAAI,EAAG;AACzC,WAAO,UAAW,UAAU,MAAM,IAAI,EAAG;AACzC,WAAO,UAAW,UAAU,MAAM,IAAI,EAAG;AACzC,WAAO;AAAA,EACR;AAcA,WAAS,QAAS,UAAU,MAAM,IAAI,IAAI,IAAI,IAAK;AAGlD,WAAO,YAAa,UAAU,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,EAAG;AAG3D,WAAO,YAAa,UAAU,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,EAAG;AAC3D,WAAO;AAAA,EACR;AAcA,WAAS,uBAAwB,QAAS;AAEzC,QAAI,UAAU,GAAI;AACjB,aAAO,EAAE,eAAe,GAAG,YAAY,KAAK;AAAA,IAC7C;AAGA,UAAM,iBAAiB,oBAAI,IAAI;AAG/B,QAAI,IAAI,SAAS;AACjB,QAAI,IAAI;AACR,QAAI,MAAM,IAAI;AAGd,UAAM,iBAAiB,CAAE,IAAI,OAAQ;AAEpC,YAAM,SAAS,KAAK;AACpB,YAAM,SAAS,KAAK;AAEpB,UAAI,CAAC,eAAe,IAAK,MAAO,GAAI;AACnC,YAAI,SAAS,GAAI;AAChB,yBAAe,IAAK,QAAQ,EAAE,QAAQ,QAAQ,SAAS,SAAS,CAAE;AAAA,QACnE,WAAW,SAAS,GAAI;AACvB,yBAAe,IAAK,QAAQ,EAAE,QAAQ,WAAW,SAAS,OAAO,CAAE;AAAA,QACpE,OAAO;AACN,yBAAe,IAAK,QAAQ,EAAE,QAAQ,QAAQ,SAAS,OAAO,CAAE;AAAA,QACjE;AAAA,MACD,OAAO;AACN,cAAM,SAAS,eAAe,IAAK,MAAO;AAK1C,YAAI,SAAS,KAAK,SAAS,OAAO,MAAO;AACxC,iBAAO,OAAO;AAAA,QACf;AACA,YAAI,SAAS,KAAK,SAAS,OAAO,OAAQ;AACzC,iBAAO,QAAQ;AAAA,QAChB;AAAA,MACD;AAAA,IACD;AAEA,WAAO,KAAK,GAAI;AAGf,qBAAiB,GAAI,CAAE;AACvB,qBAAiB,GAAI,CAAE;AACvB,qBAAgB,CAAC,GAAI,CAAE;AACvB,qBAAgB,CAAC,GAAI,CAAE;AACvB,qBAAgB,CAAC,GAAG,CAAC,CAAE;AACvB,qBAAgB,CAAC,GAAG,CAAC,CAAE;AACvB,qBAAiB,GAAG,CAAC,CAAE;AACvB,qBAAiB,GAAG,CAAC,CAAE;AAEvB;AACA,UAAI,MAAM,GAAI;AACb,eAAO,IAAI,IAAI;AAAA,MAChB,OAAO;AACN;AACA,eAAO,KAAM,IAAI,KAAM;AAAA,MACxB;AAAA,IACD;AAGA,QAAI,cAAc;AAClB,UAAM,gBAAgB,CAAC;AACvB,eAAW,CAAE,UAAU,EAAG,KAAK,eAAe,QAAQ,GAAI;AACzD,qBAAe;AACf,oBAAc,KAAM,QAAS;AAAA,IAC9B;AAEA,kBAAc,KAAM,CAAE,GAAG,MAAO,IAAI,CAAE;AAEtC,UAAM,WAAW,IAAI,aAAc,cAAc,CAAE;AACnD,QAAI,OAAO;AAGX,aAAQ,MAAM,GAAG,MAAM,cAAc,SAAS,GAAG,OAAO,GAAI;AAC3D,YAAM,WAAW,cAAe,GAAI;AACpC,YAAM,SAAS,eAAe,IAAK,QAAS;AAG5C,YAAM,SAAS,OAAO,OAAO;AAC7B,YAAM,OAAO,OAAO,QAAQ;AAG5B,aAAO,QAAS,UAAU,MAAM,QAAQ,UAAU,OAAO,GAAG,WAAW,CAAE;AAAA,IAC1E;AAEA,WAAO,EAAE,eAAe,aAAa,YAAY,SAAS;AAAA,EAC3D;AAOA,WAAS,8BAA8B;AAGtC,UAAM,cAAc;AACpB,UAAM,WAAW,IAAI,aAAc,cAAc,CAAE;AACnD,QAAI,OAAO;AAGX,WAAO,QAAS,UAAU,MAAM,GAAG,GAAG,GAAG,CAAE;AAE3C,WAAO,EAAE,eAAe,aAAa,YAAY,SAAS;AAAA,EAC3D;AAcA,WAAS,kBAAmB,WAAW,MAAO;AAE7C,UAAM,WAAW,GAAG,SAAS,IAAI,IAAI;AACrC,QAAI,gBAAgB,IAAK,QAAS,GAAI;AACrC,aAAO,gBAAgB,IAAK,QAAS;AAAA,IACtC;AAGA,QAAI;AAEJ,QAAI,cAAc,eAAgB;AACjC,iBAAW,uBAAwB,IAAK;AAAA,IACzC,OAAO;AACN,YAAM,IAAI,MAAO,gCAAgC,SAAS,EAAG;AAAA,IAC9D;AAGA,oBAAgB,IAAK,UAAU,QAAS;AAExC,WAAO;AAAA,EACR;AAkBO,WAAS,mBAAoB,YAAY,WAAW,MAAM,GAAG,GAAG,OAAQ;AAG9E,UAAM,WAAW,kBAAmB,WAAW,IAAK;AACpD,UAAM,QAAQ,WAAW,QAAmB,cAAe;AAG3D,IAAU,aAAc,YAAsB,gBAAgB,SAAS,WAAY;AAGnF,UAAM,WAAW,SAAS;AAC1B,QAAI,OAAO;AAEX,aAAS,IAAI,GAAG,IAAI,SAAS,aAAa,KAAM;AAE/C,YAAM,KAAK,SAAU,MAAO,IAAI;AAChC,YAAM,KAAK,SAAU,MAAO,IAAI;AAChC,MAAe,iBAAkB,OAAO,IAAI,IAAI,KAAM;AAAA,IACvD;AAAA,EACD;;;ACjTO,WAASC,QAAO;AAKtB,IAAgB,kBAAmB,mBAAmB,oBAAI,IAAI,CAAE;AAAA,EACjE;AAgBA,WAAS,mBAAoB,IAAI,KAAM;AAGtC,QAAI,IAAI,QAAS;AAChB,YAAM,gBAAgC,kBAAgB,IAAK,GAAI;AAC/D,UAAI,eAAgB;AAGnB,QAAU,aAAc,aAAc;AAGtC,YAAI,cAAc,OAAO,IAAK;AAG7B,gBAAM,QAAQ,cAAc;AAC5B,gBAAM,QAAQ,cAAc;AAC5B,gBAAM,SAAS,cAAc;AAG7B,gBAAM,YAAY,IAAI,WAAY,QAAQ,SAAS,CAAE;AAGrD,gBAAM,gBAAiB,MAAM,aAAa,cAAc,GAAI;AAC5D,gBAAM,WAAY,GAAG,GAAG,OAAO,QAAQ,MAAM,MAAM,MAAM,eAAe,SAAU;AAClF,gBAAM,gBAAiB,MAAM,aAAa,IAAK;AAI/C,gBAAM,UAAU,QAAQ;AACxB,gBAAM,UAAU,IAAI,WAAY,OAAQ;AACxC,mBAAS,IAAI,GAAG,IAAI,KAAK,MAAO,SAAS,CAAE,GAAG,KAAM;AACnD,kBAAM,SAAS,IAAI;AACnB,kBAAM,aAAc,SAAS,IAAI,KAAM;AAGvC,oBAAQ,IAAK,UAAU,SAAU,QAAQ,SAAS,OAAQ,CAAE;AAC5D,sBAAU,IAAK,UAAU,SAAU,WAAW,YAAY,OAAQ,GAAG,MAAO;AAC5E,sBAAU,IAAK,SAAS,SAAU;AAAA,UACnC;AAGA,aAAG;AAAA,YACF,GAAG;AAAA,YAAY;AAAA,YAAG,GAAG;AAAA,YAAM;AAAA,YAAO;AAAA,YAAQ;AAAA,YAAG,GAAG;AAAA,YAAM,GAAG;AAAA,YACzD;AAAA,UACD;AAAA,QACD,OAAO;AAGN,aAAG,gBAAiB,GAAG,kBAAkB,cAAc,GAAI;AAC3D,aAAG;AAAA,YACF,GAAG;AAAA,YAAY;AAAA,YAAG,GAAG;AAAA,YAAM;AAAA,YAAG;AAAA,YAAG,cAAc;AAAA,YAAO,cAAc;AAAA,YAAQ;AAAA,UAC7E;AACA,aAAG,gBAAiB,GAAG,kBAAkB,IAAK;AAAA,QAC/C;AAAA,MACD,OAAO;AAGN,WAAG,WAAY,GAAG,YAAY,GAAG,GAAG,MAAM,GAAG,MAAM,GAAG,eAAe,GAAI;AAAA,MAC1E;AAAA,IACD,OAAO;AACN,SAAG,WAAY,GAAG,YAAY,GAAG,GAAG,MAAM,GAAG,MAAM,GAAG,eAAe,GAAI;AAAA,IAC1E;AAAA,EACD;AAUO,WAAS,iBAAkB,YAAY,KAAM;AAInD,QAAI,oBAAoB,WAAW,gBAAgB,IAAK,GAAI;AAC5D,QAAI,CAAC,mBAAoB;AACxB,0BAAoB,oBAAI,IAAI;AAC5B,iBAAW,gBAAgB,IAAK,KAAK,iBAAkB;AAAA,IACxD;AAGA,UAAM,kBAAkC,kBAAgB,IAAK,GAAI;AACjE,QAAI,iBAAkB;AAGrB,MAAU,aAAc,eAAgB;AACxC,MAAU,gBAAiB,eAAgB;AAAA,IAC5C;AAGA,UAAM,KAAK,WAAW;AACtB,QAAI,UAAU,kBAAkB,IAAK,EAAG;AACxC,QAAI,SAAU;AAGb,UACC,eAAe,qBACb,OAAO,oBAAoB,eAAe,eAAe,mBAC3D,IAAI,QACH;AAKD,YAAI,IAAI,YAAY,UAAa,IAAI,YAAY,OAAQ;AACxD,iBAAO;AAAA,QACR;AAIA,YAAI,WAAW,UAAU,gBAAgB,IAAK,OAAQ,GAAI;AACzD,UAAU,aAAc,UAAW;AAAA,QACpC;AAGA,WAAG,YAAa,GAAG,YAAY,OAAQ;AACvC,2BAAoB,IAAI,GAAI;AAC5B,WAAG,YAAa,GAAG,YAAY,IAAK;AAAA,MACrC;AACA,aAAO;AAAA,IACR;AAGA,cAAU,GAAG,cAAc;AAC3B,QAAI,CAAC,SAAU;AACd,YAAM,QAAQ,IAAI,MAAO,4CAA6C;AACtE,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,OAAG,YAAa,GAAG,YAAY,OAAQ;AACvC,uBAAoB,IAAI,GAAI;AAG5B,OAAG,cAAe,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAQ;AACnE,OAAG,cAAe,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAQ;AACnE,OAAG,cAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAc;AACrE,OAAG,cAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAc;AAGrE,OAAG,YAAa,GAAG,YAAY,IAAK;AAGpC,sBAAkB,IAAK,IAAI,OAAQ;AAEnC,WAAO;AAAA,EACR;AAUO,WAAS,oBAAqB,YAAY,KAAM;AAGtD,UAAM,aAAa,WAAW,gBAAgB,IAAK,GAAI;AACvD,QAAI,CAAC,YAAa;AACjB;AAAA,IACD;AAGA,QAAI,WAAW,SAAS,GAAI;AAC3B,iBAAW,gBAAgB,OAAQ,GAAI;AAAA,IACxC;AAAA,EACD;AAgBO,WAAS,4BACf,YAAY,QAAQ,WAAW,OAAO,QAAQ,MAAM,MACnD;AAED,QAAI,CAAC,WAAW,IAAK;AACpB,aAAO;AAAA,IACR;AAEA,UAAM,KAAK,WAAW;AACtB,QAAI;AAGJ,QAAI,WAAW,MAAO;AACrB,gBAAU,WAAW;AACrB,UAAI,CAAC,SAAU;AACd,eAAO;AAAA,MACR;AAAA,IACD,OAAO;AAGN,gBAAU,iBAAkB,YAAY,MAAO;AAAA,IAChD;AAIA,QAAI,WAAW,UAAU,gBAAgB,IAAK,OAAQ,GAAI;AACzD,MAAU,aAAc,UAAW;AAAA,IACpC;AAEA,OAAG,YAAa,GAAG,YAAY,OAAQ;AAGvC,OAAG;AAAA,MACF,GAAG;AAAA,MAAY;AAAA,MAAG;AAAA,MAAM;AAAA,MACxB;AAAA,MAAO;AAAA,MACP,GAAG;AAAA,MAAM,GAAG;AAAA,MAAe;AAAA,IAC5B;AAGA,OAAG,cAAe,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAQ;AACnE,OAAG,cAAe,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAQ;AACnE,OAAG,cAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAc;AACrE,OAAG,cAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAc;AAErE,OAAG,YAAa,GAAG,YAAY,IAAK;AAEpC,WAAO;AAAA,EACR;AAaO,WAAS,yBAA0B,YAAY,QAAQ,WAAW,OAAO,QAAS;AAGxF,QAAI,UAAU,iBAAkB,YAAY,MAAO;AAInD,QAAI,WAAW,UAAU,iBAAiB,IAAK,OAAQ,GAAI;AAC1D,MAAU,aAAc,UAAW;AAAA,IACpC;AAEA,UAAM,KAAK,WAAW;AACtB,OAAG,YAAa,GAAG,YAAY,OAAQ;AAGvC,OAAG;AAAA,MACF,GAAG;AAAA,MAAY;AAAA,MAAG,GAAG;AAAA,MACrB;AAAA,MAAO;AAAA,MAAQ;AAAA,MACf,GAAG;AAAA,MAAM,GAAG;AAAA,MAAe;AAAA,IAC5B;AAQA,OAAG,YAAa,GAAG,YAAY,IAAK;AAEpC,WAAO;AAAA,EACR;;;AC1SO,WAASC,QAAO;AAAA,EAEvB;AAUO,WAAS,UAAW,YAAY,GAAG,GAAI;AAG7C,IAAU,aAAc,UAAW;AAEnC,UAAM,KAAK,WAAW;AACtB,UAAM,eAAe,WAAW;AAGhC,UAAM,MAAQ,eAAe,IAAM;AACnC,UAAM,MAAM,IAAI,WAAY,CAAE;AAE9B,OAAG,gBAAiB,GAAG,aAAa,WAAW,GAAI;AACnD,OAAG,WAAY,GAAG,KAAK,GAAG,GAAG,GAAG,MAAM,GAAG,eAAe,GAAI;AAC5D,OAAG,gBAAiB,GAAG,aAAa,IAAK;AAEzC,WAAe,WAAY,IAAK,CAAE,GAAG,IAAK,CAAE,GAAG,IAAK,CAAE,GAAG,IAAK,CAAE,CAAE;AAAA,EACnE;AAUO,WAAS,eAAgB,YAAY,GAAG,GAAI;AAOlD,WAAO,IAAI,QAAS,CAAE,YAAa;AAClC,MAAQC,gBAAgB,MAAM;AAC7B,gBAAS,UAAW,YAAY,GAAG,CAAE,CAAE;AAAA,MACxC,CAAE;AAAA,IACH,CAAE;AAAA,EACH;AAYO,WAAS,WAAY,YAAY,GAAG,GAAG,OAAO,QAAS;AAC7D,UAAM,KAAK,WAAW;AACtB,UAAM,cAAc,WAAW;AAC/B,UAAM,eAAe,WAAW;AAGhC,UAAM,WAAW,KAAK,IAAK,GAAG,CAAE;AAChC,UAAM,WAAW,KAAK,IAAK,GAAG,CAAE;AAChC,UAAM,eAAe,KAAK,IAAK,OAAO,cAAc,QAAS;AAC7D,UAAM,gBAAgB,KAAK,IAAK,QAAQ,eAAe,QAAS;AAGhE,QAAI,gBAAgB,KAAK,iBAAiB,GAAI;AAC7C,aAAO,CAAC;AAAA,IACT;AAGA,IAAU,aAAc,UAAW;AAGnC,UAAM,MAAM,IAAI,WAAY,eAAe,gBAAgB,CAAE;AAK7D,UAAM,UAAY,gBAAiB,WAAW;AAE9C,OAAG,gBAAiB,GAAG,aAAa,WAAW,GAAI;AACnD,OAAG,WAAY,UAAU,SAAS,cAAc,eAAe,GAAG,MAAM,GAAG,eAAe,GAAI;AAC9F,OAAG,gBAAiB,GAAG,aAAa,IAAK;AAIzC,UAAM,eAAe,IAAI,MAAO,aAAc;AAC9C,aAAS,MAAM,GAAG,MAAM,eAAe,OAAQ;AAE9C,YAAM,aAAa,IAAI,MAAO,YAAa;AAC3C,eAAS,MAAM,GAAG,MAAM,cAAc,OAAQ;AAK7C,cAAM,SAAW,gBAAgB,IAAM;AACvC,cAAM,KAAQ,eAAe,SAAW,OAAQ;AAChD,mBAAY,GAAI,IAAY;AAAA,UAC3B,IAAK,CAAE;AAAA,UAAG,IAAK,IAAI,CAAE;AAAA,UAAG,IAAK,IAAI,CAAE;AAAA,UAAG,IAAK,IAAI,CAAE;AAAA,QAClD;AAAA,MACD;AACA,mBAAc,GAAI,IAAI;AAAA,IACvB;AAEA,WAAO;AAAA,EACR;AAYO,WAAS,gBAAiB,YAAY,GAAG,GAAG,OAAO,QAAS;AAClE,WAAO,IAAI,QAAS,CAAE,YAAa;AAClC,MAAQA,gBAAgB,MAAM;AAC7B,gBAAS,WAAY,YAAY,GAAG,GAAG,OAAO,MAAO,CAAE;AAAA,MACxD,CAAE;AAAA,IACH,CAAE;AAAA,EACH;AAeO,WAAS,cAAe,YAAY,GAAG,GAAG,OAAO,QAAS;AAChE,UAAM,KAAK,WAAW;AACtB,UAAM,cAAc,WAAW;AAC/B,UAAM,eAAe,WAAW;AAGhC,UAAM,WAAW,KAAK,IAAK,GAAG,CAAE;AAChC,UAAM,WAAW,KAAK,IAAK,GAAG,CAAE;AAChC,UAAM,eAAe,KAAK,IAAK,OAAO,cAAc,QAAS;AAC7D,UAAM,gBAAgB,KAAK,IAAK,QAAQ,eAAe,QAAS;AAGhE,QAAI,gBAAgB,KAAK,iBAAiB,GAAI;AAC7C,aAAO;AAAA,IACR;AAGA,IAAU,aAAc,UAAW;AAGnC,UAAM,MAAM,IAAI,WAAY,eAAe,gBAAgB,CAAE;AAK7D,UAAM,UAAY,gBAAiB,WAAW;AAE9C,OAAG,gBAAiB,GAAG,aAAa,WAAW,GAAI;AACnD,OAAG,WAAY,UAAU,SAAS,cAAc,eAAe,GAAG,MAAM,GAAG,eAAe,GAAI;AAC9F,OAAG,gBAAiB,GAAG,aAAa,IAAK;AAGzC,WAAO;AAAA,EACR;;;AChMA,MAAM,0BAA0B;AAChC,MAAM,iBAAiB,oBAAI,IAAI;AAgB/B,WAAS,4BACR,OAAO,QAAQ,SAAS,SAAS,QAAQ,QAAQ,UAAU,GAAG,GAC7D;AAGD,UAAM,cAAc,QAAQ;AAC5B,UAAM,eAAe,SAAS;AAG9B,UAAM,YAAY,KAAK,MAAO,cAAc,OAAQ;AACpD,UAAM,YAAY,KAAK,MAAO,eAAe,OAAQ;AAGrD,UAAM,UAAU;AAAA,MACf,EAAE,KAAK,CAAC,WAAW,KAAK,CAAC,UAAU;AAAA;AAAA,MACnC,EAAE,KAAK,cAAc,WAAW,KAAK,CAAC,UAAU;AAAA;AAAA,MAChD,EAAE,KAAK,CAAC,WAAW,KAAK,eAAe,UAAU;AAAA;AAAA,MACjD,EAAE,KAAK,cAAc,WAAW,KAAK,eAAe,UAAU;AAAA;AAAA,IAC/D;AAGA,QAAI,aAAa,GAAI;AACpB,YAAM,MAAM,KAAK,IAAK,QAAS;AAC/B,YAAM,MAAM,KAAK,IAAK,QAAS;AAC/B,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAM;AACzC,cAAM,SAAS,QAAS,CAAE;AAC1B,cAAM,KAAK,OAAO,IAAI,MAAM,OAAO,IAAI;AACvC,cAAM,KAAK,OAAO,IAAI,MAAM,OAAO,IAAI;AACvC,eAAO,IAAI,KAAK;AAChB,eAAO,IAAI,KAAK;AAAA,MACjB;AAAA,IACD,OAAO;AAGN,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAM;AACzC,gBAAS,CAAE,EAAE,KAAK;AAClB,gBAAS,CAAE,EAAE,KAAK;AAAA,MACnB;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAcA,WAAS,uBACR,YAAY,SAAS,SAAS,WAAW,gBAAgB,WACxD;AAGD,UAAM,QAAQ,WAAW,QAAS,SAAU;AAC5C,IAAU,aAAc,YAAY,WAAW,GAAG,OAAQ;AAE1D,UAAM,gBAAgB,MAAM;AAC5B,UAAM,iBAAiB,MAAM;AAC7B,UAAM,cAAc,MAAM;AAG1B,UAAM,UAAU,MAAM;AACtB,UAAM,aAAa,UAAU,MAAM;AACnC,UAAM,UAAU,UAAU,MAAM;AAChC,UAAM,YAAY,UAAU,MAAM;AAGlC,QAAI,OAAO;AACX,QAAI,OAAO;AAGX,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AACxC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AAGxC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AACxC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AAGxC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AACxC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AAIxC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AACxC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AAGxC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AACxC,mBAAgB,MAAO,IAAI,UAAW,CAAE;AAGxC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,kBAAe,MAAO,IAAI,QAAS,CAAE,EAAE;AACvC,mBAAgB,MAAO,IAAI,UAAW,EAAG;AACzC,mBAAgB,MAAO,IAAI,UAAW,EAAG;AAEzC,gBAAY,IAAK,gBAAgB,SAAU;AAG3C,UAAM,SAAS;AAAA,EAChB;AAEA,WAAS,kBAAmB,OAAQ;AACnC,QAAI,iBAAiB,eAAe,IAAK,MAAM,GAAI;AAEnD,QAAI,mBAAmB,QAAY;AAGlC,UAAI,eAAe,QAAQ,yBAA0B;AACpD,uBAAe,MAAM;AAAA,MACtB;AAEA,YAAM,IAAI,MAAM;AAChB,YAAM,IAAI,MAAM;AAChB,YAAM,IAAI,MAAM;AAChB,YAAM,IAAI,MAAM;AAGhB,uBAAiB,IAAI,WAAY,EAAG;AACpC,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,CAAE,IAAI;AACtB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AACvB,qBAAgB,EAAG,IAAI;AAGvB,qBAAe,IAAK,MAAM,KAAK,cAAe;AAAA,IAC/C;AACA,WAAO;AAAA,EACR;AAiBO,WAAS,UACf,YAAY,KAAK,GAAG,GAAG,OAAO,SAAS,SAAS,QAAQ,QAAQ,UAChE,YAAsB,aACrB;AAGD,UAAM,UAAqB,iBAAkB,YAAY,GAAI;AAG7D,UAAM,WAAW,IAAI;AACrB,UAAM,YAAY,IAAI;AAGtB,UAAM,UAAU;AAAA,MACf;AAAA,MAAU;AAAA,MAAW;AAAA,MAAS;AAAA,MAAS;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAU;AAAA,MAAG;AAAA,IACrE;AAGA,UAAM,YAAY;AAAA,MACjB;AAAA,MAAG;AAAA;AAAA,MACH;AAAA,MAAG;AAAA;AAAA,MACH;AAAA,MAAG;AAAA;AAAA,MACH;AAAA,MAAG;AAAA;AAAA,MACH;AAAA,MAAG;AAAA;AAAA,MACH;AAAA,MAAG;AAAA;AAAA,IACJ;AAGA;AAAA,MACC;AAAA,MAAY;AAAA,MAAS;AAAA,MAAS;AAAA,MAAW,kBAAmB,KAAM;AAAA,MAAG;AAAA,IACtE;AAAA,EACD;AAuBO,WAAS,WACf,YAAY,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,OAAO,QAAQ,OACtD,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAC7D,YAAsB,aACrB;AAGD,UAAM,UAAqB,iBAAkB,YAAY,GAAI;AAG7D,UAAM,WAAW,IAAI;AACrB,UAAM,YAAY,IAAI;AAGtB,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,KAAK;AAChB,UAAM,MAAO,KAAK,MAAO;AACzB,UAAM,MAAO,KAAK,MAAO;AAGzB,UAAM,UAAU;AAAA,MACf;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAS;AAAA,MAAS;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAU;AAAA,MAAG;AAAA,IAC/D;AAGA,UAAM,YAAY;AAAA,MACjB;AAAA,MAAI;AAAA;AAAA,MACJ;AAAA,MAAI;AAAA;AAAA,MACJ;AAAA,MAAI;AAAA;AAAA,MACJ;AAAA,MAAI;AAAA;AAAA,MACJ;AAAA,MAAI;AAAA;AAAA,MACJ;AAAA,MAAI;AAAA;AAAA,IACL;AAGA;AAAA,MACC;AAAA,MAAY;AAAA,MAAS;AAAA,MAAS;AAAA,MAAW,kBAAmB,KAAM;AAAA,MAAG;AAAA,IACtE;AAAA,EACD;;;AC5RO,WAAS,UAAW,YAAY,GAAG,GAAG,WAAY;AAGxD,IAAU,aAAc,YAAY,WAAW,GAAG,MAAM,IAAK;AAG7D,UAAM,QAAQ,WAAW,QAAS,SAAU;AAC5C,IAAe,iBAAkB,OAAO,GAAG,GAAG,WAAW,KAAM;AAAA,EAChE;AAWO,WAAS,gBAAiB,YAAY,GAAG,GAAG,OAAO,WAAY;AAGrE,UAAM,QAAQ,WAAW,QAAS,SAAU;AAC5C,IAAe,iBAAkB,OAAO,GAAG,GAAG,KAAM;AAAA,EACrD;;;AC/BA,MAAM,SAAS,IAAI,KAAK;AACxB,MAAM,sBAAsB;AAarB,WAAS,QAAS,YAAY,IAAI,IAAI,QAAQ,QAAQ,QAAS;AACrE,UAAM,QAAQ,WAAW;AAGzB,QAAI,KAAK,eAAgB,MAAO;AAChC,QAAI,KAAK,eAAgB,MAAO;AAGhC,QAAI,OAAO,KAAK;AAChB,QAAI,OAAO,GAAI;AACd,cAAQ;AAAA,IACT;AAEA,UAAM,eAAe,QAAQ,SAAS;AACtC,UAAM,aAAa,CAAC,gBAAgB,OAAO,KAAK;AAGhD,UAAM,kBAAkB,KAAK;AAAA,MAC5B;AAAA,MACA,KAAK,KAAM,UAAW,eAAe,SAAS,KAAO;AAAA,IACtD;AAGA,UAAM,aAAuB;AAC7B,IAAU,aAAc,YAAY,YAAY,eAAgB;AAChE,UAAM,QAAQ,WAAW,QAAS,UAAW;AAG7C,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI,OAAO;AACX,QAAI,OAAO;AAEX,QAAI,CAAC,cAAe;AACnB,eAAS,KAAK,IAAK,EAAG;AACtB,eAAS,KAAK,IAAK,EAAG;AACtB,aAAO,KAAK,IAAK,EAAG;AACpB,aAAO,KAAK,IAAK,EAAG;AAAA,IACrB;AAGA,QAAI;AAEJ,QAAI,cAAe;AAClB,iBAAW,SAAU,IAAI,IAAK;AAC7B,QAAe,iBAAkB,OAAO,IAAI,IAAI,KAAM;AAAA,MACvD;AAAA,IACD,WAAW,CAAC,YAAa;AAIxB,iBAAW,SAAU,IAAI,IAAK;AAC7B,cAAM,KAAK,KAAK;AAChB,cAAM,KAAK,KAAK;AAEhB,YAAI,OAAO,KAAK,OAAO,GAAI;AAC1B;AAAA,QACD;AAEA,cAAM,MAAM,SAAS,KAAK,SAAS;AACnC,cAAM,MAAM,OAAO,KAAK,OAAO;AAE/B,YAAI,OAAO,KAAK,OAAO,GAAI;AAC1B,UAAe,iBAAkB,OAAO,IAAI,IAAI,KAAM;AAAA,QACvD;AAAA,MACD;AAAA,IACD,OAAO;AAMN,iBAAW,SAAU,IAAI,IAAK;AAC7B,cAAM,KAAK,KAAK;AAChB,cAAM,KAAK,KAAK;AAEhB,YAAI,OAAO,KAAK,OAAO,GAAI;AAC1B;AAAA,QACD;AAEA,cAAM,MAAM,SAAS,KAAK,SAAS;AACnC,cAAM,MAAM,OAAO,KAAK,OAAO;AAE/B,YAAI,EAAG,OAAO,KAAK,OAAO,IAAM;AAC/B,UAAe,iBAAkB,OAAO,IAAI,IAAI,KAAM;AAAA,QACvD;AAAA,MACD;AAAA,IACD;AAGA,UAAM,cAAc,SAAS;AAG7B,QAAI,cAAc,GAAI;AACrB;AAAA,IACD;AAEA,QAAI,gBAAgB,GAAI;AAGvB,eAAU,KAAK,GAAG,EAAG;AACrB,eAAU,KAAK,GAAG,EAAG;AACrB,eAAU,IAAI,KAAK,CAAE;AACrB,eAAU,IAAI,KAAK,CAAE;AACrB;AAAA,IACD;AAGA,QAAI,IAAI;AACR,QAAI,IAAI;AACR,QAAI,MAAM,IAAI;AAGd,aAAU,KAAK,GAAG,KAAK,CAAE;AACzB,aAAU,KAAK,GAAG,KAAK,CAAE;AACzB,aAAU,KAAK,GAAG,KAAK,CAAE;AACzB,aAAU,KAAK,GAAG,KAAK,CAAE;AAEzB,WAAO,KAAK,GAAI;AACf;AAEA,UAAI,MAAM,GAAI;AACb,eAAO,IAAI,IAAI;AAAA,MAChB,OAAO;AACN;AACA,eAAO,KAAM,IAAI,KAAM;AAAA,MACxB;AAEA,UAAI,MAAM,GAAI;AAGb,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AAAA,MAC1B,OAAO;AAGN,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AACzB,iBAAU,KAAK,GAAG,KAAK,CAAE;AAAA,MAC1B;AAAA,IACD;AAAA,EACD;AAEA,WAAS,eAAgB,OAAQ;AAChC,QAAI,aAAa,QAAQ;AACzB,QAAI,aAAa,GAAI;AACpB,oBAAc;AAAA,IACf;AACA,WAAO;AAAA,EACR;;;AC1JO,WAAS,WAAY,YAAY,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAM;AAChF,UAAM,QAAQ,WAAW;AAGzB,UAAM,WAAW;AACjB,UAAM,MAAqB;AAAA,MAC1B;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,IACzC;AAEA,QAAI,IAAI,SAAS,GAAI;AAGpB,YAAMC,SAAQ,WAAW,QAAmB,YAAa;AACzD,MAAU,aAAc,YAAsB,cAAc,CAAE;AAC9D,MAAe,iBAAkBA,QAAO,MAAM,GAAG,MAAM,GAAG,KAAM;AAChE;AAAA,IACD;AAGA,UAAM,QAAQ,oBAAI,IAAI;AACtB,UAAM,QAAQ,WAAW,QAAmB,YAAa;AAGzD,aAAS,IAAI,GAAG,IAAI,IAAI,IAAI,QAAQ,KAAK,GAAI;AAC5C,YAAM,KAAK,IAAK,CAAE,IAAI;AACtB,YAAM,KAAK,IAAK,IAAI,CAAE,IAAI;AAC1B,YAAM,KAAK,IAAK,IAAI,CAAE,IAAI;AAC1B,YAAM,KAAK,IAAK,IAAI,CAAE,IAAI;AAC1B,UAAI,OAAO,MAAM,OAAO,GAAK;AAE7B,YAAM,KAAK,KAAK,IAAK,KAAK,EAAG;AAC7B,YAAM,KAAK,KAAK,IAAK,KAAK,EAAG;AAC7B,YAAM,aAAa,KAAK,IAAK,IAAI,EAAG,IAAI;AACxC,MAAU,aAAc,YAAsB,cAAc,UAAW;AAEvE,YAAM,KAAK,KAAK,KAAK,IAAI;AACzB,YAAM,KAAK,KAAK,KAAK,IAAI;AACzB,UAAI,MAAM,KAAK;AACf,UAAI,IAAI;AACR,UAAI,IAAI;AAER,aAAO,MAAO;AACb,cAAM,MAAM,IAAI,MAAM;AACtB,YAAI,CAAC,MAAM,IAAK,GAAI,GAAI;AACvB,gBAAM,IAAK,GAAI;AACf,UAAe,iBAAkB,OAAO,GAAG,GAAG,KAAM;AAAA,QACrD;AAEA,YAAI,MAAM,MAAM,MAAM,IAAK;AAC1B;AAAA,QACD;AAEA,cAAM,KAAK,MAAM;AACjB,YAAI,KAAK,CAAC,IAAK;AACd,iBAAO;AACP,eAAK;AAAA,QACN;AACA,YAAI,KAAK,IAAK;AACb,iBAAO;AACP,eAAK;AAAA,QACN;AAAA,MACD;AAAA,IACD;AAAA,EACD;;;AC/DO,WAAS,SAAU,YAAY,IAAI,IAAI,IAAI,IAAK;AACtD,UAAM,QAAQ,WAAW;AAGzB,UAAM,KAAK,KAAK,IAAK,KAAK,EAAG;AAC7B,UAAM,KAAK,KAAK,IAAK,KAAK,EAAG;AAC7B,UAAM,aAAa,KAAK,IAAK,IAAI,EAAG,IAAI;AAGxC,UAAM,QAAQ,WAAW,QAAmB,YAAa;AACzD,IAAU,aAAc,YAAsB,cAAc,UAAW;AAGvE,UAAM,KAAK,KAAK,KAAK,IAAI;AACzB,UAAM,KAAK,KAAK,KAAK,IAAI;AACzB,QAAI,MAAM,KAAK;AAEf,QAAI,IAAI;AACR,QAAI,IAAI;AAER,WAAO,MAAO;AAGb,MAAe,iBAAkB,OAAO,GAAG,GAAG,KAAM;AAGpD,UAAI,MAAM,MAAM,MAAM,IAAK;AAC1B;AAAA,MACD;AAGA,YAAM,KAAK,MAAM;AACjB,UAAI,KAAK,CAAC,IAAK;AACd,eAAO;AACP,aAAK;AAAA,MACN;AACA,UAAI,KAAK,IAAK;AACb,eAAO;AACP,aAAK;AAAA,MACN;AAAA,IACD;AAAA,EACD;;;ACvCO,WAAS,SAAU,YAAY,GAAG,GAAG,OAAO,QAAS;AAC3D,UAAM,KAAK,IAAI,QAAQ;AACvB,UAAM,KAAK,IAAI,SAAS;AACxB,UAAM,QAAQ,WAAW;AAKzB,mBAAgB,YAAY,GAAG,GAAG,OAAO,GAAG,KAAM;AAGlD,QAAI,SAAS,GAAI;AAChB,qBAAgB,YAAY,GAAG,IAAI,SAAS,GAAG,OAAO,GAAG,KAAM;AAAA,IAChE;AAGA,QAAI,QAAQ,KAAK,SAAS,GAAI;AAC7B,qBAAgB,YAAY,IAAI,QAAQ,GAAG,IAAI,GAAG,GAAG,SAAS,GAAG,KAAM;AAAA,IACxE;AAGA,QAAI,SAAS,GAAI;AAChB,qBAAgB,YAAY,GAAG,IAAI,GAAG,GAAG,SAAS,GAAG,KAAM;AAAA,IAC5D;AAAA,EACD;AAcO,WAAS,eAAgB,YAAY,GAAG,GAAG,OAAO,QAAQ,OAAQ;AAGxE,UAAM,QAAQ,WAAW,QAAS,cAAe;AAGjD,IAAU,aAAc,YAAY,gBAAgB,CAAE;AAEtD,UAAM,KAAK;AACX,UAAM,KAAK;AACX,UAAM,KAAK,IAAI;AACf,UAAM,KAAK,IAAI;AAGf,IAAe,mBAAoB,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAM;AAGxE,IAAe,mBAAoB,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAM;AAAA,EACzE;;;AC/DO,WAAS,WAAY,YAAY,IAAI,IAAI,QAAS;AACxD,UAAM,QAAQ,WAAW;AAGzB,QAAI,UAAU,GAAI;AACjB;AAAA,IACD;AAEA,QAAI,WAAW,GAAI;AAClB,MAAU,aAAc,YAAsB,cAAc,CAAE;AAC9D,sBAAiB,YAAY,KAAK,GAAG,IAAI,OAAiB,YAAa;AACvE;AAAA,IACD;AAGA,cAAU;AAGV,QAAI,WAAW,GAAI;AAClB,MAAU,aAAc,YAAsB,cAAc,CAAE;AAC9D,sBAAiB,YAAY,KAAK,GAAG,IAAI,OAAiB,YAAa;AACvE,sBAAiB,YAAY,KAAK,GAAG,IAAI,OAAiB,YAAa;AACvE,sBAAiB,YAAY,IAAI,KAAK,GAAG,OAAiB,YAAa;AACvE,sBAAiB,YAAY,IAAI,KAAK,GAAG,OAAiB,YAAa;AACvE;AAAA,IACD;AAGA,UAAM,kBAAkB,KAAK,MAAO,IAAI,KAAK,KAAK,MAAO;AACzD,IAAU,aAAc,YAAsB,cAAc,eAAgB;AAG5E,QAAI,IAAI;AACR,QAAI,IAAI;AACR,QAAI,MAAM,IAAI;AAGd,oBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,oBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,oBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,oBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAE3E,WAAO,KAAK,GAAI;AACf;AACA,UAAI,MAAM,GAAI;AACb,eAAO,IAAI,IAAI;AAAA,MAChB,OAAO;AACN;AACA,eAAO,KAAM,IAAI,KAAM;AAAA,MACxB;AAEA,UAAI,MAAM,GAAI;AAIb,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAAA,MAC5E,OAAO;AAGN,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAC3E,wBAAiB,YAAY,KAAK,GAAG,KAAK,GAAG,OAAiB,YAAa;AAAA,MAC5E;AAAA,IACD;AAAA,EACD;AAaO,WAAS,iBAAkB,YAAY,IAAI,IAAI,QAAQ,OAAQ;AAGrE,WAAkB;AAAA,MACjB;AAAA,MAAuB;AAAA,MAAe;AAAA,MAAQ;AAAA,MAAI;AAAA,MAAI;AAAA,IACvD;AAAA,EACD;;;AC3FO,WAAS,YAAa,YAAY,IAAI,IAAI,IAAI,IAAI,WAAY;AACpE,UAAM,QAAQ,WAAW;AAGzB,QAAI,KAAK,KAAK,KAAK,GAAI;AACtB;AAAA,IACD;AAGA,QAAI,OAAO,KAAK,OAAO,GAAI;AAC1B,MAAU,aAAc,YAAsB,cAAc,CAAE;AAC9D,YAAM,cAAc,WAAW,QAAmB,YAAa;AAC/D,MAAe,iBAAkB,aAAa,IAAI,IAAI,KAAM;AAC5D;AAAA,IACD;AAIA,UAAM,IAAI;AACV,UAAM,IAAI;AACV,UAAM,YAAY,KAAK,MAAO,KAAM,IAAI,KAAM,KAAK,MAAQ,IAAI,IAAI,MAAQ,IAAI,IAAI,EAAI;AACvF,UAAM,kBAAkB,KAAK,IAAK,GAAG,KAAK,KAAM,SAAU,CAAE;AAG5D,UAAM,mBAA6B;AACnC,IAAU,aAAc,YAAY,kBAAkB,eAAgB;AACtE,UAAM,cAAc,WAAW,QAAS,gBAAiB;AAEzD,UAAM,YAAY,SAAU,IAAI,IAAK;AACpC,YAAM,KAAK,KAAK;AAChB,YAAM,KAAK,KAAK;AAChB,MAAe,iBAAkB,aAAa,IAAI,IAAI,KAAM;AAAA,IAC7D;AAGA,UAAM,gBAAgB,SAAUC,IAAGC,IAAI;AAGtC,UAAID,OAAM,GAAI;AAGb,kBAAW,IAAI,KAAKC,EAAE;AACtB,YAAIA,OAAM,GAAI;AACb,oBAAW,IAAI,KAAKA,EAAE;AAAA,QACvB;AACA;AAAA,MACD;AAEA,UAAIA,OAAM,GAAI;AAGb,kBAAW,KAAKD,IAAG,EAAG;AACtB,kBAAW,KAAKA,IAAG,EAAG;AACtB;AAAA,MACD;AAGA,gBAAW,KAAKA,IAAG,KAAKC,EAAE;AAC1B,gBAAW,KAAKD,IAAG,KAAKC,EAAE;AAC1B,gBAAW,KAAKD,IAAG,KAAKC,EAAE;AAC1B,gBAAW,KAAKD,IAAG,KAAKC,EAAE;AAAA,IAC3B;AAGA,QAAI,IAAI;AACR,QAAI,IAAI;AAER,UAAM,MAAM,KAAK;AACjB,UAAM,MAAM,KAAK;AACjB,QAAI,KAAK,IAAI,MAAM;AACnB,QAAI,KAAK,IAAI,MAAM;AAGnB,QAAI,KAAK,MAAM,MAAM,KAAK,OAAO;AACjC,kBAAe,GAAG,CAAE;AAGpB,UAAM,SAAS,cAAc,QAAQ,MAAM,KAAK,MAAM;AACtD,QAAI,iBAAiB;AACrB,QAAI,oBAAoB;AAExB,QAAI,QAAS;AAGZ,uBAAiB,oBAAI,IAAI;AAEzB,YAAM,iBAAiB,SAAU,IAAI,IAAK;AACzC,cAAM,SAAS,KAAK;AACpB,cAAM,SAAS,KAAK;AAEpB,YAAI,CAAC,eAAe,IAAK,MAAO,GAAI;AACnC,cAAI,SAAS,GAAI;AAChB,2BAAe,IAAK,QAAQ,EAAE,QAAQ,QAAQ,SAAS,SAAS,CAAE;AAAA,UACnE,WAAW,SAAS,GAAI;AACvB,2BAAe,IAAK,QAAQ,EAAE,QAAQ,WAAW,SAAS,OAAO,CAAE;AAAA,UACpE,OAAO;AACN,2BAAe,IAAK,QAAQ,EAAE,QAAQ,QAAQ,SAAS,OAAO,CAAE;AAAA,UACjE;AAAA,QACD,OAAO;AACN,gBAAM,SAAS,eAAe,IAAK,MAAO;AAG1C,cAAI,SAAS,KAAK,SAAS,OAAO,MAAO;AACxC,mBAAO,OAAO;AAAA,UACf;AACA,cAAI,SAAS,KAAK,SAAS,OAAO,OAAQ;AACzC,mBAAO,QAAQ;AAAA,UAChB;AAAA,QACD;AAAA,MACD;AAGA,qBAAiB,GAAI,CAAE;AACvB,qBAAgB,CAAC,GAAI,CAAE;AACvB,qBAAgB,CAAC,GAAG,CAAC,CAAE;AACvB,qBAAiB,GAAG,CAAC,CAAE;AAGvB,0BAAoB,SAAU,IAAI,IAAK;AACtC,uBAAiB,IAAK,EAAG;AACzB,uBAAgB,CAAC,IAAK,EAAG;AACzB,uBAAgB,CAAC,IAAI,CAAC,EAAG;AACzB,uBAAiB,IAAI,CAAC,EAAG;AAAA,MAC1B;AAAA,IACD;AAGA,WAAO,KAAK,IAAK;AAChB,UAAI,KAAK,GAAI;AACZ,aAAK;AACL,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,KAAK;AAAA,MAChB,OAAO;AACN,aAAK;AACL,aAAK;AACL,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,KAAK,KAAK;AAAA,MACrB;AAEA,oBAAe,GAAG,CAAE;AAGpB,UAAI,QAAS;AACZ,0BAAmB,GAAG,CAAE;AAAA,MACzB;AAAA,IACD;AAGA,QAAI,KAAK,OAAQ,IAAI,QAAU,IAAI,OAAQ,OAAQ,IAAI,MAAQ,IAAI,KAAM,MAAM;AAG/E,WAAO,KAAK,GAAI;AACf,UAAI,KAAK,GAAI;AACZ,aAAK;AACL,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,MAAM;AAAA,MACjB,OAAO;AACN,aAAK;AACL,aAAK;AACL,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,KAAK,KAAK;AAAA,MACrB;AAEA,oBAAe,GAAG,CAAE;AAGpB,UAAI,QAAS;AACZ,0BAAmB,GAAG,CAAE;AAAA,MACzB;AAAA,IACD;AAGA,QAAI,QAAS;AACZ,YAAM,gBAAgB,CAAC;AACvB,iBAAW,CAAE,QAAS,KAAK,eAAe,QAAQ,GAAI;AACrD,sBAAc,KAAM,QAAS;AAAA,MAC9B;AACA,oBAAc,KAAM,SAAUC,IAAGC,IAAI;AAAE,eAAOD,KAAIC;AAAA,MAAG,CAAE;AAEvD,UAAI,cAAc,UAAU,GAAI;AAC/B,cAAM,mBAAmB,cAAc,SAAS;AAChD,cAAM,cAAc,mBAAmB;AACvC,QAAU,aAAc,YAAsB,gBAAgB,WAAY;AAC1E,cAAM,WAAW,WAAW,QAAmB,cAAe;AAE9D,iBAAS,MAAM,GAAG,MAAM,cAAc,SAAS,GAAG,OAAQ;AACzD,gBAAM,WAAW,cAAe,GAAI;AACpC,gBAAM,SAAS,eAAe,IAAK,QAAS;AAG5C,cAAI,OAAO,SAAS,aAAa,OAAO,UAAU,UAAW;AAC5D;AAAA,UACD;AAGA,gBAAM,SAAS,OAAO,OAAO;AAC7B,gBAAM,OAAO,OAAO,QAAQ;AAC5B,cAAI,OAAO,QAAS;AACnB;AAAA,UACD;AAGA,gBAAM,SAAS,KAAK;AACpB,gBAAM,KAAK,KAAK;AAChB,gBAAM,KAAK,KAAK,OAAO;AAEvB,UAAe,iBAAkB,UAAU,IAAI,QAAQ,SAAU;AACjE,UAAe,iBAAkB,UAAU,IAAI,QAAQ,SAAU;AACjE,UAAe,iBAAkB,UAAU,IAAI,SAAS,GAAG,SAAU;AACrE,UAAe,iBAAkB,UAAU,IAAI,QAAQ,SAAU;AACjE,UAAe,iBAAkB,UAAU,IAAI,SAAS,GAAG,SAAU;AACrE,UAAe,iBAAkB,UAAU,IAAI,SAAS,GAAG,SAAU;AAAA,QACtE;AAAA,MACD;AAAA,IACD;AAAA,EACD;;;AC/NO,WAAS,aAAc,YAAY,SAAU;AAEnD,QAAI,WAAW,GAAI;AAClB;AAAA,IACD;AAEA,UAAM,KAAK,WAAW;AACtB,UAAM,QAAQ,WAAW;AACzB,UAAM,SAAS,WAAW;AAG1B,IAAU,aAAc,UAAW;AAWnC,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,GAAI;AACxD,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,SAAU;AAC9D,OAAG,WAAY,GAAG,GAAG,GAAG,CAAE;AAC1B,OAAG,MAAO,GAAG,gBAAiB;AAC9B,OAAG;AAAA,MACF;AAAA,MAAG;AAAA,MAAG;AAAA,MAAO,KAAK,IAAK,GAAG,SAAS,OAAQ;AAAA,MAC3C;AAAA,MAAG;AAAA,MAAS;AAAA,MAAO;AAAA,MACnB,GAAG;AAAA,MAAkB,GAAG;AAAA,IACzB;AAKA,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,GAAI;AACxD,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,SAAU;AAC9D,OAAG;AAAA,MACF;AAAA,MAAG;AAAA,MAAG;AAAA,MAAO;AAAA,MACb;AAAA,MAAG;AAAA,MAAG;AAAA,MAAO;AAAA,MACb,GAAG;AAAA,MAAkB,GAAG;AAAA,IACzB;AAGA,OAAG,gBAAiB,GAAG,kBAAkB,IAAK;AAC9C,OAAG,gBAAiB,GAAG,kBAAkB,IAAK;AAAA,EAG/C;AAaO,WAAS,IAAK,YAAY,GAAG,GAAG,OAAO,QAAS;AAGtD,QAAI,MAAM,KAAK,MAAM,KAAK,UAAU,WAAW,SAAS,WAAW,WAAW,QAAS;AACtF,MAAU,aAAc,UAAW;AAAA,IACpC,OAAO;AACN,MAAU,aAAc,UAAW;AAAA,IACpC;AAEA,UAAM,KAAK,WAAW;AAEtB,OAAG,gBAAiB,GAAG,aAAa,WAAW,GAAI;AACnD,OAAG,SAAU,GAAG,GAAG,WAAW,OAAO,WAAW,MAAO;AAEvD,QACC,MAAM,KACN,MAAM,KACN,UAAU,WAAW,SACrB,WAAW,WAAW,QACrB;AACD,SAAG,WAAY,GAAG,GAAG,GAAG,CAAE;AAC1B,SAAG,MAAO,GAAG,gBAAiB;AAAA,IAC/B,OAAO;AACN,SAAG,OAAQ,GAAG,YAAa;AAC3B,YAAM,WAAW,WAAW,UAAW,IAAI;AAC3C,SAAG,QAAS,GAAG,UAAU,OAAO,MAAO;AACvC,SAAG,WAAY,GAAG,GAAG,GAAG,CAAE;AAC1B,SAAG,MAAO,GAAG,gBAAiB;AAC9B,SAAG,QAAS,GAAG,YAAa;AAAA,IAC7B;AAEA,OAAG,gBAAiB,GAAG,aAAa,IAAK;AAAA,EAC1C;;;AvBjDA,MAAMC,aAAY,OAAO,SAAS,OAAO,SAAU,aAAc;AACjE,MAAI,qBAAqB;AASlB,WAASC,MAAMC,MAAM;AAG3B,IAAgB,kBAAmB,eAAe,KAAM;AACxD,IAAgB,kBAAmB,qBAAqB,KAAM;AAC9D,IAAgB,kBAAmB,iBAAiB,IAAK;AACzD,IAAgB,kBAAmB,MAAM,IAAK;AAC9C,IAAgB,kBAAmB,cAAc,IAAK;AACtD,IAAgB,kBAAmB,OAAO,IAAK;AAC/C,IAAgB,kBAAmB,oBAAoB,IAAK;AAC5D,IAAgB,kBAAmB,aAAa,IAAK;AAGrD,IAAgB,yBAA0BC,QAAQ;AAGlD,IAAU,KAAK;AACf,IAAUF,MAAK;AACf,IAAWA,MAAK;AAChB,IAAWA,MAAK;AAChB,IAAWA,MAAK;AAAA,EACjB;AAQO,WAAS,cAAe,YAAa;AAE3C,QAAI,SAAS,WAAW;AACxB,UAAM,QAAQ,WAAW;AACzB,UAAM,SAAS,WAAW;AAE1B,QAAI,WAAW,aAAc;AAC5B,eAAS,WAAW,OAAO;AAC3B,UAAI,CAAC,oBAAqB;AACzB,6BAAqB,OAAO,WAAY,UAAU;AAAA,UACjD,SAAS;AAAA,UACT,sBAAsB;AAAA,UACtB,aAAa;AAAA,UACb,yBAAyB;AAAA,UACzB,kBAAkB;AAAA,UAClB,aAAa;AAAA,QACd,CAAE;AAAA,MACH;AACA,iBAAW,KAAK;AAAA,IACjB,OAAO;AACN,iBAAW,KAAK,OAAO,WAAY,UAAU;AAAA,QAC5C,SAAS;AAAA,QACT,sBAAsB;AAAA,QACtB,aAAa;AAAA,QACb,yBAAyB;AAAA,QACzB,kBAAkB;AAAA,QAClB,aAAa;AAAA,MACd,CAAE;AAAA,IACH;AAGA,QAAI,CAAC,WAAW,IAAK;AACpB,YAAM,QAAQ,IAAI,MAAO,8DAA+D;AACxF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,eAAW,GAAG,SAAU,GAAG,GAAG,OAAO,MAAO;AAG5C,UAAM,gBAAgB,oBAAqB,UAAW;AACtD,eAAW,aAAa,cAAc;AACtC,eAAW,MAAM,cAAc;AAG/B,UAAM,sBAAsB,oBAAqB,UAAW;AAC5D,eAAW,mBAAmB,oBAAoB;AAClD,eAAW,YAAY,oBAAoB;AAG3C,IAAU,cAAe,UAAW;AAGpC,IAAU,mBAAoB,UAAW;AAGzC,QAAID,YAAW;AACd,YAAM,WAAW,WAAW,GAAG,aAAc,2BAA4B;AACzE,UAAI,UAAW;AACd,gBAAQ,IAAK,QAAQ,WAAW,GAAG,aAAc,SAAS,uBAAwB,CAAE;AAAA,MACrF;AAAA,IACD;AAGA,WAAO,iBAAkB,oBAAoB,CAAE,MAAO;AACrD,QAAE,eAAe;AACjB,cAAQ,KAAM,oBAAqB;AACnC,iBAAW,cAAc;AAAA,IAC1B,CAAE;AAGF,WAAO,iBAAkB,wBAAwB,MAAM;AACtD,cAAQ,IAAK,wBAAyB;AAItC,iBAAW,cAAc;AAAA,IAI1B,CAAE;AAAA,EACH;AAQA,WAAS,oBAAqB,YAAa;AAE1C,UAAM,KAAK,WAAW;AACtB,UAAM,QAAQ,WAAW;AACzB,UAAM,SAAS,WAAW;AAG1B,UAAM,aAAa,GAAG,cAAc;AACpC,QAAI,CAAC,YAAa;AACjB,YAAM,QAAQ,IAAI,MAAO,0CAA2C;AACpE,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,OAAG,YAAa,GAAG,YAAY,UAAW;AAC1C,OAAG;AAAA,MACF,GAAG;AAAA,MAAY;AAAA,MAAG,GAAG;AAAA,MACrB;AAAA,MAAO;AAAA,MAAQ;AAAA,MACf,GAAG;AAAA,MAAM,GAAG;AAAA,MAAe;AAAA,IAC5B;AAGA,OAAG,cAAe,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAQ;AACnE,OAAG,cAAe,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAQ;AACnE,OAAG,cAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAc;AACrE,OAAG,cAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAc;AAGrE,UAAM,MAAM,GAAG,kBAAkB;AACjC,OAAG,gBAAiB,GAAG,aAAa,GAAI;AAGxC,OAAG;AAAA,MACF,GAAG;AAAA,MAAa,GAAG;AAAA,MACnB,GAAG;AAAA,MAAY;AAAA,MAAY;AAAA,IAC5B;AAGA,UAAM,SAAS,GAAG,uBAAwB,GAAG,WAAY;AACzD,QAAI,WAAW,GAAG,sBAAuB;AACxC,YAAM,QAAQ,IAAI,MAAO,0CAA0C,MAAM,EAAG;AAC5E,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,OAAG,gBAAiB,GAAG,aAAa,IAAK;AACzC,OAAG,YAAa,GAAG,YAAY,IAAK;AAEpC,WAAO,EAAE,YAAY,IAAI;AAAA,EAC1B;AAQO,WAASG,SAAS,YAAa;AACrC,UAAM,KAAK,WAAW;AAGtB,eAAW,oBAAoB;AAG/B,IAAU,QAAS,UAAW;AAG9B,QAAI,WAAW,gBAAiB;AAC/B,SAAG,cAAe,WAAW,cAAe;AAC5C,SAAG,aAAc,WAAW,qBAAsB;AAAA,IACnD;AAGA,QAAI,WAAW,KAAM;AACpB,SAAG,kBAAmB,WAAW,GAAI;AACrC,SAAG,cAAe,WAAW,UAAW;AAAA,IACzC;AAGA,QAAI,WAAW,WAAY;AAC1B,SAAG,kBAAmB,WAAW,SAAU;AAC3C,SAAG,cAAe,WAAW,gBAAiB;AAAA,IAC/C;AAAA,EACD;AAOO,WAAS,cAAe,YAAa;AAE3C,QAAI,CAAC,WAAW,mBAAoB;AACnC,iBAAW,oBAAoB;AAC/B,MAAQC,gBAAgB,MAAM;AAG7B,YAAI,CAAC,WAAW,mBAAoB;AACnC;AAAA,QACD;AACA,QAAU,aAAc,UAAW;AACnC,QAAU,gBAAiB,UAAW;AACtC,mBAAW,oBAAoB;AAAA,MAChC,CAAE;AAAA,IACH;AAAA,EACD;AAQO,WAAS,iBAAkB,YAAY,gBAAiB;AAG9D,IAAU,aAAc,YAAY,cAAe;AACnD,IAAU,gBAAiB,UAAW;AAAA,EACvC;AAEO,WAAS,aAAc,YAAY,UAAU,WAAY;AAG/D,IAAU,aAAc,UAAW;AAEnC,UAAM,KAAK,WAAW;AACtB,UAAM,WAAW,WAAW;AAC5B,UAAM,YAAY,WAAW;AAG7B,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,GAAI;AACxD,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,SAAU;AAC9D,OAAG,WAAY,GAAG,GAAG,GAAG,CAAE;AAC1B,OAAG,MAAO,GAAG,gBAAiB;AAC9B,OAAG;AAAA,MACF;AAAA,MAAG;AAAA,MAAG;AAAA,MAAU;AAAA,MAChB;AAAA,MAAG;AAAA,MAAG;AAAA,MAAU;AAAA,MAChB,GAAG;AAAA,MAAkB,GAAG;AAAA,IACzB;AAGA,OAAG,YAAa,GAAG,YAAY,WAAW,UAAW;AACrD,OAAG;AAAA,MACF,GAAG;AAAA,MAAY;AAAA,MAAG,GAAG;AAAA,MACrB;AAAA,MAAU;AAAA,MAAW;AAAA,MACrB,GAAG;AAAA,MAAM,GAAG;AAAA,MAAe;AAAA,IAC5B;AACA,OAAG,YAAa,GAAG,YAAY,IAAK;AAGpC,UAAM,YAAY,KAAK,IAAK,UAAU,QAAS;AAC/C,UAAM,aAAa,KAAK,IAAK,WAAW,SAAU;AAClD,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,SAAU;AAC9D,OAAG,gBAAiB,GAAG,kBAAkB,WAAW,GAAI;AAGxD,UAAM,OAAO,KAAK,IAAK,GAAG,YAAY,SAAU;AAChD,OAAG;AAAA,MACF;AAAA,MAAG;AAAA,MAAM;AAAA,MAAW,OAAO;AAAA,MAC3B;AAAA,MAAG;AAAA,MAAG;AAAA,MAAW;AAAA,MACjB,GAAG;AAAA,MAAkB,GAAG;AAAA,IACzB;AAGA,OAAG,YAAa,GAAG,YAAY,WAAW,gBAAiB;AAC3D,OAAG;AAAA,MACF,GAAG;AAAA,MAAY;AAAA,MAAG,GAAG;AAAA,MACrB;AAAA,MAAU;AAAA,MAAW;AAAA,MACrB,GAAG;AAAA,MAAM,GAAG;AAAA,MAAe;AAAA,IAC5B;AACA,OAAG,YAAa,GAAG,YAAY,IAAK;AAEpC,OAAG,gBAAiB,GAAG,kBAAkB,IAAK;AAC9C,OAAG,gBAAiB,GAAG,kBAAkB,IAAK;AAAA,EAC/C;;;AwBhXA;AAAA;AAAA;AAAA,gBAAAC;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA,IAAA;AAAA;AAiBA,MAAM,WAAW,CAAC;AAClB,MAAM,kBAAkB,CAAC;AACzB,MAAI,eAAe;AAcZ,WAASC,MAAMC,MAAM;AAC3B,IAAAC,kBAAkBD,IAAI;AAEtB,IAAgB,kBAAmB,kBAAkB,CAAE;AACvD,IAAgB,kBAAmB,kBAAkB,CAAE;AACvD,IAAgB,kBAAmB,iBAAiB,CAAC,CAAE;AAGvD,IAAgB,sBAAuB,eAAgB;AAAA,EACxD;AAOA,WAASC,kBAAkBD,MAAM;AAChC,IAAW;AAAA,MACV;AAAA,MAAa;AAAA,MAAW;AAAA,MACxB,CAAE,OAAO,QAAQ,cAAc,eAAe,UAAU,SAAU;AAAA,IACnE;AACA,IAAW;AAAA,MACV;AAAA,MAAmB;AAAA,MAAiB;AAAA,MACpC;AAAA,QACC;AAAA,QAAO;AAAA,QAAQ;AAAA,QAAS;AAAA,QAAU;AAAA,QAAU;AAAA,QAAc;AAAA,QAAe;AAAA,QACzE;AAAA,MACD;AAAA,IACD;AACA,IAAW,WAAY,YAAY,UAAU,OAAO,CAAE,MAAO,CAAE;AAC/D,IAAW,WAAY,sBAAsB,oBAAoB,MAAM,CAAE,MAAO,GAAG,IAAK;AACxF,IAAW,WAAY,eAAe,aAAa,OAAO,CAAE,MAAO,CAAE;AACrE,IAAW;AAAA,MACV;AAAA,MAAyB;AAAA,MAAuB;AAAA,MAChD,CAAE,QAAQ,MAAM,MAAM,MAAM,IAAK;AAAA,IAClC;AACA,IAAW,WAAY,oBAAoB,kBAAkB,MAAM,CAAE,KAAK,GAAI,CAAE;AAAA,EACjF;AAqBA,WAAS,UAAW,SAAU;AAC7B,UAAM,MAAM,QAAQ;AACpB,QAAI,OAAO,QAAQ;AACnB,UAAM,aAAa,CAAC,CAAC,QAAQ;AAC7B,UAAM,cAAc,QAAQ;AAC5B,UAAM,iBAAiB,QAAQ;AAC/B,UAAM,kBAAkB,QAAQ;AAChC,UAAM,YAAY;AAIlB,QAAI,OAAO,QAAQ,UAAW;AAC7B,UAAI,QAAQ,IAAK;AAChB,cAAM,QAAQ,IAAI,UAAW,SAAU;AACvC,cAAM,OAAO;AACb,cAAM;AAAA,MACP;AAAA,IACD,WAAW,OAAO,OAAO,QAAQ,UAAW;AAC3C,UAAI,IAAI,YAAY,SAAS,IAAI,YAAY,UAAW;AACvD,cAAM,QAAQ,IAAI,UAAW,SAAU;AACvC,cAAM,OAAO;AACb,cAAM;AAAA,MACP;AAAA,IACD,OAAO;AACN,YAAM,QAAQ,IAAI,UAAW,SAAU;AACvC,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,QAAQ,OAAO,SAAS,UAAW;AACtC,YAAM,QAAQ,IAAI,UAAW,6CAA8C;AAC3E,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,QAAI,CAAC,QAAQ,SAAS,IAAK;AAC1B,sBAAgB;AAChB,aAAO,KAAK;AAAA,IACb;AACA,QAAI,SAAU,IAAK,GAAI;AACtB,YAAM,QAAQ,IAAI,UAAW,2CAA4C;AACzE,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,kBAAkB,QAAQ,CAAS,WAAY,cAAe,GAAI;AACrE,YAAM,QAAQ,IAAI,UAAW,iDAAkD;AAC/E,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AACA,QAAI,mBAAmB,QAAQ,CAAS,WAAY,eAAgB,GAAI;AACvE,YAAM,QAAQ,IAAI,UAAW,kDAAmD;AAChF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,YAAY;AAChB,QAAI,cAAc;AAClB,QAAI,YAAa;AAChB,UAAI,CAAC,MAAM,QAAS,WAAY,KAAK,YAAY,WAAW,GAAI;AAC/D,cAAM,QAAQ,IAAI;AAAA,UACjB;AAAA,QACD;AACA,cAAM,OAAO;AACb,cAAM;AAAA,MACP;AAGA,oBAAc,oBAAI,IAAI;AAGtB,kBAAY,CAAU,eAAgB,kBAAmB,CAAE;AAC3D,kBAAY,IAAK,UAAW,CAAE,EAAE,KAAK,CAAE;AAEvC,eAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,GAAI;AAChD,cAAM,cAAc,YAAa,CAAE;AACnC,cAAM,WAAmB,eAAgB,WAAY;AACrD,kBAAU,KAAM,QAAS;AACzB,oBAAY,IAAK,SAAS,KAAK,IAAI,CAAE;AAAA,MACtC;AAAA,IACD;AAGA,aAAU,IAAK,IAAI;AAAA,MAClB,UAAU;AAAA,MACV,SAAS;AAAA,MACT,SAAS;AAAA,MACT,UAAU;AAAA,MACV,cAAc;AAAA,MACd,aAAa;AAAA,MACb,eAAe;AAAA,IAChB;AAGA,UAAM,gBAAgB,CAAEE,SAAS;AAGhC,YAAM,WAAW,SAAU,IAAK;AAChC,eAAS,QAAQA;AACjB,eAAS,SAAS;AAClB,eAAS,QAAQA,KAAI;AACrB,eAAS,SAASA,KAAI;AAGtB,UAAI,SAAS,YAAa;AACzB,wBAAiB,IAAK;AAAA,MACvB;AAGA,UAAI,gBAAiB;AACpB,uBAAgB,IAAK;AAAA,MACtB;AAAA,IACD;AAGA,QAAI,OAAO,QAAQ,UAAW;AAG7B,oBAAe,GAAI;AACnB,aAAO;AAAA,IACR;AAGA,UAAM,MAAM,IAAI,MAAM;AAGtB,IAAW,KAAK;AAGhB,QAAI,SAAS,WAAW;AACvB,oBAAe,GAAI;AAGnB,MAAW,KAAK;AAAA,IACjB;AAGA,QAAI,UAAU,SAAU,OAAQ;AAG/B,eAAU,IAAK,IAAI;AAAA,QAClB,UAAU;AAAA,QACV,SAAS;AAAA,MACV;AAGA,UAAI,iBAAkB;AACrB,wBAAiB,KAAM;AAAA,MACxB;AAGA,MAAW,KAAK;AAAA,IACjB;AAGA,QAAI,MAAM;AAEV,WAAO;AAAA,EACR;AASA,WAAS,YAAa,SAAU;AAC/B,UAAM,OAAO,QAAQ;AACrB,QAAI,OAAO,SAAS,UAAW;AAC9B,YAAM,QAAQ,IAAI,UAAW,+CAAgD;AAC7E,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,UAAM,WAAW,SAAU,IAAK;AAChC,QAAI,YAAY,SAAS,OAAQ;AAEhC,YAAM,MAAM,SAAS;AAKrB,iBAAW,cAA8B,kBAAkB,GAAI;AAC9D,QAAW,oBAAqB,YAAY,GAAI;AAAA,MACjD;AAGA,UAAI,SAAS,YAAa;AAIzB,wBAAgB,OAAQ,gBAAgB,QAAS,IAAK,GAAG,CAAE;AAAA,MAC5D;AAGA,aAAO,SAAU,IAAK;AAAA,IACvB;AAAA,EACD;AAkBA,WAAS,gBAAiB,SAAU;AACnC,UAAM,MAAM,QAAQ;AACpB,QAAI,OAAO,QAAQ;AACnB,QAAI,cAAc,QAAQ;AAC1B,QAAI,eAAe,QAAQ;AAC3B,QAAI,SAAS,QAAQ;AACrB,UAAM,aAAa,CAAC,CAAC,QAAQ;AAC7B,UAAM,cAAc,QAAQ;AAC5B,UAAM,iBAAiB,QAAQ;AAC/B,UAAM,kBAAkB,QAAQ;AAChC,QAAI,SAAS;AAEb,QAAI,WAAW,MAAO;AACrB,eAAS;AAAA,IACV;AAEA,QAAI,gBAAgB,QAAQ,iBAAiB,MAAO;AACnD,eAAS;AACT,oBAAc;AACd,qBAAe;AACf,eAAS;AAAA,IACV,OAAO;AACN,oBAAc,KAAK,MAAO,WAAY;AACtC,qBAAe,KAAK,MAAO,YAAa;AACxC,eAAS,KAAK,MAAO,MAAO;AAAA,IAC7B;AAGA,QAAI,CAAC,WAAY,CAAC,OAAO,UAAW,WAAY,KAAK,CAAC,OAAO,UAAW,YAAa,IAAM;AAC1F,YAAM,QAAQ,IAAI,UAAW,qDAAsD;AACnF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,CAAC,WAAY,cAAc,KAAK,eAAe,IAAM;AACxD,YAAM,QAAQ,IAAI;AAAA,QACjB;AAAA,MACD;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,CAAC,OAAO,UAAW,MAAO,GAAI;AACjC,YAAM,QAAQ,IAAI,UAAW,6CAA8C;AAC3E,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,CAAC,QAAQ,SAAS,IAAK;AAC1B,sBAAgB;AAChB,aAAO,KAAK;AAAA,IACb;AAGA,QAAI,OAAO,SAAS,UAAW;AAC9B,YAAM,QAAQ,IAAI,UAAW,mDAAoD;AACjF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AACA,QAAI,SAAU,IAAK,GAAI;AACtB,YAAM,QAAQ,IAAI,UAAW,iDAAkD;AAC/E,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,kBAAkB,QAAQ,CAAS,WAAY,cAAe,GAAI;AACrE,YAAM,QAAQ,IAAI,UAAW,uDAAwD;AACrF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AACA,QAAI,mBAAmB,QAAQ,CAAS,WAAY,eAAgB,GAAI;AACvE,YAAM,QAAQ,IAAI,UAAW,wDAAyD;AACtF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,YAAY;AAChB,QAAI,cAAc;AAClB,QAAI,YAAa;AAChB,UAAI,CAAC,MAAM,QAAS,WAAY,KAAK,YAAY,WAAW,GAAI;AAC/D,cAAM,QAAQ,IAAI;AAAA,UACjB;AAAA,QAED;AACA,cAAM,OAAO;AACb,cAAM;AAAA,MACP;AAGA,oBAAc,oBAAI,IAAI;AAGtB,kBAAY,CAAU,eAAgB,kBAAmB,CAAE;AAC3D,kBAAY,IAAK,UAAW,CAAE,EAAE,KAAK,CAAE;AAEvC,eAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,GAAI;AAChD,cAAM,cAAc,YAAa,CAAE;AACnC,cAAM,WAAmB,eAAgB,WAAY;AACrD,kBAAU,KAAM,QAAS;AACzB,oBAAY,IAAK,SAAS,KAAK,IAAI,CAAE;AAAA,MACtC;AAAA,IACD;AAGA,cAAW;AAAA,MACV,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,eAAe;AAAA,MACf,UAAU,SAAU,WAAY;AAG/B,cAAM,YAAY,SAAU,SAAU;AACtC,kBAAU,OAAO;AACjB,kBAAU,cAAc;AACxB,kBAAU,eAAe;AACzB,kBAAU,SAAS;AACnB,kBAAU,SAAS,CAAC;AACpB,kBAAU,SAAS;AAEnB,cAAM,QAAQ,UAAU;AACxB,cAAM,SAAS,UAAU;AAEzB,YAAI,QAAS;AAGZ,iCAAwB,WAAW,OAAO,MAAO;AAAA,QAClD,OAAO;AAGN,kCAAyB,WAAW,OAAO,MAAO;AAAA,QACnD;AAGA,YAAI,gBAAiB;AACpB,yBAAgB,SAAU;AAAA,QAC3B;AAAA,MACD;AAAA,MACA,WAAW;AAAA,IACZ,CAAE;AAEF,WAAO;AAAA,EACR;AASA,WAAS,SAAU,SAAU;AAC5B,UAAM,MAAM,qBAAsB,QAAQ,MAAM,UAAW;AAG3D,QAAI,IAAI,QAAS;AAChB,YAAM,gBAAgC,cAAe,YAAY,IAAI,QAAQ,QAAS;AACtF,aAAO,sBAAuB,aAAc;AAAA,IAC7C;AACA,WAAO;AAAA,EACR;AAeA,WAAS,sBAAuB,YAAY,SAAU;AACrD,QAAI,OAAO,QAAQ;AACnB,QAAI,KAAa,OAAQ,QAAQ,IAAI,CAAE;AACvC,QAAI,KAAa,OAAQ,QAAQ,IAAI,CAAE;AACvC,QAAI,KAAa,OAAQ,QAAQ,IAAI,WAAW,QAAQ,CAAE;AAC1D,QAAI,KAAa,OAAQ,QAAQ,IAAI,WAAW,SAAS,CAAE;AAG3D,SAAa,MAAO,IAAI,GAAG,WAAW,QAAQ,CAAE;AAChD,SAAa,MAAO,IAAI,GAAG,WAAW,SAAS,CAAE;AACjD,SAAa,MAAO,IAAI,GAAG,WAAW,QAAQ,CAAE;AAChD,SAAa,MAAO,IAAI,GAAG,WAAW,SAAS,CAAE;AAGjD,UAAM,QAAQ,KAAK,IAAK,KAAK,EAAG,IAAI;AACpC,UAAM,SAAS,KAAK,IAAK,KAAK,EAAG,IAAI;AAErC,QAAI,UAAU,KAAK,WAAW,GAAI;AACjC,YAAM,QAAQ,IAAI;AAAA,QACjB;AAAA,MACD;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,UAAM,UAAU,KAAK,IAAK,IAAI,EAAG;AACjC,UAAM,UAAU,KAAK,IAAK,IAAI,EAAG;AAGjC,QAAI,CAAC,QAAQ,SAAS,IAAK;AAC1B,sBAAgB;AAChB,aAAO,KAAK;AAAA,IACb,WAAW,OAAO,SAAS,UAAW;AACrC,YAAM,QAAQ,IAAI,UAAW,yDAA0D;AACvF,YAAM,OAAO;AACb,YAAM;AAAA,IACP,WAAW,SAAU,IAAK,GAAI;AAC7B,YAAM,QAAQ,IAAI;AAAA,QACjB,gCAAgC,IAAI;AAAA,MACrC;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,UAAM,SAAS,6BAA8B,YAAY,SAAS,SAAS,OAAO,MAAO;AAGzF,aAAU,IAAK,IAAI;AAAA,MAClB,UAAU;AAAA,MACV,SAAS;AAAA,MACT,SAAS;AAAA,MACT,UAAU;AAAA,MACV,cAAc;AAAA,MACd,aAAa;AAAA,MACb,eAAe;AAAA,IAChB;AAEA,WAAO;AAAA,EACR;AAWA,WAAS,iBAAkB,YAAY,SAAU;AAChD,UAAM,UAAkB,SAAU,QAAQ,GAAG,IAAK;AAClD,UAAM,UAAkB,SAAU,QAAQ,GAAG,IAAK;AAGlD,QAAI,YAAY,QAAQ,UAAU,KAAK,UAAU,GAAI;AACpD,YAAM,QAAQ,IAAI;AAAA,QACjB;AAAA,MACD;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,QAAI,YAAY,QAAQ,UAAU,KAAK,UAAU,GAAI;AACpD,YAAM,QAAQ,IAAI;AAAA,QACjB;AAAA,MACD;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,eAAW,iBAAiB;AAC5B,eAAW,iBAAiB;AAAA,EAC7B;AAUA,WAAS,mBAAoB,YAAY,SAAU;AAClD,UAAM,OAAO,QAAQ;AAGrB,QAAI,OAAO,SAAS,UAAW;AAC9B,YAAM,QAAQ,IAAI,UAAW,sDAAuD;AACpF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,UAAM,aAAa,eAAgB,IAAK;AACxC,QAAI,CAAC,YAAa;AACjB,YAAM,QAAQ,IAAI,MAAO,oCAAoC,IAAI,cAAe;AAChF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,QAAI,WAAW,SAAS,eAAgB;AACvC,YAAM,QAAQ,IAAI,MAAO,8BAA8B,IAAI,yBAA0B;AACrF,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,UAAM,mBAAmB;AAAA,MACxB,cAAc,WAAW,OAAO;AAAA,MAChC,UAAU,CAAC;AAAA,IACZ;AAEA,aAAS,IAAI,GAAG,IAAI,WAAW,OAAO,QAAQ,KAAM;AACnD,uBAAiB,OAAO,KAAM;AAAA,QAC7B,SAAS;AAAA,QACT,KAAK,WAAW,OAAQ,CAAE,EAAE;AAAA,QAC5B,KAAK,WAAW,OAAQ,CAAE,EAAE;AAAA,QAC5B,SAAS,WAAW,OAAQ,CAAE,EAAE;AAAA,QAChC,UAAU,WAAW,OAAQ,CAAE,EAAE;AAAA,QACjC,QAAQ,WAAW,OAAQ,CAAE,EAAE;AAAA,QAC/B,OAAO,WAAW,OAAQ,CAAE,EAAE;AAAA,QAC9B,SAAS,WAAW,OAAQ,CAAE,EAAE;AAAA,QAChC,UAAU,WAAW,OAAQ,CAAE,EAAE;AAAA,MAClC,CAAE;AAAA,IACH;AAEA,WAAO;AAAA,EACR;AAkBA,WAAS,6BAA8B,YAAY,GAAG,GAAG,OAAO,QAAS;AAMxE,UAAM,YAAuB,cAAe,YAAY,GAAG,GAAG,OAAO,MAAO;AAE5E,QAAI,CAAC,WAAY;AAChB,YAAM,QAAQ,IAAI;AAAA,QACjB;AAAA,MACD;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAGA,UAAM,SAAS,SAAS,cAAe,QAAS;AAChD,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,UAAM,UAAU,OAAO,WAAY,IAAK;AAGxC,UAAM,YAAY,QAAQ,gBAAiB,OAAO,MAAO;AACzD,UAAM,aAAa,UAAU;AAK7B,aAAS,MAAM,GAAG,MAAM,QAAQ,OAAQ;AACvC,eAAS,MAAM,GAAG,MAAM,OAAO,OAAQ;AAGtC,cAAM,SAAW,SAAS,IAAM;AAChC,cAAM,YAAa,SAAS,QAAQ,OAAQ;AAG5C,cAAM,YAAa,MAAM,QAAQ,OAAQ;AAGzC,mBAAY,QAAa,IAAI,UAAW,QAAa;AACrD,mBAAY,WAAW,CAAE,IAAI,UAAW,WAAW,CAAE;AACrD,mBAAY,WAAW,CAAE,IAAI,UAAW,WAAW,CAAE;AACrD,mBAAY,WAAW,CAAE,IAAI,UAAW,WAAW,CAAE;AAAA,MACtD;AAAA,IACD;AAGA,YAAQ,aAAc,WAAW,GAAG,CAAE;AAEtC,WAAO;AAAA,EACR;AAEO,WAAS,qBAAsB,aAAa,QAAS;AAC3D,QAAI,MAAM;AAGV,QAAI,OAAO,gBAAgB,UAAW;AAGrC,YAAM,YAAY,eAAgB,WAAY;AAC9C,UAAI,CAAC,WAAY;AAChB,cAAM,QAAQ,IAAI,MAAO,GAAG,MAAM,YAAY,WAAW,cAAe;AACxE,cAAM,OAAO;AACb,cAAM;AAAA,MACP;AAGA,UAAI,UAAU,WAAW,SAAU;AAClC,cAAM,UAAU,UAAU,WAAW;AACrC,YAAI,UAAU,WAAW,WAAY;AACpC,gBAAM,QAAQ,IAAI;AAAA,YACjB,GAAG,MAAM,MAAM,OAAO;AAAA,UACvB;AACA,gBAAM,OAAO;AACb,gBAAM;AAAA,QACP;AACA,YAAI,UAAU,WAAW,SAAU;AAClC,gBAAM,QAAQ,IAAI,MAAO,GAAG,MAAM,MAAM,OAAO,mBAAoB;AACnE,gBAAM,OAAO;AACb,gBAAM;AAAA,QACP;AAAA,MACD;AAGA,YAAM,UAAU;AAAA,IACjB,WAAW,eAAe,OAAO,gBAAgB,UAAW;AAC3D,UAAI,qBAAsB,WAAY,GAAI;AACzC,cAAM;AAAA,MACP,WAAW,YAAY,WAAW,MAAO;AACxC,cAAM,gBAAgC,cAAe,QAAQ,YAAY,EAAG;AAC5E,cAAM,cAAc;AAAA,MACrB;AAAA,IACD;AAEA,QAAI,QAAQ,MAAO;AAClB,YAAM,QAAQ,IAAI;AAAA,QACjB,GAAG,MAAM;AAAA,MACV;AACA,YAAM,OAAO;AACb,YAAM;AAAA,IACP;AAEA,WAAO;AAAA,EACR;AAEA,WAAS,qBAAsB,KAAM;AACpC,WACC,eAAe,oBACf,eAAe,oBACf,eAAe,qBACf,eAAe,eACf,eAAe,aACb,OAAO,oBAAoB,eAAe,eAAe;AAAA,EAE7D;AAQO,WAAS,eAAgB,MAAO;AACtC,QAAI,OAAO,SAAS,UAAW;AAC9B,aAAO;AAAA,IACR;AACA,WAAO,SAAU,IAAK,KAAK;AAAA,EAC5B;AAEA,WAAS,gBAAiB,MAAO;AAChC,oBAAgB,KAAM,IAAK;AAG3B,UAAM,WAAW,SAAU,IAAK;AAEhC,QAAI;AAGJ,QAAI,SAAS,MAAM,YAAY,UAAW;AACzC,YAAM,SAAS,SAAS,cAAe,QAAS;AAChD,aAAO,QAAQ,SAAS;AACxB,aAAO,SAAS,SAAS;AACzB,gBAAU,OAAO,WAAY,IAAK;AAClC,cAAQ,UAAW,SAAS,OAAO,GAAG,CAAE;AACxC,eAAS,QAAQ;AAAA,IAClB,OAAO;AACN,YAAM,SAAS,SAAS;AACxB,gBAAU,OAAO,WAAY,IAAK;AAAA,IACnC;AAGA,UAAM,iBAAiB,EAAE,OAAO,SAAS,WAAW,UAAU,SAAS,YAAY;AAGnF,UAAM,YAAY,QAAQ,aAAc,GAAG,GAAG,SAAS,OAAO,SAAS,MAAO;AAC9E,UAAM,OAAO,UAAU;AACvB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAI;AACzC,YAAM,QAAgB,WAAY,KAAM,CAAE,GAAG,KAAM,IAAI,CAAE,GAAG,KAAM,IAAI,CAAE,GAAG,KAAM,IAAI,CAAE,CAAE;AACzF,YAAM,QAAiB,2BAA4B,gBAAgB,OAAO,CAAE;AAC5E,YAAM,WAAW,eAAe,IAAK,KAAM;AAC3C,UAAI,SAAS,QAAQ,MAAM,KAAM;AAChC,aAAM,CAAE,IAAI,SAAS;AACrB,aAAM,IAAI,CAAE,IAAI,SAAS;AACzB,aAAM,IAAI,CAAE,IAAI,SAAS;AACzB,aAAM,IAAI,CAAE,IAAI,SAAS;AAAA,MAC1B;AAAA,IACD;AACA,YAAQ,aAAc,WAAW,GAAG,CAAE;AAItC,aAAS,OAAO;AAGhB,eAAW,cAA8B,kBAAkB,GAAI;AAC9D,qBAAgB,YAAY,IAAK;AAAA,IAClC;AAAA,EACD;AAGO,WAAS,gBAAiB,YAAa;AAG7C,eAAW,QAAQ,iBAAkB;AACpC,qBAAgB,YAAY,IAAK;AAAA,IAClC;AAAA,EACD;AAEA,WAAS,eAAgB,YAAY,MAAO;AAG3C,UAAM,WAAW,SAAU,IAAK;AAGhC,QAAI,SAAS,UAAU,SAAS,WAAW,IAAI,QAAS;AACvD,cAAQ;AAAA,QACP,+CAA+C,IAAI;AAAA,MAEpD;AACA;AAAA,IACD;AAGA,UAAM,MAAM,SAAS,QAAQ,SAAS,SAAS;AAG/C,UAAM,sBAAsB,IAAI,kBAAmB,GAAI;AACvD,UAAM,OAAO,SAAS;AAGtB,aAAS,IAAI,GAAG,IAAI,KAAK,KAAK,GAAI;AAGjC,YAAM,MAAc;AAAA,QACnB,KAAM,CAAE;AAAA,QAAG,KAAM,IAAI,CAAE;AAAA,QAAG,KAAM,IAAI,CAAE;AAAA,QAAG,KAAK,IAAI,CAAE;AAAA,MACrD;AACA,YAAM,WAAW,SAAS,YAAY,IAAK,GAAI;AAG/C,YAAM,WAAW,WAAW,IAAK,QAAS;AAC1C,0BAAqB,CAAE,IAAI,SAAS;AACpC,0BAAqB,IAAI,CAAE,IAAI,SAAS;AACxC,0BAAqB,IAAI,CAAE,IAAI,SAAS;AACxC,0BAAqB,IAAI,CAAE,IAAI,SAAS;AAAA,IACzC;AAGA,IAAW;AAAA,MACV;AAAA,MAAY,SAAS;AAAA,MAAO;AAAA,MAAqB,SAAS;AAAA,MAAO,SAAS;AAAA,IAC3E;AAAA,EACD;AAUA,WAAS,wBAAyB,WAAW,OAAO,QAAS;AAC5D,QAAI,KAAK,UAAU;AACnB,QAAI,KAAK,UAAU;AACnB,QAAI,KAAK,KAAK,UAAU;AACxB,QAAI,KAAK,KAAK,UAAU;AAGxB,WAAO,MAAM,SAAS,UAAU,QAAS;AACxC,aAAO,MAAM,QAAQ,UAAU,QAAS;AACvC,kBAAU,OAAO,KAAM;AAAA,UACtB,KAAK;AAAA,UACL,KAAK;AAAA,UACL,SAAS,UAAU;AAAA,UACnB,UAAU,UAAU;AAAA,UACpB,SAAS,KAAK,UAAU,cAAc;AAAA,UACtC,UAAU,KAAK,UAAU,eAAe;AAAA,QACzC,CAAE;AACF,cAAM,UAAU,cAAc,UAAU;AACxC,aAAK,KAAK,UAAU;AAAA,MACrB;AACA,WAAK,UAAU;AACf,WAAK,KAAK,UAAU;AACpB,YAAM,UAAU,eAAe,UAAU;AACzC,WAAK,KAAK,UAAU;AAAA,IACrB;AAAA,EACD;AAUA,WAAS,uBAAwB,WAAW,OAAO,QAAS;AAG3D,UAAM,SAAS,SAAS,cAAe,QAAS;AAChD,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,UAAM,UAAU,OAAO,WAAY,MAAM,EAAE,sBAAsB,KAAK,CAAE;AACxE,YAAQ,UAAW,UAAU,OAAO,GAAG,CAAE;AAEzC,UAAM,OAAO,QAAQ,aAAc,GAAG,GAAG,OAAO,MAAO,EAAE;AACzD,UAAM,WAAW,IAAI,WAAY,QAAQ,MAAO;AAGhD,UAAM,OAAO;AAAA,MACZ,CAAE,IAAI,EAAG;AAAA,MAAG,CAAE,GAAG,EAAG;AAAA,MAAG,CAAE,GAAG,EAAG;AAAA,MAC/B,CAAE,IAAK,CAAE;AAAA,MAAc,CAAE,GAAI,CAAE;AAAA,MAC/B,CAAE,IAAK,CAAE;AAAA,MAAG,CAAE,GAAI,CAAE;AAAA,MAAG,CAAE,GAAI,CAAE;AAAA,IAChC;AAGA,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAI;AACzC,UAAI,KAAM,CAAE,IAAI,GAAI;AACnB,cAAM,SAAU,IAAI,KAAM;AAC1B,cAAM,KAAK,QAAQ;AACnB,cAAM,KAAK,KAAK,MAAO,QAAQ,KAAM;AACrC,cAAM,aAAa,KAAK,QAAQ;AAGhC,YAAI,SAAU,UAAW,GAAI;AAC5B;AAAA,QACD;AAGA,cAAM,YAAY;AAAA,UACjB,KAAK;AAAA,UACL,KAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU;AAAA,QACX;AAGA,cAAM,QAAQ,CAAC;AACf,cAAM,KAAM,EAAE,KAAK,IAAI,KAAK,GAAG,CAAE;AACjC,iBAAU,UAAW,IAAI;AAEzB,YAAI,OAAO;AACX,eAAO,OAAO,MAAM,QAAS;AAC5B,gBAAM,QAAQ,MAAO,MAAO;AAC5B,gBAAM,KAAK,MAAM;AACjB,gBAAM,KAAK,MAAM;AAGjB,oBAAU,IAAI,KAAK,IAAK,UAAU,GAAG,EAAG;AACxC,oBAAU,IAAI,KAAK,IAAK,UAAU,GAAG,EAAG;AACxC,oBAAU,QAAQ,KAAK,IAAK,UAAU,OAAO,EAAG;AAChD,oBAAU,SAAS,KAAK,IAAK,UAAU,QAAQ,EAAG;AAGlD,qBAAW,OAAO,MAAO;AACxB,kBAAM,KAAK,KAAK,IAAK,CAAE;AACvB,kBAAM,KAAK,KAAK,IAAK,CAAE;AAGvB,gBAAI,KAAK,KAAK,MAAM,SAAS,KAAK,KAAK,MAAM,QAAS;AACrD;AAAA,YACD;AAEA,kBAAM,SAAS,KAAK,QAAQ;AAG5B,gBAAI,SAAU,MAAO,GAAI;AACxB;AAAA,YACD;AAGA,kBAAM,YAAY,SAAS;AAC3B,gBAAI,KAAM,YAAY,CAAE,IAAI,GAAI;AAC/B,uBAAU,MAAO,IAAI;AACrB,oBAAM,KAAM,EAAE,KAAK,IAAI,KAAK,GAAG,CAAE;AAAA,YAClC;AAAA,UACD;AAAA,QACD;AAGA,kBAAU,QAAQ,UAAU,QAAQ,UAAU,IAAI;AAClD,kBAAU,SAAS,UAAU,SAAS,UAAU,IAAI;AAGpD,YAAM,UAAU,QAAQ,UAAU,SAAW,GAAI;AAChD,oBAAU,OAAO,KAAM,SAAU;AAAA,QAClC;AAAA,MACD;AAAA,IACD;AAAA,EACD;;;ADj/BA,MAAM,iBAAmB,MAAM,MAAQ;AAEvC,MAAI,eAAe,CAAC;AACpB,MAAI,kBAAkB,oBAAI,IAAI;AAC9B,MAAI,iBAAiB;AASd,WAASC,MAAMC,MAAM;AAG3B,UAAM,oBAAoB;AAAA,MACzB;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAC7E;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;AAAA,MAAW;A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",
  "names": ["queueMicrotask", "pad", "init", "init", "cleanup", "init", "display_default", "display_default", "init", "init", "api", "point_default", "image_default", "init", "point_default", "image_default", "init", "init", "init", "queueMicrotask", "batch", "x", "y", "a", "b", "m_isDebug", "init", "api", "cleanup", "queueMicrotask", "init", "init", "init", "init", "api", "registerCommands", "img", "init", "api", "registerCommands", "createColor", "init", "api", "cls", "init", "api", "resizeScreen", "registerCommands", "screen", "m_api", "init", "api", "registerCommands", "init", "m_api", "init", "api", "init", "init", "api", "registerCommands", "queueMicrotask", "init", "init", "api", "registerCommands", "init", "init", "api", "registerCommands", "init", "init", "init", "api", "registerCommands", "i", "init", "api", "registerCommands"]
}
