Files
fn_registry/docs/capabilities/gamedev-2d.md
T
egutierrez a27dcc028c docs(capabilities): unifica tag gamedev en gamedev-2d + separa gamedev-engine
El doctor reportaba el dominio gamedev en doble FAIL: el tag plano `gamedev`
(44 funciones) como `ungrouped_candidate` y la pagina `gamedev-2d.md` como
`doc_orphan`. Causa raiz: el INDEX declaraba `[gamedev](gamedev-2d.md)` y el
auditor solo registra el slug cuando label==target, asi que ni casaba la
pagina ni declaraba el tag.

Al revisar las 44 funciones habia dos clusters reales bajo el mismo tag, asi
que se separan en dos grupos honestos:

- gamedev-2d (tag canonico): 31 builders de workflow ComfyUI + 5 de apoyo
  (post-proceso + puente a Godot) = 36. Se elimina el tag plano `gamedev` de
  los builders (ya tenian `gamedev-2d`) y se reemplaza por `gamedev-2d` en las
  de apoyo.
- gamedev-engine (grupo nuevo, pagina madre nueva): runtime de juego C++
  multiplataforma (SDL3 + sokol_gfx + miniaudio, Issue 0072b) = 8. Game loop,
  camara 2D, input unificado, sprite batch, setup render/audio, build wasm.

El tag plano `gamedev` queda eliminado (count 0). INDEX corregido: fila
gamedev-2d con label==target y conteo 36 + fila nueva gamedev-engine (8).

Verificacion: `fn index` + `fn doctor capabilities` -> ambos grupos OK
(declared_in_index=yes, doc_exists=yes, sin issues); `gamedev` plano = 0.
Solo se modifico el campo `tags` de los .md, ningun archivo de codigo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 02:40:50 +02:00

39 KiB
Raw Blame History

Capability group: gamedev-2d — assets 2D para Godot (generación + post-proceso + puente)

Cluster de funciones para producir y mover assets 2D de juego entre ComfyUI (generación) y Godot 4 (consumo). Tres capas:

  1. Builders de workflow 2D (gamedev-2d, GPU): construyen el dict (API format) de los workflows ComfyUI para pixel-art, tiles seamless, isométrico, sprites de personaje y VFX en bucle. Son puros (no tocan GPU al construir); el coste GPU está al enviar con comfyui_submit_workflow.
  2. Post-proceso determinista (CPU): pixelizar, recortar a alpha.
  3. Puente de assets (CPU): coloca el resultado en un proyecto Godot con sus import settings.

Tag único del grupo: gamedev-2d (los 31 builders de workflow + las 5 funciones de apoyo de post-proceso y puente). El tag plano gamedev quedó deprecado y unificado a gamedev-2d. El runtime de juego C++ (el motor que ejecuta el juego: game loop, cámara, input, render por lotes, audio) vive en el grupo hermano gamedev-engine. Filtro: mcp__registry__fn_search query="" tag="gamedev-2d".

Documento hermano del grupo comfyui (generación genérica de imágenes/video/3D). Diseño del puente: docs/comfyui-godot-integration.md. Planes origen: reports/0135 (pixelart), reports/0139 (entornos/tiles/iso), reports/0137 (personajes/sprites), reports/0140 (VFX), reports/0143 (ronda 2b: builders), reports/0147 (item icons), reports/0149 (parallax background).

Builders de workflow 2D (gamedev-2d, puros — generación)

Construyen el dict API format listo para comfyui_submit_workflow. Cada uno compone funciones existentes del registry (comfyui_build_txt2img_workflow, comfyui_inject_*, comfyui_build_ipadapter_workflow) — no reinventan el grafo. class_types verificados contra /object_info del server (8GB lowvram). Probados e2e en GPU: pixelart, seamless, VFX (ver reports/0143).

