import type { TixyExpression, TixyRenderOptions, TixyResult } from '../core/types' import { evaluateTixyExpression } from '../core/evaluator' export function renderTixyToCanvas( expression: TixyExpression, options: TixyRenderOptions ): TixyResult { const { width, height, time, backgroundColor = '#000000', foregroundColor = '#ffffff', threshold = 0.3, pixelSize = 1 } = options const canvas = document.createElement('canvas') canvas.width = width * pixelSize canvas.height = height * pixelSize const ctx = canvas.getContext('2d')! const imageData = ctx.createImageData(width * pixelSize, height * pixelSize) const data = imageData.data const bgColor = hexToRgb(backgroundColor) const fgColor = hexToRgb(foregroundColor) for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const i = y * width + x const value = evaluateTixyExpression(expression, time, i, x, y) const color = Math.abs(value) > threshold ? { r: Math.round(fgColor.r * (Math.sign(value) > 0 ? 1 : 0.8)), g: Math.round(fgColor.g * (Math.sign(value) > 0 ? 1 : 0.8)), b: Math.round(fgColor.b * (Math.sign(value) > 0 ? 1 : 0.8)) } : bgColor for (let py = 0; py < pixelSize; py++) { for (let px = 0; px < pixelSize; px++) { const actualX = x * pixelSize + px const actualY = y * pixelSize + py const pixelIndex = (actualY * width * pixelSize + actualX) * 4 data[pixelIndex] = color.r data[pixelIndex + 1] = color.g data[pixelIndex + 2] = color.b data[pixelIndex + 3] = 255 } } } } ctx.putImageData(imageData, 0, 0) return { imageData, canvas } } export function renderTixyToImageData( expression: TixyExpression, options: TixyRenderOptions ): ImageData { return renderTixyToCanvas(expression, options).imageData } function hexToRgb(hex: string): { r: number; g: number; b: number } { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : { r: 0, g: 0, b: 0 } }