Генеративный холст
Canvas — это отложенное 2D-рисование, которое запекается в текстуру; здесь оно показано внутри UIImage. Каждое нажатие меняет зерно небольшого генератора и перерисовывает картинку, а canvas.update() отправляет новые пиксели во все изображения, которые питает канвас. Кадрового цикла нет — картинка меняется только по запросу.
// Canvas is retained 2D drawing that bakes to a texture — shown here inside a UIImage. We draw
// once, and each tap reseeds a small PRNG and redraws; canvas.update() pushes the new pixels to
// every image the canvas backs. No frame loop — the picture changes only when asked.
const SIZE = 320
const canvas = new Canvas(SIZE, SIZE, { pixelRatio: 2 })
const PALETTE = ["#FF4032", "#FFB020", "#22c55e", "#38bdf8", "#a855f7"]
let seed = 1
const rand = () => (seed = (seed * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff
function draw() {
canvas.reset()
canvas.fillStyle = "#0e121b"
canvas.fillRect(0, 0, SIZE, SIZE)
const hue = PALETTE[Math.floor(rand() * PALETTE.length)]!
const rings = 5 + Math.floor(rand() * 4)
for (let r = rings; r >= 1; r--) {
canvas.fillStyle = r % 2 === 0 ? hue : "#141a25"
canvas.beginPath().arc(SIZE / 2, SIZE / 2, (r / rings) * SIZE * 0.46, 0, Mathf.TAU).fill()
}
const petals = 2 + Math.floor(rand() * 5)
canvas.strokeStyle = "#ffffff"
canvas.lineWidth = 2
canvas.lineJoin = "round"
canvas.beginPath()
for (let i = 0; i <= 96; i++) {
const a = (i / 96) * Mathf.TAU
const rad = SIZE * (0.16 + 0.13 * Math.sin(a * petals))
const x = SIZE / 2 + Math.cos(a) * rad, y = SIZE / 2 + Math.sin(a) * rad
i === 0 ? canvas.moveTo(x, y) : canvas.lineTo(x, y)
}
canvas.closePath().stroke()
canvas.update()
}
draw()
const art = UIImage(canvas).style({ width: SIZE, height: SIZE, borderRadius: 24 })
const screen = UIScreen([
UIText("Generative").style({ fontSize: 26, fontWeight: 700, color: "white" }),
UIText("Tap the canvas to re-roll").style({ fontSize: 13, color: "#8b90a0", mb: 24 }),
UIButton([ art ]).style({ borderRadius: 24, onPressed: { opacity: 0.85 } }).onClick(draw),
]).style({ bgColor: "#0b0d12", alignItems: "center", justifyContent: "center" })
screen.open()
Нажмите «Запустить» — откроется плавающий симулятор. Он остаётся на месте, пока вы читаете: другой пример просто заменит приложение внутри.