mcpField
N
nakkas

nakkas

本地服务
github.com/arikusi媒体与设计3015 周前更新

关于 nakkas

nakkas 是一个 MCP 服务,让 AI 助手根据声明式 JSON 配置生成动画 SVG,适用于 logo、图标、加载动画、README 横幅和徽章等场景。它只使用 CSS @keyframes 与 SMIL,不含 JavaScript,并在每次渲染后返回 PNG 预览,便于 AI 迭代修改。

主要功能

  1. 01由 JSON 配置渲染动画 SVG
  2. 02每次渲染返回 PNG 预览
  3. 03SVG 以 artifact id 保存在服务端
  4. 04支持帧采样以检查 CSS 动画
  5. 05提供 preview 与 save 工具

适用场景

  1. 01生成可用于 GitHub README 的动画横幅或徽章
  2. 02制作加载动画与图标
  3. 03让 AI 通过预览反复修改设计
  4. 04将生成结果保存为 SVG 或 PNG 文件

MCP 相关

nakkas 是一个 MCP 服务,向 MCP 客户端暴露 render_svg、preview 和 save 三个工具,客户端可借此渲染、预览并保存 SVG 文件。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"arikusi-nakkas": {
"command": "npx",
"args": [
"-y",
"nakkas"
]
}
}
}
启动命令npx -y nakkas

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmnakkas0.5.0

工具

3

收录的工具列表 · 更新于 2 周前

参数类型必填说明
defsobject否
defs.masksarray否
defs.pathsarray否
defs.filtersarray否
defs.markersarray否
defs.symbolsarray否
defs.patternsarray否
defs.clipPathsarray否
defs.gradientsarray否
canvasobject是
canvas.widthnumber|string是
canvas.heightnumber|string是
canvas.viewBoxstring否
canvas.backgroundstring否
outputobject否
output.svgboolean否
output.framesnumber否
output.minifyboolean否
output.previewboolean否
output.previewWidthnumber否
elementsarray是
animationsarray否

详细介绍

nakkas

将 AI 变成 SVG 艺术家的 MCP 服务。
一个渲染引擎。由 AI 决定一切。

npm 版本 下载量 许可证 市场

已正式列入 MCP Registry、Glama、LobeHub 和 PulseMCP。

官方 MCP Registry LobeHub 询问 DeepWiki

Glama 徽章

轨道系统:点环以不同速度绕着脉动的太阳旋转,一颗彗星拖着尾迹 利萨如曲线在点阵网格上逐笔绘制

两幅图均由 AI 通过 nakkas 绘制,每幅图使用一份 JSON 配置,并根据自身的 PNG 预览反复迭代。纯 CSS 动画,无 JavaScript。

Nakkas 是一个 MCP(Model Context Protocol)服务,可让 Claude 等 AI 助手通过声明式 JSON 配置创建动画 SVG 图形:徽标、图标、加载指示器、GitHub README 横幅、徽章和生成艺术。它使用 CSS @keyframes 和 SMIL 动画进行渲染,不需要 JavaScript,因此输出可用于 GitHub README,以及任何能渲染 SVG 的 <img> 标签。每次渲染都会返回 PNG 预览和一个服务端 artifact id,让 AI 立即看到自己的作品并继续迭代,而 SVG 文本不会经过其上下文窗口。

nakkaş 在土耳其语中古意为画家/艺术家。

"make a neon terminal logo with animated binary digits"
  → AI constructs JSON config
  → nakkas renders to animated SVG
  → AI previews the PNG, critiques, revises
  → clean animated SVG output

为什么选择它

  • 一个工具,无限设计。 render_svg 接受 JSON 配置,由 AI 填入所有内容。
  • AI 能看到自己的作品。 每次渲染都会返回 PNG 预览,让模型进行评估和修改,而不是盲目设计。
  • 迭代省 token。 SVG 会作为 artifact 保存在服务端;预览和保存时通过 id 访问,因此反复修改无需为 SVG 文本付费。
  • 纯声明式 SVG。 CSS @keyframes + SMIL 动画,无 JavaScript。可通过 GitHub 的 camo 代理正常显示。
  • 零外部依赖。 无云端 API,无需 API 密钥。本地运行。

