Communitygithub.com

zk/paper-app-skill

Trabaja en la aplicación de diseño Paper (paper.design) a través de su servidor MCP local (las herramientas mcp__paper). Úsalo para diseñar, maquetar o explorar variantes en Paper, editar mesas de trabajo o diapositivas en un lienzo de Paper, tomar capturas de pantalla o exportar PNG, PDF o videos desde Paper, mover o clonar archivos de Paper, usar fuentes personalizadas o imágenes locales en Paper, o convertir un diseño de Paper en código. Cubre peculiaridades del modo de código, análisis de resultados, soluciones para exportaciones y capturas de pantalla, organización del lienzo y lo que el MCP no puede hacer.

¿Qué es paper-app-skill?

Esta skill está diseñada para agentes de IA (como Claude Code, Cursor o Codex) que necesitan interactuar con la aplicación de diseño Paper a través de su servidor MCP local. Paper es una herramienta de diseño cuyo lienzo está construido con HTML y CSS reales, y su servidor MCP permite a los agentes leer el lienzo y escribir HTML en él como nodos de diseño. La skill proporciona una guía detallada que complementa la documentación oficial del servidor, cubriendo lecciones aprendidas en sesiones reales: cómo verificar la conexión del servidor, cómo llamar a las herramientas de Paper desde el modo de código (evitando llamadas paralelas que causan fallos), cómo tomar capturas de pantalla y exportar archivos correctamente, cómo escribir HTML respetando las reglas del lienzo, cómo gestionar fuentes e imágenes locales, y cómo organizar el lienzo con mesas de trabajo y páginas. También incluye helpers de código reutilizables para simplificar tareas comunes como exportar un nodo a PNG y mostrarlo. Es compatible con Paper en macOS (el servidor MCP solo funciona mientras Paper está abierto) y está pensada para diseñadores y desarrolladores que quieran automatizar flujos de diseño con agentes de IA.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/zeke/paper-app-skill/tree/HEAD/skills/paper-app

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Vista previa

Del README del skill

paper-app-skill preview

Documentación

Paper app

Paper es una herramienta de diseño cuyo lienzo es HTML y CSS reales. La aplicación de escritorio de Paper ejecuta un servidor MCP local que permite a los agentes leer el lienzo y escribir HTML en él como nodos de diseño.

El servidor incluye su propia guía. Esta skill cubre lo que esa guía omite: lecciones aprendidas a lo largo de sesiones reales.

Antes de comenzar

  1. Verifica que las herramientas existan: await describeNamespace("mcp__paper") en modo de código. Si el espacio de nombres está vacío o ALL_TOOLS no tiene entradas mcp__paper__*, la sesión no se conectó, generalmente porque Paper no estaba abierto cuando la sesión comenzó. El servidor está en http://127.0.0.1:29979/mcp y solo responde mientras Paper esté abierto. pi mcp list (ejecutado desde bash) muestra si el servidor está saludable. Si lo está, la sesión no puede reconectarse por sí sola: pídele al usuario que ejecute /mcp reconnect paper en pi, o /reload si eso no funciona.
  2. Carga la guía oficial una vez por sesión: get_guide({ topic: "paper-mcp-instructions" }). Sigue sus indicaciones: publica un brief de diseño antes de nuevos diseños, escribe un grupo visual por llamada a write_html, revisa con capturas de pantalla y llama a finish_working_on_nodes cuando termines. Otros temas: mobile-status-bar, figma-import, image-generation.
  3. Encuentra el archivo. list_resources({ limit: 200 }) lista los archivos sin necesidad de tener uno abierto. Pasa fileId a cada llamada de ámbito de archivo. get_basic_info({ fileId }) funciona en un archivo que no está en la pestaña activa, por lo que rara vez necesitas open_file, que abre una pestaña en la aplicación del usuario.
  4. Si el proyecto tiene un AGENTS.md, busca allí el ID del archivo de Paper y las convenciones del lienzo antes de explorar.

