In partnership with

SnackOnAI Engineering | Senior AI Systems Researcher | Technical Deep Dive | November 11, 2026

That's not a flaw. It's the most interesting design decision in the model, inherited from VAST's TripoSplat. The same latent can be decoded into 32,768 Gaussians for a phone preview or 1,048,576 for a hero asset, without generating again. What Idol itself adds on top of TripoSplat is harder to pin down, because Speridlabs hasn't said.

The promise: by the end you'll know exactly how one photo becomes a 3D splat in Idol, where the million Gaussians actually come from, and what "Apache 2.0, runs on an RTX 3080" does and doesn't cover.

The fence: we read the full idol-sdk source (5 commits, October 29 to November 9, 2026, Apache 2.0): the denoiser, both decoders, the sampler, the conditioning and the PLY writer. We also read the README's benchmark and GPU tables, secondary coverage, and the TripoSplat paper's abstract via ChatPaper. Hugging Face model cards, arXiv and the Speridlabs and Tripo project pages couldn't be fetched from this environment. We didn't run the model. Speridlabs hasn't disclosed training data, training compute, the benchmark dataset, or what changed from TripoSplat.

What It Actually Does

Idol takes one image of an object (a photo, a render, or an AI-generated picture), removes the background, crops it to 1024×1024, and generates a 3D Gaussian splat: a cloud of small, colored, semi-transparent ellipsoids that renders as a 3D object from any angle, including the back the camera never saw.

Released

October 28, 2026 by Speridlabs, Apache 2.0 (SDK and Idol weights)

Builds on

TripoSplat (VAST + Tsinghua, MIT, May 2026)

Output

32,768 to 1,048,576 Gaussians (default 262,144), standard 3DGS .ply, plus the predicted input camera

Core models

DiT denoiser 370.6M · octree decoder 50.8M · Gaussian decoder 237.3M

Helper models

DINOv3 ViT-H+/16 840.6M · FLUX.2 VAE 84.1M · BiRefNet 220.7M

Full request

~1.80B parameters, 3.7 to 4.4 GB of weights, 7.2 GB peak VRAM

Sampler

Rectified flow, Euler, 50 steps, CFG 3.0, time shift 3.0

Speed (262,144 Gaussians)

B300 3.4 s · H100 6.7 s · RTX 4090 19.1 s · RTX 3080 46.2 s · M4 MacBook Air ~18 min

Think of a recipe and a baker. The diffusion model writes a short recipe for the object. The decoders are the baker, and you tell the baker how many pieces to cut it into. More pieces look smoother, but the recipe doesn't get any longer.

The Architecture, Unpacked

What to notice: generation ends at the 131,072-number latent. The Gaussian count N enters only at the octree decoder, so it's a decode-time choice, not a generation-time one.

Four decisions define the model, ranked by how much they matter.

One: learned density control instead of a fixed grid. TripoSplat's paper calls the representation DeG, Density-Sampled Gaussians: Gaussian centers are samples from a learned probability density over an octree. Detailed regions get more points automatically, and the same latent decodes at any budget.

Two: an ordered set of latent tokens. The 8,192 latent tokens are pinned to a fixed, scrambled 3D Sobol sequence, which TripoSplat calls VecSeq. That turns an unordered point set into a sequence a transformer can generate stably.

Three: two image encoders, summed. DINOv3 supplies semantics ("this is a boot, the other side has laces") and the FLUX.2 VAE supplies pixel-level color and texture. Their token grids line up exactly: 4,096 patches each, with 5 zero rows padding the VAE side to match DINOv3's class and register tokens.

Four: predict the camera, don't ask for it. A 5-number camera token is denoised alongside the object, so Idol infers the input view's angle, distance and field of view instead of requiring them.

The Code, Annotated