安装

Claude Desktop

添加到配置文件:

  • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
  • Linux:~/.config/Claude/claude_desktop_config.json
  • Windows:%APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "nakkas": {
      "command": "npx",
      "args": ["-y", "nakkas@latest"]
    }
  }
}
Claude Code(CLI)
claude mcp add nakkas npx nakkas@latest
Cursor / Zed / 其他 MCP 客户端
{
  "mcpServers": {
    "nakkas": {
      "command": "npx",
      "args": ["-y", "nakkas@latest"]
    }
  }
}
本地开发
git clone https://github.com/arikusi/nakkas
cd nakkas
npm install && npm run build
# Use dist/index.js as the command

快速入门

让你的 AI(连接 Nakkas 后):

“制作一个动画 SVG:深色终端边框(800×200),发光的青色文字 ‘NAKKAS’,霓虹发光滤镜,加载时淡入。”

“创建一个加载旋转器:一个圆形,描边绘制动画循环播放,每 1.5 秒循环一次。”

“数据可视化:动画柱状图,5 根柱子,依次以交错延迟淡入,并使用渐变填充。”

“个人资料徽章(400×120):蓝紫渐变、白色用户名文字、投影和轻微的脉冲动画。”

工具

Nakkas 提供三个工具:

工具用途
render_svg接收 SVGConfig JSON,返回 PNG 预览图 + 工件 ID(以及设计分析警告)
preview将已存储的工件(或原始 SVG)重新渲染为任意宽度的 PNG
save将已存储的工件(或原始内容)保存到磁盘,格式为 SVG(文本)或 PNG(栅格图像)

预期工作流:渲染 → 查看返回的预览 → 修改配置 → 再次渲染 → 保存。渲染后的 SVG 会作为工件保留在服务端:render_svg 会返回预览图像和类似 art-1 的 ID,preview/save 可直接接收该 ID。SVG 文本无需再经由模型的上下文窗口传回,因此迭代循环的 token 成本仅为反复粘贴 SVG 的一小部分。工件的存续时间与服务进程一致(上限为 32 个,超出时最早的工件会被移除)。

save 工具
{ "artifact": "art-1", "outputPath": "./design.svg", "format": "auto" }

传入 artifact(来自 render_svg 的 ID,推荐)或 content(原始字符串)之一。格式:auto(根据扩展名推断)、svg(文本文件)、png(先渲染为栅格图像)。如果文件已存在,会追加数字计数器以防覆盖。系统会返回实际保存路径。

render_svg 工具

输入:SVGConfig JSON 对象
**输出:**PNG 预览图像 + 包含工件 ID 的摘要,以及可选的设计分析说明

响应的结构由配置中的可选 output 块控制:

{ "output": { "svg": false, "preview": true, "previewWidth": 800, "minify": false } }
  • svg: true 会在响应中包含完整的 SVG 文本(默认关闭;预览和保存可使用工件 ID)
  • preview: false 会跳过 PNG 图像
  • previewWidth 用于缩放预览
  • minify: true 会折叠存储和保存的 SVG 中的空白字符
  • frames: N(2 到 10)会将静态预览替换为一张胶片条图像,在 N 个时间点采样 CSS 动画——这是验证动画效果的方式,因为单张预览只显示起始状态

使用 frames 时,nakkas 会自行计算 @keyframes 数值(时长、延迟、迭代次数、方向、填充模式、每个动画片段的缓动),并将每个采样状态烘焙为静态帧。根据元素几何形状,以数值方式解析通过 transform-box: fill-box 声明的变换原点。不会对 SMIL 动画进行采样。

渲染后,响应可能会包含常见问题的设计警告,例如并发动画过多、缺少 transformBox、组级缩放变换、内容超出视口(根据实际渲染边界框测量,并以像素表示溢出量),或文字与画布背景的对比度较低(WCAG 比率)。文本还会进行单独的布局审查:系统通过隔离渲染测量每个文本元素的墨迹边界框,因此会指出超出视口的文本及其精确溢出量;若两个文本相互重叠,则会返回一条列出两者名称的重叠警告。

