---
pr: 134
title: feat(draw-image): SVG template renderer for on-brand covers
---

## Что сделано
Реализован плагин `draw-image` для генерации on-brand обложек (covers) в стиле slaid098.dev. Структура:
- `.opencode/tools/draw-image.ts` — opencode plugin (spawnSync → cli.ts)
- `.opencode/draw-image/` — render-движок: render.mjs (sharp → PNG), cli.ts, src/ (config/slot-parser/fit/recolor/resolve/render), templates/cover.svg, brand.json, fonts/ (Geist TTF), icons/lucide/ (2007 иконок), brand-logos/ (пусто v1)
- Слот-система: HTML-комментарии в SVG → SlotSpec (name/x/y/w/h/fit/recolor/bg/border/radius)
- Lucide-иконки: npm-пакет lucide-static, postinstall sync в icons/lucide/, recolor stroke → accent
- Шрифты: Geist Sans TTF bundled, переданы в sharp через fontFiles
- Идемпотентность: cover.meta.json с sha256(brand+template+args)
- Тесты: 48 vitest (unit + integration + e2e) + 5 pytest (tool wrapper via _ts_loader.mjs)
- CI: npm ci + npm test в .opencode/draw-image добавлены в test job
- dependabot.yml: битый `/config` → `/.opencode` + `/.opencode/draw-image`
- docs/project-map/README.md обновлён

## Почему
В продуктовых репо slaid098 нет ни одного cover-ассета — обложки рисовались вручную или отсутствовали. Утилита обеспечивает always on-brand генерацию: цвета захардкожены в шаблоне, Geist TTF bundled, Lucide line-icons recolor в accent. Эталон — covers из slaid098-dev/src/apps/.

## Pending
—

## Watch out
- `import.meta.dir` в draw-image.ts (не `import.meta.url`) — _ts_loader.mjs заменяет только `.dir`
- CLI использует `--experimental-strip-types` (Node 22+) для запуска .ts напрямую
- lucide-static postinstall копирует 2007 SVG в icons/lucide/ (committим только mic/play, остальные через npm)
- sharp fontFiles требует Geist TTF в fonts/ (committим Regular + Bold)