Llamar a Paper desde el modo de código

  • Ejecuta las llamadas dependientes de Paper en un solo script con await, o en turnos secuenciales. Nunca las emitas como llamadas paralelas a herramientas en el mismo turno. Las llamadas paralelas causaron la mayoría de los fallos en sesiones anteriores, y cada uno se malinterpretó como un error de Paper: "Nodo no encontrado" para un nodo que una llamada hermana acababa de crear, hijos en orden desordenado, exportaciones que faltaban por escrituras recientes, y read fallando con ENOENT en una exportación que aún no se había escrito.
  • Cada herramienta de ámbito de archivo requiere fileId en su declaración de modo de código, aunque las instrucciones del servidor digan que se puede omitir. Omitirlo falla en la validación. Solo get_basic_info y get_selection aceptan que no se proporcione fileId.
  • Ejecuta describeTool("mcp__paper__<name>") antes del primer uso de una herramienta. Las formas de los argumentos no son adivinables: get_font_family_info toma familyNames: string[], set_text_content y update_styles toman un array updates, y export toma un mapa nodes.
  • Las herramientas de ámbito de archivo devuelven una sola cadena de texto: un bloque JSON de cabecera { file, contentHash }, luego el cuerpo. Las herramientas sin archivo (list_resources, create_file, open_file, get_guide) devuelven { content: [{ type: "text", text }] }. No uses expresiones regulares para extraer el primer "id" de un resultado: es el ID del archivo, y pasarlo como ID de nodo falla con "Nodo no encontrado".
  • Los fallos de ámbito de archivo y los errores de validación lanzan excepciones. Algunos fallos que no son de archivo (como "Abre un archivo de Paper para usar esta herramienta") se resuelven con isError: true en su lugar. No envuelvas las llamadas a Paper en .catch(() => {}): una forma de argumento incorrecta falla silenciosamente y la edición nunca aparece.
  • "Tu archivo de Paper está desconectado del servidor" significa que las escrituras fallan mientras las lecturas siguen funcionando. Dormir y reintentar no lo solucionó en sesiones anteriores. Pídele al usuario que traiga el archivo de Paper al primer plano y luego reintenta.
  • get_screenshot no devuelve ninguna imagen en modo de código: su resultado se aplana a la cadena de cabecera. Usa el helper shot() a continuación, que exporta un PNG y lo lee en el mismo script. Cuando un invocador llama a las herramientas MCP directamente en lugar de a través del modo de código, las imágenes de get_screenshot sí aparecen.

Formas de resultado útiles, después de analizar el cuerpo:

HerramientaCuerpo
create_artboard{ id, name, worldX, worldY, width, height }
write_html{ createdNodes: [{ id, name, component }] }, solo nodos de nivel superior
get_tree_summary{ summary }, un árbol de texto indentado con Type "name" (id) W×H
get_children{ children: [{ id, name, component, childCount, x, y }], count }
find_nodes{ nodes: [{ id, name, component, matched: [{ styleName, styleValue }] }] }
duplicate_nodes{ duplicatedNodes: [{ sourceId, newId, descendantIdMap }] }
export{ exports: [{ nodeId, filePath }] }
update_stylesLista ignoredStyles cuando un estilo es inerte en ese contexto. Revísalo.

Ayudantes

Pega estos al principio de un script de modo de código, o guárdalos una vez y haz eval en llamadas posteriores:

var F = "<fileId>";
var txt = r => typeof r === "string" ? r : (r?.content ?? []).map(c => c.text ?? "").join("\n");
// Elimina la cabecera { file, contentHash } que las herramientas de ámbito de archivo anteponen.
var body = r => { const t = txt(r); const i = t.indexOf("\n}\n"); return t.startsWith('{\n  "file"') && i > -1 ? t.slice(i + 3) : t; };
var json = r => JSON.parse(body(r));
var w = async (target, html, mode = "insert-children") =>
  json(await tools.mcp__paper__write_html({ fileId: F, targetNodeId: target, mode, html })).createdNodes;
