---
name: comfyui_generate_asset_pack_oneshot
kind: pipeline
lang: py
domain: pipelines
version: "1.0.0"
purity: impure
signature: "def comfyui_generate_asset_pack_oneshot(pack: list, *, checkpoint: str = \"IMG_dreamshaper_8.safetensors\", style: str = \"\", lora: str | None = None, lora_strength: float = 1.0, base_seed: int = 0, size: int | None = None, server: str = \"127.0.0.1:8188\", export_godot: str | None = None, out_dir: str | None = None, wait_timeout: float = 600.0, godot_bin: str | None = None) -> dict"
description: "One-shot del grupo gamedev-2d: recibe una spec de pack (lista de assets, cada uno con kind + subject) y genera el set 2D ENTERO de un juego compartiendo el MISMO checkpoint, el MISMO LoRA de estilo, un estilo comun (concatenado al subject de cada asset) y una semilla derivada (seed = base_seed + indice), de modo que sprite + iconos + tiles + UI peguen entre si (misma mano, misma paleta, mismo modelo). Despacha cada kind a su builder atomico del registry (item_icon, enemy_creature, prop_object, seamless_tile, ui_hud, particle_texture, ... 26 kinds), encola con comfyui_submit_workflow, espera con comfyui_wait_result, descarga el PNG con comfyui_fetch_output_image y (si export_godot) exporta cada asset al proyecto Godot con comfyui_export_asset_to_godot. Promueve a UNA llamada la composicion repetida 'llamar N builders con el mismo estilo' (issue 0087): el registry no crece inflando builders, crece promoviendo composiciones a pipelines. Un fallo aislado (p.ej. OOM en un asset) NO aborta el resto. Devuelve {ok, pack_dir, checkpoint, style, lora, base_seed, coherence_note, count, generated, failed, assets, error}. Impuro: HTTP a ComfyUI + disco + (export) subprocess."
tags: [gamedev-2d, pipelines, comfyui, ml, godot]
uses_functions: [comfyui_build_achievement_badge_workflow_py_ml, comfyui_build_card_art_workflow_py_ml, comfyui_build_decal_overlay_workflow_py_ml, comfyui_build_dialogue_box_workflow_py_ml, comfyui_build_emote_workflow_py_ml, comfyui_build_enemy_creature_workflow_py_ml, comfyui_build_foliage_set_workflow_py_ml, comfyui_build_item_icon_workflow_py_ml, comfyui_build_parallax_background_workflow_py_ml, comfyui_build_particle_texture_workflow_py_ml, comfyui_build_portrait_avatar_workflow_py_ml, comfyui_build_projectile_workflow_py_ml, comfyui_build_prop_object_workflow_py_ml, comfyui_build_rune_glyph_workflow_py_ml, comfyui_build_seamless_tile_workflow_py_ml, comfyui_build_skill_tree_node_workflow_py_ml, comfyui_build_splash_art_workflow_py_ml, comfyui_build_status_effect_icon_workflow_py_ml, comfyui_build_structure_workflow_py_ml, comfyui_build_title_lettering_workflow_py_ml, comfyui_build_topdown_sprite_workflow_py_ml, comfyui_build_trap_hazard_workflow_py_ml, comfyui_build_ui_hud_workflow_py_ml, comfyui_build_vehicle_mount_workflow_py_ml, comfyui_build_weather_overlay_workflow_py_ml, comfyui_build_world_map_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, comfyui_export_asset_to_godot_py_pipelines]
uses_types: []
returns: []
returns_optional: false
error_type: "error_py_core"
imports: [comfyui_build_item_icon_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, comfyui_export_asset_to_godot_py_pipelines]
tested: true
test_file_path: "python/functions/pipelines/comfyui_generate_asset_pack_oneshot_test.py"
tests: [test_dispatch_shares_checkpoint_and_seed, test_seed_is_base_plus_index, test_godot_kind_per_category, test_emote_requires_expression, test_per_item_kwargs_passthrough, test_unknown_kind_fails_without_network, test_empty_pack, test_full_flow_mocked, test_one_asset_fails_others_survive]
file_path: "python/functions/pipelines/comfyui_generate_asset_pack_oneshot.py"
params:
  - name: pack
    desc: "lista de assets. Cada item es un dict con kind (uno de los 26 soportados) + subject (que dibujar). Campos extra se reenvian como kwargs al builder si los admite (p.ej. tier para achievement_badge, expression obligatorio para emote, view/direction/glow/transparent/negative segun el kind)."
  - name: checkpoint
    desc: "modelo base COMPARTIDO por todos los assets del pack. keyword-only."
  - name: style
    desc: "estilo comun concatenado al subject de cada asset (la firma visual del pack, p.ej. 'dark fantasy, hand-painted'). El style categorico propio de cada builder se conserva. keyword-only."
  - name: lora
    desc: "LoRA de estilo COMPARTIDO; solo se aplica a builders con un param 'lora' generico (no pisa LoRAs funcionales como el de isometric/pixelart). keyword-only."
  - name: lora_strength
    desc: "fuerza del LoRA comun. keyword-only."
  - name: base_seed
    desc: "semilla base; el asset i usa seed = base_seed + i (reproducible y variado). keyword-only."
  - name: size
    desc: "resolucion cuadrada comun para builders que aceptan 'size' (icons/sprites); None deja el default de cada builder. Util para bajar VRAM (p.ej. 512 con SD1.5). keyword-only."
  - name: server
    desc: "host:port del servidor ComfyUI; se acepta con o sin esquema (http://). keyword-only."
  - name: export_godot
    desc: "ruta raiz de un proyecto Godot 4; si se da, cada asset se exporta a res://assets/... con su .import (reimport headless una sola vez al final). None = no exportar. keyword-only."
  - name: out_dir
    desc: "directorio local donde descargar los PNG; None = un dir temporal por pack (asset_pack_seed<base_seed> en tempdir). keyword-only."
  - name: wait_timeout
    desc: "segundos maximos esperando cada asset en ComfyUI. keyword-only."
  - name: godot_bin
    desc: "binario de Godot para el reimport headless; None autodetecta. keyword-only."
