Tiled Captioned KSampler
Tiled upscaling with no seam left to fix
- model
- positive
- negative
- vae
- image
- clip
- captioner
- upscale_model
- affine_schedule
- affine_options
- image
- latent
- captions
You know the drill: the picture gets bigger, the detail gets nicer, and then you spend ten minutes squinting for the grid. Tiled Captioned KSampler is the WAS Node Suite's answer - one node that takes a finished image, blows it up, and re-samples it over overlapping tiles in a single denoising pass, so the tiles blend while they're being drawn instead of being stitched afterwards.
This is the "more detail" job, not the "more pixels" job: a 1024px keeper that should be 2K, with actual texture in it. It won't rescue a soft source - that's a restorer's work.
How it actually works
The image is upscaled in pixel space first - through upscale_model if you wire one, then resized to upscale_by on whole VAE pixels - then encoded (in VAE tiles once it's past 1536×1536) and cut into a grid of overlapping latent tiles. Each tile's conditioning gets an area and a feathered blend mask, and the model is patched so every forward call runs at one tile's size. The whole grid then samples together across your entire sigma schedule, masked, and the predictions blend every step. That's why there's no seam to fix later: nothing was ever stitched.
The side effect is the good one: the model only ever reserves memory for a single tile, so a small card can produce a very large image. Tile size is your memory knob.
tiling at auto picks 512px tiles for an SD1-family model and 1024 for everything else, sharing a quarter of a tile. manual opens the tile size and overlap widgets - the setting you want when a 1024 tile OOMs, or when something shows at a very large upscale.
The inputs that matter
denoise decides whether this is a repair or a repaint, and the tooltip gives you the honest ladder: 0.2 sharpens and repairs, 0.35 (the default) adds detail, 0.6 repaints. Past 0.5 you're in did the composition change? territory. upscale_by (default 2.0) is the multiplier, and an upscale_model runs before it, so 4x-UltraSharp plus upscale_by 2 gets you a clean 8x rather than a bicubic smear.
Then the normal sampler set: model, positive, negative, vae, image, seed, steps, cfg, sampler_name, scheduler. The outputs are image, latent (for a further pass) and captions.
The captioning trick
Wire a vision model into captioner from Load CLIP - qwen3vl_8b_fp8_scaled.safetensors is the one the tooltip names - plus the model's own text encoder into clip, and each tile is prompted with a caption of what that tile actually holds, replacing the positive prompt there. prompt is context the captioner reads, and it is not sampled; style is appended to every caption.
It costs a model pass per tile, so a 4×4 grid gets noticeably slower, and per-tile captioning lands squarely on the documented weak spot of every captioner in this category: multiple subjects get attributed to the wrong body. On a single-subject image it's a genuinely better way to prompt a tile than repeating the whole-scene prompt. captions comes back one numbered line per tile.
Affine, briefly
affine at on scales and offsets the picture from inside the sampling loop, pushing grain and surface contrast in as the tiles refine. It opens affine_space and affine_acts_on, with affine_schedule and affine_options as optional dict sockets. Leave the schedule unwired and the affine ramps up over the middle of the run. Four samplers don't carry it - dpm_fast, dpm_adaptive, uni_pc, uni_pc_bh2 - and you get a console notice, not a dead run.
Installing it
Manager, search WAS Node Suite v3. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui.git
ComfyUI 0.14.0+, Python 3.10+. If your memory of this pack is from 2024, this is what changed: v3 installs nothing. requirements.txt is empty, and those old "Import Failed" threads were opencv pins fighting insightface - a class of breakage that's simply gone. First start writes config.yaml under <ComfyUI user dir>/was-node-suite/. The captioner model is your own download into ComfyUI/models/text_encoders; features.network is off by default and stays off unless you turn it on.
Where people get burned
- Nothing looks refined. With fewer than two sigma steps the node hands back the encoded image untouched, and a low denoise with few steps is easy to mistake for a no-op.
- Out of memory. That's the tile size, not your card. Manual tiling, 768 or 512.
- A faint grid at a big upscale. Raise
overlap. The other classic tile artifacts - colour drift between neighbours, a tile inventing its own window - are the divergence problem, and if you have a ControlNet wired into the positive conditioning, keep it: this node crops the control hint to each tile, which is the standard defence. - An old workflow opens with missing nodes. That's the v2 → v3 migration, not a broken install. The missing-node dialog offers the replacement.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | The model to refine with. | |
| positive | CONDITIONING | The prompt for the whole picture. With a captioner each tile takes its own caption in place of this text, keeping its other settings. | |
| negative | CONDITIONING | What every tile should avoid. | |
| vae | VAE | The VAE of the model, which encodes the picture, decodes a LATENT source and decodes the answer. | |
| image | IMAGE,LATENT | The picture to refine, as IMAGE, or a LATENT made with the VAE wired to vae; each one of a batch is sampled on its own. A LATENT at upscale_by `1.0` with no upscale model is sampled as it is, keeping its noise_mask. | |
| upscale_by | FLOAT | 2.000.25–8 | Size of the answer against the picture. `1.0` = refine at the same size; `2.0` = twice as wide and tall. The upscale model runs first where one is wired. |
| seed | INT | 00–18446744073709550000 | Seeds the noise and the captions, `0` as good as any. Captions are written again only when the seed, picture, captioner, prompt or tiling changes; set the control to `fixed` to keep them between runs. |
| steps | INT | 201–10000 | Steps over the whole schedule, as `20`, or `8` for a turbo model. |
| cfg | FLOAT | 4.50–100 | Guidance. `1.0` for a distilled model, `4.5` for most, `7.0` for SD1 and SDXL. |
| sampler_name | COMBO | euler | The algorithm the steps are taken with, as `euler` or `dpmpp_2m`. |
| scheduler | COMBO | normal | How the noise level falls across the steps, as `normal`, `simple` or `beta`. |
| denoise | FLOAT | 0.350–1 | How much of the picture is redrawn. `0.2` = sharpens and repairs; `0.35` = adds detail; `0.6` = repaints, which captions keep on subject. |
| tiling | COMBO | `auto` = tiles the size the model was trained at, 512 for SD1 and 1024 for the rest, sharing a quarter of a tile; `manual` = set the tile size and overlap. | |
| affine | COMBO | `off` = sample as it is; `on` = scale and offset the whole picture from inside the sampler's loop, which pushes texture and contrast in as the tiles refine. | |
| clipopt | CLIP | The text encoder from the loader the model came from. It encodes each tile's caption; with no captioner it is not used. | |
| captioneropt | CLIP | A vision language model from Load CLIP that writes each tile's prompt, as `qwen3vl_8b_fp8_scaled.safetensors`. Unwired, every tile takes the positive prompt. | |
| promptopt | STRING | The prompt the picture was made from, or what it shows, as `a top-down view of a space station`. The captioner reads it to name what each tile holds; it is not sampled. | |
| styleopt | STRING | Words added to the end of every tile's caption, as `oil painting, sharp focus`. | |
| upscale_modelopt | UPSCALE_MODEL | An upscale model run on the picture before it is sampled, as `4x-UltraSharp`. | |
| affine_scheduleopt | DICT | The per-step strength curve from an Affine Schedule node. Left unwired the affine ramps up over the middle of the run, from a fifth of the way in to four fifths. | |
| affine_optionsopt | DICT | Pattern parameters and mask shaping from an Affine Options node. Leave it unwired and every value takes its default. A pattern set there wins over the pattern widget. | |
| system_promptopt | STRING | You write the prompt an image model uses to repaint a crop of a larger picture. - You are shown the whole picture with its tiles ruled and numbered and the crop's tile outlined in yellow, and the crop itself at full detail. Describe only what lies inside the crop. - Name each subject and object inside the crop, largest first, including any only partly in frame. For each, say which part of it shows, where that part sits within the frame and how much of the frame it fills. For a person or animal only partly in the crop, name exactly which part of the body shows and whose it is, as the whole picture shows it. Then describe their surfaces, textures, colours and lighting, and any legible text in double quotes. - Use the whole picture and the overview only to recognise and name what the crop shows. Most of what they show lies outside the crop. Never name anything that is not inside it. - Keep the medium and style of the whole picture. - Where the crop holds only empty background, sky, water or a plain surface, name that surface and its colour in a few words. - Describe what is there directly. Write one plain paragraph of at most 60 words, with no preamble and no list. Never write the words tile, crop, overview, outlined, numbered, attached or image, and never say where the crop sits in the whole picture. | The rules each tile's caption is written under. A line such as `Name every plant species you can identify.` adds a rule. |
| stagesopt | INT | 11–8 | Passes that reach upscale_by, each enlarging by the same factor and re-captioning before it refines: `1` = one pass; `2` at upscale_by `4.0` = two 2x passes. At upscale_by `1.0` each stage refines the last one again at the same size. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | The refined pictures. |
| latent | LATENT | The refined latents, for a further pass. |
| captions | STRING | The overview and every tile's caption, one numbered line each. Empty with no captioner. |