---
name: comfyui_generate_styled_asset_oneshot
kind: pipeline
lang: py
domain: pipelines
version: "1.0.0"
purity: impure
signature: "def comfyui_generate_styled_asset_oneshot(kind: str, subject: str, style_preset: str, *, seed: int = 0, server: str = \"127.0.0.1:8188\", out_dir: str | None = None, export_godot: str | None = None, style_override: str | None = None, negative_extra: str | None = None, wait_timeout: float = 600.0, free_vram: bool = False, godot_bin: str | None = None, **builder_extra) -> dict"
description: "One-shot del grupo gamedev-2d que aplica un ESTILO curado a un asset en UNA llamada y AUTO-APLICA su post-proceso. Cierra el ultimo hueco manual del sistema de style presets (report 0190): antes habia que encadenar a mano get_gamedev_style_preset -> apply_style_preset -> despachar al builder del kind -> generar -> y llamar a mano comfyui_pixelize_image. Aqui se hace de un tiro y, para los estilos que declaran post (gameboy, pixel-art-retro), el PNG sale YA pixelizado sin paso manual. Flujo: comfyui_get_gamedev_style_preset(style_preset) -> comfyui_apply_style_preset(preset, subject) -> despacho kind->builder REUTILIZANDO el dispatch _SUPPORTED de comfyui_generate_asset_pack_oneshot -> submit/wait/fetch -> auto-post (comfyui_pixelize_image si el preset lo pide) -> export opcional a Godot (como pixelart si hubo pixelize, para fijar el filtro Nearest). Doctrina issue 0087: el registry crece promoviendo a un pipeline one-shot la composicion repetida 'elegir estilo -> aplicarlo a un kind -> generar -> post-procesar', no inflando el helper de presets ni los builders. Un kind/estilo desconocido devuelve ok=False con error claro SIN tocar la GPU. Devuelve {ok, kind, subject, style_preset, seed, prompt_id, raw_path, path, post, post_applied, size, transparent, godot_kind, exported, coherence_note, error}. Impuro: HTTP a ComfyUI + disco + (export) subprocess."
tags: [gamedev-2d, pipelines, comfyui, ml]
uses_functions: [comfyui_get_gamedev_style_preset_py_ml, comfyui_apply_style_preset_py_ml, comfyui_pixelize_image_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, comfyui_generate_asset_pack_oneshot_py_pipelines, comfyui_export_asset_to_godot_py_pipelines]
uses_types: []
returns: []
returns_optional: false
error_type: "error_py_core"
imports: [comfyui_get_gamedev_style_preset_py_ml, comfyui_apply_style_preset_py_ml, comfyui_pixelize_image_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, comfyui_generate_asset_pack_oneshot_py_pipelines, comfyui_export_asset_to_godot_py_pipelines]
tested: true
test_file_path: "python/functions/pipelines/comfyui_generate_styled_asset_oneshot_test.py"
tests: [test_unknown_kind_fails_without_network, test_unknown_style_fails_without_network, test_empty_subject_fails_without_network, test_build_only_preset_drives_workflow, test_build_only_lora_preset_injects_lora, test_catalog_has_at_least_5_styles, test_every_style_builds_a_valid_workflow, test_post_auto_applied_for_gameboy, test_no_post_keeps_raw_for_cyberpunk, test_post_failure_keeps_raw_and_flags_error, test_export_godot_uses_pixelart_when_post]
file_path: "python/functions/pipelines/comfyui_generate_styled_asset_oneshot.py"
params:
  - name: kind
    desc: "tipo de asset a generar; uno de supported_kinds() del grupo gamedev-2d (item_icon, enemy_creature, prop_object, seamless_tile, ui_hud, particle_texture, ... 26 kinds). Un kind desconocido devuelve ok=False con error claro SIN tocar la GPU."
  - name: subject
    desc: "que dibujar ('knight character', 'health potion', 'stone wall tile'). Se combina con el prefijo/sufijo del estilo. Vacio -> error sin red. Es el primer posicional."
  - name: style_preset
    desc: "nombre del estilo curado a aplicar, del catalogo de comfyui_get_gamedev_style_preset (gameboy, ghibli, pixel-art-retro, cyberpunk-neon, low-poly-flat, cartoon-cel-shaded). Insensible a mayusculas y a '_' vs '-'. Un estilo desconocido devuelve ok=False con error claro (+ lista de disponibles) SIN tocar la GPU."
  - name: seed
    desc: "semilla del KSampler para reproducibilidad. keyword-only."
  - name: server
    desc: "host:port del servidor ComfyUI; se acepta con o sin esquema (http://). keyword-only."
  - name: out_dir
    desc: "directorio local donde descargar el PNG crudo y el post-procesado; None = un dir temporal por (estilo, seed) en tempdir. keyword-only."
  - name: export_godot
    desc: "ruta de un proyecto Godot 4; si se da, el asset FINAL (ya post-procesado) se exporta a res://assets/...; si hubo pixelize se exporta como 'pixelart' (fija el filtro Nearest global). None = no exportar. keyword-only."
  - name: style_override
    desc: "sustituye el descriptor 'style' del preset (override puntual); None usa el del preset. keyword-only."
  - name: negative_extra
    desc: "negativo extra del caller; se MERGEA con el negativo del estilo (no lo reemplaza). keyword-only."
  - name: wait_timeout
    desc: "segundos maximos esperando el trabajo en ComfyUI. keyword-only."
  - name: free_vram
    desc: "si True hace POST /free ANTES de generar para liberar VRAM de tareas previas (util en 8 GB con modelos ya cargados). keyword-only."
  - name: godot_bin
    desc: "binario de Godot para el reimport headless; None autodetecta. keyword-only."
  - name: builder_extra
    desc: "kwargs extra reenviados al builder del kind: posicionales requeridos por algunos builders (p.ej. expression='angry' en emote) o passthrough que el builder admita (steps, cfg, width, height, ...). Sobreescriben la coherencia del estilo si se pasan."
