from __future__ import annotations import math import random from pathlib import Path from PIL import Image, ImageDraw ROOT = Path(__file__).resolve().parents[1] ASSET_DIR = ROOT / "public" / "assets" / "webgl" RNG = random.Random(1780504860) def save_normal(path: Path, size: int = 2048) -> None: image = Image.new("RGB", (size, size)) pixels = image.load() for y in range(size): for x in range(size): grain = ( math.sin(x * 0.028) * 8 + math.sin((x + y) * 0.011) * 5 + math.sin(x * 0.11 + y * 0.007) * 2 ) pore = math.sin(y * 0.12 + math.sin(x * 0.016) * 2.1) * 3 + (RNG.random() - 0.5) * 6 pixels[x, y] = ( max(0, min(255, round(128 + grain))), max(0, min(255, round(128 + pore))), 255, ) image.save(path) def save_dust(path: Path, size: int = 4096) -> None: image = Image.new("L", (size, size), 1) pixels = image.load() for y in range(size): ny = y / size for x in range(size): nx = x / size edge_dust = max(0, 1 - min(nx, ny, 1 - nx, 1 - ny) * 18) micro_noise = (RNG.random() ** 7.2) * 5.5 fine_film = max(0, math.sin(nx * 21 + math.sin(ny * 11) * 0.7) - 0.988) * 3 book_shelter = math.exp(-((nx - 0.5) * 2.7) ** 2 - ((ny - 0.5) * 1.8) ** 2) * 1.5 value = min(255, 1 + edge_dust * 3 + micro_noise + fine_film + book_shelter) pixels[x, y] = round(value) draw = ImageDraw.Draw(image, "L") for _ in range(1700): x = RNG.random() * size y = RNG.random() * size radius = 0.08 + RNG.random() * 0.22 value = round(230 * 0.028) draw.ellipse((x - radius, y - radius, x + radius, y + radius), fill=value) image.save(path) def soft_ellipse(draw: ImageDraw.ImageDraw, x: float, y: float, rx: float, ry: float, alpha: float) -> None: steps = 36 for step in range(steps, 0, -1): scale = step / steps value = round(220 * alpha * (scale ** 2.1)) draw.ellipse((x - rx * scale, y - ry * scale, x + rx * scale, y + ry * scale), fill=value) def save_grease(path: Path, size: int = 4096) -> None: image = Image.new("L", (size, size), 0) draw = ImageDraw.Draw(image, "L") for x, y, rx, ry, alpha in [ (0.17, 0.38, 210, 88, 0.088), (0.83, 0.24, 170, 76, 0.081), (0.73, 0.76, 185, 78, 0.072), (0.5, 0.52, 300, 120, 0.053), ]: soft_ellipse(draw, size * x, size * y, rx, ry, alpha) for _ in range(8): x = size * (0.2 + RNG.random() * 0.62) y = size * (0.18 + RNG.random() * 0.64) rx = 36 + RNG.random() * 22 ry = 14 + RNG.random() * 8 alpha = 0.102 + RNG.random() * 0.042 soft_ellipse(draw, x, y, rx, ry, alpha) for ridge in [i / 100 for i in range(-70, 71, 18)]: bbox = ( x - rx * (0.26 + abs(ridge) * 0.58), y - ry * (0.2 + abs(ridge) * 0.5), x + rx * (0.26 + abs(ridge) * 0.58), y + ry * (0.2 + abs(ridge) * 0.5), ) draw.arc(bbox, 15, 345, fill=round(245 * alpha * 0.42), width=2) image.save(path) def main() -> None: ASSET_DIR.mkdir(parents=True, exist_ok=True) save_normal(ASSET_DIR / "table_normal_2k.png") save_dust(ASSET_DIR / "table_dust_4k.png") save_grease(ASSET_DIR / "table_grease_4k.png") if __name__ == "__main__": main()