ID Firma corta Qué hace
comfyui_build_pixelart_workflow_py_ml (positive, negative=…, *, ckpt_name="juggernaut_xl_v11…", pixel_lora="pixel-art-xl…", use_lcm=True, …) -> dict Fase 1 pixel-art: SDXL + LoRA pixel-art-xl (+ LCM 8 steps). El pixel-perfect es post (comfyui_pixelize_image).
comfyui_build_seamless_tile_workflow_py_ml (positive, negative="", *, tiling="enable", copy_model="Make a copy", circular_vae=True, material_lora=None, …) -> dict Textura tileable: SeamlessTile (Conv2d circular) + CircularVAEDecode. Coste VRAM ≈0.
comfyui_build_isometric_workflow_py_ml (positive, negative=…, *, iso_lora="isometric_game_assets_sd15…", grid_image=None, …) -> dict Asset iso 2:1: LoRA iso + ControlNet grid opcional.
comfyui_build_sprite_sheet_workflow_py_ml (subject, *, ref_image=None, pose_skeleton=None, char_lora=None, transparent=True, …) -> dict UN sprite de personaje: IPAdapter-FaceID + LoRA + ControlNet OpenPose (Advanced, end<1) + Rembg. Varias poses → sheet. SD1.5.
comfyui_build_vfx_spritesheet_workflow_py_ml (prompt, *, motion_model="mm_sd_v15_v2.ckpt", num_frames=16, closed_loop=True, lora=None, …) -> dict N frames AnimateDiff loop sobre negro (insumo de luma→alpha). 8GB: 16f@512² revienta, usar ≤8f@512² o bajar resolución.
comfyui_build_item_icon_workflow_py_ml (item, *, style="game icon, clean, centered", checkpoint="dreamshaper_8…", size=512, transparent=True, lora=None, …) -> dict UN icono de item de inventario (espada/poción/anillo/libro/escudo): txt2img cuadrado + prompt scaffold de icono + LoRA estilo opcional + Rembg (alpha). Set coherente = mismo style/checkpoint/lora por item. SD1.5.
comfyui_build_portrait_avatar_workflow_py_ml (character, *, style="character portrait", ref_face=None, checkpoint="dreamshaper_8…", size=512, facedetailer=True, lora=None, …) -> dict UN retrato/avatar de personaje (busto centrado, cara al espectador, fondo simple): txt2img + prompt scaffold de retrato + FaceDetailer (cara nítida) + LoRA estilo opcional; ref_face → IPAdapter-FaceID para rostro consistente entre retratos. Diálogo/perfil/selección. SD1.5.
comfyui_build_emote_workflow_py_ml (character, expression, *, ref_face=None, style="character portrait", checkpoint="dreamshaper_8…", size=512, facedetailer=True, lora=None, …) -> dict UN emote/expresión facial del MISMO personaje (alegre/triste/enfadado/sorprendido/neutral…) para diálogo, retratos reactivos o emotes de chat: txt2img + prompt scaffold de emote (portrait of {character}, {expression} expression, emote, clean background) + FaceDetailer (conserva la expresión); ref_face → IPAdapter-FaceID para que varíe SOLO la expresión y el rostro sea el mismo. UNA expresión por llamada; set = mismas claves variando expressioncomfyui_build_grid. Probado e2e en GPU (reports/0151). SD1.5.
comfyui_build_parallax_background_workflow_py_ml (scene, *, style="game background, side-scroller…", layers=3, checkpoint="dreamshaper_8…", depth_node="DepthAnythingV2Preprocessor", width=1024, height=512, …) -> dict Fondo en capas para parallax 2.5D: genera el fondo apaisado (txt2img) + su depth map (DepthAnythingV2Preprocessor sobre el VAEDecode), dos SaveImage. El split en N bandas por profundidad es post (GAP: split_parallax_layers, aún no creada). Probado e2e en GPU (reports/0149). SD1.5.
comfyui_build_normal_map_workflow_py_ml (image, *, method="normal", strength=1.0, resolution=512, bg_threshold=0.1, filename_prefix="normal_map") -> dict Normal/depth map de un sprite existente para iluminación dinámica 2.5D (Godot CanvasItem normal_map, Unity sprite normal). LoadImage → preprocesador controlnet_aux → SaveImage. method: normal (default, BAE-NormalMapPreprocessor, normal canónico azul/violeta usable directo en motor), normal_midas (MiDaS, único con strengtha, paleta no canónica), normal_dsine (DSINE), depth (DepthAnythingV2, height en gris). image debe estar en input/ de ComfyUI. Coste VRAM ≈0. Probado e2e en GPU (reports/0150).
comfyui_build_ui_hud_workflow_py_ml (element, *, ui_style="fantasy game UI", checkpoint="dreamshaper_8…", size=512, transparent=True, lora=None, …) -> dict UN elemento de interfaz/HUD de juego (botón, marco/panel, barra de vida/maná/XP, icono de UI, cursor, viñeta de menú): txt2img cuadrado + prompt scaffold de UI ({element}, {ui_style}, game UI element, centered, clean, plain background…) + LoRA estilo opcional + Rembg (alpha). HUD coherente = mismo ui_style/checkpoint/lora por pieza, varía solo element. El texto/label lo pone el motor (negativo empuja a no text). Probado e2e en GPU (reports/0152). SD1.5.
comfyui_build_dialogue_box_workflow_py_ml (box_style="fantasy RPG dialogue box", *, shape="rounded panel", checkpoint="dreamshaper_8…", width=768, height=256, transparent=True, seed=0, lora=None, …) -> dict EL contenedor de diálogo / bocadillo / panel de texto de juego (RPG, visual novel, aventura): marco apaisado (width>height, 768×256) con borde decorativo y un interior plano/vacío reservado para que el motor renderice el texto de la conversación encima → {box_style}, {shape}, game UI dialogue box frame, ornate border, empty flat interior for text, plain background + LoRA estilo opcional + Rembg (alpha). DISTINTO de ui_hud (elementos sueltos: botón/barra/icono): esto es el panel-contenedor completo. shape (rounded panel/scroll parchment/stone tablet/speech bubble…) + set coherente = mismo box_style/shape/checkpoint/lora. El interior se mantiene liso (negativo rechaza busy/decorated interior); el texto lo pone el motor (negativo empuja a no text). Probado e2e en GPU con SD1.5 — medieval fantasy dialogue box, wood and gold 768×256 RGBA, panel madera+oro con interior plano y alpha (reports/0171). SD1.5.
comfyui_build_status_effect_icon_workflow_py_ml (effect, *, ui_style="game status icon, bold symbol, flat", checkpoint="dreamshaper_8…", size=256, transparent=True, seed=0, lora=None, …) -> dict UN icono de estado / buff-debuff (veneno, quemadura, congelación, escudo, regeneración, aturdimiento, velocidad, sangrado, maldición): símbolo compacto que se superpone al HUD para indicar un efecto activo, optimizado para legibilidad a tamaño reducido (16-32 px) → {effect} status effect icon, {ui_style}, simple bold symbol, centered, readable at small size, plain background… + LoRA estilo opcional + Rembg (alpha). size por defecto menor (256, no 512) porque se muestra pequeño; el negativo rechaza intricate details/complex/cluttered para no perder legibilidad. DISTINTO de item_icon (objeto de inventario) y ui_hud (chrome grande de interfaz): aquí es un símbolo de estado. Barra coherente = mismo ui_style/checkpoint/lora, varía solo effect (color habla del tipo). El texto/contador lo pone el motor (negativo empuja a no text). Probado e2e en GPU con SD1.5 — poison 256×256 RGBA, símbolo verde flat centrado (reports/0162). SD1.5.
comfyui_build_skill_tree_node_workflow_py_ml (skill, *, frame="hexagonal", state="unlocked", ui_style="fantasy skill tree node", checkpoint="dreamshaper_8…", size=256, transparent=True, seed=0, lora=None, …) -> dict UN nodo de árbol de habilidades / talentos (RPG, ARPG, MOBA, roguelike): el icono de una skill DENTRO de un marco (frame: hexagonal/circular/diamond/shield) que la UI de progresión pinta en la rejilla, con variante de estado visual (state: unlocked=brillante/saturado, locked=gris/desaturado) → {skill} skill icon inside a {frame} {ui_style} frame, {state} (…hint…), centered, plain background, game UI, skill tree talent node… + LoRA estilo opcional + Rembg (alpha). El marco y el estado son la firma del asset. DISTINTO de item_icon (objeto suelto sin marco), status_effect_icon (símbolo superpuesto sin marco) y ui_hud (chrome grande): aquí es el nodo enmarcado completo de la pantalla de talentos. Par de un mismo talento = mismo skill/frame/ui_style/seed, varía solo state (las dos caras de la rejilla). Árbol coherente = mismo frame/ui_style/checkpoint/lora, varía skill. El texto/coste lo pone el motor (negativo empuja a no text). Probado e2e en GPU con SD1.5 — fireball hexagonal unlocked 256×256 RGBA, nodo enmarcado brillante centrado (reports/0173). SD1.5.
comfyui_build_achievement_badge_workflow_py_ml (badge, *, tier="gold", style="game achievement badge, ornate", checkpoint="dreamshaper_8…", size=256, transparent=True, seed=0, lora=None, …) -> dict UNA insignia / medalla / logro (achievement, recompensa, rango): un trofeo, una medalla con cinta, un escudo de logro o un badge de rango que el panel de logros pinta al desbloquear un hito, con tier metálico (bronze/silver/gold/platinum/diamond) que distingue el grado → {badge} achievement badge, {tier} tier (…hint metálico…), {style}, medal with ribbon, centered, plain background, game UI reward, trophy emblem… + LoRA estilo opcional + Rembg (alpha). El tier metálico y la forma de medalla/trofeo con cinta son la firma del asset. DISTINTO de item_icon (objeto de inventario suelto, sin tier ni cinta), status_effect_icon (símbolo de estado superpuesto sin marco) y skill_tree_node (nodo enmarcado de la rejilla de talentos con estado unlocked/locked): aquí es la insignia de logro/recompensa del panel de achievements. Familia de un mismo logro = mismo badge/style/seed, varía solo tier (los grados); set coherente = mismo style/checkpoint/lora, varía badge. El nombre/descripción/fecha lo pone el motor (negativo empuja a no text). Probado e2e en GPU con SD1.5 — dragon slayer tier gold seed 77 256×256 RGBA, medalla circular dorada con emblema centrado y fondo recortado a alpha (esquina α=0, centro α=254; prompt_id 8b8b7ede, reports/0175). SD1.5.
comfyui_build_card_art_workflow_py_ml (subject, *, card_style="fantasy trading card art", checkpoint="juggernaut_xl_v11…", width=512, height=768, hires=True, seed=0, lora=None, …) -> dict LA ilustración central de UNA carta coleccionable (TCG): criatura/personaje/hechizo en formato vertical de carta (width<height, ~512×768), composición centrada + iluminación dramática ({subject}, {card_style}, dramatic lighting, detailed illustration, centered composition, full art…). hires=True → 2ª pasada de detalle (comfyui_build_hires_fix_workflow); si no, txt2img + LoRA estilo opcional. Genera SOLO la ilustración — el marco/título/stats los pone el motor/post (negativo rechaza card frame/border/text/stats/UI). Set coherente = mismo card_style/checkpoint/lora, varía solo subject. Probado e2e en GPU con SD1.5 (reports/0153); ⚠️ el path hires=True falla hoy por bug del builder comfyui_build_hires_fix_workflow (nodo UltimateSDUpscale pide batch_size) — usar hires=False hasta el fix. SD1.5/SDXL.
comfyui_build_enemy_creature_workflow_py_ml (creature, *, variant=None, style="game creature, full body", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN enemigo/criatura de juego (goblin, esqueleto, slime, dragón, boss, elemental): figura de cuerpo entero centrada, fondo limpio recortable a alpha ({variant} {creature}, {style}, full body, centered, plain background, game asset…) → txt2img cuadrado + LoRA estilo opcional + Rembg (alpha). variant (ice/fire/elite/corrupted…) se antepone a la criatura para generar la familia del MISMO enemigo (misma creature/seed/style, varía solo variant); bestiario coherente = mismo style/checkpoint/lora, varía solo creature. El negativo empuja a UNA criatura entera sin recorte. Probado e2e en GPU con SD1.5 (reports/0154). SD1.5.
comfyui_build_prop_object_workflow_py_ml (prop, *, style="game prop, isometric or side view", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN prop/objeto de escenario (barril, cofre, antorcha, planta, mueble, roca, fuente, estatua): objeto inanimado aislado a escala de escena y perspectiva de juego (iso/lateral), centrado, fondo limpio recortable a alpha ({prop}, {style}, game asset, single object, centered, plain background, scene prop, world object…) → txt2img cuadrado + LoRA estilo opcional + Rembg (alpha). Objeto de MUNDO, no icono plano de inventario (≠ item_icon, que es para una casilla de UI); este puebla el nivel. Atrezzo coherente = mismo style/checkpoint/lora, varía solo prop. El negativo excluye personas/criaturas (objeto inanimado). Probado e2e en GPU con SD1.5 (reports/0155). SD1.5.
comfyui_build_vehicle_mount_workflow_py_ml (vehicle, *, view="side", style="game vehicle", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN vehículo/montura que el personaje USA o CONDUCE (caballo, dragón-montura, nave espacial, coche, barco, carro, grifo, mecha): el vehículo COMPLETO en vista lateral o isométrica, centrado, fondo limpio recortable a alpha, SIN jinete/conductor ({vehicle}, {view} view, {style}, full vehicle, centered, plain background, game asset, no rider, empty…) → txt2img cuadrado + LoRA estilo opcional + Rembg (alpha). Se genera VACÍO (el negativo rechaza person/rider/driver/passenger) para que el motor componga al personaje encima. DISTINTO de enemy_creature (sujeto a COMBATIR) y prop_object (atrezzo inanimado que decora): aquí el objeto se MONTA/USA; una montura viva que se cabalga (caballo, dragón) entra aquí, no en enemy_creature. view (side/iso) fija la geometría del parque móvil; set coherente = mismo view/style/checkpoint/lora, varía solo vehicle. Probado e2e en GPU con SD1.5 — armored war horse with saddle side 512×512 RGBA, vehículo centrado recortado a alpha (centroide 0.55/0.54, 4 esquinas transparentes, reports/0169). SD1.5.
comfyui_build_topdown_sprite_workflow_py_ml (subject, *, direction="south", style="top-down game sprite, RPG", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN sprite en vista CENITAL (top-down) estilo RPG clásico/roguelike (Zelda, juegos cenitales): personaje/objeto visto desde arriba, centrado, fondo limpio recortable a alpha ({subject}, top-down view, overhead view, {direction} facing, {style}, centered, plain background, game asset…) → txt2img cuadrado + LoRA estilo opcional + Rembg (alpha). direction (south/north/east/west) para el sprite de movimiento: las 4 vistas del MISMO personaje = misma subject/style/seed, varía solo direction → montar con comfyui_build_grid. DISTINTO de sprite_sheet (vista lateral/frontal de plataformas): el negativo por defecto rechaza side/front/3-4/isometric/perspective para forzar la cenital. Con SD1.5 sin LoRA sale picado alto; cenital estricto pide LoRA top-down + cfg alto. Probado e2e en GPU con SD1.5 (reports/0156). SD1.5.
comfyui_build_splash_art_workflow_py_ml (scene, *, mood="epic, cinematic", checkpoint="juggernaut_xl_v11…", width=1024, height=576, hires=True, seed=0, lora=None, …) -> dict LA ilustración grande de UN splash / pantalla de carga / key art en formato pantalla apaisado 16:9 (width>height, ~1024×576), composición cinematográfica ({scene}, {mood}, key art, game splash screen, dramatic lighting, cinematic composition, wide shot, epic scale, atmospheric…). hires=True → 2ª pasada de detalle (comfyui_build_hires_fix_workflow) para verse a pantalla completa; si no, txt2img + LoRA estilo opcional. Genera SOLO la ilustración — el título/logo/barra de carga los pone el motor/post (negativo rechaza text/title/logo/UI/frame/watermark), dejando aire para superponer el título. Set coherente = mismo mood/checkpoint/lora, varía solo scene. Probado e2e en GPU con SD1.5 + hires (1024×576 → 1536×864, 54s, reports/0159). SD1.5/SDXL.
comfyui_build_world_map_workflow_py_ml (region, *, map_style="fantasy cartography, aged parchment", checkpoint="juggernaut_xl_v11…", width=768, height=768, hires=False, seed=0, lora=None, …) -> dict LA ilustración de la pantalla de mapa del juego: una lámina cartográfica en vista cenital de un continente/región/reino/mazmorra con aspecto de atlas fantasy (map of {region}, {map_style}, top-down cartographic view, illustrated game world map, labeled regions, decorative border, compass rose, fantasy atlas, no people…). Cuadrado por defecto (768×768; sube width para mundo apaisado, height para mazmorra en columna), hires=False por defecto (ponlo True para detalle fino de costas/relieve). Genera SOLO la ilustración — las marcas interactivas, los iconos pinchables, las rutas y el "estás aquí" los pone el motor SOBRE la lámina; la difusión dibuja labels/ornamentos DECORATIVOS pero NO garantiza ortografía ni posiciones usables como datos (el negativo rechaza photo/3d render/perspective/character/person para mantener la vista cenital plana). Atlas coherente = mismo map_style/checkpoint/lora, varía solo region. Probado e2e en GPU con SD1.5 — reino fantasy 768×768, lámina de pergamino con costas/montañas/regiones + borde ornamental + rosa de los vientos (prompt_id bf4861fc, reports/0167). SD1.5/SDXL.
comfyui_build_decal_overlay_workflow_py_ml (decal, *, on_black=True, style="grunge decal, high detail", checkpoint="dreamshaper_8…", size=512, seed=0, lora=None, …) -> dict UN decal/overlay con alpha para superponer sobre superficies/paredes/sprites con blend mode del motor (sangre, grietas, suciedad, óxido, quemaduras, salpicaduras, arañazos, musgo): textura aislada sobre fondo PLANO ({decal}, {style}, single isolated decal, centered, on a solid pure black background, flat backdrop, sticker, no scenery, texture overlay, game asset…) → txt2img cuadrado + LoRA estilo opcional. on_black=True (defecto) pensado para extraer alpha con comfyui_matting_luma_to_alpha (luma=alpha, conserva el falloff de translúcidos — la técnica gamedev correcta, ≠ recorte binario). NO inyecta Rembg (el matting es luma→alpha de disco, no un nodo): el SaveImage sale directo del VAEDecode. Set coherente = mismo style/checkpoint/lora, varía solo decal/seed. ⚠️ "grunge" en style arrastra fondo gris en SD1.5 → para fondo negro plano usar un style sin connotación de fondo + reroll de seed; luma Rec601 penaliza el rojo → para sangre roja pasar luma_weights con más peso al rojo. Probado e2e en GPU con SD1.5 (reports/0160). SD1.5.
comfyui_build_projectile_workflow_py_ml (projectile, *, direction="right", glow=False, style="game projectile, side view", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN proyectil orientado (flecha, bala, bola de fuego, rayo, misil, hechizo): sprite pequeño con orientación (apunta a la derecha por defecto, ángulo 0 — el motor rota el sprite), aislado, listo para instanciar. glow elige el camino a alpha: glow=False (defecto) = proyectil SÓLIDO con silueta → plain background + Rembg (alpha por recorte, como item_icon/topdown_sprite); glow=True = brillante/mágico → glowing, on black background sin Rembg (recortaría el halo), insumo de comfyui_matting_luma_to_alpha que el caller aplica luego (como vfx_spritesheet/decal_overlay). glow=True ignora transparent/rembg_model; el negativo por defecto NO rechaza "black background". direction se inserta como pointing {direction} (""/None = sin orientación). Set coherente = mismo style/checkpoint/lora, varía solo projectile/seed. Probado e2e en GPU con SD1.5 — fireball glow sobre negro + luma→alpha RGBA (reports/0161). SD1.5.
comfyui_build_structure_workflow_py_ml (structure, *, view="isometric", style="game building", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN edificio/estructura de escenario (casa, torre, castillo, tienda, posada, ruina, muralla, puente, templo, faro): UN building COMPLETO y centrado a perspectiva de juego ({view} view, iso por defecto), fondo limpio recortable a alpha ({structure}, {view} view, {style}, full building, complete structure, single building, centered, plain background, game asset, architecture…) → txt2img cuadrado + LoRA estilo/iso opcional + Rembg (alpha). EDIFICACIÓN grande que ocupa varios tiles y define el escenario, no un objeto pequeño suelto (≠ prop_object, que es atrezzo que se deja sobre un tile); el negativo rechaza small object / single item / prop / furniture. view fija la perspectiva del mapa (iso/side/front/top-down/¾); LoRA iso fija mejor el ángulo 2:1. Set coherente = mismo view/style/checkpoint/lora, varía solo structure. Probado e2e en GPU con SD1.5 — medieval blacksmith shop iso 512×512 RGBA, edificio centrado recortado a alpha (centroide 0.54/0.53, reports/0164). SD1.5.
comfyui_build_foliage_set_workflow_py_ml (plant, *, view="side", style="game foliage, stylized", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UN elemento de vegetación/foliage de escenario (árbol, arbusto, hierba alta, flores, helecho, hongo, cactus, tronco caído, juncos, hiedra): UN elemento de naturaleza ORGÁNICA AISLADO y centrado a perspectiva de juego ({view} view, side por defecto), fondo limpio recortable a alpha ({plant}, {view} view, {style}, single plant element, centered, plain background, game nature asset, natural vegetation, organic, isolated plant…) → txt2img cuadrado + LoRA estilo opcional + Rembg (alpha). Vegetación que viste el terreno, distinta del objeto MANUFACTURADO suelto (≠ prop_object: barril/cofre/mueble) y del EDIFICIO (≠ structure: casa/torre); el negativo rechaza building / manmade object / barrel / furniture / person y multiple plants / dense forest / jungle / landscape (UN elemento, no un bosque) + pot / planter / vase (planta en maceta = prop_object). Recorte por Rembg (planta opaca de silueta definida), no luma→alpha. Set coherente = mismo view/style/checkpoint/lora, varía solo plant. ⚠️ dos gotchas reales SD1.5+Rembg: (1) plantas grandes (árbol) tienden a PAISAJE (cielo+campo) en lugar de fondo plano → re-roll de seeds buscando fondo uniforme (comfyui_batch_generate); (2) follaje verde claro sobre fondo claro → Rembg se come las hojas y deja solo tronco/ramas → preferir elementos de silueta compacta y color saturado (hongo, arbusto denso) o transparent=False + matting manual. Probado e2e en GPU con SD1.5 — golden a glowing mushroom seed 7 512×512 RGBA, hongo centrado recortado a alpha limpio (centroide 0.51/0.58, opaco 19%, prompt_id 8fb65a51); evidencia del gotcha del roble en reports/0170. SD1.5.
comfyui_build_trap_hazard_workflow_py_ml (hazard, *, view="side", style="game hazard trap", checkpoint="dreamshaper_8…", size=512, transparent=True, seed=0, lora=None, …) -> dict UNA trampa/peligro JUGABLE de nivel (pinchos del suelo, sierra giratoria, foso de lava, placa de presión, columna de llamas, trampa de flechas, charco ácido, descarga eléctrica, prensa, estaca cayendo): UN objeto de peligro AISLADO y centrado a perspectiva de juego ({view} view, side por defecto), fondo limpio recortable a alpha ({hazard}, {view} view, {style}, single hazard object, trap, dangerous, centered, plain background, game asset, high detail) → txt2img cuadrado + LoRA estilo opcional + Rembg (alpha). Peligro al que el motor asigna hitbox de daño + estado activo/inactivo, distinto del objeto INERTE de decoración (≠ prop_object: barril/cofre que solo ambienta) y del enemigo VIVO (≠ enemy_creature); el negativo rechaza character / person / creature / multiple objects para que salga el mecanismo, no un enemigo ni una escena. Recorte por Rembg (trampa sólida de silueta definida: pinchos/sierra/placa); ⚠️ para hazards puramente etéreos (columna de llamas, arco eléctrico, gas) usar transparent=False + comfyui_matting_luma_to_alpha (conserva el falloff translúcido para blend aditivo), no Rembg. view fija la perspectiva del nivel (side/top-down/iso); set coherente = mismo view/style/checkpoint/lora, varía solo hazard. Probado e2e en GPU con SD1.5 — spiked floor trap side seed 7 512×512 RGBA, mecanismo de peligro centrado recortado a alpha (alpha extrema 0255, fondo transparente real, prompt_id ab1b1560, reports/0174). SD1.5.
comfyui_build_particle_texture_workflow_py_ml (particle, *, soft=True, style="particle texture, soft glow", checkpoint="dreamshaper_8…", size=256, seed=0, lora=None, …) -> dict UNA textura de partícula individual reutilizable (chispa, humo, polvo, destello/flare, gota, copo, hoja, círculo de energía) — el "ladrillo" que el sistema de partículas del motor (Godot GPUParticles2D, Unity VFX Graph) instancia a miles y anima (spawn/fade/color over lifetime). Aislada y centrada sobre fondo NEGRO (`{particle} particle, {style}, isolated on pure black background, <soft
comfyui_build_weather_overlay_workflow_py_ml (weather, *, on_black=True, style="weather overlay, atmospheric", checkpoint="dreamshaper_8…", width=1024, height=576, seed=0, lora=None, …) -> dict UNA capa de clima/atmósfera a PANTALLA COMPLETA que cubre toda la vista del jugador y se superpone sobre la escena con blend del motor (lluvia, niebla, nieve, rayos de sol/god rays, polvo, viñeta de tormenta): cobertura uniforme de borde a borde, generada APAISADA a resolución de pantalla (16:9, 1024×576 por defecto — width>height, NO cuadrado) ({weather} overlay, {style}, full screen atmospheric layer, <particles/streaks on pure black background | translucent layer>, seamless full screen coverage, edge to edge, game VFX…) → txt2img apaisado + LoRA estilo opcional. on_black elige el modo de blend: on_black=True (defecto) = clima BRILLANTE sobre NEGRO puro (estrías de lluvia, copos, haces de luz, motas), sin Rembg, insumo de comfyui_matting_luma_to_alpha (luma=alpha, blend aditivo/screen — el negro desaparece, el clima brilla sobre la escena); on_black=False = película TRANSLÚCIDA semi-transparente (niebla densa, tinte de tormenta) para blend multiply/overlay o alpha global. El negativo rechaza solid object/single subject/character/building/landscape scene/horizon line/frame (cobertura total, NO un sujeto centrado) + (si on_black) blue sky/gray/white background para forzar negro plano. DISTINTO de decal_overlay (ése es una mancha LOCALIZADA que se pega en un punto de una superficie) y de vfx_spritesheet (ése es la SECUENCIA animada de UN efecto puntual): la capa de clima es UNA película estática de cobertura full-screen que el motor anima por scroll/loop/shader. Set coherente = mismo style/checkpoint/lora, varía weather/seed. ⚠️ algunos climas (lluvia/niebla) pintan cielo azul de fondo en SD1.5 aunque pidas negro → subir cfg + re-roll de seed; climas brillantes-sobre-negro (god rays, snow, sparks) salen más limpios que los difusos (fog). luma Rec601 penaliza el azul → para lluvia azulada ajustar luma_weights/gamma en el matting. Probado e2e en GPU con SD1.5 — heavy rain on_black seed 11 1024×576 (16:9 exacto), estrías de lluvia brillantes sobre negro plano (esquinas luma 0.00, dark 89.6%, lluvia 1.4% brillante) apto luma→alpha aditivo (prompt_id 5d2300d1, reports/0176). SD1.5/SDXL.
comfyui_build_rune_glyph_workflow_py_ml (glyph, *, glow=True, style="arcane glowing rune", checkpoint="dreamshaper_8…", size=512, seed=0, lora=None, …) -> dict UNA runa / glifo / sigilo mágico (glifos rúnicos, círculos mágicos, sigilos de invocación, inscripciones brillantes) para hechizos, portales, marcas de conjuro y efectos de magia: símbolo arcano aislado sobre fondo uniforme ({glyph}, {style}, magic symbol, single isolated glyph, centered, glowing on a solid pure black background, occult sigil, arcane inscription, no scenery, game asset…) → txt2img cuadrado + LoRA estilo opcional. glow elige el camino a alpha: glow=True (defecto) = runa BRILLANTE sobre NEGRO puro, sin Rembg (recortaría el halo del resplandor), insumo de comfyui_matting_luma_to_alpha (luma=alpha, blend aditivo en el motor — conserva el glow); glow=False = runa MATE/grabada sobre fondo plano (el negativo rechaza glow/neon/bloom), recorte/inversión por el caller. El negativo rechaza realistic text/readable words/latin alphabet (un glifo arcano, no letras reales) + fondo texturizado/niebla. DISTINTO de status_effect_icon (símbolo SÓLIDO de UI, recorte Rembg, legible a 16-32 px en el HUD): la runa es una marca translúcida que emite luz e se inscribe en el mundo. Grimorio coherente = mismo style/checkpoint/lora, varía glyph/seed. ⚠️ luma Rec601 penaliza el rojo → para runas rojas (sigilo demoníaco) pasar luma_weights con más peso al rojo + subir gamma; runas blancas/azules/doradas van con pesos por defecto. Probado e2e en GPU con SD1.5 — circular summoning rune glow seed 11 512×512, círculo de invocación brillante sobre negro puro (esquinas luma 0.00, dark 83%, runa 3.4% brillante, max 255) apto luma→alpha (prompt_id 701d149a, reports/0172). SD1.5.
comfyui_build_title_lettering_workflow_py_ml (text, *, letter_style="epic fantasy metallic", checkpoint="juggernaut_xl_v11…", width=1024, height=512, transparent=True, seed=0, lora=None, …) -> dict EL texto/logo de título de un juego (el nombre del juego o una palabra) renderizado con un tratamiento de lettering (metálico, tallado en fuego/piedra/madera, neón, cristal, oro), formato apaisado (width>height, 1024×512 por defecto), fondo plano recortable a alpha (the word "{text}" as a game logo, {letter_style} lettering, stylized typography, centered, plain background…) → txt2img apaisado + LoRA estilo opcional + Rembg (alpha). El negativo NO rechaza texto (el lettering es el sujeto) y empuja contra el ruido textual (extra letters/jumbled text/deformed letters). El VALOR es el ESTILO del lettering, NO la fidelidad tipográfica: ⚠️ la difusión renderiza texto de forma imperfecta — letras de más, deformadas o mal escritas; mitigar con palabras CORTAS en MAYÚSCULA, re-roll de seeds (comfyui_batch_generate), SDXL > SD1.5 para texto, o pintar el texto real con una fuente en el motor. Una palabra que es un objeto concreto (DRAGON) → el modelo dibuja el objeto, no las letras — usar palabras abstractas o reforzar letter_style. Marca coherente = mismo letter_style/checkpoint/lora, varía solo text. Recorte por Rembg (logo sólido), no luma→alpha. Probado e2e en GPU: DRAGON/fire engraved SD1.5 1024×512 → ilustró dragones rojos (alpha OK, confirma el gotcha de palabra-objeto, prompt_id 6f3920b7); AETHER/epic fantasy metallic SDXL 768×384 → logo de texto metálico dorado legible con ortografía imperfecta + alpha (prompt_id 2a7fe8ba, reports/0165). SD1.5/SDXL.

Funciones de post-proceso y puente (gamedev-2d, CPU)

ID Firma corta Qué hace
comfyui_pixelize_image_py_ml (src, dst, *, downscale=8, colors=16, palette=None, dither=False, upscale_back=True) -> dict Pixel-perfect: downscale nearest + cuantización a N colores o paleta fija (game-boy/pico-8/nes). Fase 2 pixelart. Impura (I/O).
comfyui_matting_luma_to_alpha_py_ml (image_path, *, out_path=None, gamma=1.0, black_point=0.0, premultiply=False, luma_weights=(.299,.587,.114)) -> dict Frame VFX sobre negro -> RGBA usando luminancia como alpha (translúcidos con additive blend). Impura (I/O).
comfyui_export_asset_to_godot_py_pipelines (asset_path, kind, godot_project, *, name=None, reimport=True, godot_bin=None) -> dict Copia el asset a res://assets/<dir>/ por kind + escribe .import + filtro Nearest si pixelart + reimport headless. Pipeline impuro.
godot_map_asset_dir_py_core (kind) -> str Mapea kind -> subcarpeta de res://assets/. Pura.
godot_clean_asset_name_py_core (filename, *, override=None) -> str Normaliza el nombre <prefijo>_NNNNN_.<ext> a snake_case seguro para res://. Pura.

Ejemplo end-to-end con builder (Fase 1 GPU → Fase 2 CPU → Godot)

Flujo completo pixel-art: construir workflow → generar en ComfyUI → pixel-perfect → Godot.

import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_build_pixelart_workflow import comfyui_build_pixelart_workflow
from ml.comfyui_submit_workflow import comfyui_submit_workflow
from ml.comfyui_wait_result import comfyui_wait_result
from ml.comfyui_fetch_output_image import comfyui_fetch_output_image
from ml.comfyui_pixelize_image import comfyui_pixelize_image

# 1. Construir (puro) + 2. generar (GPU)
wf = comfyui_build_pixelart_workflow("isometric tiny house, pixel, 32x32 style", use_lcm=True, seed=42)
pid = comfyui_submit_workflow(wf)["prompt_id"]
outs = comfyui_wait_result(pid, timeout=300)
fn = next(img["filename"] for o in outs.values() for img in o.get("images", []))
raw = comfyui_fetch_output_image(fn, dest_dir="/tmp")["out_path"]
# 3. pixel-perfect (CPU) -> 4. export Godot (ver ejemplo de abajo)
px = comfyui_pixelize_image(raw, "/tmp/house_pixel.png", downscale=8, colors=16)

VFX: comfyui_build_vfx_spritesheet_workflow(prompt, num_frames=8) → submit → fetch N frames → comfyui_matting_luma_to_alpha por frame → montar sheet RGBA con Image.alpha_composite (NO comfyui_build_grid, que aplana el alpha).

Ejemplo canónico de post-proceso

Flujo: crudo generado en ComfyUI -> pixelizar -> exportar a Godot con Nearest.

import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_pixelize_image import comfyui_pixelize_image
from ml.comfyui_matting_luma_to_alpha import comfyui_matting_luma_to_alpha
from pipelines.comfyui_export_asset_to_godot import comfyui_export_asset_to_godot

OUT = os.path.expanduser("~/ComfyUI/output")
PROJ = os.path.expanduser("~/gamedev/projects/crossy_road")

# 1. Pixelizar un sprite crudo (SDXL+pixel-art-xl) a 16 colores
px = comfyui_pixelize_image(f"{OUT}/hero_00001_.png", "/tmp/hero_pixel.png",
                            downscale=8, colors=16)

# 2. Exportarlo a Godot como pixelart (carpeta sprites/, filtro Nearest, reimport)
exp = comfyui_export_asset_to_godot("/tmp/hero_pixel.png", "pixelart", PROJ)
print(exp["dest_res_path"], exp["pixelart_filter_set"], exp["reimported"])

# Rama VFX: frame de humo sobre negro -> RGBA -> carpeta vfx/
rgba = comfyui_matting_luma_to_alpha(f"{OUT}/vfx_loop_00007_.png", gamma=1.2, black_point=0.04)
comfyui_export_asset_to_godot(rgba["out_path"], "vfx", PROJ)

Fronteras (qué NO cubre)

  • Montaje de spritesheet dedicado (grid RGBA + JSON sidecar para Godot/Unity): no hay función propia todavía — el ejemplo VFX monta con Image.alpha_composite inline. comfyui_build_grid NO sirve (aplana el alpha sobre fondo oscuro). Pendiente de R4 (plan reports/0140 F2).
  • Pipelines one-shot (build → submit → wait → fetch → post en una call) para pixelart/sprite/VFX: pendientes. Hoy se encadena a mano (ver ejemplos). Candidatos a promoción a pipeline (issue 0087) cuando el patrón se repita.
  • Sprite turnaround multi-vista (orquestar N poses con identidad fija + juez): el builder comfyui_build_sprite_sheet_workflow produce UN frame; la orquestación multi-pose es pipeline pendiente (plan reports/0137 T2).
  • Paletas lospec por red (load_lospec_palette): no incluido. pixelize usa paletas fijas embebidas (game-boy/pico-8/nes) o lista de hex, sin HTTP.
  • TileSet / SpriteFrames .tres: Godot no los deriva solos; export_asset_to_godot copia la textura y avisa, pero no genera el recurso (paso manual o futura función).

Prerequisitos / notas

  • Godot CLI para el reimport headless: autodetectado en PATH y en ~/godot/Godot_v4.7-stable_linux.x86_64. Si falta, export_asset_to_godot deja el .import escrito y lo anota (no falla).
  • Filtro Nearest (Godot 4): se setea global en project.godot (default_texture_filter=0), no por .import. La función lo asegura para pixelart.
  • CPU-only: Pillow + numpy del venv del registry. Cero VRAM, cero red.