---
name: comfyui_build_decal_overlay_workflow
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_build_decal_overlay_workflow(decal: str, *, on_black: bool = True, style: str = \"grunge decal, high detail\", checkpoint: str = \"IMG_dreamshaper_8.safetensors\", size: int = 512, seed: int = 0, lora: str | None = None, lora_strength: float = 1.0, negative: str | None = None, steps: int = 28, cfg: float = 7.0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"decal_overlay\") -> dict"
description: "Construye el dict (API format) del workflow de UN decal / overlay con alpha 2D: textura aislada para superponer sobre superficies/sprites/paredes con blend mode del motor — sangre, grietas, suciedad, grunge, oxido, quemaduras, salpicaduras, arañazos, musgo. Se genera AISLADA sobre fondo uniforme; on_black=True (defecto) la pone sobre NEGRO puro, pensada para extraer alpha por luminancia con comfyui_matting_luma_to_alpha (translucido con falloff: la tecnica gamedev correcta para decals). NO inyecta Rembg (el matting de un decal es luma-to-alpha, no un nodo). Compone comfyui_build_txt2img_workflow + comfyui_inject_lora (estilo grunge opcional). Hermano de comfyui_build_seamless_tile/vfx_spritesheet_workflow. Pura, sin red ni I/O. class_types verificados contra /object_info."
tags: [comfyui, ml, gamedev-2d, decal, overlay, alpha, blood, grunge, rust, dirt, blend, luma, workflow]
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_lora_py_ml]
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: decal
    desc: "Descripcion de la textura a superponer (ej. 'blood splatter', 'wall crack', 'rust stain', 'mud splatter', 'burn mark', 'dirt grunge', 'scratch marks', 'moss patch'). Se inserta en un prompt scaffold de decal aislado. No puede estar vacio."
  - name: on_black
    desc: "Si True (defecto) genera el decal sobre fondo NEGRO puro, pensado para extraer alpha por luminancia con comfyui_matting_luma_to_alpha (translucido con falloff suave: sangre, humo, salpicadura). False = fondo BLANCO (decals oscuros sobre superficies claras, o recorte/inversion por el caller). keyword-only."
  - name: style
    desc: "Descriptor de estilo del decal (ej. 'grunge decal, high detail', 'stylized blood, painterly', 'photorealistic rust', 'cartoon crack'). Pasa el MISMO style + checkpoint + lora a todos los decals de un set para coherencia visual. keyword-only."
  - name: checkpoint
    desc: "Checkpoint del servidor. 'IMG_dreamshaper_8.safetensors' (SD1.5, holgado en 8GB lowvram) por defecto; 'IMG_juggernaut_xl_v11.safetensors' para SDXL (mas VRAM, subir size a 768/1024). keyword-only."
  - name: size
    desc: "Lado del cuadrado en px (width = height = size). 512 SD1.5 por defecto. keyword-only."
  - name: seed
    desc: "Semilla del KSampler. Misma seed + mismos decal/style -> misma textura; variar seed da variantes del mismo tipo de decal. keyword-only."
  - name: lora
    desc: "LoRA de estilo opcional en models/loras (ej. grunge/sangre/oxido). None = sin LoRA. keyword-only."
  - name: lora_strength
    desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
  - name: negative
    desc: "Prompt negativo. None usa el negativo por defecto pensado para un decal aislado (textura plana sin objetos/escena/profundidad/marco que delaten una composicion). keyword-only."
  - name: steps
    desc: "Pasos del KSampler. keyword-only."
  - name: cfg
    desc: "CFG del KSampler. keyword-only."
  - name: sampler_name
    desc: "Sampler del KSampler. keyword-only."
  - name: scheduler
    desc: "Scheduler del KSampler. keyword-only."
  - name: filename_prefix
    desc: "Prefijo del PNG en output/. keyword-only."
output: "dict en API format listo para comfyui_submit_workflow: base txt2img cuadrada con prompt scaffold de decal ('{decal}, {style}, single isolated decal, centered, on a solid pure black|white background, flat ... backdrop, sticker, ...') + el negativo refuerza fondo PLANO (rechaza fondo texturizado/grunge/del color contrario) + LoRA de estilo opcional. NO lleva Rembg: con on_black=True el PNG resultante se convierte a RGBA con comfyui_matting_luma_to_alpha (luma=alpha) en un paso posterior. UN decal; variar seed da variantes del mismo tipo."
file_path: python/functions/ml/comfyui_build_decal_overlay_workflow.py
tested: true
test_file_path: python/functions/ml/comfyui_build_decal_overlay_workflow_test.py
tests: [test_golden_decal_on_black_recipe, test_edge_on_black_toggles_background, test_edge_decal_reflected, test_edge_style_in_prompt, test_edge_size_reflected, test_edge_negative_isolates_decal, test_edge_lora_reflected, test_error_empty_decal, test_determinism]
---

Construye el dict (API format) del workflow de UN decal / overlay con alpha 2D: una
textura que se SUPERPONE sobre una superficie del juego con un blend mode del motor
(sangre, grietas, suciedad, grunge, oxido, quemaduras, salpicaduras, arañazos, musgo,
polvo). La pieza se genera AISLADA sobre un fondo uniforme para poder extraer luego el
canal alpha. Es el builder hermano de `comfyui_build_seamless_tile_workflow` /
`comfyui_build_vfx_spritesheet_workflow`: mismo patron PURO (dict API format) que
compone funciones existentes del registry sin reescribir el grafo.

## Cuando usarla

