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
- Verifica que las herramientas existan:
await describeNamespace("mcp__paper")en modo de código. Si el espacio de nombres está vacío oALL_TOOLSno tiene entradasmcp__paper__*, la sesión no se conectó, generalmente porque Paper no estaba abierto cuando la sesión comenzó. El servidor está enhttp://127.0.0.1:29979/mcpy 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 paperen pi, o/reloadsi eso no funciona. - 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 awrite_html, revisa con capturas de pantalla y llama afinish_working_on_nodescuando termines. Otros temas:mobile-status-bar,figma-import,image-generation. - Encuentra el archivo.
list_resources({ limit: 200 })lista los archivos sin necesidad de tener uno abierto. PasafileIda 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 necesitasopen_file, que abre una pestaña en la aplicación del usuario. - 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, yreadfallando con ENOENT en una exportación que aún no se había escrito. - Cada herramienta de ámbito de archivo requiere
fileIden su declaración de modo de código, aunque las instrucciones del servidor digan que se puede omitir. Omitirlo falla en la validación. Sologet_basic_infoyget_selectionaceptan que no se proporcionefileId. - Ejecuta
describeTool("mcp__paper__<name>")antes del primer uso de una herramienta. Las formas de los argumentos no son adivinables:get_font_family_infotomafamilyNames: string[],set_text_contentyupdate_stylestoman un arrayupdates, yexporttoma un mapanodes. - 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: trueen 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_screenshotno devuelve ninguna imagen en modo de código: su resultado se aplana a la cadena de cabecera. Usa el helpershot()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 deget_screenshotsí aparecen.
Formas de resultado útiles, después de analizar el cuerpo:
| Herramienta | Cuerpo |
|---|---|
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_styles | Lista 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.
exportescribe en~/Downloads/<nombre de mesa de trabajo>.png, con@2xo@0.5xpara otras escalas y sufijos(1),(2)cuando ya existe un archivo con ese nombre. Caracteres como?y:se convierten en_. Usa siempre elfilePathdevuelto. No selecciones archivos conls -t ~/Downloadso 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.5xpara capturas de revisión y ahorrar tokens,2xpara entregables (las mesas de trabajo de 1920×1080 se convierten en 3840×2160). export_combined_pdffusiona mesas de trabajo en un solo PDF, ordenadas por posición en el lienzo.exporttambién admite videomp4/webm, además desvgpara nodos SVG,jpg,webp,avifypdf.- 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 condisplay: 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 conwrite_htmlen modoreplace. - 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
backgroundcon capas de degradado ignorabackgroundColor. 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 coloresfill/strokey variables de token. Incorpora el SVG de un logotipo de marca en lugar de enlazarlo. - Los rellenos de rutas SVG son invisibles para
find_nodesyget_computed_styles(que devuelve{}para ellos). Encuentra los nodosSVGVisualElement "Path"enget_tree_summaryy cambia su color conupdate_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"conupdate_stylesen 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/Fontsen 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_artboardyduplicate_nodescolocan nuevas mesas de trabajo en el mejor espacio vacío, lo que las dispersa. Para organizarlas, establecetopyleften las mesas de trabajo conupdate_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 pasapageId). 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)o04 · ¿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.mddel 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") yget_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_filese crean fuera de las carpetas del usuario, y el usuario debe arrastrarlos. - Mover nodos entre archivos.
move_nodessolo mueve dentro de un archivo, entre páginas. Para mover el contenido de un archivo completo, usacreate_file({ cloneFileId, name }), verifica que las cantidades de nodos y mesas de trabajo coincidan, luegodelete_nodeslos originales. Confirma con el usuario antes de eliminar. - Cambiar la página que el usuario está viendo.