output: "dict con ok (bool, True si el asset se genero y, si el estilo pedia post, el post se aplico), kind/subject/style_preset/seed (eco; subject es el combinado con el estilo), prompt_id (str, id del trabajo en ComfyUI), raw_path (PNG descargado SIN post), path (PNG FINAL entregable: post-procesado si el estilo lo pedia, si no igual a raw_path), post (spec de post del estilo, {} si no pedia), post_applied ({kind, out_path, n_colors_final, size} en exito | {kind, ok:False, error} si fallo | None si el estilo no pedia post), size (int) y transparent (bool) recomendados por el estilo, godot_kind (bucket Godot usado), exported (resultado de export a Godot o None), coherence_note (str), error (str). Un fallo de post o export se anota en error pero el crudo queda en raw_path."
---

Pipeline que aplica un estilo CURADO (gameboy, ghibli, pixel-art-retro, cyberpunk-neon,
low-poly-flat, cartoon-cel-shaded, ...) a un asset de juego de un solo tiro y, lo
importante, **auto-ejecuta el post-proceso que el estilo declara**: los estilos pixelart
(gameboy, pixel-art-retro) salen ya pixelizados del pipeline, sin tener que llamar a
`comfyui_pixelize_image` a mano. Es la pieza que cerraba el sistema de style presets del
grupo `gamedev-2d` (report 0190).

## Ejemplo

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

# Estilo CON post: el icono sale YA pixelizado (paleta Game Boy de 4 tonos), sin paso manual
res = comfyui_generate_styled_asset_oneshot(
    "item_icon", "health potion", "gameboy", seed=7, out_dir="/tmp/styled_gameboy",
)
# res["raw_path"]              -> PNG crudo de la difusion
# res["path"]                  -> PNG FINAL ya pixelizado (auto-post) — distinto del crudo
# res["post_applied"]          -> {"kind":"pixelize","n_colors_final":4, ...}

# Estilo SIN post: el mismo subject en estilo neón (path == raw_path, no se pixeliza)
res = comfyui_generate_styled_asset_oneshot(
    "enemy_creature", "street samurai", "cyberpunk-neon", seed=5, out_dir="/tmp/styled_cyber",
)

# Con export directo a un proyecto Godot 4 (pixelart -> Nearest filter global automatico)
res = comfyui_generate_styled_asset_oneshot(
    "prop_object", "treasure chest", "pixel-art-retro", seed=3,
    export_godot=os.path.expanduser("~/gamedev/projects/dungeon"),
)

