/** * A color packed into 32 bits as RGBA in little-endian byte order, i.e. the * bytes in memory run R, G, B, A. That is exactly the layout a canvas * ImageData expects, so the `Uint32Array` framebuffer can be reinterpreted as * an ImageData with zero per-pixel conversion at blit time. */ export type Color = number export namespace Color { export function rgb(r: number, g: number, b: number, a = 255): Color { // The shifts coerce the (possibly fractional) inputs to int32 and pack the // channels; `>>> 0` forces an unsigned result so it stays a valid Color. return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 } export function r(c: Color): number { return c & 0xFF } export function g(c: Color): number { return (c >>> 8) & 0xFF } export function b(c: Color): number { return (c >>> 16) & 0xFF } export function a(c: Color): number { return (c >>> 24) & 0xFF } /** Multiply RGB by a scalar (for shading), keeping alpha. */ export function scale(c: Color, s: number): Color { return rgb(r(c) * s, g(c) * s, b(c) * s, a(c)) } /** Linear blend between two colors, t in 0..1. Used for fog and bilinear. */ export function lerp(from: Color, to: Color, t: number): Color { return rgb( r(from) + (r(to) - r(from)) * t, g(from) + (g(to) - g(from)) * t, b(from) + (b(to) - b(from)) * t, ) } }