---
name: comfyui_build_projectile_workflow
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_build_projectile_workflow(projectile: str, *, direction: str = \"right\", glow: bool = False, style: str = \"game projectile, side view\", checkpoint: str = \"IMG_dreamshaper_8.safetensors\", size: int = 512, transparent: bool = True, seed: int = 0, lora: str | None = None, lora_strength: float = 1.0, rembg_model: str = \"u2net\", negative: str | None = None, steps: int = 28, cfg: float = 7.0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"projectile\") -> dict"
description: "Construye el dict (API format) del workflow de UN proyectil orientado 2D: flecha, bala, bola de fuego, rayo, misil o hechizo — sprite pequeno con orientacion (horizontal por defecto, apuntando a la derecha), aislado sobre fondo recortable a alpha, listo para instanciar como proyectil en el motor (rotar segun el angulo de disparo). Opcion `direction` (right/left/up/down) y `glow`: glow=False (defecto) -> proyectil SOLIDO con Image Rembg para alpha; glow=True -> proyectil BRILLANTE/magico sobre fondo NEGRO sin Rembg, como insumo de comfyui_matting_luma_to_alpha (luminancia-como-alpha) que el caller aplica luego. Compone comfyui_build_txt2img_workflow + comfyui_inject_lora (estilo opcional) + Image Rembg (si solido y transparent). Hermano de comfyui_build_item_icon/topdown_sprite/vfx_spritesheet_workflow. Pura, sin red ni I/O. class_types verificados contra /object_info."
tags: [comfyui, ml, gamedev-2d, projectile, bullet, fireball, spell, vfx, rembg, luma-to-alpha, 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: projectile
    desc: "Nombre del proyectil (ej. 'arrow', 'bullet', 'fireball', 'lightning bolt', 'missile', 'magic spell'). Se inserta en un prompt scaffold de proyectil. No puede estar vacio."
  - name: direction
    desc: "Orientacion hacia la que apunta el proyectil. 'right' por defecto (apuntando a la derecha, angulo 0 — el convenio del motor que luego rota el sprite), 'left', 'up', 'down' (tambien diagonales como 'up-right'). None/'' = sin orientacion explicita. keyword-only."
  - name: glow
    desc: "Si True el proyectil es brillante/magico (bola de fuego, rayo, hechizo): scaffold 'glowing, on black background' y NO se inyecta Rembg (recortaria el halo translucido). La imagen queda sobre fondo negro como INSUMO de comfyui_matting_luma_to_alpha. glow=True ignora transparent/rembg_model. False (defecto) = proyectil solido por Rembg. keyword-only."
  - name: style
    desc: "Descriptor de estilo que mantiene consistentes los proyectiles del set (ej. 'game projectile, side view', 'hand-painted RPG projectile', 'pixel art bullet'). Pasa el MISMO style + checkpoint + lora a todos los proyectiles 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). keyword-only."
  - name: size
    desc: "Lado del cuadrado en px (width = height = size). 512 SD1.5 por defecto. keyword-only."
  - name: transparent
    desc: "Si True (y glow=False) inyecta Image Rembg y el PNG sale con alpha (silueta recortada). False = proyectil opaco sobre fondo plano, recortable luego por el caller. Ignorado cuando glow=True. keyword-only."
  - name: seed
    desc: "Semilla del KSampler. keyword-only."
  - name: lora
    desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.safetensors'). 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: rembg_model
    desc: "Modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo se usa si transparent=True y glow=False. keyword-only."
  - name: negative
    desc: "Prompt negativo. None usa el negativo por defecto pensado para proyectiles (un objeto aislado, sin escenario/personaje, sin texto/foto). No menciona 'black background' para no rechazar el fondo negro que glow necesita. 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 proyectil ('a {projectile}, {style}, pointing {direction}, isolated, single object, {plain background | glowing, on black background}, game asset, ...') + LoRA de estilo opcional. Si glow=False y transparent, ademas Image Rembg para alpha. Si glow=True, la imagen sale sobre fondo negro (insumo de comfyui_matting_luma_to_alpha). UN proyectil; un set -> llamar por proyectil con el mismo style/checkpoint/lora."
tested: true
tests: ["golden solido transparent: clases CheckpointLoaderSimple/KSampler/VAEDecode/SaveImage/Image Rembg; projectile + 'game projectile, side view' + 'pointing right' + 'isolated' + 'plain background' + 'game asset' en prompt; SaveImage <- Rembg; transparency True", "golden glow sobre negro: 'glowing, on black background' en prompt, sin 'plain background', sin Rembg, SaveImage <- VAEDecode", "glow ignora transparent: glow=True + transparent=True no inyecta Rembg", "edge direction reflejada: left/up/down/up-right aparecen como 'pointing {d}'", "edge direction opcional: sin direction no hay 'pointing'", "edge solido opaco: glow=False + transparent=False sin Rembg, SaveImage <- VAEDecode", "edge size: width==height==768 (cuadrado)", "edge style en prompt", "edge lora: LoraLoader presente con strength", "negativo por defecto permite black background (glow lo necesita)", "error projectile vacio -> ValueError", "determinismo"]
test_file_path: "python/functions/ml/comfyui_build_projectile_workflow_test.py"
file_path: "python/functions/ml/comfyui_build_projectile_workflow.py"
---

## Ejemplo

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

# Proyectil brillante (bola de fuego) apuntando a la derecha, sobre fondo negro
# como insumo de luma->alpha. Listo para submit.
wf = comfyui_build_projectile_workflow(
    "fireball",
    direction="right",
    glow=True,
    style="game projectile, side view",
    seed=42,
)
# comfyui_submit_workflow(wf) -> comfyui_wait_result -> comfyui_fetch_output_image
#   -> comfyui_matting_luma_to_alpha (brillante=opaco, negro=transparente)

# Proyectil solido (flecha) con alpha directo via Rembg:
wf2 = comfyui_build_projectile_workflow("arrow", direction="right", glow=False, transparent=True, seed=5)
```

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

## Cuando usarla

Cuando necesites el sprite de un PROYECTIL de juego — flecha, bala, bola de fuego,
rayo, misil, hechizo, plasma — orientado (apuntando a la derecha por defecto, angulo
0) y aislado para instanciar en el motor y rotar segun el angulo de disparo. Elige el
camino a alpha segun la naturaleza del proyectil:

- **`glow=False` (proyectil solido: flecha, bala, misil, espada lanzada)**: la silueta
  esta definida; con `transparent=True` se recorta limpio con Image Rembg dejando alpha.
- **`glow=True` (proyectil brillante/magico: bola de fuego, rayo, hechizo)**: el halo es
  translucido; se genera sobre fondo NEGRO y NO se recorta con Rembg. Despues aplica
  `comfyui_matting_luma_to_alpha` (luminancia-como-alpha) en un paso aparte para sacar
  el halo con transparencia gradual.

Usa `direction` para fijar hacia donde apunta el sprite si el motor no rota desde
"right". Pasa el MISMO `style` + `checkpoint` + (`lora`) a todos los proyectiles del
juego para que combinen.

## Gotchas

- **glow elige el camino a alpha**: `glow=True` NO inyecta Rembg (recortaria el halo) y
  pone el proyectil sobre fondo negro como insumo de `comfyui_matting_luma_to_alpha`.
  `glow=False` + `transparent=True` recorta la silueta solida con Rembg. No mezcles: un
  proyectil brillante recortado por silueta pierde el halo; uno solido por luma-to-alpha
  pierde las zonas oscuras del objeto.
- **glow=True ignora `transparent`/`rembg_model`**: el camino de un brillante es siempre
  luma-to-alpha, no Rembg. Esos dos parametros solo aplican a `glow=False`.
- **El negativo por defecto NO rechaza "black background"**: es deliberado, para que el
  fondo negro de `glow=True` salga. Si pasas un `negative` propio para un proyectil glow,
  NO incluyas "black background" o anularas el insumo de luma-to-alpha.
- **`direction` se inserta como "pointing {direction}"**: `direction="up"` -> "pointing up"
  en el prompt. Deja `direction=""`/None para un proyectil sin orientacion fija. El
  convenio tipico del motor es apuntar a la derecha (angulo 0) y rotar el sprite.
- **El matting/recorte es un paso aparte**: esta funcion solo arma el dict. La generacion
  real (GPU) la hacen `comfyui_submit_workflow` + `comfyui_wait_result` +
  `comfyui_fetch_output_image`; el luma-to-alpha de un proyectil glow es
  `comfyui_matting_luma_to_alpha` en un pipeline posterior.
- **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.
- Es una funcion **pura**: solo arma el dict, sin red ni I/O. Determinista para los mismos
  argumentos.
