import { writeFile } from 'node:fs/promises'; import { THEME, contrast } from '../src/design-tokens.js'; import { directionTheme } from '../src/art-directions.js'; import { TILE_ATLAS } from '../src/sprites.js'; import { ICON_ATLAS } from '../src/ui-skin.js'; export const paletteCounts = [4, 7, 9, 12]; const materialKeys = ['board', 'boardGrid', 'track', 'trackHalo']; const sources = { directions: 'src/art-directions.js', baseTokens: 'src/design-tokens.js', renderer: 'src/renderer.js', tokenDrawing: 'src/token-art.js', componentStyles: 'design/art-directions.css', itemStyles: 'design/game-tools.css', }; export async function buildDesignPackages(directions) { const manifest = { schemaVersion: 1, generated: true, generatedBy: 'scripts/build-art-directions.mjs', pathBase: 'repository-root', entry: 'design/README.md', agentGuide: 'design/AGENTS.md', sharedRules: 'design/shared.md', catalog: 'design/index.html', example: 'design/examples/render-design.mjs', defaultDesignId: 'calm', latestDesignId: directions.at(-1).id, selectionPolicy: 'multiple-candidates', themeIds: directions[0].themes.map(t => t.id), paletteCounts, sources, designs: directions.map(d => ({ id: d.id, code: d.code, name: d.name, artStyle: d.style, status: d.id === 'calm' ? 'existing-default' : 'review-candidate', directory: `design/directions/${d.id}`, designDoc: `design/directions/${d.id}/design.md`, tokens: `design/directions/${d.id}/tokens.json`, preview: `design/directions/${d.id}/index.html`, legacyPreview: `design/directions/${d.id}.html`, })), }; for (const direction of directions) { const tokens = { schemaVersion: 1, generated: true, generatedBy: 'scripts/build-art-directions.mjs', pathBase: 'repository-root', designId: direction.id, artStyle: direction.style, sources, accent: direction.accent, documentBackground: direction.paper, sharedSemanticColors: THEME, assets: { tileAtlas: direction.id === 'calm' ? TILE_ATLAS : null, uiIconAtlas: ICON_ATLAS }, pigments: direction.pigments.map((pigment, index) => ({ index, ...pigment })), themes: direction.themes.map(theme => { const resolved = { ...THEME, ...theme.materials }; const materials = Object.fromEntries(materialKeys.map(key => [key, resolved[key]])); return { id: theme.id, label: theme.label, name: theme.name, background: theme.background, ink: theme.ink, materials, anchorPalette: theme.palette, palettes: Object.fromEntries(paletteCounts.map(count => [count, directionTheme(direction, theme.id, count).palette])), contrast: { sceneText: contrast(theme.ink, theme.background), trackOnBoard: contrast(materials.track, materials.board) }, }; }), }; await writeFile(new URL(`../design/directions/${direction.id}/tokens.json`, import.meta.url), JSON.stringify(tokens, null, 2) + '\n'); } await writeFile(new URL('../design/manifest.json', import.meta.url), JSON.stringify(manifest, null, 2) + '\n'); }