@genart-dev/plugin-symbols 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -52,7 +52,7 @@ Renders SVG path data as a canvas layer. Paths are stored as JSON and drawn via
52
52
  - **Row 3**: Tabler icons (stroke style) — butterfly, planet, campfire, sailboat, kayak, wave-square
53
53
  - **Row 4**: Layer features — fill override (red), stroke override (green), no-aspect-preserve, fill override (blue), stroke override (gold), fill override (purple)
54
54
 
55
- Regenerate with `node render-test-symbols.cjs` (requires `canvas` dev dependency and network access).
55
+ Source: [`test-renders/symbol-layer.genart`](test-renders/symbol-layer.genart) (icon SVG data pre-fetched from Iconify). Regenerate with `bash test-renders/render.sh`.
56
56
 
57
57
  ## MCP Tools (7)
58
58
 
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  default: () => index_default,
24
+ generateBatchPlacements: () => generateBatchPlacements,
24
25
  symbolLayerType: () => symbolLayerType,
25
26
  symbolMcpTools: () => symbolMcpTools,
26
27
  symbolsPlugin: () => symbolsPlugin
@@ -540,11 +541,137 @@ var symbolMcpTools = [
540
541
  placeSymbolTool
541
542
  ];
542
543
 
544
+ // src/batch-placement.ts
545
+ function mulberry32(seed) {
546
+ let s = seed | 0;
547
+ return () => {
548
+ s = s + 1831565813 | 0;
549
+ let t = Math.imul(s ^ s >>> 15, 1 | s);
550
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
551
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
552
+ };
553
+ }
554
+ function lerp(a, b, t) {
555
+ return a + (b - a) * t;
556
+ }
557
+ function generateBatchPlacements(_symbolId, count, strategy, bounds, options = {}) {
558
+ if (count <= 0) return [];
559
+ const {
560
+ minRotation = 0,
561
+ maxRotation = 0,
562
+ minScale = 1,
563
+ maxScale = 1,
564
+ seed = 12345,
565
+ pathPoints
566
+ } = options;
567
+ const rng = mulberry32(seed);
568
+ function randomRotation() {
569
+ return lerp(minRotation, maxRotation, rng());
570
+ }
571
+ function randomScale() {
572
+ return lerp(minScale, maxScale, rng());
573
+ }
574
+ switch (strategy) {
575
+ case "grid":
576
+ return generateGrid(count, bounds, randomRotation, randomScale);
577
+ case "random":
578
+ return generateRandom(count, bounds, rng, randomRotation, randomScale);
579
+ case "along-path":
580
+ return generateAlongPath(count, pathPoints ?? [], randomRotation, randomScale);
581
+ default:
582
+ throw new Error(`Unknown placement strategy: ${strategy}`);
583
+ }
584
+ }
585
+ function generateGrid(count, bounds, rotation, scale) {
586
+ const aspect = bounds.width / bounds.height;
587
+ const cols = Math.max(1, Math.round(Math.sqrt(count * aspect)));
588
+ const rows = Math.max(1, Math.ceil(count / cols));
589
+ const cellW = bounds.width / cols;
590
+ const cellH = bounds.height / rows;
591
+ const placements = [];
592
+ for (let i = 0; i < count; i++) {
593
+ const col = i % cols;
594
+ const row = Math.floor(i / cols);
595
+ placements.push({
596
+ x: bounds.x + cellW * (col + 0.5),
597
+ y: bounds.y + cellH * (row + 0.5),
598
+ rotation: rotation(),
599
+ scale: scale()
600
+ });
601
+ }
602
+ return placements;
603
+ }
604
+ function generateRandom(count, bounds, rng, rotation, scale) {
605
+ const placements = [];
606
+ for (let i = 0; i < count; i++) {
607
+ placements.push({
608
+ x: bounds.x + rng() * bounds.width,
609
+ y: bounds.y + rng() * bounds.height,
610
+ rotation: rotation(),
611
+ scale: scale()
612
+ });
613
+ }
614
+ return placements;
615
+ }
616
+ function generateAlongPath(count, points, rotation, scale) {
617
+ if (points.length === 0) return [];
618
+ if (points.length === 1) {
619
+ const p = points[0];
620
+ return Array.from({ length: count }, () => ({
621
+ x: p.x,
622
+ y: p.y,
623
+ rotation: rotation(),
624
+ scale: scale()
625
+ }));
626
+ }
627
+ const segLengths = [];
628
+ let totalLength = 0;
629
+ for (let i = 1; i < points.length; i++) {
630
+ const dx = points[i].x - points[i - 1].x;
631
+ const dy = points[i].y - points[i - 1].y;
632
+ const len = Math.sqrt(dx * dx + dy * dy);
633
+ segLengths.push(len);
634
+ totalLength += len;
635
+ }
636
+ if (totalLength === 0) {
637
+ const p = points[0];
638
+ return Array.from({ length: count }, () => ({
639
+ x: p.x,
640
+ y: p.y,
641
+ rotation: rotation(),
642
+ scale: scale()
643
+ }));
644
+ }
645
+ const placements = [];
646
+ for (let i = 0; i < count; i++) {
647
+ const t = count === 1 ? 0 : i / (count - 1);
648
+ const targetDist = t * totalLength;
649
+ let accumulated = 0;
650
+ let segIdx = 0;
651
+ for (segIdx = 0; segIdx < segLengths.length; segIdx++) {
652
+ if (accumulated + segLengths[segIdx] >= targetDist) break;
653
+ accumulated += segLengths[segIdx];
654
+ }
655
+ segIdx = Math.min(segIdx, segLengths.length - 1);
656
+ const segStart = points[segIdx];
657
+ const segEnd = points[segIdx + 1] ?? segStart;
658
+ const segLen = segLengths[segIdx] ?? 0;
659
+ const localT = segLen > 0 ? (targetDist - accumulated) / segLen : 0;
660
+ placements.push({
661
+ x: segStart.x + (segEnd.x - segStart.x) * localT,
662
+ y: segStart.y + (segEnd.y - segStart.y) * localT,
663
+ rotation: rotation(),
664
+ scale: scale()
665
+ });
666
+ }
667
+ return placements;
668
+ }
669
+
543
670
  // src/index.ts