Cuando necesites texturas de superposicion para dar desgaste/daño/suciedad a un nivel:
manchas de sangre sobre el suelo o paredes, grietas en piedra, oxido en metal, barro en
una superficie, quemaduras, salpicaduras, arañazos. El decal se genera aislado y se
extrae su alpha para componerlo en el motor con un blend mode (multiply, additive,
overlay) encima del sprite/tile/pared base.

Flujo tipico despues de generar:

1. `comfyui_build_decal_overlay_workflow("blood splatter", on_black=True)` -> dict.
2. `comfyui_submit_workflow` -> `comfyui_wait_result` -> `comfyui_fetch_output_image`
   (PNG del decal sobre negro).
3. `comfyui_matting_luma_to_alpha(png, gamma=..., black_point=...)` -> PNG RGBA donde
   la luminancia ES el alpha: brillante=opaco, negro=transparente. Listo para el motor.

Pasa el MISMO `style` + `checkpoint` + (`lora`) a todos los decals de un set para que
combinen; varia `seed` para sacar variantes del mismo tipo (varias manchas de sangre
distintas).

**Elige este builder y NO `comfyui_build_prop_object_workflow` / `item_icon` cuando** lo
que quieres es una TEXTURA que se superpone (con falloff translucido), no un objeto
solido con silueta. Un prop/item es un sujeto recortable con Rembg; un decal es una
mancha/grunge cuyo alpha sale de la luminancia.

## Gotchas

- **on_black=True esta pensado para luma->alpha, no es opcional de adorno**: el decal se
  genera sobre NEGRO puro precisamente para que `comfyui_matting_luma_to_alpha` mapee la
  luminancia a alpha y conserve el degradado de los bordes (sangre, salpicadura, humo).
  Si extraes el alpha con un matting binario (rembg) pierdes el falloff y el decal queda
  con borde duro recortado. Para decals oscuros sobre superficie clara, usa
  `on_black=False` (fondo blanco) e invierte/recorta segun tu motor.
- **NO inyecta Rembg a proposito**: a diferencia de los builders de sprite/prop/item,
  este NO lleva 'Image Rembg (Remove Background)'. El SaveImage toma directo del
  VAEDecode (decal sobre fondo uniforme) y el matting es un paso posterior de disco.
- **Es una funcion pura**: solo arma el dict. La generacion real (GPU) la hacen
  `comfyui_submit_workflow` + `comfyui_wait_result` + `comfyui_fetch_output_image`; el
  alpha lo hace `comfyui_matting_luma_to_alpha`.
- **El fondo debe quedar PLANO**: si el modelo mete una escena/objeto/profundidad detras
  del decal, el alpha por luminancia recogera basura. El positivo fuerza "solid pure
  black/white background, flat backdrop, sticker, no scenery" y el negativo rechaza
  '3d render, object, scene, depth, vignette, frame, border' MAS el fondo texturizado/del
  color contrario (gray/grunge/white background cuando on_black=True). Si aun asi sale
  ruido de fondo, sube `cfg`.
- **"grunge" en el `style` tiende a llenar el fondo (aprendido en la prueba real)**: con
  SD1.5 (IMG_dreamshaper_8) un style que contenga "grunge" hace que el modelo pinte una
  TEXTURA de fondo gris/disco que arruina el fondo negro plano. Para un decal limpio sobre
  negro, prefiere un style que describa SOLO el decal sin connotacion de fondo (ej.
  "splatter decal, glossy red blood, high detail" en vez de "grunge decal") y haz reroll de
  `seed`: en el barrido de la prueba la seed 11 dio fondo negro plano (esquinas luma ~0.07,
  63% de pixeles oscuros) mientras otras seeds metian un disco gris.
- **luma->alpha penaliza el rojo (sangre)**: la luminancia Rec601 pesa el rojo a 0.299, asi
  que una salpicadura de sangre ROJA sobre negro sale semi-transparente con los pesos por
  defecto. Para que la sangre quede mas opaca, pasa a `comfyui_matting_luma_to_alpha` unos
  `luma_weights` con mas peso al rojo (ej. (0.6, 0.25, 0.15) o (1, 0, 0) = canal rojo puro)
  y sube `gamma`. Es ajuste del paso de matting (caller), no del builder. Para efectos
  BRILLANTES (humo blanco, fuego, destello) los pesos por defecto van perfectos.
- **SDXL pide mas VRAM y resolucion**: con `checkpoint="IMG_juggernaut_xl_v11.safetensors"`
  sube `size` a 768/1024; con IMG_dreamshaper_8 (SD1.5) deja 512 (holgado en 8GB lowvram).
  Si hay OOM, baja `size` o usa SD1.5.

## Ejemplo

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

# Un decal de sangre sobre fondo negro, listo para submit + luma-to-alpha.
wf = comfyui_build_decal_overlay_workflow(
    "blood splatter",
    on_black=True,
    style="grunge decal, high detail",
    seed=7,
)
# Pipeline completo de un decal con alpha:
#   r = comfyui_submit_workflow(wf); comfyui_wait_result(r["prompt_id"])
#   png = comfyui_fetch_output_image(...)            # decal sobre negro
#   rgba = comfyui_matting_luma_to_alpha(png, gamma=1.2, black_point=0.05)  # luma=alpha
# Variantes del mismo tipo: misma decal/style, cambia seed.
#   for s in range(4):
#       wf = comfyui_build_decal_overlay_workflow("blood splatter", seed=s)
```

O lanzable directo con: `./fn run comfyui_build_decal_overlay_workflow` (imprime nodos + class_types del ejemplo).
