#!/usr/bin/env node /** * Generates the baked nine-slice texture used by Card variant="textured". * * This file is the source of truth for the procedural visual. It deliberately * lives outside runtime code: edit the parameters below, run this script, then * visually compare the generated asset before committing it. */ import { chromium } from "@playwright/test"; import { mkdir } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; const HERE = path.dirname(fileURLToPath(import.meta.url)); const OUTPUT_DIRECTORY = path.resolve(HERE, "../../src/shared/ui/assets"); const DPR = 2; // Approved texture parameters, archived from the former runtime SVG filter. const THRESHOLD_BIAS = 0.302; const SLOPE = 8; const FREQUENCY = 0.999; const OCTAVES = 3; const SEED = 5315; const TEXTURES = [ { filename: "card-texture.png", color: "white", cardSize: 640, outset: 96, blur: 66, innerBand: 112, }, { filename: "card-texture-dark.png", color: "#171b21", cardSize: 640, outset: 96, blur: 66, innerBand: 112, }, { filename: "card-texture-compact.png", color: "white", cardSize: 320, outset: 24, blur: 24, innerBand: 44, }, { filename: "card-texture-dark-compact.png", color: "#171b21", cardSize: 320, outset: 24, blur: 24, innerBand: 44, }, ]; await mkdir(OUTPUT_DIRECTORY, { recursive: true }); const browser = await chromium.launch(); try { for (const texture of TEXTURES) { const captureSize = texture.cardSize + texture.outset * 2; const dilate = Math.round(texture.blur * 0.85); const output = path.join(OUTPUT_DIRECTORY, texture.filename); const page = await browser.newPage({ deviceScaleFactor: DPR, viewport: { height: captureSize, width: captureSize }, }); await page.setContent(`