{
  "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,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\" };", "export default { \"data\": \"data:image/webp;base64,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\" };", "/**\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": "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AAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAC7E,UAAW,UAAW,UAAW,UAAW,UAAW,SACxD,CAG0C,CAAE,EAC5CC,GAAiB,CAA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",
  "names": ["utils_exports", "__export", "calcColorDifference", "clamp", "colorToHex", "convertToColor", "copyColor", "createColor", "degreesToRadian", "errFn", "generateColorKey", "getFloat", "getInt", "hexToData", "inRange", "inRange2", "isDomElement", "isFunction", "isObjectLiteral", "pad", "padL", "parseOptions", "queueMicrotask", "radiansToDegrees", "rgbToColor", "rndRange", "commandName", "error", "args", "parameterNames", "resultOptions", "name", "isNamedParameterFound", "inputOptions", "i", "fn", "el", "obj", "proto", "hex", "width", "height", "data", "digits", "digitIndex", "y", "x", "hexPart", "num", "min", "max", "point", "hitBox", "x1", "y1", "x2", "y2", "deg", "rad", "str", "len", "c", "val", "def", "parsed", "callback", "m_colorCheckerContext", "COLOR_PROTO", "colorArray", "color", "r", "g", "b", "a", "hexToColor", "splitRgb", "colorStringToColor", "c1", "c2", "w", "dr", "dg", "db", "da", "colorSrc", "colorDest", "cToHex", "s", "parts", "colors", "colorStr", "commands_exports", "__export", "addCommand", "addSetting", "done", "init", "processCommands", "set", "wait", "screen_manager_exports", "__export", "m_activeScreenData", "addScreenCleanupFunction", "addScreenDataItem", "addScreenDataItemGetter", "addScreenInitFunction", "getActiveScreen", "getAllScreensData", "getScreenData", "init", "m_screenCanvasMap", "renderer_exports", "__export", "GEOMETRY_BATCH", "IMAGE_BATCH", "IMAGE_REPLACE_BATCH", "POINTS_BATCH", "POINTS_REPLACE_BATCH", "blendModeChanged", "cleanup", "cls", "createContext", "deleteWebGL2Texture", "displayToCanvas", "drawArc", "drawBezier", "drawCachedGeometry", "drawCircle", "drawCircleFilled", "drawEllipse", "drawImage", "drawLine", "drawPixel", "drawPixelUnsafe", "drawRect", "drawRectFilled", "drawSprite", "flushBatches", "getWebGL2Texture", "init", "prepareBatch", "readPixel", "readPixelAsync", "readPixels", "readPixelsAsync", "readPixelsRaw", "resizeScreen", "setImageDirty", "shiftImageUp", "updateWebGL2TextureImage", "updateWebGL2TextureSubImage", "display_default", "display_default", "init", "addScreenDataItem", "compileShader", "gl", "type", "source", "shader", "createShaderProgram", "vertexSrc", "fragSrc", "vertexShader", "fragmentShader", "error", "program", "errLog", "setupDisplayShader", "screenData", "display_default", "positions", "positionBuffer", "positionLoc", "textureLoc", "blends_exports", "__export", "BLENDS", "BLEND_ALPHA", "BLEND_REPLACE", "init", "BLEND_REPLACE", "BLEND_ALPHA", "BLENDS", "init", "api", "addScreenDataItem", "registerCommands", "addCommand", "setBlend", "setNoise", "screenData", "options", "blend", "error", "previousBlend", "previousBlends", "blendModeChanged", "noise", "seed", "noiseErrorMsg", "noiseResult", "validateNoiseValFn", "noiseVal", "i", "noiseRow", "j", "getInt", "val", "noiseSeed", "getFloat", "previousNoise", "previousSeed", "isNoiseChanged", "point_default", "point_default", "image_default", "image_default", "geometry_default", "POINTS_BATCH", "IMAGE_BATCH", "GEOMETRY_BATCH", "POINTS_REPLACE_BATCH", "IMAGE_REPLACE_BATCH", "MAX_SIZE_MULTIPLIER", "DEFAULT_POINT_BATCH_SIZE", "MAX_POINT_BATCH_SIZE", "DEFAULT_IMAGE_BATCH_SIZE", "MAX_IMAGE_BATCH_SIZE", "DEFAULT_GEOMETRY_BATCH_SIZE", "MAX_GEOMETRY_BATCH_SIZE", "BATCH_CAPACITY_SHRINK_INTERVAL", "BATCH_TYPES", "m_batchProto", "m_isDebug", "init", "addScreenDataItem", "createBatches", "screenData", "createBatch", "type", "gl", "batch", "vertSrc", "fragSrc", "point_default", "image_default", "geometry_default", "createShaderProgram", "resizeBatch", "newCapacity", "newVertices", "newColors", "newTexCoords", "prepareBatch", "batchType", "itemCount", "texture", "batchInfo", "batchTypeChanging", "textureChanging", "lastDrawOrderItem", "drawOrderItem", "requiredCount", "flushBatches", "blends", "uploadBatch", "BLEND_REPLACE", "drawBatch", "resetBatch", "width", "height", "startIndex", "endIndex", "noise", "noiseSeed", "noiseMin", "noiseMax", "timeValue", "resetBatches", "displayToCanvas", "program", "locations", "cleanup", "addVertexToBatch", "batch", "x", "y", "color", "idx", "cidx", "addTriangleToBatch", "x1", "y1", "x2", "y2", "x3", "y3", "tessellateCubicBezier", "x0", "y0", "x1", "y1", "x2", "y2", "x3", "y3", "maxError", "out", "pointLineDistanceSq", "px", "py", "ax", "ay", "bx", "by", "abx", "aby", "apx", "apy", "abLenSq", "t", "cx", "cy", "dx", "dy", "maxErrorSq", "maxDepth", "subdivide", "depth", "d1", "d2", "bcx", "bcy", "cdx", "cdy", "abbcx", "abbcy", "bccdx", "bccdy", "midx", "midy", "FILLED_CIRCLE", "m_geometryCache", "init", "prepopulateCache", "circle1", "generateSinglePixelGeometry", "m_geometryCache", "FILLED_CIRCLE", "radius", "cacheKey", "geometry", "generateCircleGeometry", "addVertex", "vertices", "vIdx", "x", "y", "addTriangle", "x1", "y1", "x2", "y2", "x3", "y3", "addQuad", "scanlineMinMax", "err", "updateScanline", "px", "py", "pixelY", "pixelX", "limits", "vertexCount", "sortedYCoords", "currentY", "mm", "a", "b", "row", "xStart", "xEnd", "getCachedGeometry", "cacheType", "unit", "drawCachedGeometry", "screenData", "color", "batch", "GEOMETRY_BATCH", "prepareBatch", "i", "vx", "vy", "addVertexToBatch", "init", "addScreenDataItem", "copyImageToTexture", "gl", "img", "imgScreenData", "m_screenCanvasMap", "flushBatches", "srcGl", "width", "height", "pixelData", "rowSize", "tempRow", "y", "topRow", "bottomRow", "getWebGL2Texture", "screenData", "contextTextureMap", "otherScreenData", "displayToCanvas", "texture", "error", "deleteWebGL2Texture", "contextMap", "updateWebGL2TextureSubImage", "imgKey", "dstX", "dstY", "updateWebGL2TextureImage", "readPixel", "screenData", "x", "y", "flushBatches", "gl", "glY", "buf", "rgbToColor", "readPixelAsync", "resolve", "queueMicrotask", "readPixels", "width", "height", "screenWidth", "screenHeight", "clampedX", "clampedY", "clampedWidth", "clampedHeight", "glReadY", "resultColors", "row", "resultsRow", "col", "bufRow", "i", "readPixelsAsync", "readPixelsRaw", "MAX_QUAD_COLOR_MAP_SIZE", "m_quadColorMap", "calculateTransformedCorners", "width", "height", "anchorX", "anchorY", "scaleX", "scaleY", "angleRad", "x", "y", "scaledWidth", "scaledHeight", "anchorXPx", "anchorYPx", "corners", "cos", "sin", "i", "corner", "rx", "ry", "addTexturedQuadToBatch", "screenData", "texture", "texCoords", "colorQuadArray", "batchType", "batch", "prepareBatch", "batchVertices", "batchTexCoords", "batchColors", "baseIdx", "vertexBase", "texBase", "colorBase", "vIdx", "tIdx", "getQuadColorArray", "color", "quadColorArray", "g", "b", "a", "drawImage", "img", "IMAGE_BATCH", "getWebGL2Texture", "imgWidth", "imgHeight", "drawSprite", "sx", "sy", "sw", "sh", "texWidth", "texHeight", "u0", "v0", "u1", "v1", "drawPixel", "screenData", "x", "y", "batchType", "prepareBatch", "batch", "addVertexToBatch", "drawPixelUnsafe", "color", "TWO_PI", "FULL_CIRCLE_EPSILON", "drawArc", "screenData", "cx", "cy", "radius", "angle1", "angle2", "color", "a1", "normalizeAngle", "a2", "span", "isFullCircle", "isLargeArc", "estimatedPixels", "batchIndex", "POINTS_BATCH", "prepareBatch", "batch", "startX", "startY", "endX", "endY", "setPixel", "px", "py", "addVertexToBatch", "dx", "dy", "cuw", "cvw", "finalRadius", "y", "err", "angle", "normalized", "drawBezier", "screenData", "p0x", "p0y", "p1x", "p1y", "p2x", "p2y", "p3x", "p3y", "color", "pts", "tessellateCubicBezier", "batch", "POINTS_BATCH", "prepareBatch", "addVertexToBatch", "drawn", "i", "x1", "y1", "x2", "y2", "dx", "dy", "pointCount", "sx", "sy", "err", "x", "y", "key", "e2", "drawLine", "screenData", "x1", "y1", "x2", "y2", "color", "dx", "dy", "pointCount", "batch", "POINTS_BATCH", "prepareBatch", "sx", "sy", "err", "x", "y", "addVertexToBatch", "e2", "drawRect", "screenData", "x", "y", "width", "height", "x2", "y2", "color", "drawRectFilled", "batch", "GEOMETRY_BATCH", "prepareBatch", "x1", "y1", "addTriangleToBatch", "drawCircle", "screenData", "cx", "cy", "radius", "color", "prepareBatch", "POINTS_BATCH", "drawPixelUnsafe", "perimeterPixels", "x", "y", "err", "drawCircleFilled", "drawCachedGeometry", "FILLED_CIRCLE", "drawEllipse", "screenData", "cx", "cy", "rx", "ry", "fillColor", "color", "prepareBatch", "POINTS_BATCH", "singleBatch", "addVertexToBatch", "b", "perimeter", "estimatedPixels", "pointsBatchIndex", "pointsBatch", "plotPoint", "px", "py", "ix", "iy", "plotSymmetric", "x", "y", "rx2", "ry2", "dx", "dy", "d1", "doFill", "scanlineMinMax", "updateScanlineSym", "updateScanline", "pixelY", "pixelX", "limits", "sx", "sy", "d2", "sortedYCoords", "currentY", "a", "vertexCount", "GEOMETRY_BATCH", "geoBatch", "row", "xStart", "xEnd", "yWorld", "x1", "x2", "shiftImageUp", "screenData", "yOffset", "gl", "width", "height", "flushBatches", "cls", "x", "y", "resetBatches", "scissorY", "m_isDebug", "m_offscreenContext", "init", "api", "addScreenDataItem", "addScreenCleanupFunction", "cleanup", "createContext", "screenData", "canvas", "width", "height", "error", "fboAndTexture", "createTextureAndFBO", "bufferFboAndTexture", "createBatches", "setupDisplayShader", "debugExt", "e", "gl", "fboTexture", "FBO", "status", "setImageDirty", "queueMicrotask", "flushBatches", "displayToCanvas", "blendModeChanged", "previousBlends", "resizeScreen", "oldWidth", "oldHeight", "newWidth", "newHeight", "copyWidth", "copyHeight", "srcY", "graphics_exports", "__export", "buildApi", "init", "colors_exports", "__export", "findColorIndexByColorValue", "getColorValueByIndex", "getColorValueByRawInput", "init", "images_exports", "__export", "getImageFromRawInput", "getStoredImage", "init", "palettizeImages", "m_images", "m_paletteImages", "m_imageCount", "init", "api", "registerCommands", "addScreenDataItem", "addScreenInitFunction", "palettizeImages", "addCommand", "loadImage", "loadSpritesheet", "getImage", "getSpritesheetData", "removeImage", "createImageFromScreen", "setDefaultAnchor", "options", "src", "name", "usePalette", "paletteKeys", "onLoadCallback", "onErrorCallback", "srcErrMsg", "error", "isFunction", "palColors", "palColorMap", "convertToColor", "i", "palColorRaw", "palColor", "updateImageFn", "img", "imageObj", "addPaletteImage", "wait", "done", "screenData", "getAllScreensData", "deleteWebGL2Texture", "spriteWidth", "spriteHeight", "margin", "isAuto", "imageName", "imageData", "width", "height", "processSpriteSheetAuto", "processSpriteSheetFixed", "getImageFromRawInput", "imgScreenData", "getScreenData", "x1", "getInt", "y1", "x2", "y2", "clamp", "actualX", "actualY", "canvas", "createCanvasFromScreenRegion", "anchorX", "getFloat", "anchorY", "spriteData", "getStoredImage", "spriteDataResult", "x", "y", "pixelData", "readPixelsRaw", "context", "canvasData", "row", "col", "srcIndex", "dstIndex", "imageOrName", "fnName", "imgName", "isTexImageCompatible", "fakeScreenData", "data", "color", "rgbToColor", "index", "findColorIndexByColorValue", "newColor", "palettizeImage", "len", "palettizedImageData", "key", "generateColorKey", "palIndex", "updateWebGL2TextureImage", "searched", "dirs", "pixelIndex", "frameData", "queue", "head", "pixel", "px", "py", "dir", "nx", "ny", "nIndex", "dataIndex", "MAX_DIFFERENCE", "m_defaultPal", "m_defaultPalMap", "m_defaultColor", "init", "api", "setDefaultPal", "setDefaultColor", "addScreenDataItemGetter", "registerCommands", "addCommand", "getDefaultPal", "getDefaultColor", "createColor", "setColor", "getColor", "getPal", "setPal", "getPalIndex", "setBgColor", "setContainerBgColor", "setPalColors", "addPalColors", "getPalColor", "options", "pal", "error", "convertToColor", "i", "c", "include0", "filteredPal", "startIndex", "rgbToColor", "findColorIndexByColorValue", "color", "screenData", "colorInput", "colorValue", "newPal", "currentColor", "newIndex", "palettizeImages", "tolerance", "getFloat", "colorRaw", "getColorValueByRawInput", "colorToHex", "indices", "colors", "colorSwapped", "index", "oldColor", "newIndices", "colorsAdded", "rawInput", "minSimularity", "bestMatchIndex", "bestMatchSimularity", "palColor", "difference", "calcColorDifference", "similarity", "getColorValueByIndex", "palIndex", "DEFAULT_BLIT_COLOR", "rgbToColor", "m_api", "init", "api", "buildApi", "addCommand", "cls", "addScreenInitFunction", "screenData", "s_screenData", "errFn", "s_drawArc", "drawArc", "s_drawBezier", "drawBezier", "s_drawCircle", "drawCircle", "s_drawCircleFilled", "drawCircleFilled", "s_drawEllipse", "drawEllipse", "s_drawLine", "drawLine", "s_drawPixel", "drawPixel", "s_drawRect", "drawRect", "s_drawRectFilled", "drawRectFilled", "s_drawImage", "drawImage", "s_drawSprite", "drawSprite", "s_getImageFromRawInput", "getImageFromRawInput", "s_getStoredImage", "getStoredImage", "s_isObjectLiteral", "isObjectLiteral", "s_setImageDirty", "setImageDirty", "s_getInt", "getInt", "s_getFloat", "getFloat", "s_degreesToRadian", "degreesToRadian", "s_getColorValueByRawInput", "getColorValueByRawInput", "s_pointsBatch", "POINTS_BATCH", "s_imageReplaceBatch", "IMAGE_REPLACE_BATCH", "arcFn", "x", "y", "radius", "angle1", "angle2", "pX", "pY", "pRadius", "error", "arcFnWrapper", "bezierFn", "x1", "y1", "x2", "y2", "x3", "y3", "x4", "y4", "pX1", "pY1", "pX2", "pY2", "pX3", "pY3", "pX4", "pY4", "bezierFnWrapper", "circleFn", "fillColor", "fillColorValue", "circleFnWrapper", "ellipseFn", "radiusX", "radiusY", "pRx", "pRy", "ellipseFnWrapper", "lineFn", "lineFnWrapper", "psetFn", "psetFnWrapper", "rectFn", "width", "height", "pWidth", "pHeight", "fWidth", "fHeight", "rectFnWrapper", "blitImageFn", "img", "color", "anchorX", "anchorY", "scaleX", "scaleY", "angleRad", "pAnchorX", "pAnchorY", "blitImageFnWrapper", "blitSpriteFn", "name", "frame", "spriteData", "frameData", "pColor", "blitSpriteFnWrapper", "drawImageFn", "image", "angle", "drawImageFnWrapper", "drawSpriteFn", "imgName", "drawSpriteFnWrapper", "options", "clamp", "SCREEN_API_PROTO", "m_screens", "m_screenCanvasMap", "m_screenDataItems", "m_screenDataItemGetters", "m_screenDataInitFunctions", "m_screenDataCleanupFunctions", "MAX_CANVAS_DIMENSION", "m_observedContainers", "m_nextScreenId", "m_activeScreenData", "m_resizeObserver", "m_offscreenCanvas", "init", "api", "m_resizeObserver", "entries", "entry", "canvases", "canvas", "screenId", "screenData", "m_screens", "resizeScreen", "registerCommands", "SCREEN_API_PROTO", "removeScreen", "addScreenInitFunction", "addCommand", "screen", "setScreen", "getScreen", "getAllScreens", "removeAllScreens", "widthCmd", "heightCmd", "canvasCmd", "addScreenDataItem", "name", "val", "m_screenDataItems", "addScreenDataItemGetter", "fn", "m_screenDataItemGetters", "m_screenDataInitFunctions", "addScreenCleanupFunction", "m_screenDataCleanupFunctions", "getActiveScreen", "fnName", "isScreenOptional", "m_activeScreenData", "error", "getScreenData", "getAllScreensData", "screens", "id", "options", "isFunction", "m_nextScreenId", "itemGetter", "parseAspect", "validateDimensions", "m_offscreenCanvas", "setupOffscreenCanvasOptions", "isDomElement", "setDefaultCanvasOptions", "m_observedContainers", "m_screenCanvasMap", "createContext", "aspect", "match", "width", "splitter", "height", "MAX_CANVAS_DIMENSION", "allScreenDatas", "key", "hasOtherScreens", "otherScreen", "i", "getter", "screenObj", "previousScreenId", "buildApi", "getInt", "isInit", "fromSize", "lastScreenWidth", "lastScreenHeight", "size", "getSize", "setCanvasSize", "toSize", "maxWidth", "maxHeight", "aspectData", "newCssWidth", "newCssHeight", "factorX", "factorY", "factor", "ratio1", "ratio2", "element", "m_settings", "m_commands", "m_api", "m_readyCallbacks", "m_isDocumentReady", "m_waitCount", "m_checkReadyTimeout", "init", "api", "onDocumentReady", "registerCommands", "addScreenInitFunction", "processScreenCommands", "addCommand", "ready", "set", "name", "fn", "isScreen", "parameterNames", "isScreenOptional", "settingName", "processCommands", "command", "processCommand", "args", "options", "parseOptions", "screenData", "getActiveScreen", "callback", "isFunction", "error", "resolve", "scheduleReadyCheck", "wait", "done", "checkReady", "callbacks", "item", "optionName", "setting", "argsArray", "parsedOptions", "addSetting", "plugins_exports", "__export", "init", "m_plugins", "m_waitingForDependencies", "m_clearEventsHandlers", "m_api", "init", "api", "addCommand", "registerPlugin", "getPlugins", "clearEvents", "pluginInfo", "missingDependencies", "dependency", "pi", "initializePlugin", "options", "error", "p", "isWaitingForDependencies", "screenData", "type", "lowerType", "handler", "validTypes", "errorMessage", "handlerName", "registerClearEvents", "name", "lowerName", "pluginApi", "addScreenDataItem", "addScreenDataItemGetter", "addScreenInitFunction", "addScreenCleanupFunction", "getScreenData", "getAllScreensData", "utils_exports", "wait", "done", "processCommands", "pluginError", "pixels_exports", "__export", "init", "init", "api", "registerCommands", "data", "x", "y", "include0", "putWrapper", "getActiveScreen", "addScreenInitFunction", "screenData", "addCommand", "getPixel", "getPixelAsync", "get", "getAsync", "filterImg", "options", "px", "getInt", "py", "error", "asIndex", "colorValue", "readPixel", "findColorIndexByColorValue", "readPixelAsync", "pX", "pY", "pWidth", "pHeight", "tolerance", "getFloat", "colors", "readPixels", "convertColorsToIndices", "readPixelsAsync", "width", "results", "row", "resultsRow", "rowLength", "col", "idx", "filter", "x1", "y1", "x2", "y2", "isFunction", "clamp", "temp", "height", "queueMicrotask", "applyFilter", "flushBatches", "imageData", "readPixelsRaw", "screenHeight", "filteredData", "pixelData", "srcRow", "srcIndex", "dstIndex", "dstY", "updateWebGL2TextureSubImage", "setImageDirty", "pData", "pInclude0", "isObjectLiteral", "screenW", "screenH", "startX", "startY", "pixelCount", "i", "prepareBatch", "POINTS_REPLACE_BATCH", "put", "endY", "endX", "dataY", "dataX", "colorIndex", "getColorValueByIndex", "sx", "sy", "drawPixelUnsafe", "paint_exports", "__export", "init", "init", "api", "registerCommands", "addCommand", "paint", "screenData", "options", "x", "getInt", "y", "fillColor", "tolerance", "getFloat", "boundaryColor", "error", "getColorValueByRawInput", "width", "height", "drawRectFilled", "setImageDirty", "pixels2D", "readPixels", "startColor", "weights", "maxDifference", "a", "toleranceThreshold", "visited", "queue", "shouldSkipPixel", "pixelColor", "difference", "calcColorDifference", "pixelCount", "prepareBatch", "POINTS_BATCH", "head", "pixel", "px", "py", "drawPixelUnsafe", "addToQueue", "index", "draw_exports", "__export", "init", "init", "api", "addScreenDataItem", "registerCommands", "addCommand", "draw", "screenData", "options", "drawString", "error", "tempColors", "i", "reg", "parts", "isReturn", "lastCursor", "isBlind", "isArc", "arcRadius", "arcAngle1", "arcAngle2", "scale", "drawArgs", "colorNum", "colorStr", "len", "getInt", "angle", "degreesToRadian", "boundryNumber", "clamp", "fonts_exports", "__export", "init", "setFont", "print_exports", "__export", "init", "updatePrintCursorDimensions", "init", "api", "addScreenDataItem", "registerCommands", "addCommand", "print", "setPos", "setPosPx", "getPos", "getPosPx", "getCols", "getRows", "setWordBreak", "setPrintSize", "calcWidth", "screenData", "options", "msg", "isInline", "isCentered", "error", "parts", "i", "startPrint", "col", "row", "printCursor", "x", "y", "scaleWidth", "getFloat", "scaleHeight", "padX", "getInt", "padY", "updatePrintCursorDimensions", "font", "width", "overlap", "onScreenPct", "msgSplit", "msg1", "msg2", "index", "shiftImageUp", "bitmapPrint", "getWebGL2Texture", "atlasWidth", "fontWidth", "fontHeight", "printWidth", "scaleX", "scaleY", "margin", "cellWidth", "cellHeight", "columns", "charIndex", "sx", "sy", "dx", "color", "drawSprite", "setImageDirty", "font_6x6_default", "m_font6x8", "getFontImage", "charWidth", "charHeight", "margin", "cellWidth", "cellHeight", "width", "height", "chars", "decompressFont", "data", "x", "y", "char", "dataY", "dataX", "i", "imageData", "canvas", "fontData", "numStr", "byteSize", "byteBase", "bin", "nums", "num", "index", "font_8x8_default", "font_8x14_default", "font_8x16_default", "m_fontMap", "m_defaultFontId", "m_nextFontId", "init", "api", "addScreenDataItem", "registerCommands", "loadDefaultFonts", "addScreenInitFunction", "screenData", "setFont", "addCommand", "loadFont", "setDefaultFont", "getAvailableFonts", "setChar", "font_6x6_default", "getFontImage", "font_8x8_default", "font_8x14_default", "font_8x16_default", "options", "fontSrc", "width", "getInt", "height", "margin", "cellWidth", "cellHeight", "charset", "error", "i", "temp", "chars", "font", "loadFontFromImage", "img", "wait", "done", "err", "fontId", "getWebGL2Texture", "updatePrintCursorDimensions", "fonts", "charCode", "data", "hexToData", "charIndex", "columns", "cellX", "cellY", "sx", "sy", "sw", "sh", "buf", "y", "x", "updateWebGL2TextureSubImage", "VERSION", "api", "mods", "utils_exports", "commands_exports", "screen_manager_exports", "plugins_exports", "renderer_exports", "colors_exports", "graphics_exports", "images_exports", "blends_exports", "pixels_exports", "paint_exports", "draw_exports", "fonts_exports", "print_exports", "mod", "processCommands", "index_default"]
}
