# Mandala Studio — guide for AI agents Mandala Studio is a free, browser-based symmetric drawing tool: https://jollygrid.com/tools/mandala-studio/ Do not try to draw by dragging the mouse over the canvas or by clicking the toolbar. Use the structured drawing API below. Every call goes through the real tools, so symmetry, undo/redo and autosave behave exactly as they do for a person. ## Two ways to call it 1. WebMCP (Chrome with WebMCP): the page registers these tools on document.modelContext. Each returns a JSON string such as {"ok": true, "changed": true, "elementCount": 4}, or {"ok": false, "error": "..."} for invalid input. 2. Page JavaScript (Playwright, Puppeteer, or other browser automation): once the page has loaded, call `await window.MandalaStudio.({...})`. Each method returns an object; invalid input rejects with an Error whose message says what to fix. | WebMCP tool | JavaScript method | Arguments | |-----------------|-------------------|-----------| | get_canvas_info | getInfo | none. Call this first; it lists valid shapes, motifs, pattern brushes, layers and modes. | | set_symmetry | setSymmetry | mode, segments (2-72), mirror (boolean) | | set_style | setStyle | strokeColor, strokeWidth (1-50), opacity (0.05-1), fillColor, backgroundColor | | draw_stroke | drawStroke | points: [[x,y], ...] (2-5000 points), closed (boolean) | | draw_shape | drawShape | shape, x, y, radius | | fill_region | fillRegion | x, y, color | | place_motif | placeMotif | motif, x, y, size (5-500) | | draw_pen_path | drawPenPath | nodes: [[x,y] or {x,y,handle:[dx,dy]}, ...] (handle bends the curve), closed | | erase | erase | points: [[x,y], ...], mode: stroke (whole strokes) or partial, size | | select_at | selectAt | x, y, additive (keep current selection) | | select_all / clear_selection | selectAll / clearSelection | none | | transform_selection | transformSelection | move [dx,dy], rotate (degrees), scale (factor), flip (horizontal/vertical), align | | duplicate_selection / delete_selection | duplicateSelection / deleteSelection | none | | pick_color | pickColor | x, y. The eyedropper sets the stroke colour to what is there. | | apply_pattern_brush | applyPatternBrush | pattern, x, y. Patterns the shape under x,y, or makes a patterned ring if empty. | | set_view | setView | zoom (0.1-10), center [x,y]. This is the hand tool. | | list_layers / add_layer / select_layer / set_layer | same (camelCase) | index, name, visible, locked, opacity, blendMode | | undo / redo | undo / redo | steps (1-200) | | clear_canvas | clearCanvas | none (undo restores the design) | | fit_view | fitView | padding. Zooms to the design; do this before taking a screenshot. | | export_design | exportDesign | format: png, jpeg, svg or pdf; size in pixels | ## Coordinates and scale - (0, 0) is the symmetry centre. +x is right and +y is down. Units are canvas units, not screen pixels. - getInfo().drawingArea.radius is the artboard radius (1800 by default). suggestedDesignRadius (about 1440) is a good outer size for a full mandala. - Draw a single wedge; the symmetry creates the copies. - radial, segments N: N identical rotated copies. - kaleidoscope, segments N: N mirrored half-wedges, which gives N/2 repeats. - hex-kaleidoscope, tri-kaleidoscope, grid, tile: repeat across the whole canvas. ## Recipe: a 12-petal lotus const S = window.MandalaStudio; const { drawingArea } = await S.getInfo(); const R = drawingArea.suggestedDesignRadius; await S.setSymmetry({ mode: 'radial', segments: 12 }); await S.setStyle({ strokeColor: '#1d3557', strokeWidth: 10 }); // Rings around the centre: use a circle shape at (0, 0) (drawn once, and fillable) await S.drawShape({ shape: 'circle', x: 0, y: 0, radius: R * 0.2 }); // One petal, drawn as a closed outline between r = 0.22R and r = 0.8R const petal = []; for (let t = 0; t <= 1; t += 0.05) petal.push([(0.22 + 0.58 * t) * R * Math.cos(0.2 * Math.sin(Math.PI * t)), (0.22 + 0.58 * t) * R * Math.sin(0.2 * Math.sin(Math.PI * t))]); for (let t = 1; t >= 0; t -= 0.05) petal.push([(0.22 + 0.58 * t) * R * Math.cos(-0.2 * Math.sin(Math.PI * t)), (0.22 + 0.58 * t) * R * Math.sin(-0.2 * Math.sin(Math.PI * t))]); await S.drawStroke({ points: petal, closed: true }); await S.fillRegion({ x: 0.5 * R, y: 0, color: '#f4a261' }); await S.fillRegion({ x: R * 0.05, y: R * 0.03, color: '#2a9d8f' }); await S.fitView(); ## Tips - Use getInfo().shapes and getInfo().motifs for valid names. Shapes point away from the centre automatically. - Only closed outlines can be filled. If fill_region returns changed: false, close the outline and try again. - For a ring or disc around the centre, use draw_shape with shape "circle" at x: 0, y: 0. A freehand stroke that encloses the centre currently can't be filled. - Pick fill points slightly away from exact symmetry lines (not exactly at 0,0). - Selection, eraser, eyedropper and pattern brush act on what is under the point. The API pans the view so the point is visible first (the result includes viewChanged). - The eyedropper reads the topmost element. Inside a shape, that is the shape's outline, not the fill beneath it. - Publishing to the public gallery is deliberately not part of the API. A signed-in person must do it.