SVGConfig 结构
{
  canvas: {
    width: number | string,   // e.g. 800 or "100%"
    height: number | string,
    viewBox?: string,          // "0 0 800 400"
    background?: string        // hex "#111111" or "transparent"
  },

  defs?: {
    gradients?: Gradient[],   // linearGradient | radialGradient
    filters?: Filter[],        // preset or raw primitives
    clipPaths?: ClipPath[],
    masks?: Mask[],
    symbols?: Symbol[],
    paths?: { id, d }[],      // for textPath elements
    patterns?: Pattern[],     // repeating tile fills
    markers?: Marker[]        // arrowheads: triangle | arrow | circle | square | diamond | bar
  },

  elements: Element[],         // shapes, text, groups, use instances

  animations?: CSSAnimation[]  // CSS @keyframes definitions
}
元素类型
类型必填字段说明
rectwidth、heightx、y 默认值为 0;rx/ry 用于圆角
circlercx、cy 默认值为 0
ellipserx、ry水平和垂直半径相互独立
linex1、y1、x2、y2markerStart/markerEnd 接受来自 defs.markers 的标记 ID
polylinepoints开放路径:"10,20 50,80 90,20";支持 markerStart/markerMid/markerEnd
polygonpoints自动闭合的形状
pathd完整的 SVG 路径命令
imagehref、width、heightURL 或用于嵌入图像的 data:image/... URI
textcontent字符串或 (string | Tspan)[] 数组
textPathpathId、text沿曲线排列的文本;路径定义在 defs.paths 中
groupchildren将共享属性应用于所有子元素(不支持嵌套组)
usehref通过 #id 实例化符号或克隆元素
radial-groupcx、cy、count、radius、child将 N 个副本放置在完整圆周上
arc-groupcx、cy、radius、count、startAngle、endAngle、child将 N 个副本沿圆弧放置
grid-groupcols、rows、colSpacing、rowSpacing、child将副本放置在 M×N 网格中
scatter-groupwidth、height、count、seed、child将 N 个副本散布在由种子确定的随机位置
path-groupwaypoints、count、child将 N 个副本均匀分布在折线上
parametricfn数学曲线:rose、heart、star、lissajous、spiral、superformula、epitrochoid、hypotrochoid、wave

两个字段名与原始 SVG 有意不同:text 元素的字符串放在 content 中(在 textPath 中则放在 text 中);如果混淆,验证错误会指出确切字段。图案组默认会旋转每个副本,使其朝外;当子元素是文本或任何应保持直立的形状时,请设置 rotateChildren: false。

所有可视元素(共享字段)
{
  id?: string,             // required for filter/gradient/clip references
  cssClass?: string,       // matches CSS animation names
  fill?: string,           // "#rrggbb" | "none" | "url(#gradId)"
  stroke?: string,
  strokeWidth?: number,
  strokeDasharray?: string, // "10 5", use for draw-on animation
  strokeDashoffset?: number,
  opacity?: number,        // 0–1
  filter?: string,         // "url(#filterId)"
  clipPath?: string,       // "url(#clipId)"
  transform?: string,      // "rotate(45)" "translate(100, 50)"
  transformBox?: "fill-box" | "view-box" | "stroke-box",  // set "fill-box" for CSS rotation
  transformOrigin?: string, // "center", works with fill-box
  smilAnimations?: SMILAnimation[]
}
滤镜预设

在 defs.filters 中定义后,可在任意元素上通过 filter: "url(#myId)" 引用:

