nakkas
nakkaş는 터키어(고어)로 화가/예술가를 의미합니다.
"make a neon terminal logo with animated binary digits"
→ AI constructs JSON config
→ nakkas renders to animated SVG
→ clean animated SVG output왜 사용하는가
하나의 도구, 무한한 디자인.
render_svg는 JSON 설정을 입력받습니다. AI가 모든 것을 채워 넣습니다.AI 네이티브 스키마. 모든 필드에
.describe()주석이 달려 있어 모델이 무엇을 해야 할지 알고 있습니다.순수 선언적 SVG. CSS @keyframes + SMIL 애니메이션, JavaScript 없음.
제로 외부 종속성. 클라우드 API나 API 키가 필요 없습니다. 로컬에서 실행됩니다.
설치
Claude Desktop
설정 파일에 추가하세요:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"nakkas": {
"command": "npx",
"args": ["-y", "nakkas@latest"]
}
}
}Claude Code (CLI)
claude mcp add nakkas npx nakkas@latestCursor / 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초마다 반복되는 드로우온(draw-on) 스트로크 애니메이션이 있는 원."
"데이터 시각화: 애니메이션 막대 차트, 5개의 막대, 각각 지연 시간을 두고 페이드인, 그라데이션 채우기."
"프로필 배지(400×120): 파란색에서 보라색으로 이어지는 그라데이션, 흰색 사용자 이름 텍스트, 드롭 섀도우, 은은한 펄스 애니메이션."
도구
Nakkas는 세 가지 도구를 제공합니다:
도구 | 목적 |
| SVGConfig JSON을 입력받아 SVG 문자열 + 디자인 분석 경고 반환 |
| 렌더링된 콘텐츠를 입력받아 시각적 검사를 위한 PNG 이미지 반환 |
| 렌더링된 콘텐츠를 입력받아 SVG(텍스트) 또는 PNG(래스터)로 디스크에 저장 |
권장 워크플로우: 렌더링 → 미리보기 → 반복 → 저장. save 도구는 render_svg와 분리되어 있어 저장 전 미리보기와 개선을 장려합니다.
save 도구
{ "content": "<svg ...>...</svg>", "outputPath": "./design.svg", "format": "auto" }형식: auto(확장자에서 추론), svg(텍스트 파일), png(먼저 래스터로 렌더링). 파일이 존재하면 덮어쓰기를 방지하기 위해 숫자 카운터가 추가됩니다. 실제 저장된 경로가 반환됩니다.
render_svg 도구
입력: SVGConfig JSON 객체
출력: 전체 SVG XML 문자열 및 선택적 디자인 분석 노트
렌더링 후, 응답에는 너무 많은 동시 애니메이션, 누락된 transformBox 또는 그룹 수준의 크기 변환과 같은 일반적인 문제에 대한 디자인 경고가 포함될 수 있습니다.
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
},
elements: Element[], // shapes, text, groups, use instances
animations?: CSSAnimation[] // CSS @keyframes definitions
}요소 유형
유형 | 필수 필드 | 참고 |
|
|
|
|
|
|
|
| 독립적인 가로/세로 반지름 |
|
| |
|
| 열린 경로: |
|
| 자동 닫힘 도형 |
|
| 전체 SVG 경로 명령 |
|
| 포함된 이미지를 위한 URL 또는 |
|
| 문자열 또는 |
|
| 곡선을 따르는 텍스트; 경로는 |
|
| 모든 자식에 공유 속성 적용 (중첩 그룹 없음) |
|
| 심볼 인스턴스화 또는 |
|
| 원을 따라 N개 복사본 배치 |
|
| 원호를 따라 N개 복사본 배치 |
|
| M x N 그리드에 복사본 배치 |
|
| 시드된 무작위 위치에 N개 복사본 배치 |
|
| 폴리라인을 따라 N개 복사본을 균등하게 배치 |
|
| 수학적 곡선: |
모든 시각적 요소 (공유 필드)
{
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" }프리셋 | 주요 매개변수 | 효과 |
|
| 부드러운 후광 |
|
| 강렬한 밝은 빛 |
|
| 가우시안 블러 |
|
| 그림자 |
|
| 난류 변위 (애니메이션) |
|
| 채도 제거 |
| — | 따뜻한 세피아 톤 |
| — | 색상 반전 |
|
| 채도 증가/감소 |
|
| 색조 회전 |
|
| 렌즈 왜곡 느낌을 위한 RGB 채널 분리 |
|
| 필름 그레인 및 텍스처 오버레이 |
|
| 요소 주변의 색상 외곽선 |
|
| 요소 내부 그림자 |
|
| 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 속성 키: camelCase(strokeDashoffset) 또는 kebab-case(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"): from/to 경로는 동일한 명령 유형과 개수를 가져야 합니다. 좌표만 다를 수 있습니다.
폰트
시스템 폰트는 로딩 없이 어디서나 작동합니다: Arial, Helvetica, Courier New, Georgia, Verdana, monospace, sans-serif, serif.
사용자 정의 폰트 패밀리도 허용됩니다. 렌더링 환경(폰트가 로드된 웹 페이지, 디자인 도구 등)에서 폰트를 사용할 수 있을 때 작동합니다.
사용 사례 및 호환성
컨텍스트 | CSS @keyframes | SMIL | 외부 폰트 | 상호작용 (onclick) |
GitHub README | ✅ | ✅ | ❌ | ❌ |
웹 페이지 | ✅ | ✅ | ❌ | ❌ |
웹 페이지 인라인 SVG | ✅ | ✅ | ✅ | ✅ |
디자인 도구 내보내기 | ✅ | ✅ | ✅ | — |
정적 파일 뷰어 | ✅ | ✅ | 환경에 따라 다름 | 환경에 따라 다름 |
문제 해결
"MCP error -32602: Input validation error"
이는 핸들러에 도달하기 전에 MCP SDK가 입력을 거부했음을 의미합니다. 보통 첫 번째 시도에서 발생하며 재시도하면 작동합니다. 가장 일반적인 원인:
그라데이션 유형 오타.
"linear"나"radial"이 아닌"linearGradient"또는"radialGradient"를 사용하세요. 가장 빈번한 실수입니다.문자열로 된 키프레임 오프셋.
0또는100(숫자) 또는"from"/"to"를 작성하세요."0%"또는"100%"로 작성하면 실패합니다.색상 이름.
"red"가 아닌"#ff0000"과 같은 16진수 값만 작동합니다.rgb()도 사용할 수 없습니다.요소의
type누락. 모든 요소 객체는type필드가 필요합니다.
MCP 클라이언트 통합을 구축 중인데 이 문제가 지속적으로 발생한다면, 클라이언트가 인수를 직렬화하는 방식에 문제가 있을 가능성이 높습니다. 알려진 직렬화 특이사항에 대한 맥락은 anthropics/claude-code#29104를 참조하세요.
미리보기에 빈 화면이나 예상치 못한 이미지가 표시됨
미리보기 도구는 t=0에서의 정적 스냅샷을 렌더링합니다. 애니메이션은 캡처되지 않습니다. 보이는 것은 CSS나 SMIL 애니메이션이 시작되기 전 SVG의 초기 상태입니다.
이미지가 완전히 비어 있는 경우:
요소에
fill또는stroke가 설정되어 있는지 확인하세요. 투명한 캔버스에 채우기가 없는 도형은 보이지 않습니다.좌표를 확인하세요.
800px너비의 캔버스에서x: 2000에 있는 요소는 화면 밖으로 나간 것입니다.filter: "url(#myFilter)"를 사용하는 경우,myFilter가defs.filters에 정의되어 있는지 확인하세요.
GitHub에서 애니메이션이 작동하지 않음
GitHub README는 JavaScript를 제거하지만 CSS와 SMIL은 유지하는 <img> 태그를 통해 SVG를 렌더링합니다. 로컬에서는 애니메이션이 작동하는데 GitHub에서는 작동하지 않는 경우:
<script>나 이벤트 핸들러(onclick,onmouseover)를 피하세요. 이들은 제거됩니다.외부 폰트는 로드되지 않습니다. 시스템 폰트(
Arial,Courier New,Georgia,monospace,sans-serif)를 사용하세요.폰트를 위한 CSS
@import는 차단됩니다. 특정 폰트가 필요한 경우 시스템 대체 폰트가 포함된 인라인<text>를 사용하세요.
큰 SVG 출력
render_svg가 파일 크기(50kb 이상)에 대한 경고를 반환하면, 매개변수 곡선이나 패턴 그룹이 너무 많은 요소를 생성하고 있을 가능성이 높습니다. 매개변수 곡선의 steps나 패턴 그룹의 `count
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/arikusi/nakkas'
If you have feedback or need assistance with the MCP directory API, please join our Discord server