Communitygithub.com

iggypcnfsky/figma-bridge

Controla un archivo de Figma a través del puente Figma Bridge local: lee la selección, construye frames, texto y formas, vincula variables, coloca imágenes y exporta PNG/SVG. Úsalo cuando una tarea requiera tocar el lienzo de Figma (inspeccionar un diseño, implementar una UI en Figma, intercambiar colores por tokens, exportar un activo, insertar arte generado). Requiere el servidor puente en localhost:3847 y el plugin Figma Bridge ejecutándose en el archivo de destino; si no están disponibles, no improvises: pídele al usuario que los inicie.

¿Qué es figma-bridge?

Figma Bridge es una habilidad para asistentes de IA (como Claude Code, Cursor, Codex) que permite controlar programáticamente un archivo de Figma a través de un puente local HTTP. A diferencia de la API pública de Figma, que no ofrece escritura, esta herramienta utiliza un plugin de Figma y un servidor Node.js local para ejecutar operaciones como crear frames, texto, formas, aplicar estilos, variables, cuadrículas, efectos y exportar imágenes PNG/SVG. Es útil para diseñadores y desarrolladores que necesitan automatizar tareas repetitivas en Figma: inspeccionar un diseño, implementar una UI, intercambiar colores por tokens del sistema de diseño, exportar activos o insertar arte generado por IA. La habilidad incluye comandos CLI (`figma doctor`, `figma clients`, `figma run`, `figma export`) y soporta múltiples ventanas de Figma, detección de conexión, y un flujo de trabajo de leer-planear-escribir-verificar. Está diseñada para trabajar junto con la herramienta `img-forge` para generación de imágenes. Precondiciones clave: el servidor debe estar ejecutándose en `localhost:3847` y el plugin Figma Bridge debe estar activo en la ventana del archivo objetivo.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/iggypcnfsky/figma-bridge/tree/HEAD/.agents/skills/figma-bridge

Preguntar en tu IA favorita

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

Documentación

Figma Bridge

Figma no tiene una API pública de escritura. Esta habilidad utiliza un puente local: operaciones nombradas sobre HTTP, ejecutadas dentro de Figma por un plugin a través de la API de Plugin de Figma. Sin OAuth, sin tokens.

Repositorio: https://github.com/iggypcnfsky/figma-bridge — AGENTS.md, docs/ops-reference.md.

Precondiciones — comprobar antes de cualquier otra cosa

figma está en PATH, así que nunca busques el repositorio en el sistema de archivos:

figma doctor        # repositorio, servidor, ventanas conectadas, img-forge + clave FAL en una sola ejecución
figma clients       # id, archivo, página de cada ventana de Figma conectada
figma rules         # restricciones del proyecto: tipo mínimo, cuadrícula, tamaño de frame, nomenclatura de versiones

Lee figma rules antes de diseñar. Contiene los límites no obvios — por ejemplo, "Poppins 20/25 es el mínimo" — que ninguna cantidad de lectura del lienzo te dirá. Trata "confirmed": false como una suposición que debes verificar con el usuario, y {} como "pregunta, no inventes".

Si falta el comando, usa node "$(figma where)/server.mjs" solo después de preguntar; no hagas find del repositorio ni adivines rutas.

  • pluginConnected: false → detente. Pide al usuario que ejecute Plugins → Development → Figma Bridge en la ventana del archivo que desea modificar. Reintentar no ayuda.
  • 503 de /run significa lo mismo. 504 PLUGIN_GONE significa que cerraron la ventana del plugin.
  • 409 significa que varias ventanas de Figma están conectadas y no se ha elegido ninguna. Selecciona el archivo que nombró el usuario (--file <NOMBRE>) o un id de cliente (--client <ID>); nunca reintentes a ciegas, o podrías editar el archivo equivocado.

El bucle

  1. Orientarse. ./bin/figma status → nombre del archivo, página actual, selección, todas las páginas.
  2. Leer. selection 2, node <id> 2, find {"name":"Header","allPages":true}. Nunca adivines un nodeId — los ids de Figma se ven como 4022:2 y no se pueden derivar.
  3. Planificar. Decidir padre, tamaño, orden. Los nuevos nodos van a la página actual a menos que se especifique parentId.
  4. Escribir. ./bin/figma run '[{...},{...}]'.
  5. Verificar. ./bin/figma export <id> out/check.png PNG 2 y realmente observa la imagen.

Comandos