output: "dict con ok (bool, True solo si TODOS los assets se generaron), pack_dir (str), checkpoint/style/lora/base_seed (eco de la coherencia), coherence_note (str), count/generated/failed (int), assets (list, una entrada por item: {index, kind, subject, seed, prompt_id, path, exported, ok, error}), error (str)."
---

Pipeline que genera un set COHERENTE de assets 2D para un mismo juego de un solo
tiro. Cada asset del `pack` se construye con su builder atomico de `gamedev-2d`,
pero todos comparten checkpoint, LoRA de estilo, estilo comun y una semilla
derivada — lo que hace que el set "pegue". Encola, espera y descarga cada uno, y
opcionalmente los exporta a un proyecto Godot.

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from pipelines.comfyui_generate_asset_pack_oneshot import comfyui_generate_asset_pack_oneshot

# Mini-pack coherente de 2 assets (SD1.5, 512px -> poca VRAM):
res = comfyui_generate_asset_pack_oneshot(
    [
        {"kind": "item_icon",      "subject": "magic sword"},
        {"kind": "enemy_creature", "subject": "goblin warrior"},
    ],
    checkpoint="IMG_dreamshaper_8.safetensors",
    style="dark fantasy, hand-painted",   # firma visual compartida
    base_seed=42,                          # seeds 42, 43, ...
    size=512,
    out_dir="/tmp/asset_pack_demo",
)
# res["ok"] -> True
# res["assets"][0] -> {"kind":"item_icon","seed":42,"prompt_id":"...","path":"/tmp/asset_pack_demo/item_icon_00042_.png", ...}
# res["coherence_note"] -> "Set coherente: checkpoint='IMG_dreamshaper_8.safetensors', style='dark fantasy, hand-painted', ..."