# Kind que exige un posicional extra (emote.expression) -> pasarlo como kwarg
res = comfyui_generate_styled_asset_oneshot(
    "emote", "hero", "cartoon-cel-shaded", expression="angry", seed=1,
)
```

Lanzable tambien por `fn run` (despacha como pipeline Python; corre el `__main__` de demo):

```bash
./fn run comfyui_generate_styled_asset_oneshot   # demo: item_icon "health potion" estilo gameboy
```

## Cuando usarla

Usala cuando quieras UN asset concreto con un look consistente de un catalogo de estilos
ya curados, sin acordarte del checkpoint/LoRA/negativo correctos ni del post-proceso que
ese estilo necesita. Es el reemplazo one-shot de "buscar el preset -> aplicarlo al builder
-> generar -> pixelizar a mano": una sola llamada con `(kind, subject, style_preset)`. Para
un SET de assets variados que comparten un estilo libre (no de catalogo), usa
`comfyui_generate_asset_pack_oneshot`. Para las tres representaciones (2D + direccional +
3D) de UN personaje, usa `comfyui_generate_character_set_oneshot`. Para añadir un estilo
nuevo al catalogo, edita `_PRESETS` en `comfyui_get_gamedev_style_preset` (datos puros) —
este pipeline lo recoge sin tocarse.

## Gotchas

- **Auto-post = la razon de existir.** Si el estilo declara `post` (gameboy, pixel-art-retro
  traen `{"pixelize": {...}}`), el pipeline lo ejecuta sobre el PNG descargado y devuelve la
  ruta post-procesada en `path` (el crudo queda en `raw_path`). Para estilos sin post
  (ghibli, cyberpunk-neon, low-poly-flat, cartoon-cel-shaded) `path == raw_path`.
- **post + transparent son incompatibles (el post gana).** `comfyui_pixelize_image` hace
  `convert("RGB")`, que descarta el alpha. Por eso los presets con post traen
  `transparent=False` (asset opaco). No pidas un estilo con post sobre un kind donde
  necesites alpha: el pixelize aplanaria el recorte. Los estilos sin post respetan el
  `transparent` que recomienden (cyberpunk-neon False, cartoon-cel-shaded/low-poly-flat True).
- **El post elige el bucket Godot.** Si hubo pixelize, el export va como `pixelart`
  (asegura `default_texture_filter=0` Nearest en project.godot); si no, usa el bucket
  natural del builder (sprite/vfx/tileset).
- **Reutiliza el dispatch del pack.** El mapa `kind -> (godot_kind, builder)` NO se redefine
  aqui: se importa `_SUPPORTED` de `comfyui_generate_asset_pack_oneshot`, asi que los 26
  kinds soportados son exactamente los del pack (una sola fuente de verdad).
- **Un kind o estilo desconocido NO toca la GPU.** La resolucion del preset y la
  construccion del workflow (pasos 1-3) son puras y se hacen antes de encolar; un kind/estilo
  invalido devuelve `ok=False` con error claro y `prompt_id == ""`. La parte pura es
  invocable sola con `styled_asset_build_only(...)` para inspeccionar el grafo y el post sin
  generar.
- **VRAM / OOM (RTX 3070 8 GB).** Los presets nuevos usan SD1.5 (IMG_dreamshaper_8) a 512 y caben
  holgados; pixel-art-retro usa SDXL (IMG_juggernaut_xl_v11) a 768 y pica mas. Con modelos ya
  cargados de otra tarea, pasa `free_vram=True` (hace `POST /free` antes de generar) o limpia
  tu mismo (`POST http://127.0.0.1:8188/free {"unload_models":true,"free_memory":true}`). Si
  hay OOM, baja la resolucion del preset o el `size` del builder via `builder_extra`; NO se
  matan procesos.
- **Fallo aislado de post/export no borra el crudo.** Si el pixelize o el export fallan, el
  PNG crudo sigue en `raw_path` y el error se anota; `ok=False` solo si el post pedido fallo.
- **`server`** se normaliza (acepta con o sin `http://`); internamente es `host:port`.

## Capability growth log

v1.0.0 (2026-06-27) — version inicial. Promueve a un pipeline one-shot la secuencia
"elegir un style preset curado -> aplicarlo a un kind de asset -> generar -> auto-aplicar
su post-proceso" (issue 0087). Cierra el hueco #1 del sistema de style presets (report
0190): el post-proceso (pixelize) ya no se llama a mano — los estilos pixelart salen
pixelizados directos del pipeline. Reutiliza el dispatch `_SUPPORTED` del pack one-shot
para no duplicar el mapa kind->builder.
