Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## Unreleased

### 🚀 Features

- **Agent and MCP clients build designs block by block**: the design guide now says what each block is for, asks for text blocks for the copy and one HTML block per component, and gives proven layouts with an example plan. HTML blocks must declare their colors, sizes, radius, shadow, icon and show/hide flags as annotated `:root` variables, with a worked example; `add_block` and `update_html_block` answer with hints when a block misses them or grows into a whole section

### 🐛 Fixes

- The Linux release failed while uploading the snap to the Snap Store (snapcraft renamed `push` to `upload`); the snap now goes to the GitHub release with the other packages

## v 2.0.0 - Release (September 27th, 2026)

### 🚀 Features
Expand Down
9 changes: 9 additions & 0 deletions docs/agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ the Agent system prompt and of the MCP server instructions, and
`get_design_guide` returns it for clients that ignore server instructions.
Change the guide there; the prompt, the instructions and the tool follow.

The guide asks models to build a design block by block: the background with
`set_canvas_background`, every headline and paragraph as a text block, and one
HTML block per component (a stat tile, a card, a badge row, a chart), sized to
its content and declaring its colors, sizes, radius, shadow and icon as
annotated `:root` variables. `add_block` and `update_html_block` check the
last two rules (`src/lib/agent/tools/html-hints.ts`) and answer with `hints`
when an HTML block declares no variables, covers most of the canvas or holds
paragraphs of text, so the model fixes it in the same turn.

### Brand kit

File → **Brand kit…** (or the command palette) holds the colors, fonts,
Expand Down
7 changes: 7 additions & 0 deletions docs/html-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ document.getElementById('myForm').reset();
--show-shadow: true;
}

/* A boolean is read with a style query, no JavaScript needed */
@container style(--show-shadow: false) {
.card {
box-shadow: none;
}
}