{ "type": "preset", "id": "myGlow", "preset": "glow", "stdDeviation": 8, "color": "#ff00ff" }
预设关键参数效果
glowstdDeviation、color柔和的光晕
neonstdDeviation、color强烈明亮的发光效果
blurstdDeviation高斯模糊
drop-shadowstdDeviation、offsetX、offsetY、color投影
glitchstdDeviation湍流位移(动画)
grayscalevalue(0–1)降低饱和度
sepia—暖色棕褐色调
invert—反转颜色
saturatevalue提高/降低饱和度
hue-rotatevalue(度)偏移色相
chromatic-aberrationvalue(像素偏移,默认值为 3)分离 RGB 通道,营造镜头畸变效果
noisevalue(不透明度 0 到 1,默认值为 0.25)叠加胶片颗粒和纹理
outlinecolor、value(粗细,默认值为 2)元素周围的彩色轮廓
inner-shadowcolor、stdDeviation、value(不透明度,默认值为 0.5)元素内部的阴影
embossstdDeviation、value(强度,默认值为 1.5)3D 浮雕阴影效果
CSS 动画
{
  "animations": [{
    "name": "pulse",
    "duration": "2s",
    "iterationCount": "infinite",
    "direction": "alternate",
    "keyframes": [
      { "offset": "from", "properties": { "opacity": "0.3", "transform": "scale(0.9)" } },
      { "offset": "to",   "properties": { "opacity": "1",   "transform": "scale(1.1)" } }
    ]
  }],
  "elements": [{
    "type": "circle",
    "cx": 100, "cy": 100, "r": 40,
    "cssClass": "pulse",
    "transformBox": "fill-box",
    "transformOrigin": "center"
  }]
}

CSS 属性键:驼峰式(strokeDashoffset)或短横线式(stroke-dashoffset),两种写法均可。

可动画的 CSS 属性:opacity、fill、stroke、transform、filter、clip-path、stroke-dasharray、stroke-dashoffset、font-size、letter-spacing 等。

SMIL 动画

SMIL 有三种类型,通过 smilAnimations: [] 在每个元素上内联定义:

{ "kind": "animate",          "attributeName": "d",       "from": "...", "to": "...", "dur": "2s" }
{ "kind": "animateTransform", "type": "rotate",            "from": "0 100 100", "to": "360 100 100", "dur": "3s" }
{ "kind": "animateMotion",    "path": "M 0 0 C ...",      "dur": "4s", "rotate": "auto" }

路径变形(attributeName: "d"):起始路径和目标路径必须具有相同类型和数量的命令,只能改变坐标。

字体

优先使用 CSS 通用字体族:sans-serif、serif、monospace。它们在每个平台上都能解析为实际字体,浏览器和 nakkas 预览中均如此。Arial 或 Helvetica 之类的具名字体只存在于部分系统上(大多数 Linux 机器上并没有),因此依赖这些字体的设计在其他环境中会呈现不同效果。稳妥的写法是具名字体加通用字体回退:"Georgia, serif"。

在 preview 和 PNG save 中,通用字体族会通过操作系统自身的字体映射进行解析(Linux 上为 fontconfig),因此 AI 看到的效果与该机器上的浏览器呈现效果一致。自定义字体族也受支持,只要渲染环境中有相应字体即可使用。

用例与兼容性
场景CSS @keyframesSMIL外部字体可交互(onclick)
GitHub README <img>✅✅❌❌
网页 <img>✅✅❌❌
网页内联 SVG✅✅✅✅
设计工具导出✅✅✅—
静态文件查看器✅✅视情况而定视情况而定

故障排查

“MCP error -32602: Input validation error”

这表示 MCP SDK 在输入到达处理程序之前拒绝了它。通常发生在首次尝试时,重试后即可成功。最常见的原因:

  • 渐变类型拼写错误。 使用 "linearGradient" 或 "radialGradient",不要使用 "linear" 或 "radial"。这是最常见的错误。
  • 将关键帧偏移量写成字符串。 使用 0 或 100(数字),或 "from" / "to"。写成 "0%" 或 "100%" 会导致失败。
  • 渐变和滤镜中的颜色。 渐变色标和滤镜颜色必须使用十六进制值:"#ff0000",不能用 "red" 或 rgb()。元素的 fill/stroke 接受任意绘制字符串("#ff0000"、"none"、"url(#id)"),但使用十六进制值在不同渲染器中最为稳妥。
  • 元素缺少 type。 每个元素对象都需要 type 字段。

