openpencil/packages/core/src/icon-render.ts
Anton A S d688d04bef Address PR #94 review: dedup, replace hand-rolled code, cleanup
- Replace calc.ts (150 lines) with expr-eval library
- Replace rgbLuminance with culori wcagLuminance
- Use @iconify/utils iconToSVG for viewBox normalization in iconify.ts
- Extract describe-shared.ts: findAncestorBackground, looksLikeButton, CONTAINER_TYPES
- Extract icon-render.ts: shared createIconFromPaths for create.ts and renderer.ts
- Inline codegen prompt as TS constant, remove runtime fs.readFile from MCP server
- Fix blur effect color alpha (a:1 → a:0)
- Encapsulate module-level mutable state in src/ai/tools.ts into RunState class
- Add network check to iconify tests (skip gracefully offline)
- Remove Caddyfile.dev and components.d.ts from tracking, add to .gitignore
2026-03-13 14:46:18 +03:00

68 lines
1.7 KiB
TypeScript

import { parseColor } from './color'
import type { Color } from './types'
import type { SceneGraph, SceneNode, Stroke } from './scene-graph'
import type { IconData } from './iconify'
const STROKE_CAP_MAP: Record<string, SceneNode['strokeCap']> = {
butt: 'NONE', round: 'ROUND', square: 'SQUARE'
}
const STROKE_JOIN_MAP: Record<string, SceneNode['strokeJoin']> = {
miter: 'MITER', round: 'ROUND', bevel: 'BEVEL'
}
export function createIconFromPaths(
graph: SceneGraph,
icon: IconData,
name: string,
size: number,
color: Color,
parentId: string,
overrides?: Partial<SceneNode>
): SceneNode {
const frame = graph.createNode('FRAME', parentId, {
name: `Icon / ${name}`,
width: size,
height: size,
fills: [],
...overrides
})
for (const path of icon.paths) {
const vector = graph.createNode('VECTOR', frame.id, {
name: 'path',
width: size,
height: size,
vectorNetwork: path.vectorNetwork
})
vector.x = 0
vector.y = 0
if (path.fill) {
const fillColor = path.fill === 'currentColor' ? color : parseColor(path.fill)
graph.updateNode(vector.id, {
fills: [{ type: 'SOLID', color: fillColor, opacity: 1, visible: true }]
})
} else {
graph.updateNode(vector.id, { fills: [] })
}
if (path.stroke) {
const strokeColor = path.stroke === 'currentColor' ? color : parseColor(path.stroke)
const stroke: Stroke = {
color: strokeColor,
weight: path.strokeWidth,
opacity: 1,
visible: true,
align: 'CENTER',
cap: STROKE_CAP_MAP[path.strokeCap] ?? 'NONE',
join: STROKE_JOIN_MAP[path.strokeJoin] ?? 'MITER'
}
graph.updateNode(vector.id, { strokes: [stroke] })
}
}
return frame
}