feat: complete WorkBuddy parity and Windows release workflow
This commit is contained in:
1 parent
143516b3a8
commit
d5512df549
434 files changed
+54977
-1854
No files matched your search
@@ -0,0 +1,70 @@
|
||||
/** Code-native artwork for YCode's five general development roles. No remote image service. */
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { Resvg } from '@resvg/resvg-js'
|
||||
|
||||
const project = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const palettes = {
|
||||
explorer: ['#E4F3ED', '#9DCCB9', '#558E79', '#D8EEE4', '#1D3E37'],
|
||||
implementer: ['#E7EFFB', '#A6BCE2', '#668CC3', '#E0EBFA', '#253D60'],
|
||||
verifier: ['#FAF0DE', '#E6C384', '#B98B42', '#F8E9CB', '#55412B'],
|
||||
reviewer: ['#EDEAF7', '#B9AADC', '#8770B5', '#E9E1F6', '#3D3258'],
|
||||
debugger: ['#F7E9E6', '#DBADA5', '#B6786C', '#F5DDD6', '#533730']
|
||||
}
|
||||
const marks = {
|
||||
explorer: '<circle cx="204" cy="202" r="8"/><path d="m210 208 8 8"/>',
|
||||
implementer: '<path d="m199 195-7 8 7 8m13-16 7 8-7 8m-7-19-3 22"/>',
|
||||
verifier: '<path d="m194 203 8 8 15-17"/>',
|
||||
reviewer: '<path d="m205 190 13 5v9c0 8-8 13-13 15-5-2-13-7-13-15v-9z"/><path d="m199 203 4 4 8-9"/>',
|
||||
debugger: '<path d="M191 204h7l4-10 7 19 4-9h7"/>'
|
||||
}
|
||||
function avatar(role) {
|
||||
const [background, accent, edge, highlight, ink] = palettes[role]
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
|
||||
<defs>
|
||||
<linearGradient id="${role}-bg" x2=".8" y2="1"><stop stop-color="${background}"/><stop offset="1" stop-color="${accent}"/></linearGradient>
|
||||
<linearGradient id="${role}-shell" x2=".3" y2="1"><stop stop-color="#FFFFFF"/><stop offset="1" stop-color="${highlight}"/></linearGradient>
|
||||
<linearGradient id="${role}-screen" x2=".7" y2="1"><stop stop-color="${ink}"/><stop offset="1" stop-color="#172A31"/></linearGradient>
|
||||
<clipPath id="${role}-clip"><rect width="256" height="256" rx="48"/></clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#${role}-clip)">
|
||||
<rect width="256" height="256" fill="url(#${role}-bg)"/>
|
||||
<circle cx="128" cy="95" r="94" fill="#FFFFFF" opacity=".2"/>
|
||||
<ellipse cx="128" cy="254" rx="94" ry="20" fill="${edge}" opacity=".16"/>
|
||||
<path d="M48 256v-23c0-31 32-49 80-49s80 18 80 49v23" fill="${edge}"/>
|
||||
<path d="M62 256v-23c0-24 26-40 66-40s66 16 66 40v23" fill="url(#${role}-shell)"/>
|
||||
<path d="M106 175h44v24c-11 9-33 9-44 0z" fill="${accent}"/>
|
||||
<path d="M128 55V34" stroke="${edge}" stroke-width="8" stroke-linecap="round"/>
|
||||
<circle cx="128" cy="30" r="10" fill="${edge}"/>
|
||||
<circle cx="125" cy="27" r="4" fill="#FFFFFF" opacity=".7"/>
|
||||
<rect x="43" y="97" width="22" height="44" rx="11" fill="${edge}"/>
|
||||
<rect x="191" y="97" width="22" height="44" rx="11" fill="${edge}"/>
|
||||
<rect x="54" y="55" width="148" height="128" rx="42" fill="${edge}" opacity=".18" transform="translate(0 5)"/>
|
||||
<rect x="54" y="51" width="148" height="128" rx="42" fill="url(#${role}-shell)"/>
|
||||
<path d="M78 72c12-8 25-10 50-10" stroke="#FFFFFF" stroke-width="6" stroke-linecap="round" opacity=".9"/>
|
||||
<rect x="69" y="87" width="118" height="66" rx="25" fill="url(#${role}-screen)"/>
|
||||
<rect x="87" y="105" width="16" height="23" rx="8" fill="${highlight}"/>
|
||||
<rect x="153" y="105" width="16" height="23" rx="8" fill="${highlight}"/>
|
||||
<path d="M119 136q9 6 18 0" fill="none" stroke="${highlight}" stroke-width="3.5" stroke-linecap="round"/>
|
||||
<circle cx="79" cy="137" r="5" fill="${accent}" opacity=".55"/>
|
||||
<circle cx="177" cy="137" r="5" fill="${accent}" opacity=".55"/>
|
||||
<path d="M102 225h52" stroke="${accent}" stroke-width="7" stroke-linecap="round"/>
|
||||
<path d="M114 239h28" stroke="${accent}" stroke-width="5" stroke-linecap="round" opacity=".65"/>
|
||||
<circle cx="205" cy="204" r="29" fill="#FFFFFF" opacity=".28"/>
|
||||
<circle cx="205" cy="203" r="25" fill="${ink}"/>
|
||||
<g fill="none" stroke="${highlight}" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round">${marks[role]}</g>
|
||||
</g>
|
||||
</svg>\n`
|
||||
}
|
||||
const directory = path.join(project, 'resources/agents/avatars')
|
||||
await fs.mkdir(directory, { recursive: true })
|
||||
for (const role of Object.keys(palettes)) {
|
||||
const source = avatar(role)
|
||||
await fs.writeFile(path.join(directory, `${role}.svg`), source)
|
||||
await fs.writeFile(path.join(directory, `${role}.png`), new Resvg(source).render().asPng())
|
||||
}
|
||||
await fs.mkdir(path.join(project, '.tmp'), { recursive: true })
|
||||
const preview = `<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="216" viewBox="0 0 1000 216"><rect width="1000" height="216" fill="#F8F9FA"/>${Object.keys(palettes).map((role, index) => `<g transform="translate(${index * 200 + 12},20) scale(.6875)">${avatar(role)}</g>`).join('')}</svg>`
|
||||
await fs.writeFile(path.join(project, '.tmp/general-agent-avatars.png'), new Resvg(preview).render().asPng())
|
||||
console.log('Generated five SVG sources, five 256px PNG avatars and .tmp/general-agent-avatars.png')
|
||||
Reference in new issue
Block a user