到达处理程序的验证错误会指出确切的失败字段(例如 elements.1.content: Required),并附上失败元素类型的字段引用,因此通常只需修正一次即可重试成功。数字字段中的数字字符串(letterSpacing: "6")会自动转换,不会导致失败。

处理程序还会在渲染前检查引用的完整性:fill/stroke/filter/clipPath/mask 中悬空的 url(#id)、指向不存在位置的 use.href、在 defs.paths 中缺失的 textPath.pathId,或重复的 ID,都会作为错误返回,并附上确切字段路径和已定义 ID 列表,而不会静默渲染出损坏的内容。

如果你正在构建 MCP 客户端集成并持续遇到此问题,很可能是客户端序列化参数的方式有误。有关已知序列化问题的背景,请参阅 anthropics/claude-code#29104。

预览显示空白图像或意外图像

单次预览会在动画开始前的 t=0 渲染静态快照。若要查看动画效果,请使用 output: { frames: 4 } 渲染(最多 10 帧):nakkas 会在 N 个时间点采样 CSS 动画,并返回一张带标签的胶片条图像。SMIL 动画是例外;它们不会被采样,始终显示其基础状态。

如果图像完全空白:

  • 检查元素是否设置了 fill 或 stroke。在透明画布上,没有填充的形状不可见。
  • 检查坐标。在宽度为 800px 的画布上,位于 x: 2000 的元素会在屏幕外。
  • 如果使用 filter: "url(#myFilter)",请确保 defs.filters 中确实定义了 myFilter。
GitHub 上的动画无法运行

GitHub README 会通过 <img> 标签渲染 SVG,这会移除 JavaScript,但保留 CSS 和 SMIL。如果动画在本地可以运行,但在 GitHub 上无法运行:

  • 避免使用 <script> 或事件处理程序(onclick、onmouseover)。这些内容会被移除。
  • 外部字体无法加载。请使用通用字体系列(monospace、sans-serif、serif),或指定字体并提供通用字体作为回退。
  • 字体的 CSS @import 会被阻止。如果需要特定字体,请在 <text> 中直接设置,并提供系统字体作为回退。
SVG 输出过大

如果 render_svg 返回文件大小警告(超过 50kb),参数曲线可能采样了过多点;请减小 steps。图案组开销很小:子元素只定义一次,并通过 <use> 实例化,因此 cols: 50, rows: 50 的网格组只需一个子元素定义和 2500 个单行 <use> 标签。要生成尽可能小的文件,请添加 output: { minify: true }。

测试方式

每次发布前都会进行一次真实环境自测:通过真实的 MCP stdio 层,使用刚构建的服务生成设计,并反复执行渲染 → 预览 → 评审 → 修改,直到效果达标。测试设计会针对待测更改量身定制,因此该流程能验证新功能在真实使用场景中的表现,而不只是确认没有破坏现有功能。完整日志(包含提示词、迭代次数和生成的资源)见 dogfooding.md。

这一流程能发现实际漏洞。v0.3.0 的缓动自测发现,像 translateX 这样的 CSS 轴向简写会原样写入 SVG 的 transform 属性中,而这类写法无效,会导致元素静默冻结;修复随即在同一版本中发布。output.frames 背后的动画帧采样器会通过真实浏览器验证:使用随机种子(包括随机三次贝塞尔曲线)生成的动画,会通过负动画延迟技巧在无头 Chromium 中冻结,其采样位置必须与 nakkas 的采样结果相差不超过一个像素。这项交叉验证会在 CI 中作为 tests/browser-truth.test.ts 运行;原始手动测试脚本保留在 scripts/easing-browser-truth.sh。

除了自测流程外,还有 397 项单元测试和集成测试,其中包括 MCP stdio 端到端覆盖。

技术栈

  • TypeScript + Node.js 18+
  • @modelcontextprotocol/sdk(MCP 服务)
  • zod(架构验证和 AI 类型指导)
  • 不依赖外部 SVG 库,直接构造 XML
  • Vitest(397 项测试)

许可证

MIT。由 arikusi 开发。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。