diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/colors.js | 143 | ||||
-rw-r--r-- | tools/gencolor.js | 27 | ||||
-rw-r--r-- | tools/gentextures.sh | 4 | ||||
-rw-r--r-- | tools/parse-layout.js | 167 | ||||
-rw-r--r-- | tools/rock_overlay@2x.png | bin | 0 -> 160515 bytes |
5 files changed, 341 insertions, 0 deletions
diff --git a/tools/colors.js b/tools/colors.js new file mode 100644 index 0000000..16378f7 --- /dev/null +++ b/tools/colors.js @@ -0,0 +1,143 @@ +"use strict" + +function rgb_from_any(color) { + if (typeof color === "string") + color = parse_hex(color) + switch (color.mode) { + case "rgb": return color + case "lrgb": return rgb_from_lrgb(color) + case "oklab": return rgb_from_oklab(color) + } +} + +function lrgb_from_any(color) { + switch (color.mode) { + case "rgb": return lrgb_from_rgb(color) + case "lrgb": return color + case "oklab": return lrgb_from_oklab(color) + } +} + +function oklab_from_any(color) { + switch (color.mode) { + case "rgb": return oklab_from_rgb(color) + case "lrgb": return oklab_from_lrgb(color) + case "oklab": return color + } +} + +function format_hex(color) { + let { r, g, b } = rgb_from_any(color) + let adj = 1 + r = Math.round(Math.max(0, Math.min(1, r)) * 255) + g = Math.round(Math.max(0, Math.min(1, g)) * 255) + b = Math.round(Math.max(0, Math.min(1, b)) * 255) + let x = (r << 16) | (g << 8) | b + return "#" + x.toString(16).padStart(6, "0") +} + +function parse_hex(str) { + let x = parseInt(str.substring(1), 16) + return { + mode: "rgb", + r: ((x >> 16) & 255) / 255.0, + g: ((x >> 8) & 255) / 255.0, + b: ((x) & 255) / 255.0 + } +} + +function lrgb_from_rgb({ r, g, b }) { + function to_linear(c) { + let ac = Math.abs(c) + if (ac < 0.04045) + return c / 12.92 + return (Math.sign(c) || 1) * Math.pow((ac + 0.055) / 1.055, 2.4) + } + return { + mode: "lrgb", + r: to_linear(r), + g: to_linear(g), + b: to_linear(b) + } +} + +function rgb_from_lrgb({ r, g, b }) { + function from_linear(c) { + let ac = Math.abs(c) + if (ac > 0.0031308) + return (Math.sign(c) || 1) * (1.055 * Math.pow(ac, 1 / 2.4) - 0.055) + return c * 12.92 + } + return { + mode: "rgb", + r: from_linear(r), + g: from_linear(g), + b: from_linear(b) + } +} + +function oklab_from_lrgb({ r, g, b }) { + let L = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b) + let M = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b) + let S = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b) + return { + mode: "oklab", + l: 0.2104542553 * L + 0.793617785 * M - 0.0040720468 * S, + a: 1.9779984951 * L - 2.428592205 * M + 0.4505937099 * S, + b: 0.0259040371 * L + 0.7827717662 * M - 0.808675766 * S + } +} + +function lrgb_from_oklab({ l, a, b }) { + let L = Math.pow(l + 0.3963377774 * a + 0.2158037573 * b, 3) + let M = Math.pow(l - 0.1055613458 * a - 0.0638541728 * b, 3) + let S = Math.pow(l - 0.0894841775 * a - 1.291485548 * b, 3) + return { + mode: "lrgb", + r: +4.0767416621 * L - 3.3077115913 * M + 0.2309699292 * S, + g: -1.2684380046 * L + 2.6097574011 * M - 0.3413193965 * S, + b: -0.0041960863 * L - 0.7034186147 * M + 1.707614701 * S + } +} + +function oklab_from_rgb(rgb) { + return oklab_from_lrgb(lrgb_from_rgb(rgb)) +} + +function rgb_from_oklab(oklab) { + return rgb_from_lrgb(lrgb_from_oklab(oklab)) +} + +function format_hsl(rgb) { + let { r, g, b } = rgb_from_any(color) + let cmin = Math.min(r, g, b) + let cmax = Math.max(r, g, b) + let delta = cmax - cmin + let h = 0, s = 0, l = 0 + + if (delta == 0) + h = 0 + else if (cmax == r) + h = ((g - b) / delta) % 6 + else if (cmax == g) + h = (b - r) / delta + 2 + else + h = (r - g) / delta + 4 + + h = Math.round(h * 60) + + if (h < 0) + h += 360 + + l = (cmax + cmin) / 2 + + s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)) + + s = Math.round(s * 100) + l = Math.round(l * 100) + + return "hsl(" + h + "," + s + "%," + l + "%)" +} + +if (typeof module === "object") + module.exports = { format_hex, parse_hex, rgb_from_any, lrgb_from_any, oklab_from_any, format_hsl } diff --git a/tools/gencolor.js b/tools/gencolor.js new file mode 100644 index 0000000..ea804e6 --- /dev/null +++ b/tools/gencolor.js @@ -0,0 +1,27 @@ +"use strict" + +const colors = require("./colors.js") + +function lerp(v0, v1, t) { + return v0 + t * (v1 - v0) +} + +function lerp_rgb(rgb, x=0, t=0) { + let lab = colors.oklab_from_any(colors.parse_hex(rgb)) + lab.l = lerp(lab.l, x, t) + return colors.format_hex(lab) +} + +function make_colors(rgb, sel) { + let bg = lerp_rgb(rgb, 1.0, 0.0) + let hi = lerp_rgb(rgb, 1.0, 0.4) + let sh = lerp_rgb(rgb, 0.2, 0.4) + let bd = lerp_rgb(rgb, 0.2, 0.8) + console.log(sel + ` { background-color: ${bg}; border-color: ${hi} ${sh} ${sh} ${hi}; box-shadow: 0 0 0 1px ${bd}, 0px 1px 4px #0008; }`) +} + +make_colors("#bbbbbb", ".token.white") +make_colors("#ef0500", ".token.red") +make_colors("#da997b", ".token.pink") +make_colors("#bbb079", ".token.brown") +make_colors("#a6a6a8", ".token.gray") diff --git a/tools/gentextures.sh b/tools/gentextures.sh new file mode 100644 index 0000000..b9eabb9 --- /dev/null +++ b/tools/gentextures.sh @@ -0,0 +1,4 @@ +#!/bin/bash +pngtopnm tools/rock_overlay@2x.png | pnmnorm | pgmtoppm "#000000-#111111" | ppmquant 2 | pnmtopng > tools/texture_mask.png +convert tools/texture_mask.png -alpha copy -fx '#fff' images/texture.png +zopflipng -m -y images/texture.png images/texture.png diff --git a/tools/parse-layout.js b/tools/parse-layout.js new file mode 100644 index 0000000..5dcf4f8 --- /dev/null +++ b/tools/parse-layout.js @@ -0,0 +1,167 @@ +const fs = require("fs") + +const { round, floor, ceil } = Math + +let boxes = {} +let nodes = [] +let edges = [] +let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2 +let scale = 1 + +function flush() { + if (mode === 'path') { + edges.push({ x1: x, y1: y, x2, y2 }) + } + if (mode === 'rect') { + boxes[name] = [ x * scale |0, y * scale |0, w * scale |0, h * scale |0 ] + nodes.push({ name, x: x + w/2, y: y + h/2 }) + } + if (mode === 'circle') { + x = cx - rx + y = cy - ry + w = rx * 2 + h = ry * 2 + boxes[name] = [ x * scale |0, y * scale |0, w * scale |0, h * scale |0 ] + nodes.push({ name, x: cx, y: cy }) + } + x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0 + name = null +} + +function parse_path_data(path) { + let cx = 0 + let cy = 0 + let abs = 0 + for (let i = 0; i < path.length;) { + switch (path[i]) { + case 'M': + x = cx = Number(path[i+1]) + y = cy = Number(path[i+2]) + i += 3 + abs = true + break + case 'm': + x = cx = cx + Number(path[i+1]) + y = cy = cy + Number(path[i+2]) + i += 3 + abs = false + break + case 'C': + x2 = cx = Number(path[i+5]) + y2 = cy = Number(path[i+6]) + i += 7 + abs = true + break + case 'L': + i += 1 + abs = true + break + case 'H': + x2 = cx = Number(path[i+1]) + i += 2 + abs = true + break + case 'V': + y2 = cy = Number(path[i+1]) + i += 2 + abs = true + break + case 'c': + x2 = cx = cx + Number(path[i+5]) + y2 = cy = cy + Number(path[i+6]) + i += 7 + break + case 'l': + i += 1 + abs = false + break + case 'h': + x2 = cx = cx + Number(path[i+1]) + i += 2 + abs = false + break + case 'v': + y2 = cy = cy + Number(path[i+1]) + i += 2 + abs = false + break + default: + if (abs) { + x2 = cx = Number(path[i+0]) + y2 = cy = Number(path[i+1]) + } else { + x2 = cx = cx + Number(path[i+0]) + y2 = cy = cy + Number(path[i+1]) + } + i += 2 + break + } + } +} + +for (let line of fs.readFileSync("tools/layout.svg", "utf-8").split("\n")) { + line = line.trim() + if (line.startsWith("<rect")) { + flush() + mode = "rect" + x = y = w = h = 0 + } else if (line.startsWith("<ellipse") || line.startsWith("<circle")) { + flush() + mode = "circle" + cx = cy = rx = ry = 0 + } else if (line.startsWith("<path")) { + flush() + mode = "path" + } else if (line.startsWith('x="')) + x = round(Number(line.split('"')[1])) + else if (line.startsWith('y="')) + y = round(Number(line.split('"')[1])) + else if (line.startsWith('width="')) + w = round(Number(line.split('"')[1])) + else if (line.startsWith('height="')) + h = round(Number(line.split('"')[1])) + else if (line.startsWith('cx="')) + cx = round(Number(line.split('"')[1])) + else if (line.startsWith('cy="')) + cy = round(Number(line.split('"')[1])) + else if (line.startsWith('r="')) + rx = ry = round(Number(line.split('"')[1])) + else if (line.startsWith('rx="')) + rx = round(Number(line.split('"')[1])) + else if (line.startsWith('ry="')) + ry = round(Number(line.split('"')[1])) + else if (line.startsWith('inkscape:label="')) + name = line.split('"')[1] + else if (line.startsWith('d="')) + parse_path_data(line.split('"')[1].split(/[ ,]/)) +} + +flush() + +console.log("const boxes = {") +for (let key in boxes) + console.log("\t\"" + key + "\": " + JSON.stringify(boxes[key]) + ",") +console.log("}") + +function find_closest_node(x, y) { + let nd = Infinity, nn = null + + for (let n of nodes) { + let d = Math.hypot(n.x - x, n.y - y) + if (d < nd) { + nd = d + nn = n.name + } + } + + if (!nn) + console.log("NOT FOUND", x, y) + + return nn +} + +for (let e of edges) { + let n1 = find_closest_node(e.x1, e.y1) + let n2 = find_closest_node(e.x2, e.y2) + console.log(`edge("${n1}", "${n2}", ${e.x1|0}, ${e.y1|0}, ${e.x2|0}, ${e.y2|0})`) +} diff --git a/tools/rock_overlay@2x.png b/tools/rock_overlay@2x.png Binary files differnew file mode 100644 index 0000000..8710ab6 --- /dev/null +++ b/tools/rock_overlay@2x.png |