---
name: comfyui_build_isometric_workflow
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_build_isometric_workflow(positive: str, negative: str = \"perspective, vanishing point, blurry, low quality\", *, ckpt_name: str = \"IMG_dreamshaper_8.safetensors\", iso_lora: str = \"SD15_isometric_game_assets.safetensors\", lora_strength: float = 0.9, grid_image: str | None = None, controlnet_name: str = \"control_v11p_sd15_canny_fp16.safetensors\", controlnet_strength: float = 0.6, steps: int = 28, cfg: float = 6.0, width: int = 1024, height: int = 1024, seed: int = 0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"isometric\") -> dict"
description: "Construye el dict (API format) de un workflow ComfyUI isometrico: txt2img + LoRA isometrica (SD15_isometric_game_assets) que impone el angulo 2:1, con ControlNet grid opcional (plantilla de rejilla iso preprocesada) para reforzar el layout. Compone comfyui_build_txt2img_workflow + comfyui_inject_lora (+ comfyui_inject_controlnet si grid_image). Pura, sin red ni I/O. class_types verificados contra /object_info."
tags: [comfyui, ml, gamedev-2d, isometric, tile, workflow, stable-diffusion]
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_lora_py_ml, comfyui_inject_controlnet_py_ml]
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: positive
    desc: "Prompt del asset iso (ej. 'isometric medieval house, game asset, 2:1 projection'). No puede estar vacio."
  - name: negative
    desc: "Prompt negativo. Por defecto evita perspectiva de fuga que rompe el angulo iso."
  - name: ckpt_name
    desc: "Checkpoint base. Default 'IMG_dreamshaper_8.safetensors' (SD1.5 holgado, casa con la LoRA iso SD1.5). keyword-only."
  - name: iso_lora
    desc: "LoRA isometrica en models/loras. Default 'SD15_isometric_game_assets.safetensors'. keyword-only."
  - name: lora_strength
    desc: "Fuerza de la LoRA iso sobre model y clip (recomendado 0.9). keyword-only."
  - name: grid_image
    desc: "Nombre de una plantilla de rejilla iso ya preprocesada (line-art/canny) en input/ del servidor. Si se pasa, inyecta un ControlNet que fuerza el grid 2:1. None = solo LoRA. keyword-only."
  - name: controlnet_name
    desc: "Modelo ControlNet para el grid (default canny SD1.5; debe casar con la familia del checkpoint). keyword-only."
  - name: controlnet_strength
    desc: "Fuerza del ControlNet del grid (0..1). keyword-only."
  - name: steps
    desc: "Pasos del KSampler. keyword-only."
  - name: cfg
    desc: "CFG del KSampler. keyword-only."
  - name: width
    desc: "Ancho en px. keyword-only."
  - name: height
    desc: "Alto en px. keyword-only."
  - name: seed
    desc: "Semilla 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: txt2img base + LoraLoader (iso) y, si grid_image, una rama ControlNet (LoadImage + ControlNetLoader + ControlNetApply) que condiciona el positivo."
tested: true
tests: ["golden: 1 LoraLoader iso@0.9, sin ControlNet, KSampler dpmpp_2m/karras", "edge grid_image: ControlNetApply + ControlNetLoader (canny) + LoadImage con la plantilla", "error positive vacio -> ValueError", "determinismo"]
test_file_path: "python/functions/ml/comfyui_build_isometric_workflow_test.py"
file_path: "python/functions/ml/comfyui_build_isometric_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_isometric_workflow import comfyui_build_isometric_workflow

# Solo LoRA iso (via principal):
wf = comfyui_build_isometric_workflow(
    "isometric medieval blacksmith building, game asset, vibrant",
    seed=11,
)
# Con rejilla guia (refuerza el angulo 2:1):
wf_grid = comfyui_build_isometric_workflow(
    "isometric grass tile, game asset",
    grid_image="iso_grid_template.png",   # plantilla canny/line-art en input/
    seed=11,
)
# -> comfyui_submit_workflow + comfyui_wait_result + comfyui_fetch_output_image
```

O lanzable directo con: `./fn run comfyui_build_isometric_workflow` (imprime los node_ids de ambos ejemplos).

## Cuando usarla

Cuando necesites assets con proyección isométrica 2:1 (edificios, tiles, props
para un juego iso/top-down). La LoRA sola suele bastar; añade `grid_image` cuando
el prompt se desvíe del ángulo y quieras forzar la rejilla. Para una textura iso
*tileable*, combínala con `comfyui_build_seamless_tile_workflow`.

## Gotchas

- **Requiere la LoRA `SD15_isometric_game_assets.safetensors` en models/loras**
  (ya presente). Es SD1.5: usa un checkpoint SD1.5 (`IMG_dreamshaper_8`).
- **`comfyui_inject_controlnet` NO preprocesa**: `grid_image` debe ser una imagen
  de control ya en line-art/canny limpio. Si partes de un render, preprocésala
  antes con `CannyEdgePreprocessor`/`LineArtPreprocessor` (ya instalados).
- El ControlNet del grid usa el legacy `ControlNetApply` (solo condiciona el
  positivo) — suficiente para una rejilla guía.
- Función pura: no valida contra el server. LoRA/ControlNet ausente -> HTTP 400 al
  enviar.
