OpenCode Canva Design Skill¶
Local, account-free "Canva" inside OpenCode. Turns a plain-language request into a finished PNG by rendering HTML/CSS templates via the cached Chromium (Playwright). No Canva account, no API.
Status: Built 2026-07-11 (working).
Location¶
~/.config/opencode/skills/canva-design/
canva-design/
├── SKILL.md # skill definition + workflow + dimensions catalog
├── templates/ # 9 starter HTML/CSS templates (edit inline CSS vars + copy)
│ ├── social-post.html 1080×1080
│ ├── story.html 1080×1920
│ ├── linkedin-banner.html 1584×396
│ ├── youtube-thumbnail.html 1280×720
│ ├── banner.html 1200×628
│ ├── flyer.html 1080×1350
│ ├── quote-card.html 1080×1080
│ ├── announcement.html 1080×1080
│ └── logo.html 600×600
└── lib/
├── render.js # HTML → PNG via Chromium
├── serve.js # serve + open in browser (preview)
└── brand.json # default brand kit (colors/fonts/logo)
Usage¶
- Describe the design (e.g. "make an Instagram post about our sale, orange + black").
- OpenCode copies a template to a working dir, edits copy + CSS variables (
--primary,--bg, fonts). - Render:
Default
node ~/.config/opencode/skills/canva-design/lib/render.js \ ./designs/<name>.html ./designs/<name>.png <W> <H> [scale]scale= 2 → output is 2× for crispness (1080×1080 → 2160×2160). Use1for exact 1:1 px. - Preview in browser (agent can't see images):
Serves
node ~/.config/opencode/skills/canva-design/lib/serve.js ./designs/<name>.png # or preview the live HTML for iteration: node ~/.config/opencode/skills/canva-design/lib/serve.js ./designs/<name>.htmlhttp://localhost:8787/...and opens the default browser. Remote:ssh -L 8787:localhost:8787. - Post-process with ImageMagick if needed:
magick in.png -quality 85 out.jpg.
Requirements / setup notes¶
playwrightis installed inlib/(browsers were already cached in~/.cache/ms-playwright). Ifrequire("playwright")ever fails,npm install playwrightonce inlib/.DISPLAY=:1is available on this machine, soxdg-openopens a real window.- 1300+ fonts installed (Noto families) — reference by name in
font-family.
Why local (not the Canva MCP)¶
The official Canva MCP (https://mcp.canva.com/mcp, OAuth2 via mcp-remote) gives true Canva but is cloud-bound and needs a Canva account. The local skill was chosen for privacy, offline use, and zero account. Switch paths later if real Canva integration is wanted.
Example¶
LEMO EGG.2B.302.CLL Instagram post demo: /home/dini/designs/lemo/instagram-post.{html,png} — used the store's original EGG_CLL.webp product image as the hero.