./bin/figma op '{"op":"status"}'
./bin/figma run '[{"op":"createFrame","name":"Card","width":320,"height":200,"fill":"#0B0B0F",
                   "props":{"cornerRadius":16,"layoutMode":"VERTICAL","paddingTop":24,"paddingLeft":24,"itemSpacing":12}}]'
./bin/figma run '[{"op":"createText","parentId":"12:34","characters":"Title","fontSize":24,"color":"#FFFFFF"}]'
./bin/figma op '{"op":"varFill","nodeId":"12:34","variableName":"color/bg/surface"}'
./bin/figma export 12:34 out/card.png PNG 2
./bin/figma image 12:34 out/cover.png FILL      # archivo de imagen local → relleno (sin subida a la nube)

Operaciones: ping status pages variables styles fonts inventory · selection node find · createFrame createRect createEllipse createText createPage createInstance · update clone reparent remove goto group ungroup select · grids setGrids align distribute effects · applyStyle varFill · export imageFill · exec. Parámetros completos: docs/ops-reference.md.

Atajos de trabajo de diseño que vale la pena conocer:

  • grid significa CUADRÍCULA: cuando el usuario dice "poner una cuadrícula", quiere la cuadrícula de diseño cuadrada, no columnas: {"op":"setGrids","nodeId":"…","grid":true} (celdas de 40 px, 40% por defecto) o "grid":40. Usa columns/rows solo cuando digan columnas, una cuadrícula de 12 columnas, o den valores de medianil/margen. Nunca simules una cuadrícula con rectángulos; applyStyle con kind:"grid" aplica un estilo de cuadrícula guardado.
  • filas de elementos: constrúyelos, luego {"op":"align","nodeIds":[…],"mode":"TOP"} y {"op":"distribute","nodeIds":[…],"axis":"HORIZONTAL","gap":24}.
  • profundidad: {"op":"effects","nodeId":"…","shadow":{"y":8,"blur":24,"color":"#00000033"}} o {"op":"effects","nodeId":"…","blur":{"type":"BACKGROUND","radius":20}}.
  • degradados: {"op":"gradient","nodeId":"…","kind":"linear","angle":135,"stops":[[0,"#8B76FF"],[1,"#0E0E12"]]} — el ángulo 0 es izquierda → derecha, 90 es arriba → abajo. Nunca simules un degradado con rectángulos apilados.
  • sistema de diseño: createInstance con un id de COMPONENT, luego instanceProps para variantes (lee los nombres primero) e instanceText para cambiar el texto sin desvincular; applyStyle para estilos. No redibujes lo que la biblioteca ya proporciona y no desvincules una instancia para "arreglar" su texto.
  • comprobaciones de espaciado: {"op":"measure","a":"1:2","b":"1:3"} devuelve espacios por lado y distancia al centro; úsalo en lugar de exportar una captura de pantalla para juzgar la alineación.
  • estilos: saveStyle crea o actualiza un estilo text / paint / effect / grid por nombre, y applyStyle lo aplica. Crea el token una vez, aplícalo en todas partes.
  • responsivo: sizing establece HUG/FILL/FIXED por eje más min/max; constraints cubre hijos sin auto-layout (STRETCH/MIN/MAX/CENTER/SCALE). Lee ambos de node antes de cambiarlos — sizing devuelve skipped con la razón de Figma cuando una propiedad no aplica.

Imágenes

¿Necesitas arte? Genéralo con el CLI hermano img-forge (https://github.com/iggypcnfsky/img-forge), luego colócalo — la generación permanece fuera de Figma para que la clave API nunca entre en el código del plugin y un render lento no pueda bloquear el lienzo:

cd ../img-forge
./img gen --prompt "abstract gradient cover, purple to black" --preset 16:9@2k --out out/cover.png
./img edit --prompt "make it night with neon accents" --ref out/cover.png   # o editar un activo existente
cd ../figma-bridge
./bin/figma image 12:34 ../img-forge/out/cover.png FILL

FILL recorta al nodo, FIT encuadra con bandas, TILE repite, CROP respeta el recorte existente. Para editar lo que el usuario seleccionó, expórtalo primero (./bin/figma export <nodeId> out/sel.png PNG 2) y pasa ese archivo como --ref.

La ventana del plugin también tiene un panel Generate / Edit para humanos (modelo, preajustes de tamaño, costo, insertar). No manejes el panel mediante programación — usa el CLI; expone más (máscara, variantes, ejecución en seco). Los preajustes guardados en ese panel residen en figma-bridge/presets.json.

Construir sobre un borrador existente

Un borrador que "no está terminado" aún codifica decisiones: qué está al lado de qué, qué está agrupado, el orden de los elementos, el ritmo de espaciado. Léelo antes de diseñar, luego consérvalo.

  1. {"op":"inventory"} — los frames, sus tamaños y estadísticas de tipografía.
  2. {"op":"structure","nodeId":"<frame>"} — hijos agrupados en filas con espacios y un readingOrder; esa es la agrupación que el autor eligió. {"op":"node",…,"depth":2} da el mismo árbol con más profundidad.
  3. Observa el patrón (un margen izquierdo que se repite, un título que siempre está sobre tres columnas) y consérvalo. Cambia lo que la solicitud necesita, deja el resto donde está.
  4. Informa las desviaciones que hayas hecho — "moví el pie de página 40 píxeles hacia arriba", no solo "mejoré el diseño".

Nunca normalices un borrador en silencio. Si la coherencia requiere mover cosas que el usuario colocó, dilo y pregunta; una diapositiva que se ve ordenada pero perdió sus agrupaciones es una regresión, no una mejora.

Reglas

  • Leer antes de escribir. Mínimo dos llamadas: inspeccionar, luego mutar.
  • Un lote = un pensamiento. Una operación no puede hacer referencia al resultado de una operación anterior, así que si necesitas el id del nuevo nodo, divide en dos llamadas.
  • Respeta la disposición que heredas: el orden de los hermanos, la proximidad y la agrupación son intención. No reorganices un borrador para que se vea más ordenado a menos que te lo pidan; pregunta primero cuando la coherencia movería sus elementos.
  • Nunca toques las capas existentes del usuario (update, remove, reparent) sin instrucción explícita. Prefija tus propias creaciones: Bridge / ….
  • Una reforma va justo al lado del original, lo más cerca posible. Si te piden rehacer una diapositiva/pantalla/sección: duplícala, llama {"op":"placeNear","nodeId":"<nuevo id>","move":true,"gap":80,"name":"Bridge / v2 — <nombre>"} para que la copia aterrice en el primer lado libre en lugar de una coordenada adivinada, y deja el original intacto. Si la herramienta informa free: false, pregunta dónde debe ir. Reemplaza elementos en su lugar solo cuando el usuario lo pida explícitamente.
  • goto cambia la vista del usuario — solo a petición.
  • exec es un último recurso. Funciona (el sandbox de Figma permite new Function) y evita toda validación de parámetros. Devuelve solo valores serializables en JSON.
  • Limpia los artefactos de prueba, o pregunta si conservarlos.

Errores comunes

  • Usa localhost, nunca 127.0.0.1: el manifiesto del plugin solo permite http://localhost:3847 (devAllowedDomains); Figma rechaza las IP. El servidor escucha tanto en 127.0.0.1 como en ::1.
  • figma.currentPage es la página abierta en esa ventana de Figma — no un puntero guardado. Cambiar de pestaña cambia lo que ves en la siguiente llamada.
  • Las posiciones son relativas al padre, y omitir parentId significa la página actual.
  • Las preguntas de tipografía (qué fuentes, tamaños, recuentos) son una sola llamada: {"op":"fonts"}; añade "allPages":true para todo el archivo. No recorras los frames con tu propio script.
  • Una vista general de la presentación de diapositivas es también una sola llamada: {"op":"inventory"} devuelve cada frame con geometría, minFontSize, fuentes, recuento de cuadrículas y rellenos — suficiente para elegir "frames 11–19" o encontrar texto por debajo de un tamaño mínimo.
  • Nunca indexes un campo que la referencia no liste. summary lleva font, fontSize, lineHeight y letterSpacing para TEXT; todo lo demás proviene de exec con el nombre real de la API. Los estilos mixtos son la cadena "MIXED", así que protégete con .get() y valores por defecto.
  • Un rectángulo no puede tener hijos; usa un frame cuando el texto o los iconos deban estar dentro de una forma.
  • Sin variables locales → variables devuelve collections: [] y varFill falla. Compruébalo primero.
  • El texto necesita una fuente: createText la carga mediante loadFontAsync; si la familia falta, usa Inter.
  • export tiene un límite de 8 MB — baja scale en lugar de reintentar.
  • Leer hijos de una página que no es la actual necesita loadAllPagesAsync; el puente reintenta una vez automáticamente, pero prefiere find con allPages: true.
  • Después de editar los archivos del plugin (code.js, ui.html) el usuario debe volver a ejecutar el plugin; los cambios en manifest.json necesitan una reimportación.

Skills relacionados