# Con export directo a un proyecto Godot 4 (cada PNG a res://assets/... + .import):
res = comfyui_generate_asset_pack_oneshot(
    [{"kind": "ui_hud", "subject": "health bar"},
     {"kind": "seamless_tile", "subject": "mossy stone floor"}],
    style="dark fantasy, hand-painted", base_seed=42, size=512,
    export_godot=os.path.expanduser("~/gamedev/projects/dungeon"),
)
```

Lanzable tambien por `fn run` (despacha como pipeline Python):

```bash
./fn run comfyui_generate_asset_pack_oneshot   # corre el __main__ de demo (2 assets)
```

## Cuando usarla

Usala cuando necesites MAS DE UN asset 2D que tengan que verse del mismo juego:
el sprite del heroe + sus iconos de inventario + los tiles del nivel + la UID del
HUD. En vez de llamar a cada builder a mano repitiendo el mismo `checkpoint`/`lora`/
`style` y acordandote de variar la seed, le pasas la spec del pack una vez y obtienes
el set entero coherente. Para UN solo asset aislado, usa directamente su builder
atomico (`comfyui_build_item_icon_workflow`, etc.) — este pipeline es para el *set*.
Si ademas quieres llevarlos a Godot sin tocar imports, pasa `export_godot`.

## Gotchas

- **Coherencia = mismo modelo + estilo en el subject.** El `style` comun se concatena
  al `subject` de cada asset (no pisa el `style` categorico propio del builder, p.ej.
  "game icon, clean, centered"). Si un item trae su propio `checkpoint`/`style` en
  los kwargs extra, ESE asset rompe la coherencia a proposito (override explicito).
- **VRAM / OOM.** Genera secuencialmente (un asset cada vez), pero cada uno carga el
  modelo. Con poca VRAM usa SD1.5 (`IMG_dreamshaper_8`) + `size=512` y packs pequenos.
  Si un asset peta por OOM, **NO** aborta el pack: ese asset queda `ok=False` con su
  `error` y el resto continua. Reduce el pack o `size`, no mates procesos. Conviene
  liberar VRAM antes: `POST http://127.0.0.1:8188/free {"unload_models":true,"free_memory":true}`.
- **`lora` comun solo en builders genericos.** Se aplica solo a builders con un param
  `lora` (la mayoria de iconos/sprites). Builders con LoRA funcional propio
  (isometric `iso_lora`, pixelart `pixel_lora`, seamless `material_lora`,
  sprite_sheet `char_lora`) NO se ven afectados — su LoRA es parte de su tecnica, no
  estilo de pack.
- **`kind` desconocido = fail-fast sin GPU.** Si algun item trae un `kind` no
  soportado, devuelve `ok=False` con la lista de kinds soportados ANTES de encolar
  nada (no malgasta GPU). Kinds: ver `supported_kinds()` (26 hoy).
- **Posicionales extra.** Algun builder pide mas que `subject` (p.ej. `emote`
  requiere `expression`). Pasalo como campo del item (`{"kind":"emote","subject":
  "hero","expression":"angry"}`); si falta, ese asset falla con error claro.
- **`server`** se normaliza (acepta con o sin `http://`). La convencion interna del
  registry es `host:port` sin esquema.
- **Export a Godot** hace el reimport headless UNA sola vez (en el ultimo asset
  exportado) para no relanzar Godot N veces. Si no encuentra el binario, deja los
  `.import` escritos y lo anota; no falla la generacion.

## Capability growth log

v1.0.0 (2026-06-27) — version inicial. Promueve la composicion "N builders gamedev-2d
con estilo/checkpoint/lora/seed compartidos" a un pipeline one-shot (issue 0087).
Despacha 26 kinds; coherencia por checkpoint + style-en-subject + lora generico +
seed = base_seed + indice; export opcional a Godot.