// Exporta un nodo a PNG, muéstralo y luego elimina el archivo de ~/Downloads.
var shot = async (id, scale = "1x") => {
  const { exports } = json(await tools.mcp__paper__export({ fileId: F, nodes: { [id]: [{ format: "png", scale }] } }));
  const p = exports[0].filePath;
  image(await tools.read({ path: p, offset: null, limit: null }));
  await tools.bash({ command: `rm -f "${p}"`, timeout: 5 });
};

Para reutilizar ayudantes entre llamadas: store("paper", helperSource), luego eval(load("paper")) al principio de cada script posterior. Declara los ayudantes con var, porque const y let dentro de eval no se filtran. store() solo conserva valores cuando el script tiene éxito, así que guarda los ayudantes en un script que no haga nada más.

Capturas de pantalla y exportaciones

  • Toma capturas de pantalla en una llamada de modo de código separada de las ediciones. Una exportación en el mismo script que las escrituras puede ejecutarse antes de que Paper renderice los cambios, por lo que el PNG muestra contenido faltante o desactualizado.
  • export escribe en ~/Downloads/<nombre de mesa de trabajo>.png, con @2x o @0.5x para otras escalas y sufijos (1), (2) cuando ya existe un archivo con ese nombre. Caracteres como ? y : se convierten en _. Usa siempre el filePath devuelto. No selecciones archivos con ls -t ~/Downloads o globs de nombres: eso ha recogido exportaciones obsoletas de ejecuciones anteriores.
  • Mueve o elimina las exportaciones después de leerlas para que no se acumulen en ~/Downloads. Deja en paz los archivos que no creaste.
  • Usa 0.5x para capturas de revisión y ahorrar tokens, 2x para entregables (las mesas de trabajo de 1920×1080 se convierten en 3840×2160).
  • export_combined_pdf fusiona mesas de trabajo en un solo PDF, ordenadas por posición en el lienzo. export también admite video mp4/webm, además de svg para nodos SVG, jpg, webp, avif y pdf.
  • Para convertir mesas de trabajo en Google Slides, consulta references/slides-export.md.

Escribir HTML

