Install
$ agentstack add skill-mrstev3n-balise-skills-balise-affinity-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Affinity MCP Automation
Use the Affinity MCP as a live application-control surface. Work from the open document, inspect before editing, prefer small reversible commands, and verify visual results.
Standard Workflow
- Load Affinity tools if they are not already present.
- Read SDK documentation in this order:
- Always read
preamblefirst. - Call
list_sdk_documentation. - Read only the topics needed for the task, such as
application.js,document.js,nodes.js,commands.js,geometry.js,colours.js,fills.js,linestyle.js,storybuilder.js,glyphatts.js,paragraphatts.js, orexportconfig.js.
- Inspect the current document before making changes.
- Choose the narrowest edit: selected object first, current spread next, whole document only when requested.
- Execute scripts with the Affinity MCP
execute_scriptcapability; a harness may expose a qualified tool name. Useconsole.log(JSON.stringify(...))for observable output. - Verify with
render_selection(document_session_uuid)whenever the result is visual. - Do not save, export, flatten, delete broad selections, or resize the spread unless the user asked for that kind of change.
Document Inspection
Use this baseline probe before editing:
const {Document} = require('/document');
const doc = Document.current;
if (!doc) {
console.log(JSON.stringify({ok: false, reason: 'NO_CURRENT_DOCUMENT'}));
} else {
console.log(JSON.stringify({
ok: true,
title: doc.title,
path: doc.path,
sessionUuid: doc.sessionUuid,
isReadOnly: doc.isReadOnly,
isDirty: doc.isDirty,
needsSaving: doc.needsSaving,
pageCount: doc.pageCount,
spreadCount: doc.spreadCount,
selectedCount: doc.selection.nodes.length,
currentSpreadBox: doc.currentSpread.baseBox
}, null, 2));
}
Stop cleanly if Document.current is null or doc.isReadOnly is true.
Object Operations
Use node operations for visible document objects:
doc.selectionreturns the current selection.doc.selection.nodesgives selected nodes.node.userDescription = '...'is useful for naming automation-created objects.doc.selectAll(false)selects all document objects; use it deliberately because it changes selection.doc.deleteSelection(selection)deletes selected objects; only use when the user wants replacement or cleanup.doc.setVisible(visible, selection),doc.lockSelection(selection), anddoc.unlockSelection(selection)operate through document commands.- For new nodes,
doc.addNode(def, doc.currentSpread)adds to the current spread and selects the new object.
Use descriptions and final selection intentionally so the user can inspect or undo the right thing.
Geometry And Appearance
For basic shapes:
- Create a
ShapeNodeDefinition. - Set a shape, such as
ShapeRectangle.create()orShapeEllipse.create(). - Set the bounding rectangle.
- Add it to the current spread.
- Apply fill and stroke to the resulting selection.
For exact freeform shapes:
- Build a closed path with
CurveBuilder. - Add it to a
PolyCurve. - Put it into
PolyCurveNodeDefinition. - Add it to the document.
For appearance:
- Use
RGBA8(r,g,b,a)from/colours. - Use
FillDescriptor.createSolid(colour)for brush or pen fill. - Use
FillDescriptor.createNone()to remove fill or stroke. - Use
/linestyleanddoc.setLineStyleDescriptor(...)when stroke weight, caps, joins, or alignment matter.
Read references/affinity-js-patterns.md for tested snippets. Read references/affinity-concepts-and-nuances.md when the task requires choosing between Affinity object types, text modes, non-destructive techniques, or verification methods.
Text Operations
Do not assume text node defaults exist. In current SDK usage, these fail:
FrameTextNodeDefinition.createDefault()ArtTextNodeDefinition.createDefault()TextNodeDefinition.createDefault()
Use StoryBuilder plus FrameTextNodeDefinition.createFromStoryBuilder(frameBox, storyBuilder) or ArtTextNodeDefinition.createFromStoryBuilder(point, storyBuilder):
- Set defaults with
sb.setToFrameTextDefaultStyle(doc.dpi, doc.format). - For Artistic Text, set defaults with
sb.setToArtisticTextDefaultStyle(doc.dpi, doc.format). - Configure
sb.glyphAttsfor font, height, fill, and optional spacing. - Configure
sb.paragraphAttsfor alignment and explicit leading. - Add text line by line.
- Use generous frame bounds, then render-check for clipping.
- Treat
glyph.characterSpacingas an em-like value. Use small values such as-0.02,0, or0.03; values like-1or-4can collapse glyph advance and make characters appear stacked.
For existing selected text, read commands.js and storydelta.js before applying formatting commands such as doc.formatText(...).
Artistic Text vs Frame Text
Choose the text object type intentionally:
- Use Artistic Text for short display text, labels, numerals, titles, and poster-like fragments where the text box should hug the text content.
- Use Frame Text for paragraphs, fixed-width copy blocks, multi-line text areas, and text that needs a deliberately sized container.
- Frame Text has a container frame in the editing UI. That frame can be visually distracting while designing, but it is not part of the artwork/export unless an actual stroke/fill/decoration has been applied.
- For rotated labels, create Artistic Text first, retrieve the created node, rotate it with
DocumentCommand.createTransform(...), then measurenode.spreadVisibleBoxand translate it into place. - If a user complains about boxes around all text, first check whether objects are selected and render the spread. If
render_spreadshows no boxes, explain that the boxes are UI overlays/text containers, not exported artwork. - For visual verification of the full composition, prefer
render_spreadoverdoc.selectAll(false)plusrender_selection, because selecting all objects can make UI selection boxes look like a design problem in the live app.
Document Features
Prefer documented command helpers over ad hoc state mutation:
- Guides:
DocumentCommand.createAddGuide(...). - Document/spread sizing:
doc.setSpreadSizeWithAnchor(...); remember this can affect layout. - History:
doc.undo(),doc.redo(),doc.undoDescription,doc.redoDescription. - Export: read
document.jsandexportconfig.js; useFileExportOptionsandFileExportAreaintentionally. - AI or image features: read
commands.jsfirst. Commands such as generate image, remove background, select subject, and generative edit may be restricted by Affinity settings; reportNOT_ALLOWEDclearly.
Verification And Reporting
After a meaningful operation, report:
- What changed.
- Whether the current document is dirty or needs saving.
- Whether the result was visually verified.
- Any known limitation, such as text clipping risk, missing selection, restricted feature, or unsaved file.
Use render_selection for visual checks. If the task modifies a single object, leave that object selected; if it rebuilds a composition, select all relevant objects before rendering.
For whole-layout verification, use render_spread when available. This is the best default for checking whether a composition itself is clean, because selecting everything can introduce UI overlays that are not part of exported artwork.
Learning Loop
When a new Affinity SDK lesson is discovered:
- Confirm it with a small script or visual check.
- If the MCP exposes
add_sdk_hint, add a concise entry for future sessions. - Update this skill only when the lesson is general enough to apply beyond the immediate artifact.
Keep this skill about manipulation of Affinity objects and features. Treat poster or layout recreation as one application of those primitives, not as the center of the skill.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mrstev3n
- Source: mrstev3n/balise-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.