nakkas
nakkaş significa pintor/artista en turco (antiguo).
"make a neon terminal logo with animated binary digits"
→ AI constructs JSON config
→ nakkas renders to animated SVG
→ clean animated SVG outputPor qué
Una herramienta, diseños infinitos.
render_svgtoma una configuración JSON. La IA completa todo.Esquema nativo para IA. Cada campo tiene anotaciones
.describe()para que el modelo sepa qué hacer.SVG declarativo puro. CSS @keyframes + animaciones SMIL, sin JavaScript.
Cero dependencias externas. Sin API en la nube, sin claves API. Se ejecuta localmente.
Instalación
Claude Desktop
Añade a tu archivo de configuración:
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 / Otros clientes MCP
{
"mcpServers": {
"nakkas": {
"command": "npx",
"args": ["-y", "nakkas@latest"]
}
}
}Desarrollo local
git clone https://github.com/arikusi/nakkas
cd nakkas
npm install && npm run build
# Use dist/index.js as the commandInicio rápido
Pide a tu IA (con Nakkas conectado):
"Haz un SVG animado: marco de terminal oscuro (800×200), texto cian brillante 'NAKKAS', filtro de neón, desvanecimiento al cargar."
"Crea un spinner de carga: un círculo con una animación de trazo que se repite cada 1.5 segundos."
"Visualización de datos: gráfico de barras animado, 5 barras, cada una desvaneciéndose con un retraso escalonado, rellenos degradados."
"Insignia de perfil (400×120): degradado de azul a morado, texto de nombre de usuario en blanco, sombra paralela, animación de pulso sutil."
Herramientas
Nakkas proporciona tres herramientas:
Herramienta | Propósito |
| Toma JSON de SVGConfig, devuelve cadena SVG + advertencias de análisis de diseño |
| Toma contenido renderizado, devuelve una imagen PNG para inspección visual |
| Toma contenido renderizado, guarda en disco como SVG (texto) o PNG (ráster) |
El flujo de trabajo previsto: renderizar → previsualizar → iterar → guardar. La herramienta save está separada de render_svg para fomentar la previsualización y el refinamiento antes de guardar.
La herramienta save
{ "content": "<svg ...>...</svg>", "outputPath": "./design.svg", "format": "auto" }Formatos: auto (deducido de la extensión), svg (archivo de texto), png (renderiza a ráster primero). Si el archivo existe, se añade un contador numérico para evitar sobrescribir. Se devuelve la ruta guardada real.
La herramienta render_svg
Entrada: Objeto JSON SVGConfig
Salida: Cadena XML SVG completa más notas opcionales de análisis de diseño
Después de renderizar, la respuesta puede incluir advertencias de diseño sobre problemas comunes como demasiadas animaciones simultáneas, falta de transformBox o transformaciones de escala a nivel de grupo.
Estructura de 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
}Tipos de elementos
Tipo | Campos requeridos | Notas |
|
|
|
|
|
|
|
| Radios horizontal/vertical independientes |
|
| |
|
| Ruta abierta: |
|
| Forma cerrada automáticamente |
|
| Comandos de ruta SVG completos |
|
| URL o URI |
|
| Cadena o matriz |
|
| Texto siguiendo una curva; ruta definida en |
|
| Atributos compartidos aplicados a todos los hijos (sin grupos anidados) |
|
| Instanciar un símbolo o clonar un elemento por |
|
| Colocar N copias alrededor de un círculo completo |
|
| Colocar N copias a lo largo de un arco circular |
|
| Colocar copias en una cuadrícula de M por N |
|
| Dispersar N copias en posiciones aleatorias con semilla |
|
| Distribuir N copias uniformemente a lo largo de una polilínea |
|
| Curva matemática: |
Todos los elementos visuales (Campos compartidos)
{
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[]
}Ajustes preestablecidos de filtros
Referencia como filter: "url(#myId)" en cualquier elemento después de definirlo en defs.filters:
{ "type": "preset", "id": "myGlow", "preset": "glow", "stdDeviation": 8, "color": "#ff00ff" }Ajuste | Parámetros clave | Efecto |
|
| Halo suave |
|
| Brillo intenso |
|
| Desenfoque gaussiano |
|
| Sombra paralela |
|
| Desplazamiento de turbulencia (animado) |
|
| Desaturar |
| — | Tono sepia cálido |
| — | Invertir colores |
|
| Aumentar/reducir saturación |
|
| Cambiar tonos |
|
| División de canal RGB para efecto de distorsión de lente |
|
| Grano de película y superposición de textura |
|
| Contorno coloreado alrededor del elemento |
|
| Sombra dentro del elemento |
|
| Efecto de sombreado en relieve 3D |
Animaciones 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"
}]
}Claves de propiedad CSS: camelCase (strokeDashoffset) o kebab-case (stroke-dashoffset). Ambos funcionan.
Propiedades CSS animables: opacity, fill, stroke, transform, filter, clip-path, stroke-dasharray, stroke-dashoffset, font-size, letter-spacing y más.
Animaciones SMIL
Tres tipos de SMIL, definidos en línea en cada elemento mediante 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" }Morfología de ruta (attributeName: "d"): las rutas de origen/destino deben tener tipos y recuentos de comandos idénticos. Solo pueden diferir las coordenadas.
Fuentes
Las fuentes del sistema funcionan en todas partes sin necesidad de carga: Arial, Helvetica, Courier New, Georgia, Verdana, monospace, sans-serif, serif.
También se aceptan familias de fuentes personalizadas. Funcionan cuando la fuente está disponible en el entorno de renderizado (página web con fuentes cargadas, herramienta de diseño, etc.).
Casos de uso y compatibilidad
Contexto | CSS @keyframes | SMIL | Fuentes externas | Interactivo (onclick) |
GitHub README | ✅ | ✅ | ❌ | ❌ |
Página web | ✅ | ✅ | ❌ | ❌ |
SVG en línea en página web | ✅ | ✅ | ✅ | ✅ |
Exportación de herramienta de diseño | ✅ | ✅ | ✅ | — |
Visor de archivos estáticos | ✅ | ✅ | depende | depende |
Solución de problemas
"MCP error -32602: Input validation error"
Esto significa que el SDK de MCP rechazó la entrada antes de que llegara al controlador. Suele ocurrir en el primer intento y funciona al reintentar. Los disparadores más comunes:
Error tipográfico en el tipo de degradado. Usa
"linearGradient"o"radialGradient", no"linear"o"radial". Este es el error más frecuente.Desplazamiento de fotograma clave como cadena. Escribe
0o100(números) o"from"/"to". Escribir"0%"o"100%"fallará.Colores con nombre. Solo funcionan los valores hexadecimales:
"#ff0000", no"red". Tampocorgb().Falta
typeen los elementos. Cada objeto de elemento necesita un campotype.
Si estás creando una integración de cliente MCP y ves esto constantemente, el problema probablemente esté en cómo tu cliente serializa los argumentos. Consulta anthropics/claude-code#29104 para obtener contexto sobre peculiaridades de serialización conocidas.
La vista previa muestra una imagen en blanco o inesperada
La herramienta de vista previa renderiza una instantánea estática en t=0. Las animaciones no se capturan. Lo que ves es el estado inicial del SVG antes de que comience cualquier animación CSS o SMIL.
Si la imagen está completamente en blanco:
Comprueba que tus elementos tengan
fillostrokeconfigurados. Una forma sin relleno en un lienzo transparente es invisible.Comprueba las coordenadas. Un elemento en
x: 2000en un lienzo de800pxde ancho está simplemente fuera de la pantalla.Si usas
filter: "url(#myFilter)", asegúrate de quemyFilteresté realmente definido endefs.filters.
Las animaciones no funcionan en GitHub
Los README de GitHub renderizan SVG a través de etiquetas <img>, que eliminan JavaScript pero mantienen CSS y SMIL. Si tu animación funciona localmente pero no en GitHub:
Evita
<script>o controladores de eventos (onclick,onmouseover). Estos se eliminan.Las fuentes externas no se cargarán. Limítate a las fuentes del sistema:
Arial,Courier New,Georgia,monospace,sans-serif.CSS
@importpara fuentes está bloqueado. Si necesitas una fuente específica, usa<text>en línea con una alternativa del sistema.
Salida SVG grande
Si render_svg devuelve una advertencia sobre el tamaño del archivo (más de 50kb), las curvas paramétricas o los grupos de patrones probablemente estén generando demasiados elementos. Reduce steps en las curvas paramétricas o count en los grupos de patrones. Un grid-group con cols: 50, rows: 50 produce 2500 elementos, lo cual suma rápidamente.
Stack tecnológico
TypeScript + Node.js 18+
@modelcontextprotocol/sdk(servidor MCP)zod(validación de esquema y guía de tipos para IA)Sin bibliotecas SVG externas, construcción XML pura
Vitest (280 pruebas)
Licencia
MIT. Creado por arikusi.
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