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.
This commit is contained in:
2025-09-29 14:44:48 +02:00
parent b564e41820
commit 623082ce3b
79 changed files with 6247 additions and 951 deletions

View File

@ -0,0 +1,79 @@
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 }
}