Snippet one: how a budget becomes geometry (excerpt from idol/models/decoder.py, our comments marked # SnackOnAI:).

prev_coords_int = torch.zeros(B, 1, 3, dtype=torch.long, device=device)
prev_counts = torch.full((B, 1), num_points, dtype=torch.long, device=device)  # SnackOnAI: the whole budget starts in the root cell

for l in range(1, level + 1):
    res_p = 1 << (l - 1)
    parent_coords_norm = (prev_coords_int.to(torch.float32) + 0.5) / res_p
    res_tensor = torch.full((B,), 1 << l, dtype=torch.long, device=device)
    pred_probs = torch.softmax(model(parent_coords_norm, res_tensor, cond), dim=-1)    # [B, Np, 8]
    sampled = systematic_sample(pred_probs, prev_counts).flatten(1, 2)     # ← THIS is the trick: split each cell's
                                                                           #   point COUNT among 8 children, not a yes/no
    child_coords_int = (prev_coords_int[:, :, None, :] * 2 + child_offset[None, None, :, :]).flatten(1, 2)
    mask = sampled > 0                                                     # SnackOnAI: empty space is pruned for free,
    ...                                                                    #   so cost scales with the surface, not the volume

# each point lands at a uniformly random position inside its leaf cell
coords_int = torch.repeat_interleave(prev_coords_int.flatten(0, 1), prev_counts.flatten(0, 1), dim=0)
return (coords_int.to(torch.float32) + torch.rand_like(coords_int, dtype=torch.float32)) / (1 << level)

Systematic resampling guarantees the counts add up to exactly the budget you asked for, so "262,144 Gaussians" is a promise, not an approximation. The random jitter inside each leaf is why the seed matters even after the latent is fixed.

Snippet two: one anchor, thirty-two Gaussians (excerpt, same file).

# output channels per anchor: offset (3), colour (3), scale (3), rotation (4), opacity (1), offset scale (1)
self.layout = {
    '_xyz': (3,), '_features_dc': (1, 3),         # SnackOnAI: DC colour only, no spherical harmonics
    '_scaling': (3,), '_rotation': (4,),
    '_opacity': (1,), '_offset_scale': (1,),
}
...
offset_scale = F.softplus(self._slice(features, '_offset_scale') + self.base_offset_scale)
offset = self._slice(features, '_xyz') * config['lr']['_xyz'] + self.points_offset_perturbation
offset = torch.tanh(offset) * 0.5 * config['perturbe_size'] * offset_scale   # ← THIS is the trick: each Gaussian
                                                                             #   stays within a learned radius of its anchor
raw_xyz = (offset[i] + points[i, :, None, :]).flatten(0, 1)                  # SnackOnAI: 32 children per anchor

Two consequences. Color is view-independent: with no spherical harmonics, highlights and reflections are painted on, not rendered. And tanh bounds every Gaussian near its anchor, so fine detail can never stray far from where the octree put the anchors.

Snippet three: the sampler (from idol/sampler.py).

t_seq = np.linspace(1, 0, steps + 1)
t_seq = rescale_t * t_seq / (1 + (rescale_t - 1) * t_seq)   # SnackOnAI: shift 3.0 crowds steps toward high noise,
                                                            #   where the overall shape gets decided
for i in range(steps):
    t, t_prev = t_seq[i], t_seq[i + 1]
    if cfg_strength > 0 and batch_cfg:
        both = velocity(torch.cat([sample, sample]), t, torch.cat([cond, neg_cond]))   # ← THIS is the trick:
        v = (1 + cfg_strength) * both[:n] - cfg_strength * both[n:]                    #   one batch-2 pass, not two
    ...
    sample = sample - v * (t - t_prev)                       # SnackOnAI: plain Euler on the rectified-flow velocity

Batched guidance, torch.compile, TF32 and cuDNN attention make up the "optimize" path. The coverage puts it at about 1.7x at equal quality. It's CUDA-only, which is why a Mac runs the eager path and takes minutes.

Snippet four: our arithmetic (from the code's shapes and the PLY writer's 17 float32 fields).

latent = 8192 * 16                                   # 131,072 numbers: everything the diffusion model generates
for n in (32_768, 262_144, 1_048_576):
    anchors, params = n // 32, n * 14                # 14 stored values per Gaussian (xyz, rgb, scale, rot, opacity)
    print(f"{n:>9,} Gaussians: {anchors:>6,} anchors, {params/latent:5.1f}x expansion, "
          f"PLY {n*68/1e6:5.1f} MB")                 # 17 float32 fields = 68 bytes, 3 of them zero normals
#    32,768 Gaussians:  1,024 anchors,   3.5x expansion, PLY   2.2 MB
#   262,144 Gaussians:  8,192 anchors,  28.0x expansion, PLY  17.8 MB
# 1,048,576 Gaussians: 32,768 anchors, 112.0x expansion, PLY  71.3 MB
print("DiT sequence:", 8192 + 4101 + 1, "tokens × 50 steps × 2 (CFG) = 100 passes")   # 12,294 tokens

At the maximum setting, every generated number turns into 112 stored values. The extra Gaussians add smoothness, not information the model generated.

It In Action

Input: one product photo of a hiking boot, mode="real", seed 42, default settings, on an RTX 4090.

Step one, preprocess. The short side is scaled to 1024. BiRefNet cuts out the boot. The crop takes 1.7× the bounding box (photos get more margin than renders), and the result is composited on black at 1024×1024.

Step two, encode. DINOv3 produces 4,101 tokens of 1,280 dimensions. The FLUX.2 VAE produces a 128×128×32 latent, packed into 4,096 tokens of 128 dimensions plus 5 zero rows. Both are projected to the model width and added together.

Step three, denoise. Starting from noise, 50 Euler steps run on a 12,294-token sequence, with conditional and unconditional passes batched together: 100 transformer passes. The camera token converges to the photo's predicted yaw, pitch, distance and field of view.

Step four, decode. The octree decoder distributes 8,192 anchors (262,144 ÷ 32) through the octree, and the Gaussian decoder expands each into 32 Gaussians.

Output (README numbers; file sizes are our arithmetic):

Setting

Gaussians

Anchors

PLY size

RTX 4090 time

H100 time

Preview

32,768

1,024

2.2 MB

n/a

n/a

Default

262,144

8,192

17.8 MB

19.1 s

6.7 s

Maximum

1,048,576

32,768

71.3 MB

not published

not published

request time at 262,144 Gaussians (README, median of 8 images)
 B300      ██                            3.4 s
 H100      ████                          6.7 s
 RTX 5090  ████████                     14.1 s
 RTX 4090  ███████████                  19.1 s
 RTX 3080  ███████████████████████████  46.2 s

Only the denoiser runs 100 times. At the maximum setting the decoder's self-attention covers 32,768 anchors, 16x the attention work of the default. The README publishes no timing or memory figure for that setting.

Why This Design Works (and what it trades away)

It works because density is learned, not assigned. A voxel grid spends Gaussians evenly across a bounding box. DeG's octree spends them where the rendering loss says detail matters. The paper presents its rendering-loss gradient as a differentiable stand-in for the hand-tuned densify-and-prune heuristics of classic Gaussian splatting.

It works because the latent is small and ordered. 8,192 tokens at fixed Sobol positions is a short, stable sequence for a 370M transformer. Small enough to denoise in 100 passes on a consumer GPU, structured enough to train reliably.

It works because both encoders do different jobs. DINOv3 knows what the object is and how its hidden side probably looks. The FLUX.2 VAE knows the exact colors and texture of the visible side.

It trades away view-dependent appearance. DC color only means no spherical harmonics. Metal, glass and glossy plastic look matte or have reflections baked in from the input angle. The coverage also flags thin structures and translucency as hard cases.

It trades away detail beyond the latent. A million Gaussians from 131,072 numbers is interpolation, however good. Fine text, small logos and intricate patterns on the unseen side are invented by the model, not recovered.

It trades away speed on anything but recent NVIDIA hardware. It takes 46 s on a 3080, about 18 minutes on an M4 MacBook Air at default settings, and the fast path needs CUDA and compute capability 8.0+ for cuDNN attention.

It trades away a single license. The Idol weights and SDK are Apache 2.0, but they depend on DINOv3 and a FLUX.2 VAE downloaded from gated repos.

Technical Moats

  • Mostly TripoSplat's. The representation (DeG), the token ordering (VecSeq), and the component list (BiRefNet, DINOv3 ViT-H, FLUX.2 VAE, a diffusion model, a Gaussian decoder) all match TripoSplat's published release. Idol's README says it "builds on TripoSplat."

  • Training data, if anything. Better scores on a near-identical architecture point to better data, longer training or better tuning. None of that is disclosed, so it can't be evaluated or reproduced.

  • Shipping polish is real. Clear gated-access errors, offline encoder loading, an MPS path, a T4 fallback for cuDNN attention, a 93-example demo, and community ComfyUI and MLX ports. Four outside contributors merged fixes in the first eleven days.

Contrarian Insights

One: Idol is a retrained TripoSplat with an undisclosed recipe, and the benchmark can't tell you how much better it is. Against TripoSplat, Idol's input-view gains are small: SSIM +0.014, LPIPS −0.012, IoU +0.002. Its novel-view gains are larger: DINOv2 +0.038, CLIP +0.017, sharpness distance −0.22. But the evaluation dataset, its size and its object categories aren't stated, and every model scores around 12 dB PSNR, low enough that pixel metrics barely separate them, as the README itself admits about LGM. The 6.8 s vs 9.9 s speed gap is 1.46x, about what the CUDA optimize path alone provides (around 1.7x). The speed likely comes from engineering, not the model. The README's "under 2 seconds" claim matches no row in its own tables, where the fastest result is 3.4 s on a B300.

Two: "Apache 2.0, runs on a 3080" covers about half the parameters that actually run. DINOv3 (840.6M) and the FLUX.2 VAE (84.1M) make up 51% of the 1.80B parameters in a request. Both sit in gated repos under their own terms, and the default pulls the VAE from FLUX.2-dev. The README shows a way to load the same autoencoder from another FLUX.2 repo, such as FLUX.2-klein-4B, and teams shipping commercially should read those licenses before calling the stack Apache. The 7.2 GB peak is also measured at default settings, with DINOv3 in bf16 (fp32 adds 1.7 GB), and isn't published for the 1M setting.

Surprising Takeaway

The diffusion model in a "million Gaussian" generator produces 131,072 numbers. Everything else is decoding. The Gaussian count is chosen after generation, from 32,768 to 1,048,576, and at the top setting each generated number becomes 112 stored values. That makes level of detail nearly free: generate once, then decode a light preview for the web and a dense version for offline rendering from the same latent. Fixed-grid 3D generators can't do this without generating again.

TL;DR For Engineers

  • Idol is a 0.66B core (370.6M DiT plus two decoders) that uses DINOv3 and a FLUX.2 VAE to turn one image into a 3DGS .ply. A full request is ~1.80B parameters with a 7.2 GB peak at default settings.

  • The diffusion model generates 8,192 × 16 latent values. An octree decoder then places N/32 anchors by learned density, and each anchor becomes 32 Gaussians. N is a decode-time slider.

  • Color is DC-only, so expect baked reflections and matte metals. Thin and translucent objects are hard cases.

  • The architecture is TripoSplat's (MIT, May 2026). Idol's training data, recipe and benchmark set are undisclosed, and its gains are small on input-view metrics and larger on novel views.

  • Budget for a 71.3 MB uncompressed PLY at 1M Gaussians, 46 s on a 3080, and gated access to two encoders under their own licenses.

Explain It Like I'm New

Making 3D models of real objects, for games, online shops or AR, normally takes a skilled artist hours, or a scanning rig and dozens of photos. Idol tries to do it from a single picture.

The output is a "Gaussian splat." Instead of a surface made of triangles, the object is a cloud of hundreds of thousands of tiny, fuzzy, colored blobs. Seen together from any angle, they look like a solid object. This format has become popular because it captures soft, natural-looking detail and renders fast.

The hard part is the back of the object, which the photo never showed. Idol uses a large image-understanding model that has seen enormous numbers of pictures, so it can make a reasonable guess about what the hidden side looks like, the way you can picture the back of a chair from its front.

Under the hood, Idol first writes a compact description of the object, then turns that description into blobs. You can ask for more or fewer blobs from the same description, a bit like printing one photo at different resolutions.

Tools like this are pushing 3D content creation from specialists toward anyone with a photo and a gaming graphics card.

See It In Action

  • Idol demo, Speridlabs on Hugging Face Spaces. Try it with your own image. 93 ready-made examples (furniture, food, toys, objects) plus uploads, running on ZeroGPU.

  • Idol gallery and examples, Speridlabs on GitHub. See the turntables. Input images next to the generated objects turning, a quick way to judge the unseen-side quality.

  • TripoSplat release, VAST on Hugging Face. Explore the base model. The MIT-licensed model Idol builds on, worth comparing on the same images.

We found no talk or independent video review of Idol as of November 9.

Community Conversation

  • ComfyUI Wiki, release coverage. Notes that the "under 2 seconds" claim isn't reproduced in the published tables, flags thin and translucent objects as hard cases, and points to a community ComfyUI node (Nynxz/ComfyUI-Idol).

  • AlphaSignal, via Hermes AI, launch summary. Highlights the decode-time Gaussian count ("scale from about 32,000 without retraining"), but cites a 600M DiT in one place and 370M in another. Treat the core's parameter split as the README's.

  • Runjie Yan, Yan-Pei Cao and co-authors (Tsinghua, VAST), TripoSplat paper summary. The source of DeG and VecSeq: they argue that anchoring latent tokens to a deterministic Sobol sequence turns unordered set generation into stable sequence modeling, and that one latent can be decoded at different resolutions.

  • idol-sdk contributors, commit history. Four outside fixes merged on day eleven: Apple Silicon support, local encoder loading, a cuDNN fallback for pre-Ampere GPUs, and a transformers deprecation fix. Early adoption is real, and it's concentrated on making the model run in more places.

Conclusion: A Polished Release of Someone Else's Best Idea

Idol is a well-packaged, genuinely usable image-to-3D model. One photo produces a standard splat in 19 seconds on a 4090, with a camera estimate and a Gaussian budget you choose after generation. The best ideas in it, learned octree density and Sobol-ordered latents, are TripoSplat's, and Speridlabs hasn't said what it changed, what it trained on, or what its benchmark measures. Use it when you need a decent 3D draft from a single image on hardware you own. Decode at the density your viewer can handle, expect baked reflections, check the encoder licenses, and run TripoSplat on the same images before assuming the newer model is better.

References

Summary

Idol turns one image into a 3D Gaussian splat by denoising an 8,192 × 16 latent, then decoding N/32 octree anchors into 32 Gaussians each, so the Gaussian count is chosen after generation. It runs in 19 seconds on an RTX 4090 at a 7.2 GB peak. Its architecture is TripoSplat's, and its training recipe and benchmark set are undisclosed.

Sponsored Ad If you enjoy practical AI insights, check out SnackOnAI and support the newsletter by subscribing, sharing, and exploring our sponsored ad—it helps us keep building and delivering value 🚀

Analytics on Live Data Without Leaving Postgres

When analytics on Postgres slows down, most teams add a second database. Then come the pipelines, the sync jobs, and a copy of your data that's always a little behind.

TimescaleDB takes a different approach: extend Postgres instead of splitting away from it. Hypertables partition your data automatically as volume grows. Hypercore compression cuts storage up to 95%. Continuous aggregates keep dashboards live without re-querying everything.

CERN runs Postgres this way for sensor data from the Large Hadron Collider.

No split architecture, no pipeline lag, no new query language to learn. Same SQL, same drivers, same tools.

Start on Tiger Cloud and get $1000 in credits.

Recommended for you

View all
caret-right