import { listOutputFiles, Template } from './index.js'; import { Accents, colorSetToVariants } from '../color-set/index.js'; import { source } from 'common-tags'; const SIZE = 70; const MAX_DISTANCE = SIZE * 5; const LEAK_FACTOR = 0.25; function getClampedPoint( x1: number, y1: number, maxX: number, maxY: number, ): [number, number] { const distance = Math.sqrt(Math.pow(maxX - x1, 2) + Math.pow(maxY - y1, 2)); const x2 = x1 + (MAX_DISTANCE / distance) * (maxX - x1); const y2 = y1 + (MAX_DISTANCE / distance) * (maxY - y1); const croppedDistance = Math.sqrt( Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2), ); return croppedDistance > distance ? [maxX, maxY] : [x2, y2]; } const template: Template = { name: 'Burst wallpaper', render: async function* (colorSet, options) { const variants = colorSetToVariants(colorSet); for (const variant of variants) { for (const size of options.wallpaperSizes) { const focalPoint = { x: size.w / 2, y: size.h / 2, }; const svg = source` ${Array(Math.round(size.w / SIZE)) .fill(null) .map((_, i, { length: xCount }) => Array(Math.round(size.h / SIZE)) .fill(null) .map((_, j, { length: yCount }) => { const cellWidth = size.w / xCount; const cellHeight = size.h / yCount; const x1 = i * cellWidth + Math.random() * cellWidth; const y1 = j * cellHeight + Math.random() * cellHeight; const [x2, y2] = getClampedPoint( x1, y1, focalPoint.x, focalPoint.y, ); const keys: (keyof Accents)[] = [ 'accent0', 'accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6', 'accent7', ]; const accentKey = keys[ (Math.round( (i / xCount) * keys.length + (Math.random() * LEAK_FACTOR * 2 - LEAK_FACTOR), ) + keys.length) % keys.length ]; const color = variant.colors[accentKey!]; const id = `${i}-${j}`; return source` `; }) .join('\n'), ) .join('\n')} `; yield { path: `${variant.title.kebab}-${size.w}x${size.h}.svg`, content: svg, }; } } }, renderInstructions: listOutputFiles, }; export default template;