Latent Channel Linear Transform
Glitch, Rotate, and Rearrange Features
- latent
- mask
- latent
A latent isn't a picture, it's a stack of feature maps - and most people never touch the individual channels. Latent Channel Linear Transform lets you operate on that channel dimension directly, mixing, permuting, and rotating the features before the VAE decodes them. The results range from subtle material shifts to full-blown codec glitch, all with one seed. If you've ever wanted to break a perfectly good render on purpose, this is the node.
It's one of the four operation modes on a single socket, and each one is a different kind of damage:
signed_permute- reorders channels and optionally flips their signs. Crunchy, codec-like glitches that keep the overall structure recognizable.orthogonal_rotate- mixes all channels with an energy-preserving rotation. The README calls this the one that gives smooth "style drift" in material and texture without tearing. This is usually the sweet spot: interesting but not broken.householder_reflect- reflects along one random feature direction. Can feel like a latent "photonegative" or specular inversion.low_rank_shear- measures along one direction, adds along another. Creates blooming or melting effects.
The reason the pack bothers with four modes instead of one "scramble" button is that permutation and rotation are mathematically very different. A permutation just reorders which channel is where; a rotation actually mixes energy across channels. Same seed, wildly different art direction.
What you actually set, beyond the mode:
seed- drives which channels get picked and how they transform.selection_modeand friends -allhits every channel;randompicks a seeded subset;top_varianceandtop_roughnesspick the channels that carry the most activity or texture (withselection_orderchoosing highest or lowest).indiceslets you type an explicit comma-separated list intoselection_indices.mix- your safety dial, 0 to 1. Crank it down and the transform blends with the original. This is the difference between "let me try a thing" and "I regret everything."match_stats- after the transform, re-normalize each channel's mean and standard deviation back to what it was. This keeps the edit from wrecking the latent's statistical profile, which matters if you're feeding the result back into a sampler.
There's also tile_size (per-tile permutations for localized glitches) and block_size (channels per orthogonal block) for the fiddly end of the parameter space. Skip them until you know what you're doing. Output is a single LATENT - decode it to see the damage.
Where it fits
The obvious use is aesthetic: rotate a channel mix, decode, and get a texture/color shift you can blend over a base render in img2img. It's also legitimately useful for data augmentation if you train LoRAs, and for stress-testing what a checkpoint actually encodes. Pair it with LatentChannelStatsPreview so you can see how the channel means and stds move as you drag mix - the two nodes are clearly designed to go together, and the README's own quick-start chains a rotation into the pack's swirl-noise node before decode.
Installing
This is part of the Skoogeer-Noise pack by ttulttul. One install, whole pack:
cd ComfyUI/custom_nodes
git clone https://github.com/ttulttul/Skoogeer-Noise
Restart, or grab it via ComfyUI Manager (search "Skoogeer-Noise"). Dependencies are torch, numpy>=1.26, einops, pyyaml - all usually present. No model downloads, no weights, nothing to fetch.
Gotchas
The classic beginner trap is leaving mix at 1.0, running signed_permute on everything, and getting a mess - dial mix down to 0.3–0.6 first and let the node's mask input localize the effect if you only want part of the image touched. Also, match_stats is on by default in some workflows you'll find online but off here; turn it on if your decoded output is shifting wildly in color. One honest caveat: on Flux.2's patchified 128-channel latents, channel ops hit the 2x2 patch blocks rather than true spatial neighborhoods, so unwrap with the pack's Unpatchify Flux.2 Latent first and re-patchify after.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | Latent to transform in channel-space. | |
| operation | COMBO | Linear channel-space transform to apply. | |
| seed | INT | 00–18446744073709550000 | Seed for deterministic channel selection and random transforms. |
| sign_flip_prob | FLOAT | 0.500–1 | Probability of flipping channel signs when using signed_permute. |
| tile_size | INT | 00–512 | When >0 and operation is signed_permute, apply a new permutation per tile (latent pixels). |
| block_size | INT | 00–4096 | Channels per orthogonal block. 0 means full rotation. |
| alpha | FLOAT | 0.50-4–4 | Shear strength for low_rank_shear. |
| selection_mode | COMBO | all | How to choose which channels are transformed. |
| selection_fraction | FLOAT | 1.000–1 | Fraction of channels to select when selection_count is 0. |
| selection_count | INT | 00–4096 | Exact number of channels to select (overrides selection_fraction when >0). |
| selection_order | COMBO | highest | Whether to pick high or low variance/roughness channels. |
| selection_indices | STRING | Comma-separated channel indices to select when selection_mode=indices. | |
| mix | FLOAT | 1.000–1 | Blend factor for the transformed channels (0=off, 1=full). |
| match_stats | BOOLEAN | false | Match per-channel mean/std after the transform (stabilizes latent stats). |
| maskopt | MASK | Optional mask to limit the transform to masked areas. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |