Files
coolsoup/src/generators/tixy-generator/renderer/canvas.ts
Raphaël Forment 623082ce3b Initial CoolSoup implementation
CoolSoup is a React + TypeScript + Vite application that generates visual patterns and converts them to audio through spectral synthesis. Features multiple image generators (Tixy expressions, geometric tiles, external APIs) and an advanced audio synthesis engine that treats images as spectrograms.
2025-09-29 14:44:48 +02:00

79 lines
2.2 KiB
TypeScript

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 }
}