Skip to content

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

  1. Describe the design (e.g. "make an Instagram post about our sale, orange + black").
  2. OpenCode copies a template to a working dir, edits copy + CSS variables (--primary, --bg, fonts).
  3. Render:
    node ~/.config/opencode/skills/canva-design/lib/render.js \
      ./designs/<name>.html ./designs/<name>.png <W> <H> [scale]
    
    Default scale = 2 → output is 2× for crispness (1080×1080 → 2160×2160). Use 1 for exact 1:1 px.
  4. Preview in browser (agent can't see images):
    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>.html
    
    Serves http://localhost:8787/... and opens the default browser. Remote: ssh -L 8787:localhost:8787.
  5. Post-process with ImageMagick if needed: magick in.png -quality 85 out.jpg.

Requirements / setup notes

  • playwright is installed in lib/ (browsers were already cached in ~/.cache/ms-playwright). If require("playwright") ever fails, npm install playwright once in lib/.
  • DISPLAY=:1 is available on this machine, so xdg-open opens 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.