Element Tiled Upscale
Tiled upscaling that actually uses the edit model's reference channel
- model
- vae
- image
- clip
- image
- split_images
- resampler_images
- grid
Every tiled upscaler you've used has the same flaw: denoise is doing two jobs at once. Crank it and faces drift; drop it and you get the plastic smeared look that isn't an upscale so much as a blur with extra steps. Ultimate SD Upscale, TTP, Tiled Diffusion - they all live in that 0.2–0.5 cage because the only thing anchoring a tile to the original is img2img.
Element Tiled Upscale takes a different swing. If you're running an edit model - Qwen-Image 2.1, Edit 2509/2511, FLUX.2 klein, Krea 2 - it feeds the original crop into the model's reference-latent channel instead. That reference isn't noised and doesn't decay with denoise; it's a separate signal. So you can run denoise at 0.7–1.0, let the model invent real detail, and still keep the face you started with.
Fair warning: solo-author pack, essentially no community coverage yet. You'll be reading the source when something goes weird.
How it works
Give it a model, VAE, CLIP and image. It upscales by upscale_by, plans a grid of tiles, samples each at full tile resolution, and accumulates them onto one canvas with feathered weights.
Two details make it more than a loop. Generated tiles go into a running context buffer, and the next tile's input is mixed toward it - the blend ramps in as more of that tile's neighbourhood exists. Tiles arrive knowing what their neighbours look like. The first tile has none, so redo_first_tile (on by default) resamples it once at the end. Each tile also gets a deterministic seed from seed plus its index, so runs reproduce tile-for-tile.
What to actually set
denoise matters most, and the right value depends on your model. Edit models: 0.7–1.0. SDXL, Qwen-Image-2512, plain Flux t2i: under 0.5 - the reference apparatus does nothing there, you're back to ordinary tiled img2img, and TTP or Ultimate SD Upscale will serve you just as well.
tile_size at 0 auto-picks about a quarter of your longest side, clamped to 1024–1536. Keep tiles at or under ~2MP; identity-edit LoRAs were trained around there and 1536² (2.36MP) is already over the line. Short on VRAM? Drop tile_size first.
overlap at 0 means 15% of the tile size, capped at 256px. More overlap, smoother seams, more compute. feather (default 1) is the crossfade width as a fraction of that overlap. tile_mode flips between a fixed columns × rows grid and a tile_size-driven one; fixed counts are nice when you want a predictable runtime.
reference_strength is a comma-separated ramp, one value per step - default 1.0,1.0,0.95,0.9,0.8, a hold-tight-then-loosen curve. Don't let it fall below 0.7 across the board or you'll see drift. Fewer values than steps repeats the last one.
prompt can't be empty and it goes to every tile, so write something true of any crop: "sharpen and refine, preserve identity and structure, neutral daylight". Naming objects ("woman at a desk") breaks the moment a tile is all desk.
Then steps, cfg, sampler_name, scheduler behave like a normal KSampler - though prefer a base model with a turbo LoRA at ~0.8 over a distilled turbo checkpoint: you keep the detail and dodge the high-frequency speckle turbo leaves on upscales.
reference_mode is the Krea 2 path. Off, the tile rides in as a reference latent. On, it runs Krea 2's in-context forward, which needs clip and the krea2_identity_edit LoRA. grounding_px sizes the vision slot the text encoder gets; Qwen Image 2.1 ignores it entirely, and Edit 2509/2511 reads 0 or anything ≥384 as the official 384×384 bucket.
Outputs
image is the merged result - the one you save. split_images and resampler_images hand you the source crops and generated tiles as lists, which is how you spot the one tile that went sideways. grid is what Element Tile Merge expects if you re-blend by hand.
Install
In ComfyUI Manager, search ComfyUI-Element_TileEdit - the pack was renamed from TileUpscale, so the old name may not find it. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/supElement/ComfyUI-Element_TileUpscale
Restart. No requirements.txt, and pyproject.toml declares no runtime dependencies - it all ships with ComfyUI. The only extra file is the krea2_identity_edit LoRA, and only for the Krea 2 route.
Where it bites
The node identifies your model by peeking at internals - class-name matching, tokenizer signature inspection, attribute probing. None of that is a stable API. When ComfyUI or a model shifts, it can stop detecting the reference channel and quietly degrade to plain img2img. Edits suddenly losing identity after an update? First suspect.
It's heavier than classic tiled upscaling too: every tile re-encodes its own reference latent, and with grounding every tile re-runs the text encoder's vision path. The Krea 2 in-context route is heavier still - a full DiT forward over text + source + target tokens.
And the author's own caveat: on models without reference-latent support it is not better than the incumbents. The anchor is the whole advantage. Take it away and you're paying complexity for nothing.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| vae | VAE | — | |
| image | IMAGE | — | |
| clip | CLIP | — | |
| upscale_by | FLOAT | 1.001–16 | — |
| tile_mode | BOOLEAN | true | On: grid driven by columns/rows. Off: grid driven by tile_size. |
| columns | INT | 21–16 | Tile columns across the width. |
| rows | INT | 21–16 | Tile rows down the height. |
| tile_size | INT | 00–4096 | Resolution each tile is regenerated at. 0 picks one from the output size: about four tiles along the longest side, kept between 1024 and 1536.keep each tile ≤ 2MP for identity-edit LoRAs. |
| overlap | INT | 00–2048 | How much neighbouring tiles share. 0 = auto: 15% of the tile size, capped at 256px (whichever is smaller). Any non-zero value is used as-is, with no cap. Higher = smoother seams but more compute. |
| feather | FLOAT | 1.000–1 | — |
| seed | INT | 00–18446744073709550000 | — |
| steps | INT | 81–10000 | — |
| cfg | FLOAT | 1.00–100 | — |
| sampler_name | COMBO | euler | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 |
| scheduler | COMBO | simple | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 |
| denoise | FLOAT | 1.000–1 | — |
| reference_modeopt | BOOLEAN | false | Off: tile is attached as reference latent; with 'clip'+'prompt' it also enters the text encoder's vision slot. On: Krea 2 identity-edit in-context forward, requires 'clip'. |
| redo_first_tileopt | BOOLEAN | true | After all other tiles finish, regenerate the first tile once more so it can see its finished neighbours as context. Only applies when there is more than one tile. |
| grounding_pxopt | INT | 7680–4096 | Vision-slot size for the per-tile text encode. Qwen Edit 2509/2511: area bucket, 0 or >=384 = official 384x384 resize. Qwen Image 2.1: ignored. Krea 2: caps the vision input's longest side, 0 = tile size. |
| reference_strengthopt | STRING | 1.0,1.0,0.95,0.9,0.8 | A list of reference strengths for each step, corresponding strictly to the number of steps.Supports delimiters such as commas (Chinese or English), enumeration commas (、), and colons. A single value applies to all steps; if fewer values are provided than the number of steps, the last value is repeated; if more are provided, only the initial portion is used. |
| promptopt | STRING | enhance quality preserving all the details | Positive condition; encoded tile-by-tile alongside the tile map; cannot be empty. |
| negative_promptopt | STRING | Leave blank = Encode an empty string as the baseline negative condition. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| split_images | IMAGE | — |
| resampler_images | IMAGE | — |
| grid | ELEMENT_TILE_GRID | — |