544
671
  var symbolsPlugin = {
545
672
  id: "symbols",
546
673
  name: "Symbols & Icons",
547
- version: "0.1.0",
674
+ version: "0.2.0",
548
675
  tier: "free",
549
676
  description: "Vector symbol library with Iconify integration. Search, fetch, and place symbols on the design canvas or embed in algorithms.",
550
677
  layerTypes: [symbolLayerType],
@@ -559,6 +686,7 @@ var symbolsPlugin = {
559
686
  var index_default = symbolsPlugin;
560
687
  // Annotate the CommonJS export names for ESM import in node:
561
688
  0 && (module.exports = {
689
+ generateBatchPlacements,
562
690
  symbolLayerType,
563
691
  symbolMcpTools,
564
692
  symbolsPlugin
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/symbol-layer.ts","../src/symbol-tools.ts"],"sourcesContent":["import type { DesignPlugin, PluginContext } from \"@genart-dev/core\";\nimport { symbolLayerType } from \"./symbol-layer.js\";\nimport { symbolMcpTools } from \"./symbol-tools.js\";\n\nconst symbolsPlugin: DesignPlugin = {\n id: \"symbols\",\n name: \"Symbols & Icons\",\n version: \"0.1.0\",\n tier: \"free\",\n description:\n \"Vector symbol library with Iconify integration. Search, fetch, and place symbols on the design canvas or embed in algorithms.\",\n layerTypes: [symbolLayerType],\n tools: [],\n exportHandlers: [],\n mcpTools: symbolMcpTools,\n async initialize(_context: PluginContext): Promise<void> {},\n dispose(): void {},\n};\n\nexport default symbolsPlugin;\nexport { symbolsPlugin };\nexport { symbolLayerType };\nexport { symbolMcpTools };\n","import type {\n LayerTypeDefinition,\n LayerPropertySchema,\n LayerProperties,\n LayerBounds,\n RenderResources,\n} from \"@genart-dev/core\";\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\n\nconst SYMBOL_PROPERTIES: LayerPropertySchema[] = [\n { key: \"symbolId\", label: \"Symbol ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"iconifyId\", label: \"Iconify ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"viewBox\", label: \"ViewBox\", type: \"string\", default: \"0 0 24 24\", group: \"symbol\" },\n { key: \"paths\", label: \"Paths (JSON)\", type: \"string\", default: \"[]\", group: \"data\" },\n { key: \"fillOverride\", label: \"Fill Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"strokeOverride\", label: \"Stroke Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"preserveAspect\", label: \"Preserve Aspect\", type: \"boolean\", default: true, group: \"layout\" },\n];\n\nexport const symbolLayerType: LayerTypeDefinition = {\n typeId: \"symbols:symbol\",\n displayName: \"Symbol\",\n icon: \"symbol\",\n category: \"image\",\n properties: SYMBOL_PROPERTIES,\n propertyEditorId: \"symbols:symbol-editor\",\n\n createDefault(): LayerProperties {\n return {\n symbolId: \"\",\n iconifyId: \"\",\n viewBox: \"0 0 24 24\",\n paths: \"[]\",\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n };\n },\n\n render(\n properties: LayerProperties,\n ctx: CanvasRenderingContext2D,\n bounds: LayerBounds,\n _resources: RenderResources,\n ): void {\n const pathsJson = String(properties.paths ?? \"[]\");\n let paths: SymbolPath[];\n try {\n paths = JSON.parse(pathsJson) as SymbolPath[];\n } catch {\n return;\n }\n if (paths.length === 0) return;\n\n const viewBoxStr = String(properties.viewBox ?? \"0 0 24 24\");\n const vb = viewBoxStr.split(/\\s+/).map(Number);\n const vbX = vb[0] ?? 0;\n const vbY = vb[1] ?? 0;\n const vbW = vb[2] ?? 24;\n const vbH = vb[3] ?? 24;\n\n const preserveAspect = Boolean(properties.preserveAspect ?? true);\n const fillOverride = String(properties.fillOverride ?? \"\") || undefined;\n const strokeOverride = String(properties.strokeOverride ?? \"\") || undefined;\n\n let scaleX = bounds.width / vbW;\n let scaleY = bounds.height / vbH;\n\n let offsetX = 0;\n let offsetY = 0;\n\n if (preserveAspect) {\n const uniformScale = Math.min(scaleX, scaleY);\n offsetX = (bounds.width - vbW * uniformScale) / 2;\n offsetY = (bounds.height - vbH * uniformScale) / 2;\n scaleX = uniformScale;\n scaleY = uniformScale;\n }\n\n ctx.save();\n ctx.translate(bounds.x + offsetX - vbX * scaleX, bounds.y + offsetY - vbY * scaleY);\n ctx.scale(scaleX, scaleY);\n\n for (const p of paths) {\n const path = new Path2D(p.d);\n if (p.fill !== \"none\") {\n ctx.fillStyle = fillOverride ?? p.fill ?? \"#000000\";\n ctx.fill(path);\n }\n if (p.stroke || strokeOverride) {\n ctx.strokeStyle = strokeOverride ?? p.stroke ?? \"#000000\";\n ctx.lineWidth = (p.strokeWidth ?? 1) / Math.max(scaleX, scaleY);\n ctx.stroke(path);\n }\n }\n\n ctx.restore();\n },\n\n validate(): null { return null; },\n};\n","import type {\n McpToolDefinition,\n McpToolContext,\n McpToolResult,\n JsonSchema,\n} from \"@genart-dev/core\";\nimport { resolveComponents } from \"@genart-dev/core\";\nimport type {\n SymbolCategory,\n SymbolStyle,\n SketchSymbolDef,\n} from \"@genart-dev/symbols\";\n\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\nimport {\n SYMBOL_REGISTRY,\n listCategories,\n searchSymbols,\n resolveSymbol,\n validateSymbol,\n searchIconify,\n fetchAndParseIcon,\n SAFE_PREFIXES,\n} from \"@genart-dev/symbols\";\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface ThirdPartyNotice {\n readonly name: string;\n readonly license: string;\n readonly copyright: string;\n readonly url: string;\n}\n\nfunction textResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }] };\n}\n\nfunction errorResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\nconst VALID_STYLES: readonly SymbolStyle[] = [\"geometric\", \"organic\", \"silhouette\", \"sketch\"];\nconst JS_RENDERERS = new Set([\"p5\", \"three\", \"canvas2d\", \"svg\"]);\n\nconst ICONIFY_NOTICES: Readonly<Record<string, ThirdPartyNotice>> = {\n ph: {\n name: \"Phosphor Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2023 Phosphor Icons\",\n url: \"https://github.com/phosphor-icons/core\",\n },\n lucide: {\n name: \"Lucide\",\n license: \"ISC\",\n copyright: \"Copyright (c) 2022 Lucide Contributors\",\n url: \"https://github.com/lucide-icons/lucide\",\n },\n tabler: {\n name: \"Tabler Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020-2024 Paweł Kuna\",\n url: \"https://github.com/tabler/tabler-icons\",\n },\n heroicons: {\n name: \"Heroicons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Tailwind Labs, Inc.\",\n url: \"https://github.com/tailwindlabs/heroicons\",\n },\n bi: {\n name: \"Bootstrap Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2019-2024 The Bootstrap Authors\",\n url: \"https://github.com/twbs/icons\",\n },\n mdi: {\n name: \"Material Design Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) Google LLC\",\n url: \"https://github.com/google/material-design-icons\",\n },\n ri: {\n name: \"Remix Icon\",\n license: \"Remix Icon License v1.0\",\n copyright: \"Copyright (c) 2017-2024 Remix Design\",\n url: \"https://github.com/Remix-Design/RemixIcon\",\n },\n carbon: {\n name: \"Carbon Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) 2015 IBM Corp.\",\n url: \"https://github.com/carbon-design-system/carbon\",\n },\n fluent: {\n name: \"Fluent UI System Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Microsoft Corporation\",\n url: \"https://github.com/microsoft/fluentui-system-icons\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// search_symbols\n// ---------------------------------------------------------------------------\n\nexport const searchSymbolsTool: McpToolDefinition = {\n name: \"search_symbols\",\n description: \"Search the symbol registry by keyword, category, and/or style. Returns symbols with their IDs, tags, and available styles.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to match against symbol name, tags, and description\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Filter by category\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Filter by available style\" },\n limit: { type: \"number\", description: \"Maximum results to return (default: 20)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const results = searchSymbols({\n query: input[\"query\"] as string | undefined,\n category: input[\"category\"] as SymbolCategory | undefined,\n style: input[\"style\"] as SymbolStyle | undefined,\n limit: (input[\"limit\"] as number | undefined) ?? 20,\n });\n return textResult(JSON.stringify({ count: results.length, symbols: results }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// list_symbol_categories\n// ---------------------------------------------------------------------------\n\nexport const listSymbolCategoriesTool: McpToolDefinition = {\n name: \"list_symbol_categories\",\n description: \"List all symbol categories with symbol counts. Use this to browse the symbol library before searching.\",\n inputSchema: {\n type: \"object\",\n properties: {} as Record<string, JsonSchema>,\n },\n async handler(_input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const categories = listCategories();\n const total = Object.keys(SYMBOL_REGISTRY).length;\n const breakdown = categories.map((cat) => ({\n category: cat,\n count: Object.values(SYMBOL_REGISTRY).filter((s) => s.category === cat).length,\n }));\n return textResult(JSON.stringify({ categories: breakdown, total }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// add_symbol\n// ---------------------------------------------------------------------------\n\nexport const addSymbolTool: McpToolDefinition = {\n name: \"add_symbol\",\n description: \"Add a symbol from the registry to a sketch. Resolves the symbol's SVG path data and caches it in the sketch file. Automatically adds the symbol-draw component if not already present.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID (e.g. 'pine-tree', 'sailboat', 'mountain')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Style variant to use (default: 'geometric')\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n const renderer = context.sketch.getRenderer();\n\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer (p5, canvas2d, svg, three). Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const resolved = resolveSymbol(symbolName, style);\n\n const existing = context.sketch.getSymbols();\n if (existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is already present in the sketch`);\n }\n\n const newSymbols: Record<string, unknown> = { ...existing, [symbolName]: resolved };\n\n // Ensure symbol-draw component is present\n const existingComponents = context.sketch.getComponents();\n if (!existingComponents[\"symbol-draw\"]) {\n const compMap: Record<string, string> = {};\n for (const [name, value] of Object.entries(existingComponents)) {\n if (typeof value === \"string\") {\n compMap[name] = value;\n } else if (value && typeof value === \"object\" && \"version\" in value) {\n compMap[name] = (value as { version: string }).version;\n }\n }\n compMap[\"symbol-draw\"] = \"^1.0.0\";\n const resolved2 = resolveComponents(compMap, renderer as Parameters<typeof resolveComponents>[1]);\n const resolvedRecord: Record<string, unknown> = {};\n for (const rc of resolved2) {\n resolvedRecord[rc.name] = { version: rc.version, code: rc.code, exports: [...rc.exports] };\n }\n context.sketch.setComponents(resolvedRecord);\n }\n\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n const added = Object.keys(newSymbols).filter((k) => !existing[k]);\n\n return textResult(JSON.stringify({\n success: true,\n added,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// remove_symbol\n// ---------------------------------------------------------------------------\n\nexport const removeSymbolTool: McpToolDefinition = {\n name: \"remove_symbol\",\n description: \"Remove a symbol from a sketch. Warns if the algorithm references the symbol ID.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID to remove\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n\n const existing = context.sketch.getSymbols();\n if (!existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is not present in the sketch`);\n }\n\n const newSymbols = { ...existing };\n delete newSymbols[symbolName];\n\n context.sketch.setSymbols(\n Object.keys(newSymbols).length > 0 ? newSymbols : undefined,\n );\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n removed: symbolName,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// create_symbol\n// ---------------------------------------------------------------------------\n\nexport const createSymbolTool: McpToolDefinition = {\n name: \"create_symbol\",\n description: \"Create a custom AI-generated symbol with SVG path data. Validates path syntax and enforces a 10KB size limit. Caches it in the sketch file for use with drawSymbol().\",\n inputSchema: {\n type: \"object\",\n required: [\"name\", \"category\", \"tags\", \"description\", \"paths\", \"viewBox\", \"style\"],\n properties: {\n name: { type: \"string\", description: \"Human-readable symbol name (e.g. 'Weeping Willow')\" },\n id: { type: \"string\", description: \"Symbol ID (kebab-case, auto-generated from name if omitted)\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Symbol category\" },\n tags: { type: \"array\", items: { type: \"string\" }, description: \"Search tags (e.g. ['tree', 'weeping', 'willow', 'nature'])\" },\n description: { type: \"string\", description: \"Short description of the symbol\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\", description: \"Semantic role (e.g. 'trunk', 'canopy')\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 100 100')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Visual style of these paths\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const paths = input[\"paths\"] as SymbolPath[];\n const viewBox = input[\"viewBox\"] as string;\n\n const errors = validateSymbol(paths, viewBox);\n if (errors.length > 0) {\n return errorResult(`Symbol validation failed:\\n${errors.join(\"\\n\")}`);\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const name = input[\"name\"] as string;\n const id = (input[\"id\"] as string | undefined) ?? name.toLowerCase().replace(/\\s+/g, \"-\").replace(/[^a-z0-9-]/g, \"\");\n\n const symbolDef: SketchSymbolDef = {\n id,\n name,\n style,\n paths,\n viewBox,\n custom: true,\n };\n\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [id]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n symbol: symbolDef,\n tip: `Use drawSymbol(ctx, \"${id}\", x, y, width, height) to render this symbol in your algorithm.`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// fetch_symbol\n// ---------------------------------------------------------------------------\n\nexport const fetchSymbolTool: McpToolDefinition = {\n name: \"fetch_symbol\",\n description: \"Search Iconify for professional icons (275k+ from Phosphor, Lucide, Tabler, MDI, etc.) or embed one into a sketch. Two modes: (1) Search — provide query to get a list of iconifyIds; (2) Embed — provide iconifyId (e.g. 'ph:cat') to fetch SVG, parse paths, and embed as a SketchSymbolDef. Approved prefixes: ph, lucide, tabler, heroicons, bi, mdi, ri, carbon, fluent.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to search Iconify (e.g. 'cat', 'arrow left', 'sun'). Returns a list of iconifyIds — no SVG fetched yet.\" },\n iconifyId: { type: \"string\", description: \"Iconify icon ID to embed (e.g. 'ph:cat', 'lucide:arrow-left'). Fetches SVG, parses paths, embeds in sketch.\" },\n prefix: { type: \"string\", description: \"Limit search to a specific icon set (e.g. 'ph', 'lucide', 'tabler'). Ignored when using iconifyId.\" },\n limit: { type: \"number\", description: \"Maximum search results to return (default: 10)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const query = input[\"query\"] as string | undefined;\n const iconifyId = input[\"iconifyId\"] as string | undefined;\n\n // ---- Search mode ----\n if (query && !iconifyId) {\n const prefixes = input[\"prefix\"] ? [input[\"prefix\"] as string] : undefined;\n const results = await searchIconify(query, (input[\"limit\"] as number | undefined) ?? 10, prefixes);\n return textResult(JSON.stringify({\n mode: \"search\",\n results,\n tip: \"Call fetch_symbol with iconifyId to embed one of these icons into a sketch\",\n }));\n }\n\n // ---- Embed mode ----\n if (!iconifyId) {\n return errorResult(\n \"Provide either query (to search) or iconifyId (to embed). Approved prefixes: \" +\n Object.keys(SAFE_PREFIXES).join(\", \"),\n );\n }\n\n let iconData: Awaited<ReturnType<typeof fetchAndParseIcon>>;\n try {\n iconData = await fetchAndParseIcon(iconifyId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"not in the approved list\")) {\n return textResult(JSON.stringify({ warning: msg }));\n }\n return errorResult(msg);\n }\n\n const symbolId = iconData.iconifyId.replace(\":\", \"-\");\n\n const symbolDef: SketchSymbolDef = {\n id: symbolId,\n name: iconData.name,\n paths: iconData.paths,\n viewBox: iconData.viewBox,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n };\n\n // Embed into sketch\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [symbolId]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n\n // Merge third-party notice\n const notice = ICONIFY_NOTICES[iconData.prefix];\n const existingNotices = context.sketch.getThirdParty();\n const alreadyPresent = existingNotices.some(\n (n: Record<string, unknown>) => (n as { name?: string }).name === notice?.name,\n );\n if (notice && !alreadyPresent) {\n context.sketch.setThirdParty([\n ...existingNotices as Record<string, unknown>[],\n notice as unknown as Record<string, unknown>,\n ]);\n }\n\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n mode: \"embedded\",\n symbolId,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n viewBox: iconData.viewBox,\n pathCount: iconData.paths.length,\n tip: `drawSymbol(ctx, \"${symbolId}\", x, y, width, height)`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// place_symbol\n// ---------------------------------------------------------------------------\n\nexport const placeSymbolTool: McpToolDefinition = {\n name: \"place_symbol\",\n description: \"Place a symbol as a design layer on the canvas. Creates a symbols:symbol layer with embedded SVG path data for visual composition.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbolId\", \"viewBox\", \"paths\"],\n properties: {\n symbolId: { type: \"string\", description: \"Symbol ID (e.g. 'ph-cat')\" },\n iconifyId: { type: \"string\", description: \"Original Iconify ID (e.g. 'ph:cat')\" },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 256 256')\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n x: { type: \"number\", description: \"X position (default: 0)\" },\n y: { type: \"number\", description: \"Y position (default: 0)\" },\n width: { type: \"number\", description: \"Layer width (default: 100)\" },\n height: { type: \"number\", description: \"Layer height (default: 100)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolId = input[\"symbolId\"] as string;\n const iconifyId = (input[\"iconifyId\"] as string | undefined) ?? \"\";\n const viewBox = input[\"viewBox\"] as string;\n const paths = input[\"paths\"] as SymbolPath[];\n const x = (input[\"x\"] as number | undefined) ?? 0;\n const y = (input[\"y\"] as number | undefined) ?? 0;\n const width = (input[\"width\"] as number | undefined) ?? 100;\n const height = (input[\"height\"] as number | undefined) ?? 100;\n\n const id = `symbol-${symbolId}-${Date.now()}`;\n context.layers.add({\n id,\n type: \"symbols:symbol\",\n name: symbolId,\n visible: true,\n locked: false,\n opacity: 1,\n blendMode: \"normal\",\n transform: {\n x, y, width, height,\n rotation: 0, scaleX: 1, scaleY: 1, anchorX: 0.5, anchorY: 0.5,\n },\n properties: {\n symbolId,\n iconifyId,\n viewBox,\n paths: JSON.stringify(paths),\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n },\n } as Parameters<typeof context.layers.add>[0]);\n\n context.emitChange(\"layer-added\");\n\n return textResult(JSON.stringify({\n layerId: id,\n symbolId,\n position: { x, y },\n size: { width, height },\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// Export all tools\n// ---------------------------------------------------------------------------\n\nexport const symbolMcpTools: McpToolDefinition[] = [\n searchSymbolsTool,\n listSymbolCategoriesTool,\n addSymbolTool,\n removeSymbolTool,\n createSymbolTool,\n fetchSymbolTool,\n placeSymbolTool,\n];\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/symbol-layer.ts","../src/symbol-tools.ts","../src/batch-placement.ts"],"sourcesContent":["import type { DesignPlugin, PluginContext } from \"@genart-dev/core\";\nimport { symbolLayerType } from \"./symbol-layer.js\";\nimport { symbolMcpTools } from \"./symbol-tools.js\";\n\nconst symbolsPlugin: DesignPlugin = {\n id: \"symbols\",\n name: \"Symbols & Icons\",\n version: \"0.2.0\",\n tier: \"free\",\n description:\n \"Vector symbol library with Iconify integration. Search, fetch, and place symbols on the design canvas or embed in algorithms.\",\n layerTypes: [symbolLayerType],\n tools: [],\n exportHandlers: [],\n mcpTools: symbolMcpTools,\n async initialize(_context: PluginContext): Promise<void> {},\n dispose(): void {},\n};\n\nexport default symbolsPlugin;\nexport { symbolsPlugin };\nexport { symbolLayerType };\nexport { symbolMcpTools };\nexport {\n generateBatchPlacements,\n type PlacementBounds,\n type Placement,\n type PlacementStrategy,\n type BatchPlacementOptions,\n} from \"./batch-placement.js\";\n","import type {\n LayerTypeDefinition,\n LayerPropertySchema,\n LayerProperties,\n LayerBounds,\n RenderResources,\n} from \"@genart-dev/core\";\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\n\nconst SYMBOL_PROPERTIES: LayerPropertySchema[] = [\n { key: \"symbolId\", label: \"Symbol ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"iconifyId\", label: \"Iconify ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"viewBox\", label: \"ViewBox\", type: \"string\", default: \"0 0 24 24\", group: \"symbol\" },\n { key: \"paths\", label: \"Paths (JSON)\", type: \"string\", default: \"[]\", group: \"data\" },\n { key: \"fillOverride\", label: \"Fill Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"strokeOverride\", label: \"Stroke Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"preserveAspect\", label: \"Preserve Aspect\", type: \"boolean\", default: true, group: \"layout\" },\n];\n\nexport const symbolLayerType: LayerTypeDefinition = {\n typeId: \"symbols:symbol\",\n displayName: \"Symbol\",\n icon: \"symbol\",\n category: \"image\",\n properties: SYMBOL_PROPERTIES,\n propertyEditorId: \"symbols:symbol-editor\",\n\n createDefault(): LayerProperties {\n return {\n symbolId: \"\",\n iconifyId: \"\",\n viewBox: \"0 0 24 24\",\n paths: \"[]\",\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n };\n },\n\n render(\n properties: LayerProperties,\n ctx: CanvasRenderingContext2D,\n bounds: LayerBounds,\n _resources: RenderResources,\n ): void {\n const pathsJson = String(properties.paths ?? \"[]\");\n let paths: SymbolPath[];\n try {\n paths = JSON.parse(pathsJson) as SymbolPath[];\n } catch {\n return;\n }\n if (paths.length === 0) return;\n\n const viewBoxStr = String(properties.viewBox ?? \"0 0 24 24\");\n const vb = viewBoxStr.split(/\\s+/).map(Number);\n const vbX = vb[0] ?? 0;\n const vbY = vb[1] ?? 0;\n const vbW = vb[2] ?? 24;\n const vbH = vb[3] ?? 24;\n\n const preserveAspect = Boolean(properties.preserveAspect ?? true);\n const fillOverride = String(properties.fillOverride ?? \"\") || undefined;\n const strokeOverride = String(properties.strokeOverride ?? \"\") || undefined;\n\n let scaleX = bounds.width / vbW;\n let scaleY = bounds.height / vbH;\n\n let offsetX = 0;\n let offsetY = 0;\n\n if (preserveAspect) {\n const uniformScale = Math.min(scaleX, scaleY);\n offsetX = (bounds.width - vbW * uniformScale) / 2;\n offsetY = (bounds.height - vbH * uniformScale) / 2;\n scaleX = uniformScale;\n scaleY = uniformScale;\n }\n\n ctx.save();\n ctx.translate(bounds.x + offsetX - vbX * scaleX, bounds.y + offsetY - vbY * scaleY);\n ctx.scale(scaleX, scaleY);\n\n for (const p of paths) {\n const path = new Path2D(p.d);\n if (p.fill !== \"none\") {\n ctx.fillStyle = fillOverride ?? p.fill ?? \"#000000\";\n ctx.fill(path);\n }\n if (p.stroke || strokeOverride) {\n ctx.strokeStyle = strokeOverride ?? p.stroke ?? \"#000000\";\n ctx.lineWidth = (p.strokeWidth ?? 1) / Math.max(scaleX, scaleY);\n ctx.stroke(path);\n }\n }\n\n ctx.restore();\n },\n\n validate(): null { return null; },\n};\n","import type {\n McpToolDefinition,\n McpToolContext,\n McpToolResult,\n JsonSchema,\n} from \"@genart-dev/core\";\nimport { resolveComponents } from \"@genart-dev/core\";\nimport type {\n SymbolCategory,\n SymbolStyle,\n SketchSymbolDef,\n} from \"@genart-dev/symbols\";\n\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\nimport {\n SYMBOL_REGISTRY,\n listCategories,\n searchSymbols,\n resolveSymbol,\n validateSymbol,\n searchIconify,\n fetchAndParseIcon,\n SAFE_PREFIXES,\n} from \"@genart-dev/symbols\";\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface ThirdPartyNotice {\n readonly name: string;\n readonly license: string;\n readonly copyright: string;\n readonly url: string;\n}\n\nfunction textResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }] };\n}\n\nfunction errorResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\nconst VALID_STYLES: readonly SymbolStyle[] = [\"geometric\", \"organic\", \"silhouette\", \"sketch\"];\nconst JS_RENDERERS = new Set([\"p5\", \"three\", \"canvas2d\", \"svg\"]);\n\nconst ICONIFY_NOTICES: Readonly<Record<string, ThirdPartyNotice>> = {\n ph: {\n name: \"Phosphor Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2023 Phosphor Icons\",\n url: \"https://github.com/phosphor-icons/core\",\n },\n lucide: {\n name: \"Lucide\",\n license: \"ISC\",\n copyright: \"Copyright (c) 2022 Lucide Contributors\",\n url: \"https://github.com/lucide-icons/lucide\",\n },\n tabler: {\n name: \"Tabler Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020-2024 Paweł Kuna\",\n url: \"https://github.com/tabler/tabler-icons\",\n },\n heroicons: {\n name: \"Heroicons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Tailwind Labs, Inc.\",\n url: \"https://github.com/tailwindlabs/heroicons\",\n },\n bi: {\n name: \"Bootstrap Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2019-2024 The Bootstrap Authors\",\n url: \"https://github.com/twbs/icons\",\n },\n mdi: {\n name: \"Material Design Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) Google LLC\",\n url: \"https://github.com/google/material-design-icons\",\n },\n ri: {\n name: \"Remix Icon\",\n license: \"Remix Icon License v1.0\",\n copyright: \"Copyright (c) 2017-2024 Remix Design\",\n url: \"https://github.com/Remix-Design/RemixIcon\",\n },\n carbon: {\n name: \"Carbon Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) 2015 IBM Corp.\",\n url: \"https://github.com/carbon-design-system/carbon\",\n },\n fluent: {\n name: \"Fluent UI System Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Microsoft Corporation\",\n url: \"https://github.com/microsoft/fluentui-system-icons\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// search_symbols\n// ---------------------------------------------------------------------------\n\nexport const searchSymbolsTool: McpToolDefinition = {\n name: \"search_symbols\",\n description: \"Search the symbol registry by keyword, category, and/or style. Returns symbols with their IDs, tags, and available styles.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to match against symbol name, tags, and description\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Filter by category\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Filter by available style\" },\n limit: { type: \"number\", description: \"Maximum results to return (default: 20)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const results = searchSymbols({\n query: input[\"query\"] as string | undefined,\n category: input[\"category\"] as SymbolCategory | undefined,\n style: input[\"style\"] as SymbolStyle | undefined,\n limit: (input[\"limit\"] as number | undefined) ?? 20,\n });\n return textResult(JSON.stringify({ count: results.length, symbols: results }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// list_symbol_categories\n// ---------------------------------------------------------------------------\n\nexport const listSymbolCategoriesTool: McpToolDefinition = {\n name: \"list_symbol_categories\",\n description: \"List all symbol categories with symbol counts. Use this to browse the symbol library before searching.\",\n inputSchema: {\n type: \"object\",\n properties: {} as Record<string, JsonSchema>,\n },\n async handler(_input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const categories = listCategories();\n const total = Object.keys(SYMBOL_REGISTRY).length;\n const breakdown = categories.map((cat) => ({\n category: cat,\n count: Object.values(SYMBOL_REGISTRY).filter((s) => s.category === cat).length,\n }));\n return textResult(JSON.stringify({ categories: breakdown, total }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// add_symbol\n// ---------------------------------------------------------------------------\n\nexport const addSymbolTool: McpToolDefinition = {\n name: \"add_symbol\",\n description: \"Add a symbol from the registry to a sketch. Resolves the symbol's SVG path data and caches it in the sketch file. Automatically adds the symbol-draw component if not already present.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID (e.g. 'pine-tree', 'sailboat', 'mountain')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Style variant to use (default: 'geometric')\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n const renderer = context.sketch.getRenderer();\n\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer (p5, canvas2d, svg, three). Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const resolved = resolveSymbol(symbolName, style);\n\n const existing = context.sketch.getSymbols();\n if (existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is already present in the sketch`);\n }\n\n const newSymbols: Record<string, unknown> = { ...existing, [symbolName]: resolved };\n\n // Ensure symbol-draw component is present\n const existingComponents = context.sketch.getComponents();\n if (!existingComponents[\"symbol-draw\"]) {\n const compMap: Record<string, string> = {};\n for (const [name, value] of Object.entries(existingComponents)) {\n if (typeof value === \"string\") {\n compMap[name] = value;\n } else if (value && typeof value === \"object\" && \"version\" in value) {\n compMap[name] = (value as { version: string }).version;\n }\n }\n compMap[\"symbol-draw\"] = \"^1.0.0\";\n const resolved2 = resolveComponents(compMap, renderer as Parameters<typeof resolveComponents>[1]);\n const resolvedRecord: Record<string, unknown> = {};\n for (const rc of resolved2) {\n resolvedRecord[rc.name] = { version: rc.version, code: rc.code, exports: [...rc.exports] };\n }\n context.sketch.setComponents(resolvedRecord);\n }\n\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n const added = Object.keys(newSymbols).filter((k) => !existing[k]);\n\n return textResult(JSON.stringify({\n success: true,\n added,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// remove_symbol\n// ---------------------------------------------------------------------------\n\nexport const removeSymbolTool: McpToolDefinition = {\n name: \"remove_symbol\",\n description: \"Remove a symbol from a sketch. Warns if the algorithm references the symbol ID.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID to remove\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n\n const existing = context.sketch.getSymbols();\n if (!existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is not present in the sketch`);\n }\n\n const newSymbols = { ...existing };\n delete newSymbols[symbolName];\n\n context.sketch.setSymbols(\n Object.keys(newSymbols).length > 0 ? newSymbols : undefined,\n );\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n removed: symbolName,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// create_symbol\n// ---------------------------------------------------------------------------\n\nexport const createSymbolTool: McpToolDefinition = {\n name: \"create_symbol\",\n description: \"Create a custom AI-generated symbol with SVG path data. Validates path syntax and enforces a 10KB size limit. Caches it in the sketch file for use with drawSymbol().\",\n inputSchema: {\n type: \"object\",\n required: [\"name\", \"category\", \"tags\", \"description\", \"paths\", \"viewBox\", \"style\"],\n properties: {\n name: { type: \"string\", description: \"Human-readable symbol name (e.g. 'Weeping Willow')\" },\n id: { type: \"string\", description: \"Symbol ID (kebab-case, auto-generated from name if omitted)\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Symbol category\" },\n tags: { type: \"array\", items: { type: \"string\" }, description: \"Search tags (e.g. ['tree', 'weeping', 'willow', 'nature'])\" },\n description: { type: \"string\", description: \"Short description of the symbol\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\", description: \"Semantic role (e.g. 'trunk', 'canopy')\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 100 100')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Visual style of these paths\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const paths = input[\"paths\"] as SymbolPath[];\n const viewBox = input[\"viewBox\"] as string;\n\n const errors = validateSymbol(paths, viewBox);\n if (errors.length > 0) {\n return errorResult(`Symbol validation failed:\\n${errors.join(\"\\n\")}`);\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const name = input[\"name\"] as string;\n const id = (input[\"id\"] as string | undefined) ?? name.toLowerCase().replace(/\\s+/g, \"-\").replace(/[^a-z0-9-]/g, \"\");\n\n const symbolDef: SketchSymbolDef = {\n id,\n name,\n style,\n paths,\n viewBox,\n custom: true,\n };\n\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [id]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n symbol: symbolDef,\n tip: `Use drawSymbol(ctx, \"${id}\", x, y, width, height) to render this symbol in your algorithm.`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// fetch_symbol\n// ---------------------------------------------------------------------------\n\nexport const fetchSymbolTool: McpToolDefinition = {\n name: \"fetch_symbol\",\n description: \"Search Iconify for professional icons (275k+ from Phosphor, Lucide, Tabler, MDI, etc.) or embed one into a sketch. Two modes: (1) Search — provide query to get a list of iconifyIds; (2) Embed — provide iconifyId (e.g. 'ph:cat') to fetch SVG, parse paths, and embed as a SketchSymbolDef. Approved prefixes: ph, lucide, tabler, heroicons, bi, mdi, ri, carbon, fluent.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to search Iconify (e.g. 'cat', 'arrow left', 'sun'). Returns a list of iconifyIds — no SVG fetched yet.\" },\n iconifyId: { type: \"string\", description: \"Iconify icon ID to embed (e.g. 'ph:cat', 'lucide:arrow-left'). Fetches SVG, parses paths, embeds in sketch.\" },\n prefix: { type: \"string\", description: \"Limit search to a specific icon set (e.g. 'ph', 'lucide', 'tabler'). Ignored when using iconifyId.\" },\n limit: { type: \"number\", description: \"Maximum search results to return (default: 10)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const query = input[\"query\"] as string | undefined;\n const iconifyId = input[\"iconifyId\"] as string | undefined;\n\n // ---- Search mode ----\n if (query && !iconifyId) {\n const prefixes = input[\"prefix\"] ? [input[\"prefix\"] as string] : undefined;\n const results = await searchIconify(query, (input[\"limit\"] as number | undefined) ?? 10, prefixes);\n return textResult(JSON.stringify({\n mode: \"search\",\n results,\n tip: \"Call fetch_symbol with iconifyId to embed one of these icons into a sketch\",\n }));\n }\n\n // ---- Embed mode ----\n if (!iconifyId) {\n return errorResult(\n \"Provide either query (to search) or iconifyId (to embed). Approved prefixes: \" +\n Object.keys(SAFE_PREFIXES).join(\", \"),\n );\n }\n\n let iconData: Awaited<ReturnType<typeof fetchAndParseIcon>>;\n try {\n iconData = await fetchAndParseIcon(iconifyId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"not in the approved list\")) {\n return textResult(JSON.stringify({ warning: msg }));\n }\n return errorResult(msg);\n }\n\n const symbolId = iconData.iconifyId.replace(\":\", \"-\");\n\n const symbolDef: SketchSymbolDef = {\n id: symbolId,\n name: iconData.name,\n paths: iconData.paths,\n viewBox: iconData.viewBox,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n };\n\n // Embed into sketch\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [symbolId]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n\n // Merge third-party notice\n const notice = ICONIFY_NOTICES[iconData.prefix];\n const existingNotices = context.sketch.getThirdParty();\n const alreadyPresent = existingNotices.some(\n (n: Record<string, unknown>) => (n as { name?: string }).name === notice?.name,\n );\n if (notice && !alreadyPresent) {\n context.sketch.setThirdParty([\n ...existingNotices as Record<string, unknown>[],\n notice as unknown as Record<string, unknown>,\n ]);\n }\n\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n mode: \"embedded\",\n symbolId,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n viewBox: iconData.viewBox,\n pathCount: iconData.paths.length,\n tip: `drawSymbol(ctx, \"${symbolId}\", x, y, width, height)`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// place_symbol\n// ---------------------------------------------------------------------------\n\nexport const placeSymbolTool: McpToolDefinition = {\n name: \"place_symbol\",\n description: \"Place a symbol as a design layer on the canvas. Creates a symbols:symbol layer with embedded SVG path data for visual composition.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbolId\", \"viewBox\", \"paths\"],\n properties: {\n symbolId: { type: \"string\", description: \"Symbol ID (e.g. 'ph-cat')\" },\n iconifyId: { type: \"string\", description: \"Original Iconify ID (e.g. 'ph:cat')\" },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 256 256')\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n x: { type: \"number\", description: \"X position (default: 0)\" },\n y: { type: \"number\", description: \"Y position (default: 0)\" },\n width: { type: \"number\", description: \"Layer width (default: 100)\" },\n height: { type: \"number\", description: \"Layer height (default: 100)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolId = input[\"symbolId\"] as string;\n const iconifyId = (input[\"iconifyId\"] as string | undefined) ?? \"\";\n const viewBox = input[\"viewBox\"] as string;\n const paths = input[\"paths\"] as SymbolPath[];\n const x = (input[\"x\"] as number | undefined) ?? 0;\n const y = (input[\"y\"] as number | undefined) ?? 0;\n const width = (input[\"width\"] as number | undefined) ?? 100;\n const height = (input[\"height\"] as number | undefined) ?? 100;\n\n const id = `symbol-${symbolId}-${Date.now()}`;\n context.layers.add({\n id,\n type: \"symbols:symbol\",\n name: symbolId,\n visible: true,\n locked: false,\n opacity: 1,\n blendMode: \"normal\",\n transform: {\n x, y, width, height,\n rotation: 0, scaleX: 1, scaleY: 1, anchorX: 0.5, anchorY: 0.5,\n },\n properties: {\n symbolId,\n iconifyId,\n viewBox,\n paths: JSON.stringify(paths),\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n },\n } as Parameters<typeof context.layers.add>[0]);\n\n context.emitChange(\"layer-added\");\n\n return textResult(JSON.stringify({\n layerId: id,\n symbolId,\n position: { x, y },\n size: { width, height },\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// Export all tools\n// ---------------------------------------------------------------------------\n\nexport const symbolMcpTools: McpToolDefinition[] = [\n searchSymbolsTool,\n listSymbolCategoriesTool,\n addSymbolTool,\n removeSymbolTool,\n createSymbolTool,\n fetchSymbolTool,\n placeSymbolTool,\n];\n","/**\n * Batch placement utilities for distributing symbols across a region.\n */\n\n/** Bounds rectangle for placement region. */\nexport interface PlacementBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** A single placement result. */\nexport interface Placement {\n x: number;\n y: number;\n rotation: number;\n scale: number;\n}\n\n/** Placement strategy: grid, random, or along-path. */\nexport type PlacementStrategy = \"grid\" | \"random\" | \"along-path\";\n\n/** Options for along-path strategy. */\nexport interface PathOptions {\n /** Path points to distribute along. */\n points: Array<{ x: number; y: number }>;\n}\n\n/**\n * Options for `generateBatchPlacements`.\n */\nexport interface BatchPlacementOptions {\n /** Minimum rotation in radians (default 0). */\n minRotation?: number;\n /** Maximum rotation in radians (default 0). */\n maxRotation?: number;\n /** Minimum scale factor (default 1). */\n minScale?: number;\n /** Maximum scale factor (default 1). */\n maxScale?: number;\n /** Seed for deterministic random placement (optional). */\n seed?: number;\n /** Path points for 'along-path' strategy. */\n pathPoints?: Array<{ x: number; y: number }>;\n}\n\n/**\n * Simple seeded PRNG (mulberry32).\n */\nfunction mulberry32(seed: number): () => number {\n let s = seed | 0;\n return () => {\n s = (s + 0x6d2b79f5) | 0;\n let t = Math.imul(s ^ (s >>> 15), 1 | s);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\n/**\n * Generate batch placements for a symbol using the given strategy.\n *\n * @param _symbolId - The symbol identifier (reserved for future per-symbol sizing)\n * @param count - Number of placements to generate\n * @param strategy - Placement strategy: 'grid', 'random', or 'along-path'\n * @param bounds - Bounding rectangle for placement\n * @param options - Additional options for rotation, scale, seed, path\n * @returns Array of Placement objects\n */\nexport function generateBatchPlacements(\n _symbolId: string,\n count: number,\n strategy: PlacementStrategy,\n bounds: PlacementBounds,\n options: BatchPlacementOptions = {},\n): Placement[] {\n if (count <= 0) return [];\n\n const {\n minRotation = 0,\n maxRotation = 0,\n minScale = 1,\n maxScale = 1,\n seed = 12345,\n pathPoints,\n } = options;\n\n const rng = mulberry32(seed);\n\n function randomRotation(): number {\n return lerp(minRotation, maxRotation, rng());\n }\n\n function randomScale(): number {\n return lerp(minScale, maxScale, rng());\n }\n\n switch (strategy) {\n case \"grid\":\n return generateGrid(count, bounds, randomRotation, randomScale);\n case \"random\":\n return generateRandom(count, bounds, rng, randomRotation, randomScale);\n case \"along-path\":\n return generateAlongPath(count, pathPoints ?? [], randomRotation, randomScale);\n default:\n throw new Error(`Unknown placement strategy: ${strategy}`);\n }\n}\n\nfunction generateGrid(\n count: number,\n bounds: PlacementBounds,\n rotation: () => number,\n scale: () => number,\n): Placement[] {\n // Compute grid dimensions that best fill the bounds\n const aspect = bounds.width / bounds.height;\n const cols = Math.max(1, Math.round(Math.sqrt(count * aspect)));\n const rows = Math.max(1, Math.ceil(count / cols));\n\n const cellW = bounds.width / cols;\n const cellH = bounds.height / rows;\n\n const placements: Placement[] = [];\n for (let i = 0; i < count; i++) {\n const col = i % cols;\n const row = Math.floor(i / cols);\n placements.push({\n x: bounds.x + cellW * (col + 0.5),\n y: bounds.y + cellH * (row + 0.5),\n rotation: rotation(),\n scale: scale(),\n });\n }\n return placements;\n}\n\nfunction generateRandom(\n count: number,\n bounds: PlacementBounds,\n rng: () => number,\n rotation: () => number,\n scale: () => number,\n): Placement[] {\n const placements: Placement[] = [];\n for (let i = 0; i < count; i++) {\n placements.push({\n x: bounds.x + rng() * bounds.width,\n y: bounds.y + rng() * bounds.height,\n rotation: rotation(),\n scale: scale(),\n });\n }\n return placements;\n}\n\nfunction generateAlongPath(\n count: number,\n points: Array<{ x: number; y: number }>,\n rotation: () => number,\n scale: () => number,\n): Placement[] {\n if (points.length === 0) return [];\n if (points.length === 1) {\n const p = points[0]!;\n return Array.from({ length: count }, () => ({\n x: p.x,\n y: p.y,\n rotation: rotation(),\n scale: scale(),\n }));\n }\n\n // Compute cumulative segment lengths\n const segLengths: number[] = [];\n let totalLength = 0;\n for (let i = 1; i < points.length; i++) {\n const dx = points[i]!.x - points[i - 1]!.x;\n const dy = points[i]!.y - points[i - 1]!.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n segLengths.push(len);\n totalLength += len;\n }\n\n if (totalLength === 0) {\n const p = points[0]!;\n return Array.from({ length: count }, () => ({\n x: p.x,\n y: p.y,\n rotation: rotation(),\n scale: scale(),\n }));\n }\n\n const placements: Placement[] = [];\n for (let i = 0; i < count; i++) {\n const t = count === 1 ? 0 : i / (count - 1);\n const targetDist = t * totalLength;\n\n // Find the segment\n let accumulated = 0;\n let segIdx = 0;\n for (segIdx = 0; segIdx < segLengths.length; segIdx++) {\n if (accumulated + segLengths[segIdx]! >= targetDist) break;\n accumulated += segLengths[segIdx]!;\n }\n segIdx = Math.min(segIdx, segLengths.length - 1);\n\n const segStart = points[segIdx]!;\n const segEnd = points[segIdx + 1] ?? segStart;\n const segLen = segLengths[segIdx] ?? 0;\n const localT = segLen > 0 ? (targetDist - accumulated) / segLen : 0;\n\n placements.push({\n x: segStart.x + (segEnd.x - segStart.x) * localT,\n y: segStart.y + (segEnd.y - segStart.y) * localT,\n rotation: rotation(),\n scale: scale(),\n });\n }\n\n return placements;\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -4,6 +4,57 @@ declare const symbolLayerType: LayerTypeDefinition;
4
4
 
5
5
  declare const symbolMcpTools: McpToolDefinition[];
6
6
 
7
+ /**
8
+ * Batch placement utilities for distributing symbols across a region.
9
+ */
10
+ /** Bounds rectangle for placement region. */
11
+ interface PlacementBounds {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ }
17
+ /** A single placement result. */
18
+ interface Placement {
19
+ x: number;
20
+ y: number;
21
+ rotation: number;
22
+ scale: number;
23
+ }
24
+ /** Placement strategy: grid, random, or along-path. */
25
+ type PlacementStrategy = "grid" | "random" | "along-path";
26
+ /**
27
+ * Options for `generateBatchPlacements`.
28
+ */
29
+ interface BatchPlacementOptions {
30
+ /** Minimum rotation in radians (default 0). */
31
+ minRotation?: number;
32
+ /** Maximum rotation in radians (default 0). */
33
+ maxRotation?: number;
34
+ /** Minimum scale factor (default 1). */
35
+ minScale?: number;
36
+ /** Maximum scale factor (default 1). */
37
+ maxScale?: number;
38
+ /** Seed for deterministic random placement (optional). */
39
+ seed?: number;
40
+ /** Path points for 'along-path' strategy. */
41
+ pathPoints?: Array<{
42
+ x: number;
43
+ y: number;
44
+ }>;
45
+ }
46
+ /**
47
+ * Generate batch placements for a symbol using the given strategy.
48
+ *
49
+ * @param _symbolId - The symbol identifier (reserved for future per-symbol sizing)
50
+ * @param count - Number of placements to generate
51
+ * @param strategy - Placement strategy: 'grid', 'random', or 'along-path'
52
+ * @param bounds - Bounding rectangle for placement
53
+ * @param options - Additional options for rotation, scale, seed, path
54
+ * @returns Array of Placement objects
55
+ */
56
+ declare function generateBatchPlacements(_symbolId: string, count: number, strategy: PlacementStrategy, bounds: PlacementBounds, options?: BatchPlacementOptions): Placement[];
57
+
7
58
  declare const symbolsPlugin: DesignPlugin;
8
59
 
9
- export { symbolsPlugin as default, symbolLayerType, symbolMcpTools, symbolsPlugin };
60
+ export { type BatchPlacementOptions, type Placement, type PlacementBounds, type PlacementStrategy, symbolsPlugin as default, generateBatchPlacements, symbolLayerType, symbolMcpTools, symbolsPlugin };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,57 @@ declare const symbolLayerType: LayerTypeDefinition;
4
4
 
5
5
  declare const symbolMcpTools: McpToolDefinition[];
6
6
 
7
+ /**
8
+ * Batch placement utilities for distributing symbols across a region.
9
+ */
10
+ /** Bounds rectangle for placement region. */
11
+ interface PlacementBounds {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ }
17
+ /** A single placement result. */
18
+ interface Placement {
19
+ x: number;
20
+ y: number;
21
+ rotation: number;
22
+ scale: number;
23
+ }
24
+ /** Placement strategy: grid, random, or along-path. */
25
+ type PlacementStrategy = "grid" | "random" | "along-path";
26
+ /**
27
+ * Options for `generateBatchPlacements`.
28
+ */
29
+ interface BatchPlacementOptions {
30
+ /** Minimum rotation in radians (default 0). */
31
+ minRotation?: number;
32
+ /** Maximum rotation in radians (default 0). */
33
+ maxRotation?: number;
34
+ /** Minimum scale factor (default 1). */
35
+ minScale?: number;
36
+ /** Maximum scale factor (default 1). */
37
+ maxScale?: number;
38
+ /** Seed for deterministic random placement (optional). */
39
+ seed?: number;
40
+ /** Path points for 'along-path' strategy. */
41
+ pathPoints?: Array<{
42
+ x: number;
43
+ y: number;
44
+ }>;
45
+ }
46
+ /**
47
+ * Generate batch placements for a symbol using the given strategy.
48
+ *
49
+ * @param _symbolId - The symbol identifier (reserved for future per-symbol sizing)
50
+ * @param count - Number of placements to generate
51
+ * @param strategy - Placement strategy: 'grid', 'random', or 'along-path'
52
+ * @param bounds - Bounding rectangle for placement
53
+ * @param options - Additional options for rotation, scale, seed, path
54
+ * @returns Array of Placement objects
55
+ */
56
+ declare function generateBatchPlacements(_symbolId: string, count: number, strategy: PlacementStrategy, bounds: PlacementBounds, options?: BatchPlacementOptions): Placement[];
57
+
7
58
  declare const symbolsPlugin: DesignPlugin;
8
59
 
9
- export { symbolsPlugin as default, symbolLayerType, symbolMcpTools, symbolsPlugin };
60
+ export { type BatchPlacementOptions, type Placement, type PlacementBounds, type PlacementStrategy, symbolsPlugin as default, generateBatchPlacements, symbolLayerType, symbolMcpTools, symbolsPlugin };
package/dist/index.js CHANGED
@@ -520,11 +520,137 @@ var symbolMcpTools = [
520
520
  placeSymbolTool
521
521
  ];
522
522
 
523
+ // src/batch-placement.ts
524
+ function mulberry32(seed) {
525
+ let s = seed | 0;
526
+ return () => {
527
+ s = s + 1831565813 | 0;
528
+ let t = Math.imul(s ^ s >>> 15, 1 | s);
529
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
530
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
531
+ };
532
+ }
533
+ function lerp(a, b, t) {
534
+ return a + (b - a) * t;
535
+ }
536
+ function generateBatchPlacements(_symbolId, count, strategy, bounds, options = {}) {
537
+ if (count <= 0) return [];
538
+ const {
539
+ minRotation = 0,
540
+ maxRotation = 0,
541
+ minScale = 1,
542
+ maxScale = 1,
543
+ seed = 12345,
544
+ pathPoints
545
+ } = options;
546
+ const rng = mulberry32(seed);
547
+ function randomRotation() {
548
+ return lerp(minRotation, maxRotation, rng());
549
+ }
550
+ function randomScale() {
551
+ return lerp(minScale, maxScale, rng());
552
+ }
553
+ switch (strategy) {
554
+ case "grid":
555
+ return generateGrid(count, bounds, randomRotation, randomScale);
556
+ case "random":
557
+ return generateRandom(count, bounds, rng, randomRotation, randomScale);
558
+ case "along-path":
559
+ return generateAlongPath(count, pathPoints ?? [], randomRotation, randomScale);
560
+ default:
561
+ throw new Error(`Unknown placement strategy: ${strategy}`);
562
+ }
563
+ }
564
+ function generateGrid(count, bounds, rotation, scale) {
565
+ const aspect = bounds.width / bounds.height;
566
+ const cols = Math.max(1, Math.round(Math.sqrt(count * aspect)));
567
+ const rows = Math.max(1, Math.ceil(count / cols));
568
+ const cellW = bounds.width / cols;
569
+ const cellH = bounds.height / rows;
570
+ const placements = [];
571
+ for (let i = 0; i < count; i++) {
572
+ const col = i % cols;
573
+ const row = Math.floor(i / cols);
574
+ placements.push({
575
+ x: bounds.x + cellW * (col + 0.5),
576
+ y: bounds.y + cellH * (row + 0.5),
577
+ rotation: rotation(),
578
+ scale: scale()
579
+ });
580
+ }
581
+ return placements;
582
+ }
583
+ function generateRandom(count, bounds, rng, rotation, scale) {
584
+ const placements = [];
585
+ for (let i = 0; i < count; i++) {
586
+ placements.push({
587
+ x: bounds.x + rng() * bounds.width,
588
+ y: bounds.y + rng() * bounds.height,
589
+ rotation: rotation(),
590
+ scale: scale()
591
+ });
592
+ }
593
+ return placements;
594
+ }
595
+ function generateAlongPath(count, points, rotation, scale) {
596
+ if (points.length === 0) return [];
597
+ if (points.length === 1) {
598
+ const p = points[0];
599
+ return Array.from({ length: count }, () => ({
600
+ x: p.x,
601
+ y: p.y,
602
+ rotation: rotation(),
603
+ scale: scale()
604
+ }));
605
+ }
606
+ const segLengths = [];
607
+ let totalLength = 0;
608
+ for (let i = 1; i < points.length; i++) {
609
+ const dx = points[i].x - points[i - 1].x;
610
+ const dy = points[i].y - points[i - 1].y;
611
+ const len = Math.sqrt(dx * dx + dy * dy);
612
+ segLengths.push(len);
613
+ totalLength += len;
614
+ }
615
+ if (totalLength === 0) {
616
+ const p = points[0];
617
+ return Array.from({ length: count }, () => ({
618
+ x: p.x,
619
+ y: p.y,
620
+ rotation: rotation(),
621
+ scale: scale()
622
+ }));
623
+ }
624
+ const placements = [];
625
+ for (let i = 0; i < count; i++) {
626
+ const t = count === 1 ? 0 : i / (count - 1);
627
+ const targetDist = t * totalLength;
628
+ let accumulated = 0;
629
+ let segIdx = 0;
630
+ for (segIdx = 0; segIdx < segLengths.length; segIdx++) {
631
+ if (accumulated + segLengths[segIdx] >= targetDist) break;
632
+ accumulated += segLengths[segIdx];
633
+ }
634
+ segIdx = Math.min(segIdx, segLengths.length - 1);
635
+ const segStart = points[segIdx];
636
+ const segEnd = points[segIdx + 1] ?? segStart;
637
+ const segLen = segLengths[segIdx] ?? 0;
638
+ const localT = segLen > 0 ? (targetDist - accumulated) / segLen : 0;
639
+ placements.push({
640
+ x: segStart.x + (segEnd.x - segStart.x) * localT,
641
+ y: segStart.y + (segEnd.y - segStart.y) * localT,
642
+ rotation: rotation(),
643
+ scale: scale()
644
+ });
645
+ }
646
+ return placements;
647
+ }
648
+
523
649
  // src/index.ts
524
650
  var symbolsPlugin = {
525
651
  id: "symbols",
526
652
  name: "Symbols & Icons",
527
- version: "0.1.0",
653
+ version: "0.2.0",
528
654
  tier: "free",
529
655
  description: "Vector symbol library with Iconify integration. Search, fetch, and place symbols on the design canvas or embed in algorithms.",
530
656
  layerTypes: [symbolLayerType],
@@ -539,6 +665,7 @@ var symbolsPlugin = {
539
665
  var index_default = symbolsPlugin;
540
666
  export {
541
667
  index_default as default,
668
+ generateBatchPlacements,
542
669
  symbolLayerType,
543
670
  symbolMcpTools,
544
671
  symbolsPlugin
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/symbol-layer.ts","../src/symbol-tools.ts","../src/index.ts"],"sourcesContent":["import type {\n LayerTypeDefinition,\n LayerPropertySchema,\n LayerProperties,\n LayerBounds,\n RenderResources,\n} from \"@genart-dev/core\";\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\n\nconst SYMBOL_PROPERTIES: LayerPropertySchema[] = [\n { key: \"symbolId\", label: \"Symbol ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"iconifyId\", label: \"Iconify ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"viewBox\", label: \"ViewBox\", type: \"string\", default: \"0 0 24 24\", group: \"symbol\" },\n { key: \"paths\", label: \"Paths (JSON)\", type: \"string\", default: \"[]\", group: \"data\" },\n { key: \"fillOverride\", label: \"Fill Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"strokeOverride\", label: \"Stroke Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"preserveAspect\", label: \"Preserve Aspect\", type: \"boolean\", default: true, group: \"layout\" },\n];\n\nexport const symbolLayerType: LayerTypeDefinition = {\n typeId: \"symbols:symbol\",\n displayName: \"Symbol\",\n icon: \"symbol\",\n category: \"image\",\n properties: SYMBOL_PROPERTIES,\n propertyEditorId: \"symbols:symbol-editor\",\n\n createDefault(): LayerProperties {\n return {\n symbolId: \"\",\n iconifyId: \"\",\n viewBox: \"0 0 24 24\",\n paths: \"[]\",\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n };\n },\n\n render(\n properties: LayerProperties,\n ctx: CanvasRenderingContext2D,\n bounds: LayerBounds,\n _resources: RenderResources,\n ): void {\n const pathsJson = String(properties.paths ?? \"[]\");\n let paths: SymbolPath[];\n try {\n paths = JSON.parse(pathsJson) as SymbolPath[];\n } catch {\n return;\n }\n if (paths.length === 0) return;\n\n const viewBoxStr = String(properties.viewBox ?? \"0 0 24 24\");\n const vb = viewBoxStr.split(/\\s+/).map(Number);\n const vbX = vb[0] ?? 0;\n const vbY = vb[1] ?? 0;\n const vbW = vb[2] ?? 24;\n const vbH = vb[3] ?? 24;\n\n const preserveAspect = Boolean(properties.preserveAspect ?? true);\n const fillOverride = String(properties.fillOverride ?? \"\") || undefined;\n const strokeOverride = String(properties.strokeOverride ?? \"\") || undefined;\n\n let scaleX = bounds.width / vbW;\n let scaleY = bounds.height / vbH;\n\n let offsetX = 0;\n let offsetY = 0;\n\n if (preserveAspect) {\n const uniformScale = Math.min(scaleX, scaleY);\n offsetX = (bounds.width - vbW * uniformScale) / 2;\n offsetY = (bounds.height - vbH * uniformScale) / 2;\n scaleX = uniformScale;\n scaleY = uniformScale;\n }\n\n ctx.save();\n ctx.translate(bounds.x + offsetX - vbX * scaleX, bounds.y + offsetY - vbY * scaleY);\n ctx.scale(scaleX, scaleY);\n\n for (const p of paths) {\n const path = new Path2D(p.d);\n if (p.fill !== \"none\") {\n ctx.fillStyle = fillOverride ?? p.fill ?? \"#000000\";\n ctx.fill(path);\n }\n if (p.stroke || strokeOverride) {\n ctx.strokeStyle = strokeOverride ?? p.stroke ?? \"#000000\";\n ctx.lineWidth = (p.strokeWidth ?? 1) / Math.max(scaleX, scaleY);\n ctx.stroke(path);\n }\n }\n\n ctx.restore();\n },\n\n validate(): null { return null; },\n};\n","import type {\n McpToolDefinition,\n McpToolContext,\n McpToolResult,\n JsonSchema,\n} from \"@genart-dev/core\";\nimport { resolveComponents } from \"@genart-dev/core\";\nimport type {\n SymbolCategory,\n SymbolStyle,\n SketchSymbolDef,\n} from \"@genart-dev/symbols\";\n\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\nimport {\n SYMBOL_REGISTRY,\n listCategories,\n searchSymbols,\n resolveSymbol,\n validateSymbol,\n searchIconify,\n fetchAndParseIcon,\n SAFE_PREFIXES,\n} from \"@genart-dev/symbols\";\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface ThirdPartyNotice {\n readonly name: string;\n readonly license: string;\n readonly copyright: string;\n readonly url: string;\n}\n\nfunction textResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }] };\n}\n\nfunction errorResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\nconst VALID_STYLES: readonly SymbolStyle[] = [\"geometric\", \"organic\", \"silhouette\", \"sketch\"];\nconst JS_RENDERERS = new Set([\"p5\", \"three\", \"canvas2d\", \"svg\"]);\n\nconst ICONIFY_NOTICES: Readonly<Record<string, ThirdPartyNotice>> = {\n ph: {\n name: \"Phosphor Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2023 Phosphor Icons\",\n url: \"https://github.com/phosphor-icons/core\",\n },\n lucide: {\n name: \"Lucide\",\n license: \"ISC\",\n copyright: \"Copyright (c) 2022 Lucide Contributors\",\n url: \"https://github.com/lucide-icons/lucide\",\n },\n tabler: {\n name: \"Tabler Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020-2024 Paweł Kuna\",\n url: \"https://github.com/tabler/tabler-icons\",\n },\n heroicons: {\n name: \"Heroicons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Tailwind Labs, Inc.\",\n url: \"https://github.com/tailwindlabs/heroicons\",\n },\n bi: {\n name: \"Bootstrap Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2019-2024 The Bootstrap Authors\",\n url: \"https://github.com/twbs/icons\",\n },\n mdi: {\n name: \"Material Design Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) Google LLC\",\n url: \"https://github.com/google/material-design-icons\",\n },\n ri: {\n name: \"Remix Icon\",\n license: \"Remix Icon License v1.0\",\n copyright: \"Copyright (c) 2017-2024 Remix Design\",\n url: \"https://github.com/Remix-Design/RemixIcon\",\n },\n carbon: {\n name: \"Carbon Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) 2015 IBM Corp.\",\n url: \"https://github.com/carbon-design-system/carbon\",\n },\n fluent: {\n name: \"Fluent UI System Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Microsoft Corporation\",\n url: \"https://github.com/microsoft/fluentui-system-icons\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// search_symbols\n// ---------------------------------------------------------------------------\n\nexport const searchSymbolsTool: McpToolDefinition = {\n name: \"search_symbols\",\n description: \"Search the symbol registry by keyword, category, and/or style. Returns symbols with their IDs, tags, and available styles.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to match against symbol name, tags, and description\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Filter by category\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Filter by available style\" },\n limit: { type: \"number\", description: \"Maximum results to return (default: 20)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const results = searchSymbols({\n query: input[\"query\"] as string | undefined,\n category: input[\"category\"] as SymbolCategory | undefined,\n style: input[\"style\"] as SymbolStyle | undefined,\n limit: (input[\"limit\"] as number | undefined) ?? 20,\n });\n return textResult(JSON.stringify({ count: results.length, symbols: results }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// list_symbol_categories\n// ---------------------------------------------------------------------------\n\nexport const listSymbolCategoriesTool: McpToolDefinition = {\n name: \"list_symbol_categories\",\n description: \"List all symbol categories with symbol counts. Use this to browse the symbol library before searching.\",\n inputSchema: {\n type: \"object\",\n properties: {} as Record<string, JsonSchema>,\n },\n async handler(_input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const categories = listCategories();\n const total = Object.keys(SYMBOL_REGISTRY).length;\n const breakdown = categories.map((cat) => ({\n category: cat,\n count: Object.values(SYMBOL_REGISTRY).filter((s) => s.category === cat).length,\n }));\n return textResult(JSON.stringify({ categories: breakdown, total }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// add_symbol\n// ---------------------------------------------------------------------------\n\nexport const addSymbolTool: McpToolDefinition = {\n name: \"add_symbol\",\n description: \"Add a symbol from the registry to a sketch. Resolves the symbol's SVG path data and caches it in the sketch file. Automatically adds the symbol-draw component if not already present.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID (e.g. 'pine-tree', 'sailboat', 'mountain')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Style variant to use (default: 'geometric')\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n const renderer = context.sketch.getRenderer();\n\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer (p5, canvas2d, svg, three). Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const resolved = resolveSymbol(symbolName, style);\n\n const existing = context.sketch.getSymbols();\n if (existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is already present in the sketch`);\n }\n\n const newSymbols: Record<string, unknown> = { ...existing, [symbolName]: resolved };\n\n // Ensure symbol-draw component is present\n const existingComponents = context.sketch.getComponents();\n if (!existingComponents[\"symbol-draw\"]) {\n const compMap: Record<string, string> = {};\n for (const [name, value] of Object.entries(existingComponents)) {\n if (typeof value === \"string\") {\n compMap[name] = value;\n } else if (value && typeof value === \"object\" && \"version\" in value) {\n compMap[name] = (value as { version: string }).version;\n }\n }\n compMap[\"symbol-draw\"] = \"^1.0.0\";\n const resolved2 = resolveComponents(compMap, renderer as Parameters<typeof resolveComponents>[1]);\n const resolvedRecord: Record<string, unknown> = {};\n for (const rc of resolved2) {\n resolvedRecord[rc.name] = { version: rc.version, code: rc.code, exports: [...rc.exports] };\n }\n context.sketch.setComponents(resolvedRecord);\n }\n\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n const added = Object.keys(newSymbols).filter((k) => !existing[k]);\n\n return textResult(JSON.stringify({\n success: true,\n added,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// remove_symbol\n// ---------------------------------------------------------------------------\n\nexport const removeSymbolTool: McpToolDefinition = {\n name: \"remove_symbol\",\n description: \"Remove a symbol from a sketch. Warns if the algorithm references the symbol ID.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID to remove\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n\n const existing = context.sketch.getSymbols();\n if (!existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is not present in the sketch`);\n }\n\n const newSymbols = { ...existing };\n delete newSymbols[symbolName];\n\n context.sketch.setSymbols(\n Object.keys(newSymbols).length > 0 ? newSymbols : undefined,\n );\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n removed: symbolName,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// create_symbol\n// ---------------------------------------------------------------------------\n\nexport const createSymbolTool: McpToolDefinition = {\n name: \"create_symbol\",\n description: \"Create a custom AI-generated symbol with SVG path data. Validates path syntax and enforces a 10KB size limit. Caches it in the sketch file for use with drawSymbol().\",\n inputSchema: {\n type: \"object\",\n required: [\"name\", \"category\", \"tags\", \"description\", \"paths\", \"viewBox\", \"style\"],\n properties: {\n name: { type: \"string\", description: \"Human-readable symbol name (e.g. 'Weeping Willow')\" },\n id: { type: \"string\", description: \"Symbol ID (kebab-case, auto-generated from name if omitted)\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Symbol category\" },\n tags: { type: \"array\", items: { type: \"string\" }, description: \"Search tags (e.g. ['tree', 'weeping', 'willow', 'nature'])\" },\n description: { type: \"string\", description: \"Short description of the symbol\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\", description: \"Semantic role (e.g. 'trunk', 'canopy')\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 100 100')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Visual style of these paths\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const paths = input[\"paths\"] as SymbolPath[];\n const viewBox = input[\"viewBox\"] as string;\n\n const errors = validateSymbol(paths, viewBox);\n if (errors.length > 0) {\n return errorResult(`Symbol validation failed:\\n${errors.join(\"\\n\")}`);\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const name = input[\"name\"] as string;\n const id = (input[\"id\"] as string | undefined) ?? name.toLowerCase().replace(/\\s+/g, \"-\").replace(/[^a-z0-9-]/g, \"\");\n\n const symbolDef: SketchSymbolDef = {\n id,\n name,\n style,\n paths,\n viewBox,\n custom: true,\n };\n\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [id]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n symbol: symbolDef,\n tip: `Use drawSymbol(ctx, \"${id}\", x, y, width, height) to render this symbol in your algorithm.`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// fetch_symbol\n// ---------------------------------------------------------------------------\n\nexport const fetchSymbolTool: McpToolDefinition = {\n name: \"fetch_symbol\",\n description: \"Search Iconify for professional icons (275k+ from Phosphor, Lucide, Tabler, MDI, etc.) or embed one into a sketch. Two modes: (1) Search — provide query to get a list of iconifyIds; (2) Embed — provide iconifyId (e.g. 'ph:cat') to fetch SVG, parse paths, and embed as a SketchSymbolDef. Approved prefixes: ph, lucide, tabler, heroicons, bi, mdi, ri, carbon, fluent.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to search Iconify (e.g. 'cat', 'arrow left', 'sun'). Returns a list of iconifyIds — no SVG fetched yet.\" },\n iconifyId: { type: \"string\", description: \"Iconify icon ID to embed (e.g. 'ph:cat', 'lucide:arrow-left'). Fetches SVG, parses paths, embeds in sketch.\" },\n prefix: { type: \"string\", description: \"Limit search to a specific icon set (e.g. 'ph', 'lucide', 'tabler'). Ignored when using iconifyId.\" },\n limit: { type: \"number\", description: \"Maximum search results to return (default: 10)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const query = input[\"query\"] as string | undefined;\n const iconifyId = input[\"iconifyId\"] as string | undefined;\n\n // ---- Search mode ----\n if (query && !iconifyId) {\n const prefixes = input[\"prefix\"] ? [input[\"prefix\"] as string] : undefined;\n const results = await searchIconify(query, (input[\"limit\"] as number | undefined) ?? 10, prefixes);\n return textResult(JSON.stringify({\n mode: \"search\",\n results,\n tip: \"Call fetch_symbol with iconifyId to embed one of these icons into a sketch\",\n }));\n }\n\n // ---- Embed mode ----\n if (!iconifyId) {\n return errorResult(\n \"Provide either query (to search) or iconifyId (to embed). Approved prefixes: \" +\n Object.keys(SAFE_PREFIXES).join(\", \"),\n );\n }\n\n let iconData: Awaited<ReturnType<typeof fetchAndParseIcon>>;\n try {\n iconData = await fetchAndParseIcon(iconifyId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"not in the approved list\")) {\n return textResult(JSON.stringify({ warning: msg }));\n }\n return errorResult(msg);\n }\n\n const symbolId = iconData.iconifyId.replace(\":\", \"-\");\n\n const symbolDef: SketchSymbolDef = {\n id: symbolId,\n name: iconData.name,\n paths: iconData.paths,\n viewBox: iconData.viewBox,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n };\n\n // Embed into sketch\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [symbolId]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n\n // Merge third-party notice\n const notice = ICONIFY_NOTICES[iconData.prefix];\n const existingNotices = context.sketch.getThirdParty();\n const alreadyPresent = existingNotices.some(\n (n: Record<string, unknown>) => (n as { name?: string }).name === notice?.name,\n );\n if (notice && !alreadyPresent) {\n context.sketch.setThirdParty([\n ...existingNotices as Record<string, unknown>[],\n notice as unknown as Record<string, unknown>,\n ]);\n }\n\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n mode: \"embedded\",\n symbolId,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n viewBox: iconData.viewBox,\n pathCount: iconData.paths.length,\n tip: `drawSymbol(ctx, \"${symbolId}\", x, y, width, height)`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// place_symbol\n// ---------------------------------------------------------------------------\n\nexport const placeSymbolTool: McpToolDefinition = {\n name: \"place_symbol\",\n description: \"Place a symbol as a design layer on the canvas. Creates a symbols:symbol layer with embedded SVG path data for visual composition.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbolId\", \"viewBox\", \"paths\"],\n properties: {\n symbolId: { type: \"string\", description: \"Symbol ID (e.g. 'ph-cat')\" },\n iconifyId: { type: \"string\", description: \"Original Iconify ID (e.g. 'ph:cat')\" },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 256 256')\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n x: { type: \"number\", description: \"X position (default: 0)\" },\n y: { type: \"number\", description: \"Y position (default: 0)\" },\n width: { type: \"number\", description: \"Layer width (default: 100)\" },\n height: { type: \"number\", description: \"Layer height (default: 100)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolId = input[\"symbolId\"] as string;\n const iconifyId = (input[\"iconifyId\"] as string | undefined) ?? \"\";\n const viewBox = input[\"viewBox\"] as string;\n const paths = input[\"paths\"] as SymbolPath[];\n const x = (input[\"x\"] as number | undefined) ?? 0;\n const y = (input[\"y\"] as number | undefined) ?? 0;\n const width = (input[\"width\"] as number | undefined) ?? 100;\n const height = (input[\"height\"] as number | undefined) ?? 100;\n\n const id = `symbol-${symbolId}-${Date.now()}`;\n context.layers.add({\n id,\n type: \"symbols:symbol\",\n name: symbolId,\n visible: true,\n locked: false,\n opacity: 1,\n blendMode: \"normal\",\n transform: {\n x, y, width, height,\n rotation: 0, scaleX: 1, scaleY: 1, anchorX: 0.5, anchorY: 0.5,\n },\n properties: {\n symbolId,\n iconifyId,\n viewBox,\n paths: JSON.stringify(paths),\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n },\n } as Parameters<typeof context.layers.add>[0]);\n\n context.emitChange(\"layer-added\");\n\n return textResult(JSON.stringify({\n layerId: id,\n symbolId,\n position: { x, y },\n size: { width, height },\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// Export all tools\n// ---------------------------------------------------------------------------\n\nexport const symbolMcpTools: McpToolDefinition[] = [\n searchSymbolsTool,\n listSymbolCategoriesTool,\n addSymbolTool,\n removeSymbolTool,\n createSymbolTool,\n fetchSymbolTool,\n placeSymbolTool,\n];\n","import type { DesignPlugin, PluginContext } from \"@genart-dev/core\";\nimport { symbolLayerType } from \"./symbol-layer.js\";\nimport { symbolMcpTools } from \"./symbol-tools.js\";\n\nconst symbolsPlugin: DesignPlugin = {\n id: \"symbols\",\n name: \"Symbols & Icons\",\n version: \"0.1.0\",\n tier: \"free\",\n description:\n \"Vector symbol library with Iconify integration. Search, fetch, and place symbols on the design canvas or embed in algorithms.\",\n layerTypes: [symbolLayerType],\n tools: [],\n exportHandlers: [],\n mcpTools: symbolMcpTools,\n async initialize(_context: PluginContext): Promise<void> {},\n dispose(): void {},\n};\n\nexport default symbolsPlugin;\nexport { symbolsPlugin };\nexport { symbolLayerType };\nexport { symbolMcpTools };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/symbol-layer.ts","../src/symbol-tools.ts","../src/batch-placement.ts","../src/index.ts"],"sourcesContent":["import type {\n LayerTypeDefinition,\n LayerPropertySchema,\n LayerProperties,\n LayerBounds,\n RenderResources,\n} from \"@genart-dev/core\";\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\n\nconst SYMBOL_PROPERTIES: LayerPropertySchema[] = [\n { key: \"symbolId\", label: \"Symbol ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"iconifyId\", label: \"Iconify ID\", type: \"string\", default: \"\", group: \"symbol\" },\n { key: \"viewBox\", label: \"ViewBox\", type: \"string\", default: \"0 0 24 24\", group: \"symbol\" },\n { key: \"paths\", label: \"Paths (JSON)\", type: \"string\", default: \"[]\", group: \"data\" },\n { key: \"fillOverride\", label: \"Fill Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"strokeOverride\", label: \"Stroke Override\", type: \"string\", default: \"\", group: \"appearance\" },\n { key: \"preserveAspect\", label: \"Preserve Aspect\", type: \"boolean\", default: true, group: \"layout\" },\n];\n\nexport const symbolLayerType: LayerTypeDefinition = {\n typeId: \"symbols:symbol\",\n displayName: \"Symbol\",\n icon: \"symbol\",\n category: \"image\",\n properties: SYMBOL_PROPERTIES,\n propertyEditorId: \"symbols:symbol-editor\",\n\n createDefault(): LayerProperties {\n return {\n symbolId: \"\",\n iconifyId: \"\",\n viewBox: \"0 0 24 24\",\n paths: \"[]\",\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n };\n },\n\n render(\n properties: LayerProperties,\n ctx: CanvasRenderingContext2D,\n bounds: LayerBounds,\n _resources: RenderResources,\n ): void {\n const pathsJson = String(properties.paths ?? \"[]\");\n let paths: SymbolPath[];\n try {\n paths = JSON.parse(pathsJson) as SymbolPath[];\n } catch {\n return;\n }\n if (paths.length === 0) return;\n\n const viewBoxStr = String(properties.viewBox ?? \"0 0 24 24\");\n const vb = viewBoxStr.split(/\\s+/).map(Number);\n const vbX = vb[0] ?? 0;\n const vbY = vb[1] ?? 0;\n const vbW = vb[2] ?? 24;\n const vbH = vb[3] ?? 24;\n\n const preserveAspect = Boolean(properties.preserveAspect ?? true);\n const fillOverride = String(properties.fillOverride ?? \"\") || undefined;\n const strokeOverride = String(properties.strokeOverride ?? \"\") || undefined;\n\n let scaleX = bounds.width / vbW;\n let scaleY = bounds.height / vbH;\n\n let offsetX = 0;\n let offsetY = 0;\n\n if (preserveAspect) {\n const uniformScale = Math.min(scaleX, scaleY);\n offsetX = (bounds.width - vbW * uniformScale) / 2;\n offsetY = (bounds.height - vbH * uniformScale) / 2;\n scaleX = uniformScale;\n scaleY = uniformScale;\n }\n\n ctx.save();\n ctx.translate(bounds.x + offsetX - vbX * scaleX, bounds.y + offsetY - vbY * scaleY);\n ctx.scale(scaleX, scaleY);\n\n for (const p of paths) {\n const path = new Path2D(p.d);\n if (p.fill !== \"none\") {\n ctx.fillStyle = fillOverride ?? p.fill ?? \"#000000\";\n ctx.fill(path);\n }\n if (p.stroke || strokeOverride) {\n ctx.strokeStyle = strokeOverride ?? p.stroke ?? \"#000000\";\n ctx.lineWidth = (p.strokeWidth ?? 1) / Math.max(scaleX, scaleY);\n ctx.stroke(path);\n }\n }\n\n ctx.restore();\n },\n\n validate(): null { return null; },\n};\n","import type {\n McpToolDefinition,\n McpToolContext,\n McpToolResult,\n JsonSchema,\n} from \"@genart-dev/core\";\nimport { resolveComponents } from \"@genart-dev/core\";\nimport type {\n SymbolCategory,\n SymbolStyle,\n SketchSymbolDef,\n} from \"@genart-dev/symbols\";\n\ninterface SymbolPath {\n readonly d: string;\n readonly fill?: string;\n readonly stroke?: string;\n readonly strokeWidth?: number;\n readonly role?: string;\n}\nimport {\n SYMBOL_REGISTRY,\n listCategories,\n searchSymbols,\n resolveSymbol,\n validateSymbol,\n searchIconify,\n fetchAndParseIcon,\n SAFE_PREFIXES,\n} from \"@genart-dev/symbols\";\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface ThirdPartyNotice {\n readonly name: string;\n readonly license: string;\n readonly copyright: string;\n readonly url: string;\n}\n\nfunction textResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }] };\n}\n\nfunction errorResult(text: string): McpToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\nconst VALID_STYLES: readonly SymbolStyle[] = [\"geometric\", \"organic\", \"silhouette\", \"sketch\"];\nconst JS_RENDERERS = new Set([\"p5\", \"three\", \"canvas2d\", \"svg\"]);\n\nconst ICONIFY_NOTICES: Readonly<Record<string, ThirdPartyNotice>> = {\n ph: {\n name: \"Phosphor Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2023 Phosphor Icons\",\n url: \"https://github.com/phosphor-icons/core\",\n },\n lucide: {\n name: \"Lucide\",\n license: \"ISC\",\n copyright: \"Copyright (c) 2022 Lucide Contributors\",\n url: \"https://github.com/lucide-icons/lucide\",\n },\n tabler: {\n name: \"Tabler Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020-2024 Paweł Kuna\",\n url: \"https://github.com/tabler/tabler-icons\",\n },\n heroicons: {\n name: \"Heroicons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Tailwind Labs, Inc.\",\n url: \"https://github.com/tailwindlabs/heroicons\",\n },\n bi: {\n name: \"Bootstrap Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2019-2024 The Bootstrap Authors\",\n url: \"https://github.com/twbs/icons\",\n },\n mdi: {\n name: \"Material Design Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) Google LLC\",\n url: \"https://github.com/google/material-design-icons\",\n },\n ri: {\n name: \"Remix Icon\",\n license: \"Remix Icon License v1.0\",\n copyright: \"Copyright (c) 2017-2024 Remix Design\",\n url: \"https://github.com/Remix-Design/RemixIcon\",\n },\n carbon: {\n name: \"Carbon Icons\",\n license: \"Apache-2.0\",\n copyright: \"Copyright (c) 2015 IBM Corp.\",\n url: \"https://github.com/carbon-design-system/carbon\",\n },\n fluent: {\n name: \"Fluent UI System Icons\",\n license: \"MIT\",\n copyright: \"Copyright (c) 2020 Microsoft Corporation\",\n url: \"https://github.com/microsoft/fluentui-system-icons\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// search_symbols\n// ---------------------------------------------------------------------------\n\nexport const searchSymbolsTool: McpToolDefinition = {\n name: \"search_symbols\",\n description: \"Search the symbol registry by keyword, category, and/or style. Returns symbols with their IDs, tags, and available styles.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to match against symbol name, tags, and description\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Filter by category\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Filter by available style\" },\n limit: { type: \"number\", description: \"Maximum results to return (default: 20)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const results = searchSymbols({\n query: input[\"query\"] as string | undefined,\n category: input[\"category\"] as SymbolCategory | undefined,\n style: input[\"style\"] as SymbolStyle | undefined,\n limit: (input[\"limit\"] as number | undefined) ?? 20,\n });\n return textResult(JSON.stringify({ count: results.length, symbols: results }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// list_symbol_categories\n// ---------------------------------------------------------------------------\n\nexport const listSymbolCategoriesTool: McpToolDefinition = {\n name: \"list_symbol_categories\",\n description: \"List all symbol categories with symbol counts. Use this to browse the symbol library before searching.\",\n inputSchema: {\n type: \"object\",\n properties: {} as Record<string, JsonSchema>,\n },\n async handler(_input: Record<string, unknown>, _context: McpToolContext): Promise<McpToolResult> {\n const categories = listCategories();\n const total = Object.keys(SYMBOL_REGISTRY).length;\n const breakdown = categories.map((cat) => ({\n category: cat,\n count: Object.values(SYMBOL_REGISTRY).filter((s) => s.category === cat).length,\n }));\n return textResult(JSON.stringify({ categories: breakdown, total }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// add_symbol\n// ---------------------------------------------------------------------------\n\nexport const addSymbolTool: McpToolDefinition = {\n name: \"add_symbol\",\n description: \"Add a symbol from the registry to a sketch. Resolves the symbol's SVG path data and caches it in the sketch file. Automatically adds the symbol-draw component if not already present.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID (e.g. 'pine-tree', 'sailboat', 'mountain')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Style variant to use (default: 'geometric')\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n const renderer = context.sketch.getRenderer();\n\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer (p5, canvas2d, svg, three). Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const resolved = resolveSymbol(symbolName, style);\n\n const existing = context.sketch.getSymbols();\n if (existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is already present in the sketch`);\n }\n\n const newSymbols: Record<string, unknown> = { ...existing, [symbolName]: resolved };\n\n // Ensure symbol-draw component is present\n const existingComponents = context.sketch.getComponents();\n if (!existingComponents[\"symbol-draw\"]) {\n const compMap: Record<string, string> = {};\n for (const [name, value] of Object.entries(existingComponents)) {\n if (typeof value === \"string\") {\n compMap[name] = value;\n } else if (value && typeof value === \"object\" && \"version\" in value) {\n compMap[name] = (value as { version: string }).version;\n }\n }\n compMap[\"symbol-draw\"] = \"^1.0.0\";\n const resolved2 = resolveComponents(compMap, renderer as Parameters<typeof resolveComponents>[1]);\n const resolvedRecord: Record<string, unknown> = {};\n for (const rc of resolved2) {\n resolvedRecord[rc.name] = { version: rc.version, code: rc.code, exports: [...rc.exports] };\n }\n context.sketch.setComponents(resolvedRecord);\n }\n\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n const added = Object.keys(newSymbols).filter((k) => !existing[k]);\n\n return textResult(JSON.stringify({\n success: true,\n added,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// remove_symbol\n// ---------------------------------------------------------------------------\n\nexport const removeSymbolTool: McpToolDefinition = {\n name: \"remove_symbol\",\n description: \"Remove a symbol from a sketch. Warns if the algorithm references the symbol ID.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbol\"],\n properties: {\n symbol: { type: \"string\", description: \"Symbol ID to remove\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolName = input[\"symbol\"] as string;\n\n const existing = context.sketch.getSymbols();\n if (!existing[symbolName]) {\n return errorResult(`Symbol \"${symbolName}\" is not present in the sketch`);\n }\n\n const newSymbols = { ...existing };\n delete newSymbols[symbolName];\n\n context.sketch.setSymbols(\n Object.keys(newSymbols).length > 0 ? newSymbols : undefined,\n );\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n removed: symbolName,\n symbolCount: Object.keys(newSymbols).length,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// create_symbol\n// ---------------------------------------------------------------------------\n\nexport const createSymbolTool: McpToolDefinition = {\n name: \"create_symbol\",\n description: \"Create a custom AI-generated symbol with SVG path data. Validates path syntax and enforces a 10KB size limit. Caches it in the sketch file for use with drawSymbol().\",\n inputSchema: {\n type: \"object\",\n required: [\"name\", \"category\", \"tags\", \"description\", \"paths\", \"viewBox\", \"style\"],\n properties: {\n name: { type: \"string\", description: \"Human-readable symbol name (e.g. 'Weeping Willow')\" },\n id: { type: \"string\", description: \"Symbol ID (kebab-case, auto-generated from name if omitted)\" },\n category: { type: \"string\", enum: [\"nature\", \"architecture\", \"people\", \"vehicles\", \"objects\", \"animals\", \"abstract\", \"celestial\", \"flora\", \"weather\"], description: \"Symbol category\" },\n tags: { type: \"array\", items: { type: \"string\" }, description: \"Search tags (e.g. ['tree', 'weeping', 'willow', 'nature'])\" },\n description: { type: \"string\", description: \"Short description of the symbol\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\", description: \"Semantic role (e.g. 'trunk', 'canopy')\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 100 100')\" },\n style: { type: \"string\", enum: [\"geometric\", \"organic\", \"silhouette\", \"sketch\"], description: \"Visual style of these paths\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const paths = input[\"paths\"] as SymbolPath[];\n const viewBox = input[\"viewBox\"] as string;\n\n const errors = validateSymbol(paths, viewBox);\n if (errors.length > 0) {\n return errorResult(`Symbol validation failed:\\n${errors.join(\"\\n\")}`);\n }\n\n const style = ((input[\"style\"] as string | undefined) ?? \"geometric\") as SymbolStyle;\n if (!VALID_STYLES.includes(style)) {\n return errorResult(`Unknown style \"${style}\". Valid styles: ${VALID_STYLES.join(\", \")}`);\n }\n\n const name = input[\"name\"] as string;\n const id = (input[\"id\"] as string | undefined) ?? name.toLowerCase().replace(/\\s+/g, \"-\").replace(/[^a-z0-9-]/g, \"\");\n\n const symbolDef: SketchSymbolDef = {\n id,\n name,\n style,\n paths,\n viewBox,\n custom: true,\n };\n\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [id]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n success: true,\n symbol: symbolDef,\n tip: `Use drawSymbol(ctx, \"${id}\", x, y, width, height) to render this symbol in your algorithm.`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// fetch_symbol\n// ---------------------------------------------------------------------------\n\nexport const fetchSymbolTool: McpToolDefinition = {\n name: \"fetch_symbol\",\n description: \"Search Iconify for professional icons (275k+ from Phosphor, Lucide, Tabler, MDI, etc.) or embed one into a sketch. Two modes: (1) Search — provide query to get a list of iconifyIds; (2) Embed — provide iconifyId (e.g. 'ph:cat') to fetch SVG, parse paths, and embed as a SketchSymbolDef. Approved prefixes: ph, lucide, tabler, heroicons, bi, mdi, ri, carbon, fluent.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Keyword to search Iconify (e.g. 'cat', 'arrow left', 'sun'). Returns a list of iconifyIds — no SVG fetched yet.\" },\n iconifyId: { type: \"string\", description: \"Iconify icon ID to embed (e.g. 'ph:cat', 'lucide:arrow-left'). Fetches SVG, parses paths, embeds in sketch.\" },\n prefix: { type: \"string\", description: \"Limit search to a specific icon set (e.g. 'ph', 'lucide', 'tabler'). Ignored when using iconifyId.\" },\n limit: { type: \"number\", description: \"Maximum search results to return (default: 10)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const query = input[\"query\"] as string | undefined;\n const iconifyId = input[\"iconifyId\"] as string | undefined;\n\n // ---- Search mode ----\n if (query && !iconifyId) {\n const prefixes = input[\"prefix\"] ? [input[\"prefix\"] as string] : undefined;\n const results = await searchIconify(query, (input[\"limit\"] as number | undefined) ?? 10, prefixes);\n return textResult(JSON.stringify({\n mode: \"search\",\n results,\n tip: \"Call fetch_symbol with iconifyId to embed one of these icons into a sketch\",\n }));\n }\n\n // ---- Embed mode ----\n if (!iconifyId) {\n return errorResult(\n \"Provide either query (to search) or iconifyId (to embed). Approved prefixes: \" +\n Object.keys(SAFE_PREFIXES).join(\", \"),\n );\n }\n\n let iconData: Awaited<ReturnType<typeof fetchAndParseIcon>>;\n try {\n iconData = await fetchAndParseIcon(iconifyId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"not in the approved list\")) {\n return textResult(JSON.stringify({ warning: msg }));\n }\n return errorResult(msg);\n }\n\n const symbolId = iconData.iconifyId.replace(\":\", \"-\");\n\n const symbolDef: SketchSymbolDef = {\n id: symbolId,\n name: iconData.name,\n paths: iconData.paths,\n viewBox: iconData.viewBox,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n };\n\n // Embed into sketch\n const renderer = context.sketch.getRenderer();\n if (!JS_RENDERERS.has(renderer)) {\n return errorResult(\n `Symbols require a JS-based renderer. Renderer \"${renderer}\" does not support symbols.`,\n );\n }\n\n const existing = context.sketch.getSymbols();\n const newSymbols: Record<string, unknown> = { ...existing, [symbolId]: symbolDef };\n context.sketch.setSymbols(newSymbols);\n\n // Merge third-party notice\n const notice = ICONIFY_NOTICES[iconData.prefix];\n const existingNotices = context.sketch.getThirdParty();\n const alreadyPresent = existingNotices.some(\n (n: Record<string, unknown>) => (n as { name?: string }).name === notice?.name,\n );\n if (notice && !alreadyPresent) {\n context.sketch.setThirdParty([\n ...existingNotices as Record<string, unknown>[],\n notice as unknown as Record<string, unknown>,\n ]);\n }\n\n context.sketch.setGenartVersion(\"1.3\");\n context.emitChange(\"sketch-updated\");\n\n return textResult(JSON.stringify({\n mode: \"embedded\",\n symbolId,\n iconifyId: iconData.iconifyId,\n license: iconData.license,\n viewBox: iconData.viewBox,\n pathCount: iconData.paths.length,\n tip: `drawSymbol(ctx, \"${symbolId}\", x, y, width, height)`,\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// place_symbol\n// ---------------------------------------------------------------------------\n\nexport const placeSymbolTool: McpToolDefinition = {\n name: \"place_symbol\",\n description: \"Place a symbol as a design layer on the canvas. Creates a symbols:symbol layer with embedded SVG path data for visual composition.\",\n inputSchema: {\n type: \"object\",\n required: [\"symbolId\", \"viewBox\", \"paths\"],\n properties: {\n symbolId: { type: \"string\", description: \"Symbol ID (e.g. 'ph-cat')\" },\n iconifyId: { type: \"string\", description: \"Original Iconify ID (e.g. 'ph:cat')\" },\n viewBox: { type: \"string\", description: \"SVG viewBox (e.g. '0 0 256 256')\" },\n paths: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n d: { type: \"string\", description: \"SVG path d attribute\" },\n fill: { type: \"string\" },\n stroke: { type: \"string\" },\n strokeWidth: { type: \"number\" },\n role: { type: \"string\" },\n },\n required: [\"d\"],\n },\n description: \"Array of SVG path objects\",\n },\n x: { type: \"number\", description: \"X position (default: 0)\" },\n y: { type: \"number\", description: \"Y position (default: 0)\" },\n width: { type: \"number\", description: \"Layer width (default: 100)\" },\n height: { type: \"number\", description: \"Layer height (default: 100)\" },\n } as Record<string, JsonSchema>,\n },\n async handler(input: Record<string, unknown>, context: McpToolContext): Promise<McpToolResult> {\n const symbolId = input[\"symbolId\"] as string;\n const iconifyId = (input[\"iconifyId\"] as string | undefined) ?? \"\";\n const viewBox = input[\"viewBox\"] as string;\n const paths = input[\"paths\"] as SymbolPath[];\n const x = (input[\"x\"] as number | undefined) ?? 0;\n const y = (input[\"y\"] as number | undefined) ?? 0;\n const width = (input[\"width\"] as number | undefined) ?? 100;\n const height = (input[\"height\"] as number | undefined) ?? 100;\n\n const id = `symbol-${symbolId}-${Date.now()}`;\n context.layers.add({\n id,\n type: \"symbols:symbol\",\n name: symbolId,\n visible: true,\n locked: false,\n opacity: 1,\n blendMode: \"normal\",\n transform: {\n x, y, width, height,\n rotation: 0, scaleX: 1, scaleY: 1, anchorX: 0.5, anchorY: 0.5,\n },\n properties: {\n symbolId,\n iconifyId,\n viewBox,\n paths: JSON.stringify(paths),\n fillOverride: \"\",\n strokeOverride: \"\",\n preserveAspect: true,\n },\n } as Parameters<typeof context.layers.add>[0]);\n\n context.emitChange(\"layer-added\");\n\n return textResult(JSON.stringify({\n layerId: id,\n symbolId,\n position: { x, y },\n size: { width, height },\n }));\n },\n};\n\n// ---------------------------------------------------------------------------\n// Export all tools\n// ---------------------------------------------------------------------------\n\nexport const symbolMcpTools: McpToolDefinition[] = [\n searchSymbolsTool,\n listSymbolCategoriesTool,\n addSymbolTool,\n removeSymbolTool,\n createSymbolTool,\n fetchSymbolTool,\n placeSymbolTool,\n];\n","/**\n * Batch placement utilities for distributing symbols across a region.\n */\n\n/** Bounds rectangle for placement region. */\nexport interface PlacementBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** A single placement result. */\nexport interface Placement {\n x: number;\n y: number;\n rotation: number;\n scale: number;\n}\n\n/** Placement strategy: grid, random, or along-path. */\nexport type PlacementStrategy = \"grid\" | \"random\" | \"along-path\";\n\n/** Options for along-path strategy. */\nexport interface PathOptions {\n /** Path points to distribute along. */\n points: Array<{ x: number; y: number }>;\n}\n\n/**\n * Options for `generateBatchPlacements`.\n */\nexport interface BatchPlacementOptions {\n /** Minimum rotation in radians (default 0). */\n minRotation?: number;\n /** Maximum rotation in radians (default 0). */\n maxRotation?: number;\n /** Minimum scale factor (default 1). */\n minScale?: number;\n /** Maximum scale factor (default 1). */\n maxScale?: number;\n /** Seed for deterministic random placement (optional). */\n seed?: number;\n /** Path points for 'along-path' strategy. */\n pathPoints?: Array<{ x: number; y: number }>;\n}\n\n/**\n * Simple seeded PRNG (mulberry32).\n */\nfunction mulberry32(seed: number): () => number {\n let s = seed | 0;\n return () => {\n s = (s + 0x6d2b79f5) | 0;\n let t = Math.imul(s ^ (s >>> 15), 1 | s);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\n/**\n * Generate batch placements for a symbol using the given strategy.\n *\n * @param _symbolId - The symbol identifier (reserved for future per-symbol sizing)\n * @param count - Number of placements to generate\n * @param strategy - Placement strategy: 'grid', 'random', or 'along-path'\n * @param bounds - Bounding rectangle for placement\n * @param options - Additional options for rotation, scale, seed, path\n * @returns Array of Placement objects\n */\nexport function generateBatchPlacements(\n _symbolId: string,\n count: number,\n strategy: PlacementStrategy,\n bounds: PlacementBounds,\n options: BatchPlacementOptions = {},\n): Placement[] {\n if (count <= 0) return [];\n\n const {\n minRotation = 0,\n maxRotation = 0,\n minScale = 1,\n maxScale = 1,\n seed = 12345,\n pathPoints,\n } = options;\n\n const rng = mulberry32(seed);\n\n function randomRotation(): number {\n return lerp(minRotation, maxRotation, rng());\n }\n\n function randomScale(): number {\n return lerp(minScale, maxScale, rng());\n }\n\n switch (strategy) {\n case \"grid\":\n return generateGrid(count, bounds, randomRotation, randomScale);\n case \"random\":\n return generateRandom(count, bounds, rng, randomRotation, randomScale);\n case \"along-path\":\n return generateAlongPath(count, pathPoints ?? [], randomRotation, randomScale);\n default:\n throw new Error(`Unknown placement strategy: ${strategy}`);\n }\n}\n\nfunction generateGrid(\n count: number,\n bounds: PlacementBounds,\n rotation: () => number,\n scale: () => number,\n): Placement[] {\n // Compute grid dimensions that best fill the bounds\n const aspect = bounds.width / bounds.height;\n const cols = Math.max(1, Math.round(Math.sqrt(count * aspect)));\n const rows = Math.max(1, Math.ceil(count / cols));\n\n const cellW = bounds.width / cols;\n const cellH = bounds.height / rows;\n\n const placements: Placement[] = [];\n for (let i = 0; i < count; i++) {\n const col = i % cols;\n const row = Math.floor(i / cols);\n placements.push({\n x: bounds.x + cellW * (col + 0.5),\n y: bounds.y + cellH * (row + 0.5),\n rotation: rotation(),\n scale: scale(),\n });\n }\n return placements;\n}\n\nfunction generateRandom(\n count: number,\n bounds: PlacementBounds,\n rng: () => number,\n rotation: () => number,\n scale: () => number,\n): Placement[] {\n const placements: Placement[] = [];\n for (let i = 0; i < count; i++) {\n placements.push({\n x: bounds.x + rng() * bounds.width,\n y: bounds.y + rng() * bounds.height,\n rotation: rotation(),\n scale: scale(),\n });\n }\n return placements;\n}\n\nfunction generateAlongPath(\n count: number,\n points: Array<{ x: number; y: number }>,\n rotation: () => number,\n scale: () => number,\n): Placement[] {\n if (points.length === 0) return [];\n if (points.length === 1) {\n const p = points[0]!;\n return Array.from({ length: count }, () => ({\n x: p.x,\n y: p.y,\n rotation: rotation(),\n scale: scale(),\n }));\n }\n\n // Compute cumulative segment lengths\n const segLengths: number[] = [];\n let totalLength = 0;\n for (let i = 1; i < points.length; i++) {\n const dx = points[i]!.x - points[i - 1]!.x;\n const dy = points[i]!.y - points[i - 1]!.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n segLengths.push(len);\n totalLength += len;\n }\n\n if (totalLength === 0) {\n const p = points[0]!;\n return Array.from({ length: count }, () => ({\n x: p.x,\n y: p.y,\n rotation: rotation(),\n scale: scale(),\n }));\n }\n\n const placements: Placement[] = [];\n for (let i = 0; i < count; i++) {\n const t = count === 1 ? 0 : i / (count - 1);\n const targetDist = t * totalLength;\n\n // Find the segment\n let accumulated = 0;\n let segIdx = 0;\n for (segIdx = 0; segIdx < segLengths.length; segIdx++) {\n if (accumulated + segLengths[segIdx]! >= targetDist) break;\n accumulated += segLengths[segIdx]!;\n }\n segIdx = Math.min(segIdx, segLengths.length - 1);\n\n const segStart = points[segIdx]!;\n const segEnd = points[segIdx + 1] ?? segStart;\n const segLen = segLengths[segIdx] ?? 0;\n const localT = segLen > 0 ? (targetDist - accumulated) / segLen : 0;\n\n placements.push({\n x: segStart.x + (segEnd.x - segStart.x) * localT,\n y: segStart.y + (segEnd.y - segStart.y) * localT,\n rotation: rotation(),\n scale: scale(),\n });\n }\n\n return placements;\n}\n","import type { DesignPlugin, PluginContext } from \"@genart-dev/core\";\nimport { symbolLayerType } from \"./symbol-layer.js\";\nimport { symbolMcpTools } from \"./symbol-tools.js\";\n\nconst symbolsPlugin: DesignPlugin = {\n id: \"symbols\",\n name: \"Symbols & Icons\",\n version: \"0.2.0\",\n tier: \"free\",\n description:\n \"Vector symbol library with Iconify integration. Search, fetch, and place symbols on the design canvas or embed in algorithms.\",\n layerTypes: [symbolLayerType],\n tools: [],\n exportHandlers: [],\n mcpTools: symbolMcpTools,\n async initialize(_context: PluginContext): Promise<void> {},\n dispose(): void {},\n};\n\nexport default symbolsPlugin;\nexport { symbolsPlugin };\nexport { symbolLayerType };\nexport { symbolMcpTools };\nexport {\n generateBatchPlacements,\n type PlacementBounds,\n type Placement,\n type PlacementStrategy,\n type BatchPlacementOptions,\n} from \"./batch-placement.js\";\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genart-dev/plugin-symbols",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Vector symbol library plugin for genart.dev — design layer rendering, Iconify integration, and symbol management tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -53,12 +53,10 @@
53
53
  "prepublishOnly": "npm run build"
54
54
  },
55
55
  "dependencies": {
56
- "@genart-dev/core": "^0.3.0",
56
+ "@genart-dev/core": "^0.11.0",
57
57
  "@genart-dev/symbols": "^0.1.0"
58
58
  },
59
59
  "devDependencies": {
60
- "canvas": "^3.2.1",
61
- "path2d": "^0.3.1",
62
60
  "tsup": "^8.3.6",
63
61
  "typescript": "^5.7.3",
64
62
  "vitest": "^3.0.5"