.card {
background: var(--card-bg);
border: 2px solid var(--card-border);
Expand Down
9 changes: 9 additions & 0 deletions electron-builder.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@
"icon": "./src-electron/assets/icon.png",
"category": "Graphics"
},
"snap": {
"publish": [
{
"provider": "github",
"protocol": "https",
"releaseType": "release"
}
]
},
"nsis": {
"oneClick": false,
"perMachine": false,
Expand Down
76 changes: 62 additions & 14 deletions src/lib/agent/core/design-guide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,32 @@ Set the size before adding blocks (create_workspace or set_canvas_size). When th
- Slide or desktop showcase: 1920×1080
No platform given: 1080×1350 for a post, 1600×900 for a code snippet or product screenshot.

## Build it block by block
An image is a stack of separate blocks, never one big block. Plan it, then add it one piece at a time:
1. Background: set_canvas_background (color, gradient, texture, image or dynamic). Never an HTML block that fills the canvas.
2. The hero: the one thing people look at first (a mockup, a big number, a code window, a headline).
3. Headline and supporting text: text blocks, one per line of meaning (eyebrow, headline, subtitle, caption).
4. Supporting pieces: one block each, a component, a logo, an icon, a badge row.
5. Look (get_canvas_snapshot), then fix spacing and alignment.
One add_block call per piece, from the back to the front, each placed at its own x, y, width and height on the grid. When the user asks for "a post with X and Y", that is several blocks, not one HTML block containing X and Y.

## What each block is for
- Text (\`text\`): every headline, subtitle, paragraph, label and call to action. The user edits it on the canvas and changes its font; set fontFamily and fontSource, textSize, fontWeight, color, lineHeight, letterSpacing and textAlign. Use width with sizing "fixed-width" for text that wraps.
- Code (\`code\`): source code in a window, highlighted. Mockups (\`window\` browser or app window, \`phone_mockup\`): screenshots and app screens.
- Image (\`image\`): photos, screenshots, logos (the brand logo with add_brand_logo). Icon (\`icon\`): a single icon, find its name with search_icons.
- Shape (\`shape\`): rectangles, pills, circles, lines, arrows, stars and dividers, with solid or gradient fill and a stroke. Prefer a shape over an HTML block for simple geometry. Drawing (\`drawing\`): a hand-drawn stroke or underline. QR (\`qr\`): links people should scan.
- HTML (\`html\`): one self-contained component that the other blocks cannot draw: a stat or KPI tile, a card, a row of badges, a checklist, a pricing card, a testimonial, a chart in inline SVG, a progress ring, a timeline, a table, a small UI screen.
- Components (add_component): ready-made HTML components from the user's library; use one when it fits instead of writing your own.

## Layout
- One focal point. Decide what must be read first and make it the largest, highest-contrast element.
- Margins of at least 6% of the short side on every edge (64 px on a 1080 canvas, 96 px on 1600×900). Backgrounds bleed; content never touches the edge.
- Work on an 8 px grid: positions, sizes and gaps in multiples of 8, with a small set of gaps (16, 24, 32, 48, 64).
- Align to few shared edges: one left edge, or one centered axis. Use align_blocks and distribute_blocks instead of eyeballing.
- Keep 30–40% of the canvas empty. Fewer, larger elements beat many small ones.
- Group related items; separate groups with at least twice the gap used inside a group.
- Proven layouts: a left-aligned stack (eyebrow, headline, subtitle, then the hero below); a split (text on one half, the mockup on the other, both vertically centered); a centered hero (big number or headline in the middle, one line under it); a grid of 2–4 equal cards with the same gap on every side.
- Example plan for 1080×1350 (margins 80): eyebrow text at y 120; headline at y 168, width 920; subtitle 32 px under it; the hero from y 560 to 1150 across 920 px; a footer line (logo or handle) at y 1206.

## Typography
- At most 2 typefaces (one for headlines, one for text) and 3 sizes.
Expand All @@ -39,23 +58,49 @@ No platform given: 1080×1350 for a post, 1600×900 for a code snippet or produc
- Gradients between neighbouring hues (under ~60° apart) or two shades of one hue; no rainbows. A little noise (3–6) adds depth to flat gradients.
- Dark designs: background #0b0d12–#17191f rather than pure black, text #f5f5f7, muted #9aa3b2. Light designs: #f7f7f8 background, #111318 text.
- Spend the accent only on what matters: a keyword, a number, a call to action.
- Use the same colors in every block: the text blocks, the shapes and the :root variables of the HTML blocks share one palette.

## Depth and finish
- One family of corner radii (e.g. 12/20/28) and soft shadows: large blur, low opacity, a downward offset. No hard black shadows.
- Mockups (code, window, phone) are the hero: 60–80% of the canvas width, on the grid, with a soft shadow.
- Code shots: at most ~15 lines and ~60 columns of real, correct code, a meaningful window title, a theme that contrasts with the background.

## HTML blocks — for everything native blocks do not do well
Use an \`html\` block for composed UI: stat and KPI tiles, feature cards and grids, pills and badges, checklists and icon lists, pricing cards, testimonials and fake posts, charts as inline SVG, progress bars and rings, timelines, comparison tables, app screens, wordmarks, decorative backgrounds (SVG patterns, blobs, grids).
- Self-contained HTML and CSS. No JavaScript unless something has to be computed: scripts are off by default and the design must look finished without them.
- The root element fills the block (\`width: 100%; height: 100%\`, the block is a flex container). Give the block the size of its content with the width and height of add_block.
- Put every value a user may tweak in one \`:root { }\` block, annotated so the properties panel shows controls:
\`/* @type:color */ --accent: #f43f5e;\` · \`/* @type:number min:0 max:64 step:1 unit:px */ --radius: 24px;\` · \`/* @type:shadow */ --shadow: #00000040 0px 24px 48px 0px;\` · \`/* @type:boolean */ --show-badge: true;\`
Colors in hex, shadows with 8-digit hex, numbers with px, %, em or rem. No nested braces inside \`:root\`.
- Icons: put the icon in a \`/* @type:icon */ --my-icon: FaRocket;\` variable so the user can swap it from the panel (Font Awesome names, or \`<prefix>:<name>\` from an installed icon pack; find them with search_icons) and draw it with \`<span class="k-icon" style="--k-icon: var(--my-icon)"></span>\`, which takes the text color. Shapes no icon set has: inline SVG with \`fill="currentColor"\`.
- Fonts: write the Google font name in font-family; the app loads it.
- No @keyframes or animations (an export is a single frame), no remote images unless the user gave the URL; prefer CSS gradients and inline SVG.
- Keep text as text so it stays editable, and keep it inside the block (no overflow).
## HTML blocks: one component each, with editable variables
Every HTML block follows this contract:
- One component, sized to its content with the width and height of add_block (a stat tile is about 400×220, not the canvas). Its root element fills the block: \`width: 100%; height: 100%; box-sizing: border-box\`.
- Short labels only; headlines and paragraphs are text blocks next to it. Text that changes from post to post uses a project variable: \`{{title}}\` in the HTML.
- **Declare what the user may tweak.** Start the CSS with one \`:root { }\` block listing every color, size, radius, shadow, icon and show/hide flag of the component as an annotated variable, then use only var(--…) for those values below it. Each annotation becomes a control in the properties panel:
- \`/* @type:color */ --accent: #f43f5e;\` (hex, 6 or 8 digits)
- \`/* @type:number min:0 max:48 step:1 unit:px */ --radius: 24px;\` (with px, %, em or rem)
- \`/* @type:shadow */ --shadow: #00000040 0px 24px 48px 0px;\` (8-digit hex color, then x y blur spread)
- \`/* @type:icon */ --icon: FaRocket;\` (drawn with \`<span class="k-icon" style="--k-icon: var(--icon)"></span>\`, which takes the text color; names from search_icons)
- \`/* @type:boolean */ --show-badge: true;\` (hide with \`@container style(--show-badge: false) { .badge { display: none } }\`)
One annotation per variable, on the line above it; no nested braces inside \`:root\`. Aim for 4–8 variables.
- Self-contained HTML and CSS, no JavaScript (scripts are off by default). No @keyframes (an export is one frame), no remote images unless the user gave the URL; draw with CSS gradients and inline SVG (\`fill="currentColor"\`).
- Fonts: write the Google font name in font-family; the app loads it. Use the same fonts as the text blocks.
- Keep everything inside the block (no overflow, no negative margins past its edge).

Example: a stat tile, added with add_block { type: "html", x: 80, y: 840, width: 440, height: 240, properties: { html, css } }
html: \`<div class="tile"><span class="k-icon icon" style="--k-icon: var(--icon)"></span><p class="value">128k</p><p class="label">monthly users</p></div>\`
css:
\`\`\`
:root {
/* @type:color */ --bg: #16161a;
/* @type:color */ --text: #f5f5f7;
/* @type:color */ --accent: #fb7185;
/* @type:number min:0 max:48 step:1 unit:px */ --radius: 28px;
/* @type:number min:40 max:120 step:1 unit:px */ --value-size: 88px;
/* @type:shadow */ --shadow: #00000059 0px 24px 48px 0px;
/* @type:icon */ --icon: FaUsers;
/* @type:boolean */ --show-icon: true;
}
.tile { width: 100%; height: 100%; box-sizing: border-box; padding: 32px; display: flex; flex-direction: column; justify-content: center; gap: 8px; background: var(--bg); color: var(--text); border-radius: var(--radius); box-shadow: var(--shadow); font-family: Inter, sans-serif; }
.icon { color: var(--accent); font-size: 36px; }
@container style(--show-icon: false) { .icon { display: none; } }
.value { margin: 0; font-size: var(--value-size); font-weight: 800; line-height: 1; }
.label { margin: 0; font-size: 28px; opacity: .7; }
\`\`\`
add_block and update_html_block answer with hints when a block misses its variables or grows into a whole section; fix them before moving on.

## Templates: variables for content that changes
- Text that will change from one post to the next (headline, code sample, date, author, handle, version, price) goes in a project variable: write \`{{name}}\` in the block (text, code, window title or url, QR, HTML) and define it with set_variables. The next post is then one set_variables call instead of a redesign.
Expand All @@ -65,11 +110,14 @@ Use an \`html\` block for composed UI: stat and KPI tiles, feature cards and gri
## Workflow
1. Read the brand kit with get_brand_kit. When it has colors, fonts, logos or guidelines, they come first: use them instead of the palettes and fonts suggested here, and place the logo with add_brand_logo when the design calls for one.
2. Understand the goal: platform, message, audience. Choose the size, palette and fonts before adding blocks.
3. Build from the back: background, hero element, headline, supporting elements.
4. Look at the result with get_canvas_snapshot when it is available and check it against the list below. Fix what fails and look again, at most twice.
5. Summarize in a sentence or two.
3. Plan the blocks: list each piece with its type and its box (x, y, width, height) on the grid, using one of the layouts above.
4. Build it step by step, one add_block per piece, from the back: background, hero, headline and text, supporting pieces.
5. Look at the result with get_canvas_snapshot when it is available and check it against the list below. Fix what fails with update_block, align_blocks or distribute_blocks, and look again, at most twice.
6. Summarize in a sentence or two.

## Checklist before finishing
- The image is several blocks: background, text blocks for the copy, one block per component. No HTML block covers most of the canvas.
- Every HTML block declares its colors, sizes, radius, shadow and icon as annotated :root variables.
- Nothing touches or crosses the canvas edge by accident; margins are respected.
- Text is readable on a phone (over 24 px on a 1080 px canvas) and passes contrast.
- At most 2 fonts and 3 text sizes; edges line up.
Expand Down
4 changes: 2 additions & 2 deletions src/lib/agent/core/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ How to work:
- Before a new design, read the brand kit (get_brand_kit) and follow it: its colors, fonts, logos (add_brand_logo) and guidelines.
- Call get_workspace before editing an existing design, and use the block ids it returns. Coordinates are canvas pixels from the top-left corner.
- Call list_block_types when you need the properties of a block type.
- Prefer a few precise tool calls over many small ones. Update several properties of a block in one update_block call.
- Reach for an html block whenever a native block cannot express the design well (cards, stat tiles, badges, lists with icons, charts, testimonials, UI screens, decorative backgrounds). Follow the HTML block rules below.
- Build every design block by block, step by step: plan the pieces, then one add_block per piece (background, hero, each text, each component), never the whole image or a whole section in one HTML block. Update several properties of one block in a single update_block call.
- Headlines and paragraphs are text blocks. An html block is one component the native blocks cannot draw (a stat tile, a card, a badge row, a chart), sized to its content, and it always declares its colors, sizes, radius, shadow and icon as annotated :root variables so the user can adjust it. Follow the HTML block rules below; add_block and update_html_block answer with hints when a block breaks them.
- The component library (list_components) holds ready-made HTML components; add_component puts one on the canvas.
- When you add a code block, put the code in its \`code\` property as plain text and set \`lang\` and a fitting \`wintitle\`.
- Text blocks take a font: set \`fontFamily\` to a family the machine has or to a Google font, with \`fontSource\` as \`system\` or \`google\`, plus alignment, weight, line height, letter spacing, an outline and a shadow of the letters.
Expand Down
4 changes: 2 additions & 2 deletions src/lib/agent/mcp/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export const MCP_INSTRUCTIONS = `Karbonized is an editor for social media graphi

- Call get_workspace before editing an existing design and use the block ids it returns. Coordinates are canvas pixels from the top-left.
- Read the user's brand kit with get_brand_kit before a new design and use its colors, fonts and logos (add_brand_logo).
- For a new design, set the canvas size first (create_workspace or set_canvas_size), then the background, then blocks.
- Use html blocks (HTML + CSS) for anything native blocks cannot express: cards, stat tiles, badges, icon lists, charts, testimonials, UI screens.
- For a new design, set the canvas size first (create_workspace or set_canvas_size), then the background, then build it block by block: one add_block per piece (hero, each text, each component), never the whole image in one HTML block.
- Headlines and paragraphs are text blocks. Use an html block for one component native blocks cannot draw (a stat tile, a card, a badge row, a chart), sized to its content, and declare its colors, sizes, radius, shadow and icon as annotated :root variables (see the HTML block rules below). add_block and update_html_block answer with hints when a block breaks these rules.
- Find icon names with search_icons; never guess them. Icon packs (.kcomponent files with type: icon-pack) add icons named <prefix>:<name>.
- Check the result with get_canvas_snapshot and fix what fails the checklist below.
- Designs can be templates: get_workspace lists project variables, and blocks show {{name}} as their value. To make a new version, change the values with set_variables instead of editing blocks.
Expand Down
Loading
Loading