#!/usr/bin/env node // Erzeugt die Item-Icons als SVG. Die PNGs macht danach ImageMagick daraus: // // node icons/gen-icons.mjs // for f in icons/src/*.svg; do magick -background none "$f" -resize 128x128 "icons/$(basename "$f" .svg).png"; done // // Nur SVG 1.1 mit Presentation-Attributen, keine CSS-Bloecke und keine Filter - // gerendert wird mit librsvg 2.40, und das ist alt. // // librsvg 2.40 wirft bei jedem -Element ein // WARNING: Invalid UTF-8 string passed to pango_layout_set_text() // Das ist harmlos und tritt auch beim minimalsten Testfall auf - die Zahlen auf // den Flaschen rendern korrekt. Nachgeprueft, nicht ignoriert. // // Erzeugt nebenbei icons/_check.html: alle Icons auf Schachbrett, in Slot-Groesse // und klein, zum Gegenschauen nach Aenderungen. import { writeFileSync, mkdirSync } from 'node:fs'; import { join, dirname } from 'node:path'; const OUT = join(process.argv[2] ?? 'icons', 'src'); mkdirSync(OUT, { recursive: true }); const S = 128; // Canvas, quadratisch const C = { steelLight: '#cbd5e1', steel: '#94a3b8', steelDark: '#64748b', valve: '#334155', valveDark: '#1e293b', glass: '#38bdf8', glassDark: '#0284c7', rubber: '#1e293b', outline: '#0f172a' }; /** Farbband pro Groesse, damit die Flaschen im Inventar auf einen Blick unterscheidbar sind. */ const BANDS = { small: '#4ade80', medium: '#38bdf8', large: '#fbbf24', xl: '#f472b6', trimix: '#a78bfa' }; const defs = ` `; const svg = (body) => ` ${defs} ${body} `; /** * Eine Tauchflasche. cx = Mittelachse, w = Breite, top/bottom = Koerper in y. * minutes = Laufzeit aufs Band gedruckt. Ohne die Zahl sind die Einzelflaschen * bei kleiner Darstellung nur noch an der Bandfarbe auseinanderzuhalten. */ function tank(cx, w, top, bottom, band, minutes) { const x = cx - w / 2; const h = bottom - top; const valveW = w * 0.4; const bandY = top + h * 0.34; const bandH = 22; const label = minutes ? `${minutes}` : ''; return ` ${label} `; } // --- Flaschen: gleiche Breite, wachsende Hoehe. Die Silhouette traegt die Info, // --- das Farbband hilft zusaetzlich. const sizes = { diving_tank_small: { w: 42, top: 48, bottom: 114, band: BANDS.small, minutes: 5 }, diving_tank_medium: { w: 46, top: 36, bottom: 116, band: BANDS.medium, minutes: 10 }, diving_tank_large: { w: 50, top: 26, bottom: 118, band: BANDS.large, minutes: 15 } }; for (const [name, cfg] of Object.entries(sizes)) { writeFileSync(join(OUT, `${name}.svg`), svg(tank(64, cfg.w, cfg.top, cfg.bottom, cfg.band, cfg.minutes))); } // --- XL = Doppelflasche, passend zum Label. Die Zahl steht auf einem Band // --- ueber beide Flaschen, sonst muesste sie zweimal auftauchen. writeFileSync(join(OUT, 'diving_tank_xl.svg'), svg( ` ${tank(46, 38, 38, 118, BANDS.xl)} ${tank(82, 38, 38, 118, BANDS.xl)} 20` )); // --- Trimix: Doppelflasche mit eigenem Farbband, deutlich abgesetzt von den // --- Pressluft-Flaschen, weil die Verwechslung teuer waere. writeFileSync(join(OUT, 'diving_tank_trimix.svg'), svg( ` ${tank(46, 38, 38, 118, BANDS.trimix)} ${tank(82, 38, 38, 118, BANDS.trimix)} TRIMIX` )); // --- Tauchmaske writeFileSync(join(OUT, 'diving_gear.svg'), svg( ` ` )); // --- Pressluft-Kartusche: liegende, gedrungene Form mit Manometer. Bewusst quer // --- statt hochkant, damit sie sich auf einen Blick von den Flaschen abhebt. writeFileSync(join(OUT, 'diving_fill.svg'), svg( ` ` )); // --- Kontrollblatt const NAMES = [ 'diving_gear', 'diving_fill', 'diving_tank_small', 'diving_tank_medium', 'diving_tank_large', 'diving_tank_xl', 'diving_tank_trimix' ]; const slots = (extra = '') => NAMES.map((n) => `
${n}
`).join(''); writeFileSync(join(dirname(OUT), '_check.html'), `

Transparenz

${slots()}

Inventar-Slot 100px

${slots()}

Klein 56px

${slots()}
`); console.log('SVGs in', OUT, '+ _check.html');