La descripción de la herramienta write_html enumera las reglas (estilos en línea, flex, sin margin, sin display: grid, sin tablas, layer-name para nombres de capa). Hallazgos adicionales:

  • Un <div> vacío se convierte en un nodo Rectángulo, incluso con display: flex, y los Rectángulos no pueden tener hijos. Escribir en uno falla con "no puede tener hijos". Escribe un contenedor junto con su primer hijo, o reemplaza el Rectángulo con write_html en modo replace.
  • El texto enriquecido no es compatible. Para código resaltado sintácticamente o una frase con una palabra de color, construye una fila flex de nodos de texto separados, uno por token, cada uno con white-space: pre. El código se convierte en una fila por línea. Genera el HTML con un ayudante en lugar de escribirlo a mano.
  • Un background con capas de degradado ignora backgroundColor. Agrega el color base como la última capa: linear-gradient(#F6F7F9, #F6F7F9).
  • El <svg> en línea funciona para iconos, logotipos y líneas de conexión, y acepta colores fill/stroke y variables de token. Incorpora el SVG de un logotipo de marca en lugar de enlazarlo.
  • Los rellenos de rutas SVG son invisibles para find_nodes y get_computed_styles (que devuelve {} para ellos). Encuentra los nodos SVGVisualElement "Path" en get_tree_summary y cambia su color con update_styles({ styles: { fill } }), que sí funciona.
  • Las imágenes locales necesitan una ruta absoluta con el esquema paper-asset://: <img src="paper-asset:///private/tmp/spec/foo.png">.
  • Las columnas de igual ancho en una fila flex necesitan flex: 1; flex-basis: 0. De lo contrario, el padding en una columna la hace más ancha que sus hermanas.
  • Si el contenido se recorta, establece la mesa de trabajo en height: "fit-content" con update_styles en lugar de adivinar una nueva altura.

Fuentes

  • get_font_family_info({ fileId, familyNames: [...] }) verifica las fuentes instaladas en la máquina y Google Fonts. Llámala antes del primer estilo tipográfico en una sesión.
  • Las fuentes instaladas durante la sesión (por ejemplo, en ~/Library/Fonts en macOS) no aparecen hasta que Paper se reinicia. Pídele al usuario que cierre y vuelva a abrir Paper. No lo cierres tú mismo, ya que podrías perder su estado.
  • Verifica la licencia de una fuente antes de que aparezca en un sitio público. Muchas fuentes de dafont.com son solo para uso personal gratuito.
  • Para comparar muchas fuentes sin reiniciar Paper, renderiza muestras en PNG transparentes localmente (por ejemplo, con Pillow), colócalas como imágenes paper-asset:// en una mesa de trabajo de muestras y luego instala solo las finalistas.

Organizar el lienzo

  • Cuando iteres sobre un diseño, duplica la mesa de trabajo y modifica la copia. No edites las mesas anteriores en su lugar: los usuarios quieren ver la progresión y a menudo piden volver a una versión anterior. Un usuario tuvo que pedir esto dos veces en una sesión.
  • create_artboard y duplicate_nodes colocan nuevas mesas de trabajo en el mejor espacio vacío, lo que las dispersa. Para organizarlas, establece top y left en las mesas de trabajo con update_styles. Mantén al menos 80px entre mesas de trabajo.
  • Mantén las exploraciones de diseño separadas de la dirección elegida: en su propia región del lienzo o en su propia página (create_page, luego pasa pageId). No puedes cambiar la página que el usuario está viendo.
  • Para decks y conjuntos de variantes, usa una cuadrícula fija (por ejemplo, cuatro por fila, x = x0 + col × (width + gap)). Cuando se agrega o elimina una mesa de trabajo, redistribuye el resto para que no haya espacios y renumerar sus nombres.
  • Para variantes claras y oscuras, coloca la fila clara arriba y la versión oscura correspondiente directamente debajo de cada una. Para hacer las versiones oscuras, consulta references/dark-mode-variants.md.
  • Asigna a las mesas de trabajo nombres descriptivos como Inicio · A (Editorial) o 04 · ¿Qué son los Workers?. Los nombres de archivo de exportación provienen de ellos.
  • Los IDs de nodo no sobreviven a la sesión. Escribe el ID del archivo, URL, esquema de nombres, fórmula de cuadrícula y reglas de estilo en el AGENTS.md del proyecto para que la próxima sesión pueda continuar.

Del diseño al código

  • Lee valores exactos con get_jsx (format: "inline-styles" o "tailwind") y get_computed_styles. Nunca midas tamaños o colores a partir de una captura de pantalla.
  • Los colores calculados pueden devolverse como oklab(...). Cópialos textualmente en lugar de convertirlos.
  • Después de construir la página, compárala en un navegador real con una exportación de Paper, en modo claro y oscuro.

Lo que el MCP no puede hacer

  • Compartir archivos o gestionar permisos. El usuario comparte desde la aplicación Paper: invita a personas al equipo para que puedan editar, o envía la URL del archivo para acceso de solo lectura.
  • Mover archivos a carpetas. Los nuevos archivos de create_file se crean fuera de las carpetas del usuario, y el usuario debe arrastrarlos.
  • Mover nodos entre archivos. move_nodes solo mueve dentro de un archivo, entre páginas. Para mover el contenido de un archivo completo, usa create_file({ cloneFileId, name }), verifica que las cantidades de nodos y mesas de trabajo coincidan, luego delete_nodes los originales. Confirma con el usuario antes de eliminar.
  • Cambiar la página que el usuario está viendo.

Skills relacionados