VAE Decoder Bridge (LRW)
The entry ticket to LRW's latent-space geometry
- vae
- latent
- metric
- latent
If you want to run any of the LRW geometry nodes on a normal image model - geodesic interpolation, parallel transport, latent trajectories - this is where the graph starts. Almost none of them will even accept a wire until you've produced a METRIC, and this bridge is the standard way to make one.
Here's the idea in one sentence: LRW treats latent space as a curved surface, and to know how curved it is at any point it needs to be able to decode a latent and measure how the output changes. The VAE Decoder Bridge takes your ComfyUI VAE, wraps its decoder in the shape LRW's PullbackMetric expects, and hands you a ready-to-use metric plus your latent back, untouched.
How it works
Under the hood it does G(z) = JᵀJ - the pullback of the decoder's Jacobian. Flatten your latent to (B, D), run it through vae.decode, and the metric describes how a tiny nudge in latent space stretches the pixels that come out. The regularization input (default 1e-5) adds a small diagonal term so the geometry stays numerically stable. You'll basically never touch it, though nudging it up is the first thing to try if a downstream solver starts wobbling.
The one thing to know before you reach for this: it is the expensive path. That Jacobian lives in a space with D = C×H×W dimensions, and this is exactly why the pack's WAN nodes exist - WAN's VAE decode isn't vmap-safe, so the WAN workflow deliberately avoids this node and uses LRW_WanTemporalMetric instead. On a small-ish SD/SDXL latent it's fine; on something huge expect a wait and some VRAM pressure.
The inputs and outputs that matter
Three inputs, one of them you care about:
vae- your model's VAE, straight from CheckpointLoader.latent- a latent from VAEEncode (or KSampler output).regularization- leave it at1e-5unless a solver complains.
Two outputs:
metric- feed this into themetricsocket ofLRW_GeodesicInterpolate,LRW_GeodesicDistance,LRW_ParallelTransport,LRW_LatentTrajectory, orLRW_LatentCurvatureMap.latent- the same latent you put in, passed through so you don't have to rewire around the node.
The source's own suggested pipeline is: CheckpointLoader → LRW_VAEDecoderBridge → LRW_GeodesicInterpolate / LRW_ParallelTransport / LRW_LatentTrajectory. If your latent already came from VAEEncode and you just want to experiment, wire that in directly.
Install
Search comfyui-lrw-nodes in ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/lajjadred/comfyui-lrw-nodes
cd comfyui-lrw-nodes
pip install -r requirements.txt
Then restart ComfyUI. The real dependency is latent-riemannian-world >= 0.3.0 (the author's core LRW package) plus torch >= 2.4; Python 3.12+ per the project config. Note the license is BSL-1.1, which is source-available rather than OSI open source - fine for personal use, worth knowing before you vendor it.
Gotchas
The pack is young and was rough around the edges at launch. An early __init__.py had an import path bug that made nodes show up as broken or "UNKNOWN" until the author pushed a fix - if you installed an early copy, git pull inside the folder and fully restart ComfyUI, and make sure you don't have two copies of the pack in custom_nodes (Manager + git clone does this). Also manage expectations: the pullback-metric "true geodesic" path is the mathematically interesting one, but for WAN video you want the lrw/wan branch, which trades that purity for something that actually fits in VRAM.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| vae | VAE | — | |
| latent | LATENT | — | |
| regularization | FLOAT | 0.00001e-8–0.1 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| metric | METRIC | — |
| latent | LATENT | — |