Mapa de ambas estructuras (output/ de ComfyUI + res://assets/ de Godot 4), tabla tipo-de-asset → carpeta destino → import settings clave, y propuesta de pipeline export_asset_to_godot que compone helpers atómicos + reimport headless (gap confirmado: 0 funciones godot en el registry). Documenta el gotcha de Godot 4: el filtro Nearest del pixelart se setea global (default_texture_filter=0) o por override, no por .import por defecto. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
19 KiB
Integración ComfyUI → Godot: puente de assets ordenado y gestionado
Diseño del puente entre la generación de assets en ComfyUI (~/ComfyUI/) y su consumo en
proyectos Godot 4 (~/gamedev/projects/). El objetivo es que un asset generado (sprite,
tileset, pixelart, spritesheet VFX, audio, malla 3D GLB) viaje a un proyecto Godot a la carpeta
correcta, con los import settings adecuados a su tipo, sin romper los archivos .import
existentes ni desordenar el proyecto.
- Fecha: 26/06/2026
- Alcance: mapa de ambas estructuras + convención de carpetas destino + tabla
tipo-de-asset → carpeta Godot → import settings + propuesta de función(es) del registry para
automatizar el traslado. Es documento de diseño; la implementación se delega a
fn-constructor. - Fuera de alcance: generación (GPU, otro agente), implementación de las funciones, descarga de modelos.
Documento hermano del catálogo de capacidades de generación: ~/ComfyUI/CAPABILITIES.md (fuera
del repo) y docs/capabilities/comfyui-overview.md (versionable). Este documento añade la pata
que faltaba: qué pasa con el asset una vez generado.
1. Mapa de ComfyUI (origen de los assets)
ComfyUI vive en ~/ComfyUI/ (clon del repo, no versionado en fn_registry). Las carpetas
relevantes para el puente son:
~/ComfyUI/
├── output/ # ★ AQUÍ caen TODOS los assets generados
│ ├── *.png # imágenes (sprites, pixelart, tiles) — ~150 hoy
│ ├── *.webp # spritesheets animados / vídeo corto (SaveAnimatedWEBP)
│ ├── *.mp4 # vídeo (SaveVideo)
│ ├── *.glb / *.obj / *.ply # mallas 3D (SaveGLB)
│ └── 3D/ # subcarpeta de salidas 3D (texturizadas, multi-vista)
├── input/ # imágenes de entrada (img2img, image-to-3d)
├── models/ + /mnt/2tb/comfyui_models/ # checkpoints/loras/vae/... (vía extra_model_paths.yaml)
├── user/default/workflows/ # grafos UI, agrupados por capacidad (01_txt2img, 02_img2img, …)
├── skills_library/<slug>/ # recetas de estilo reproducibles (recipe.json + samples)
└── custom_nodes/ # nodos extra (PixelArt-Detector, IPAdapter, Hunyuan3D, …)
output/es el único punto de origen del puente. Cada nodoSave*escribe ahí con un patrón de nombre<prefijo>_NNNNN_.<ext>(sufijo numérico de 5 dígitos). Ejemplos reales en disco hoy:bench160_3000_00001_.png,svd_motion_hi_00001_.webp,3d_robot_mesh_00001_.glb,output/3D/character_clean_textured_00001_.glb.- Modelos centralizados en
/mnt/2tb/comfyui_models/víaextra_model_paths.yaml(is_default: true). No intervienen en el puente (son insumo de generación, no asset de salida). - Tipos que generamos hoy (recuento real del
output/):png(mayoría),glb(15),mp4(6),webp(2),obj/ply(formatos 3D crudos). Audio aún no se genera en ComfyUI (no haywav/ogg/mp3enoutput/); el plan de audio existe como report aparte. El puente lo contempla igualmente porque Godot lo consume y porque el audio puede llegar de otra fuente. - Catálogo navegable de qué sabemos generar y con qué función/grafo:
~/ComfyUI/CAPABILITIES.md.
2. Mapa de Godot (destino de los assets)
Los proyectos viven en ~/gamedev/projects/ (fuera de fn_registry, igual que ComfyUI). Hay una
biblioteca maestra de assets en ~/gamedev/assets/ y, por proyecto, una copia local de los
assets que usa. Proyectos reales localizados:
~/gamedev/projects/crossy_road/(juego "LizardRoad", Godot 4.7, móvil portrait 640×1280)~/gamedev/projects/risk/(pilotaje previo)
Estructura canónica de un proyecto Godot 4 (tomada de crossy_road, que es el patrón real):
~/gamedev/projects/crossy_road/
├── project.godot # config del proyecto (nombre, autoloads, rendering, display)
├── .godot/ # ★ caché de import (regenerable) — NUNCA se versiona ni se toca a mano
│ └── imported/ # binarios .ctex/.sample/... generados desde los .import
├── assets/ # assets del proyecto (copia local de la biblioteca)
│ ├── biomas/ agua.png + agua.png.import (par obligatorio por cada asset)
│ ├── kenney/ packs CC0
│ ├── external/ otros CC0
│ └── audio/sfx/ step.wav + step.wav.import
├── scenes/ *.tscn (escenas)
├── scripts/ *.gd + *.gd.uid
├── addons/godot_ai/ addon del MCP (control del editor desde Claude)
└── export_presets.cfg / android/ (build móvil)
Cómo importa Godot 4 cada asset — el archivo .import
Regla de oro: en Godot, cada asset es un par <archivo> + <archivo>.import. El
.import es un INI que declara el importer, el type de recurso resultante, un uid://
estable y los parámetros de importación. Godot genera el binario importado en .godot/imported/
y lo regenera al reimportar. Romper o desincronizar el .import = el asset no carga o se
reimporta con settings por defecto. Por eso el puente debe respetar este par.
Ejemplos reales de .import por tipo (de crossy_road):
Textura (importer="texture", type="CompressedTexture2D"):
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cedkstexk3ciw"
path="res://.godot/imported/agua.png-<hash>.ctex"
[params]
compress/mode=0 ; 0=Lossless (correcto para pixelart), 2=VRAM
mipmaps/generate=false ; off para 2D/pixelart
process/fix_alpha_border=true
detect_3d/compress_to=1
Audio WAV (importer="wav", type="AudioStreamWAV"):
[remap]
importer="wav"
type="AudioStreamWAV"
[params]
edit/loop_mode=0 ; 0=Disabled (sfx), 1=Forward (música en bucle)
compress/mode=2
force/mono=false
Malla 3D GLB (importer="scene", produce PackedScene): el GLB se importa como escena glTF;
sus opciones (escala raíz, generación de colisión, manejo de materiales/texturas) viven en el
.import de tipo scene. No había ninguno en los proyectos actuales (son 2D), pero es el
importer canónico de Godot para .glb/.gltf.
El gotcha del filtro de textura (Godot 4 ≠ Godot 3)
En Godot 4 el filtro Nearest/Linear no es un campo del .import por defecto (en Godot 3
sí lo era). El filtro se controla de dos formas:
- Global del proyecto (recomendado, KISS): Project Settings → Rendering → Textures →
Canvas Textures → Default Texture Filter → Nearest. En
project.godotes la claverendering/textures/canvas_textures/default_texture_filter=0(0 = Nearest). Tras cambiarlo hay que reimportar las texturas. - Override por asset: en el panel Import de una textura concreta, Texture > Filter →
Nearest(override del default). Esto sí escribe la opción en su.import.
Hallazgo (read-only) en
crossy_road: suproject.godotno declaradefault_texture_filter, así que usa el default Linear → cualquier asset pixelart se ve borroso (susbiomas/*.pngtienenmipmaps/generate=falseycompress/mode=0, correcto, pero les falta el Nearest). Para un proyecto pixelart, setear el global una vez es el primer paso del puente. (No se modificó nada; queda anotado para el constructor.)
3. El puente: convención de carpetas destino en Godot
Convención propuesta para la copia local de assets dentro de cada proyecto, alineada con lo que
ya existe (assets/audio/sfx/, assets/kenney/) y extendida a todos los tipos que generamos:
res://assets/
├── sprites/ # PNG individuales: personajes, props, objetos sueltos
├── tilesets/ # PNG de tiles + el recurso TileSet .tres derivado
├── vfx/ # spritesheets / animaciones (WEBP, o PNG en grid) → SpriteFrames/AtlasTexture
├── audio/
│ ├── sfx/ # efectos cortos (WAV) — loop OFF
│ └── music/ # música (OGG/WAV) — loop ON
├── models/ # mallas 3D GLB (+ sus texturas/materiales)
└── _generated/ # opcional: zona de aterrizaje de lo recién traído de ComfyUI, antes de clasificar
pixelartno es una carpeta, es un atributo transversal: un sprite, tile o VFX puede ser pixelart. Lo que cambia es el import setting (Nearest + Lossless), no la ubicación. El pixelart va asprites//tilesets//vfx/según su rol, y el proyecto entero se marca Nearest a nivel global cuando es un juego pixelart.- Biblioteca maestra vs copia local:
~/gamedev/assets/es la fuente ordenada; cada proyecto guarda dentro su copia (<proyecto>/assets/...) porque Godot referencia por rutasres://relativas a la raíz del proyecto. El puente copia de~/ComfyUI/output/→ bien a la biblioteca maestra, bien directo a un proyecto.
Naming y versionado
- ComfyUI nombra
<prefijo>_NNNNN_.<ext>(p. ej.svd_motion_hi_00001_.webp). Al exportar, renombrar a snake_case limpio y semántico quitando el sufijo_NNNNN_y los guiones bajos de cola:svd_motion_hi_00001_.webp→explosion_loop.webp. - Sin espacios ni mayúsculas en nombres de archivo (consistencia con
res://y multiplataforma). - Versionado: sufijo opcional
_vNcuando se itera un asset que ya está en uso (hero_idle.png→hero_idle_v2.png), para no pisar eluid://del que ya referencian escenas. Nunca sobrescribir un asset en uso sin querer: cambia su contenido pero conserva suuid, lo que puede ser deseable (hot-swap) o no (regresión visual). Decisión explícita por asset.
4. Tabla: tipo de asset ComfyUI → carpeta Godot → import settings clave
| Tipo (ComfyUI) | Ext salida | Carpeta Godot destino | Importer Godot (type) |
Import settings clave |
|---|---|---|---|---|
| Sprite individual | .png |
res://assets/sprites/ |
texture → CompressedTexture2D |
compress/mode=0 (Lossless); mipmaps/generate=false; repeat off; filtro = default del proyecto (Linear si arte vectorial, Nearest si pixelart) |
| Pixelart (sprite/tile) | .png |
sprites/ o tilesets/ (según rol) |
texture → CompressedTexture2D |
CRÍTICO: Nearest (global default_texture_filter=0 o override por asset); compress/mode=0 Lossless; mipmaps/generate=false; repeat off |
| Tileset | .png |
res://assets/tilesets/ |
texture + recurso TileSet (.tres) manual/script |
Nearest (suele ser pixelart); además crear TileSet con tamaño de celda (region grid) — Godot no deriva el TileSet automáticamente del PNG |
| VFX spritesheet | .webp / .png (grid) |
res://assets/vfx/ |
texture → SpriteFrames (AnimatedSprite2D) o AtlasTexture por frame |
Nearest si pixelart; definir hframes/vframes o regiones por frame; Godot no convierte un sheet a SpriteFrames solo: se hace en editor o por script de import |
| Audio SFX | .wav |
res://assets/audio/sfx/ |
wav → AudioStreamWAV |
edit/loop_mode=0 (Disabled); compress/mode según peso |
| Audio música | .ogg / .wav |
res://assets/audio/music/ |
oggvorbisstr (OGG) / wav |
loop ON (edit/loop_mode=1 en WAV; loop=true en OGG) |
| Malla 3D | .glb (preferido) |
res://assets/models/ |
scene → PackedScene (glTF) |
escala raíz coherente; generar colisión si se necesita; si la textura es pixelart, poner el material en Nearest; preferir .glb sobre .obj/.ply (los lleva embebidos) |
Notas que la tabla condensa:
- Godot no automatiza dos conversiones clave: (1) PNG de tiles → recurso
TileSet, y (2) spritesheet →SpriteFrames. Ambas requieren un paso manual en editor o un script de import (o un addon, p. ej. el TexturePacker importer / aseprite-importers). El puente puede generar el.trespor script a partir de la geometría conocida del grid. - WEBP animado (SVD): nuestros
svd_*.webpson clips de Stable Video Diffusion. Para usarlos como animación 2D en Godot, lo robusto es descomponer en frames (PNG en grid) y construirSpriteFrames, no cargar el WEBP animado tal cual. - 3D pixelart/low-poly: el GLB importa como escena; cuidar que el material no aplique filtro Linear a una textura pixelart (se setea en el material/import de la malla).
5. Propuesta de función(es) del registry (diseño, NO implementación)
Búsqueda en el registry: mcp__registry__fn_search query="godot export asset import" → 0
resultados. Gap limpio. Hoy llevar un asset de ComfyUI a Godot es manual (copiar + abrir editor
- tocar import a mano). Alineado con la doctrina del registry (registry-first + crecer por composición de helpers atómicos, issue 0087), la propuesta es un pipeline one-shot que compone helpers pequeños:
Pipeline principal
export_asset_to_godot_py_pipelines (impura, kind=pipeline, tag de grupo: godot, comfyui)
Firma:
export_asset_to_godot(
asset_path: str, # ruta en ~/ComfyUI/output/ (o cualquier archivo)
kind: str, # "sprite" | "pixelart" | "tileset" | "vfx" | "sfx" | "music" | "model"
godot_project: str, # ruta raíz del proyecto Godot destino
dest_name: str = "", # nombre limpio destino (default: snake_case del origen sin _NNNNN_)
pixelart: bool = False, # fuerza Nearest + Lossless en la textura
loop: bool = False, # audio en bucle (música)
reimport: bool = True, # lanza reimport headless al final
) -> dict # {dest_res_path, import_written, reimported, warnings[]}
Comportamiento:
- Resolver la carpeta destino por
kind(tabla §4) dentro deres://assets/. - Copiar el archivo con nombre limpio (snake_case, sin sufijo
_NNNNN_). - Escribir/asegurar el
.importadecuado al tipo (texture/wav/scene) con los settings clave. - Si
pixelart=True, además asegurar el global del proyecto (default_texture_filter=0enproject.godot) o el override por asset. - Si
reimport=True, lanzar reimport headless para que Godot regenere.godot/imported/. - Devolver el
res://final + avisos (p. ej. "tileset copiado pero falta crear el TileSet .tres", "WEBP animado: descomponer en frames antes de SpriteFrames").
Helpers atómicos que compone (delegar a fn-constructor en paralelo)
| Helper (id tentativo) | Pureza | Qué hace |
|---|---|---|
godot_asset_dest_dir_py_core |
pura | mapea kind → subdir de res://assets/ (tabla §4) |
godot_clean_asset_name_py_core |
pura | quita sufijo _NNNNN_, normaliza a snake_case, sin espacios |
godot_write_texture_import_py_infra |
impura | escribe .import de textura (compress/mipmaps/filter) preservando uid si ya existe |
godot_write_audio_import_py_infra |
impura | escribe .import de audio (loop_mode) |
godot_ensure_pixelart_project_py_infra |
impura | setea default_texture_filter=0 en project.godot (idempotente) |
godot_reimport_headless_bash_infra |
impura | godot --headless --path <proj> --import para regenerar la caché |
godot_build_spriteframes_tres_py_infra |
impura | genera .tres de SpriteFrames/AtlasTexture a partir de un sheet + geometría de grid |
godot_build_tileset_tres_py_infra |
impura | genera .tres de TileSet a partir de un PNG + tamaño de celda |
DoD esbozado (según dod_quality.md)
- Golden:
export_asset_to_godot("~/ComfyUI/output/hero.png", "pixelart", "~/gamedev/projects/crossy_road")dejares://assets/sprites/hero.png+ su.importcon Nearest + Lossless, elproject.godotcondefault_texture_filter=0, y la reimport headless sale con exit 0; assert: el.importcontiene el override Nearest y el binario aparece en.godot/imported/. - Edge 1 (audio música):
kind="music", loop=True→.importconedit/loop_mode=1. - Edge 2 (GLB 3D):
kind="model"copia ares://assets/models/y la escena glTF carga (reimport sin error). - Edge 3 (tileset): copia el PNG y avisa que falta el
.tresdel TileSet (o lo genera congodot_build_tileset_tres), sin romper nada. - Error path:
kinddesconocido → error claro sin copiar nada;godot_projectsinproject.godot→ aborta y no escribe; nunca sobrescribe un asset en uso sindest_nameexplícito. - Idempotencia: re-exportar el mismo asset preserva el
uid://existente (no rompe las referencias de las escenas que ya lo usan).
¿Automatizar el import vía MCP godot-ai?
El addon godot_ai (MCP, server 127.0.0.1:8000/mcp) está presente en crossy_road y risk.
Con el editor abierto, filesystem_manage op reimport (recibe paths) puede forzar reimport
desde el editor vivo. Pero la convención (CONVENTIONS.md de gamedev) ya observa que el
reimport por MCP suele ser innecesario: project_run recompila desde disco al arrancar, y un
godot --headless --import regenera la caché sin editor abierto. Recomendación: el puente usa
reimport headless por CLI (godot_reimport_headless_bash_infra) como mecanismo por defecto
(no requiere editor abierto ni MCP), y deja el MCP como opción cuando el editor ya está vivo y se
quiere refrescar en caliente.
6. Resumen operativo (TL;DR)
- Origen: todo asset generado cae en
~/ComfyUI/output/(PNG/WEBP/MP4/GLB). - Destino:
res://assets/{sprites,tilesets,vfx,audio/{sfx,music},models}/dentro del proyecto Godot; cada asset es un pararchivo+archivo.import. - Import por tipo: textura (Lossless, mipmaps off, Nearest si pixelart), audio (loop off=sfx / on=música), GLB (escena glTF). Tabla §4.
- Gotcha Godot 4: el Nearest pixelart se setea global (
default_texture_filter=0) o por override de asset — no es un flag por defecto del.import.crossy_roadhoy está en Linear (pixelart borroso): anotado. - Godot no automatiza PNG→TileSet ni sheet→SpriteFrames: paso manual o script de import.
- Automatización: pipeline
export_asset_to_godot(gap confirmado, 0 funciones hoy) que compone helpers atómicos + reimport headless. Diseño en §5; implementación se delega afn-constructor.
Fuentes
- ComfyUI:
~/ComfyUI/CAPABILITIES.md,~/ComfyUI/extra_model_paths.yaml, listado de~/ComfyUI/output/(read-only). - Godot:
~/gamedev/CONVENTIONS.md,~/gamedev/README.md,~/gamedev/projects/crossy_road/project.godoty sus*.import(read-only). - Godot 4 pixel art texture filter: GDQuest — Setting up pixel art graphics in Godot 4, Godot Forum — How to import pixel art in Godot 4.
- Godot 4 sprite sheets: Godot docs — 2D sprite animation, godot-4-aseprite-importers.