~/satyajit

WorldCrafter: skipping the reconstruction, not the 3D

mdjsonmcp

2026-09-26 · 23 min · world-models · video-generation · 3d · diffusion · open-weights · explainer

Walk a video world model around a courtyard and back to where you started, and you usually arrive somewhere else. The pavilion has a different roof. The pond moved. Nothing is wrong with any single frame; the model simply has no record of the first visit that survives the trip.

The standard fix is to give it one in 3D: estimate depth for past frames, lift them into a point cloud, and warp that cloud into the view you are about to render. WorldCrafter, from ARC Lab at Tencent with Peking University, asks the obvious question. What if you skip the reconstruction entirely?

Having read the paper and the released code, my answer is that it skips the reconstruction but not the 3D. There is no depth map, no point cloud and no warp at inference. But 3D reasoning enters twice. Once in how past frames are chosen, which is a plain geometric frustum test on camera poses. And once in what they are fed through: a memory encoder initialised from a model trained to do novel-view synthesis. What reaches the video generator is shaped, literally, like four latent frames for where the camera is about to be. In effect, a learned view renderer stands where the explicit one used to.

Four rows of generated frames with keyboard overlays. Row a, static scene: a classroom whose blackboard reads WorldCrafter beside a chalk globe, seen at 0.0 s, then exploring toward a door at 12.4 s, turning to a window at 24.8 s, and back at the blackboard at 37.1 s, with a reconstructed point cloud of the room and its camera path. Row b, dynamic scene: a tabby cat riding a robot vacuum in a living room, first visit at 0.0 s, explore, turn, and revisit at 43.5 s, plus a point cloud. Row c: a brown and white horse visible at 2.5 s, out of sight at 7.5 and 12.5 s while the camera faces a barn, and back in view at 17.5 and 23.8 s. Row d: text-to-world frames of a red balloon in an abandoned street from 0.0 to 54.0 s.
What the paper claims the memory buys: the same blackboard after 37.1 s, the same cat and room after 43.5 s, the same horse after it leaves the frame, and a text-prompted street held for 54 s. The point clouds are reconstructed from the generated video by the authors as a consistency check, not part of the model. (WorldCrafter paper, Figure 1.)

Why a revisit breaks

WorldCrafter is a chunked autoregressive video model. It generates nine latent frames (33 video frames) at a time, conditioned on a short window of what came before, then slides forward. In the paper's notation, each chunk's latent zt\mathbf{z}_t flows under a velocity predicted from the memory M\mathbf{M}, the recent frames zr\mathbf{z}^{\mathrm{r}}, the target camera trajectory C\mathbf{C} and the text y\mathbf{y}:

dztdt=vθ ⁣(zt,t∣M,zr,C,y)\frac{\mathrm{d}\mathbf{z}_{t}}{\mathrm{d}t}=\mathbf{v}_{\theta}\!\left(\mathbf{z}_{t},t\mid\mathbf{M},\mathbf{z}^{\mathrm{r}},\mathbf{C},\mathbf{y}\right)

Drop M\mathbf{M} and you have an ordinary streaming generator, of the kind ABot-World-0 runs on one desktop GPU. Its recent window is enough to keep motion continuous. It is not enough to remember a room you left a minute ago, because that room is no longer in the window.

The paper sorts the existing fixes into three families, and each has a known cost:

WorldCrafter is in the third family, with a different donor. It takes its encoder from LagerNVS, a model trained to synthesise novel views, on the argument that reconstructing an unseen view forces a representation to keep geometry and appearance. That is the whole bet.

The window, counted

Before the mechanism, the budget it has to live in. WorldCrafter's DiT is initialised from Helios-base, and its config is the familiar Wan-shaped one: 40 layers, 40 heads of 128, a 5,120-wide residual stream. Helios's window held a nine-frame noisy chunk plus a FramePack-style clean history: a compressed 16-frame segment, a 2-frame segment, the latest frame and an attention-sink frame. WorldCrafter deletes the 16-frame segment and puts memory tokens in its place, "equivalent in number to the tokens of 4 uncompressed history frames."

Counted from the shipped files, that is this:

one chunk's attention window, to scale14,640 tokens
WorldCraftermemory = latest + 8 retrieved latent frames, encoded and read out at 4 upcoming posesmemory · 4 target viewssink + latestchunk being denoisedcontext-memory ablationsame slot, filled with 4 retrieved raw frames4 retrieved framessink + latestchunk being denoised3,840240 mid history1,9208,640camera branch (UCPE) acts here onlyclean context, run at timestep 0one latent frame: 48 x 80 latent, 1 x 2 x 2 patches = 960 tokens · mid history uses 2 x 4 x 4 patchesthe memory slot is 26% of the window, whatever fills it; the ablation holds it fixedand changes only what goes in. Revisit LPIPS: 0.497 with raw frames, 0.255 with the memory encoder.token counts: my arithmetic from the shipped config and safetensors shapes · LPIPS: paper, ablation table

A 384×640 frame is a 48×80 latent; at 1×2×2 patches that is 960 tokens per latent frame. The window is 3,840 memory tokens, 240 tokens of mid history (two frames at 2×4×4 patches), 1,920 for the sink and the latest frame, and 8,640 for the chunk being denoised: 14,640 in all, with memory at 26%. Those counts are my arithmetic from transformer/config.json and the safetensors shapes of patch_memory, patch_mid and patch_short, not figures the paper states.

Two details in the code matter. The memory arrives shaped exactly like four latent frames, [16, 4, 48, 80], and enters through its own patch embedding that is initialised from the clean-history one, so the DiT first sees memory as if it were four more clean frames. And only the noisy chunk gets the camera branch; memory and history run at timestep zero and carry no camera injection.

The ablation that matters most keeps this slot fixed and changes only what fills it. Put four retrieved raw latent frames there and revisit LPIPS is 0.497. Put the memory encoder's output there and it is 0.255. Same tokens, same training schedule, half the error. Everything below is about what the encoder does with its 3,840 tokens that four raw frames cannot.

Step one: pick the past by coverage, not similarity

The memory encoder takes a fixed nine latent frames. One is always the latest frame. The other eight come from the entire history, which is never thrown away; only the encoder's input is bounded.

The usual way to pick is to rank past frames by how much their field of view overlaps the target and take the top few. WorldCrafter's select_trajectory_fov_history does something more careful. It takes the four poses the next chunk will render (latent slots 2, 4, 6 and 8), samples each one's viewing frustum as a 10×10×10 grid of points from 0.1 m to 30 m, and marks which grid points each past frame's frustum contains. Then it picks greedily:

# worldcrafter/repencoder/trajectory_fov.py (trimmed; bookkeeping removed)
covered = anchor_fov.clone()                    # the latest frame is always in
for slot in range(budget):                      # budget = 8
    resulting = covered.unsqueeze(0) | candidate_fov
    full_fairness = torch.sort(resulting.float().mean(dim=2), dim=1).values
    connected = (candidate_fov & covered.unsqueeze(0)).sum(dim=(1, 2)) > 0
    rows = torch.cat((full_fairness, frontier_ratio[:, -1:], frontier_fairness,
                      new_fov_total[:, None], new_frontier_total[:, None]), dim=1)
    eligible = available & connected
    if not eligible.any():
        eligible = available                    # "disconnected fill"
    chosen = _pick_best(rows, available=eligible, stable_values=candidates)
    covered = resulting[chosen]

The key is lexicographic, and its first four entries are the per-target coverage sorted ascending. So each pick is the frame that most raises the worst-covered upcoming view, then the next worst, and so on. After that come "frontier" terms: the part of each target view that neither the latest frame nor an earlier target in the same chunk can see, which is the part memory has to supply. Candidates must share covered points with what is already chosen unless none do, and ties go to the more recent frame.

I ported that function to a top-down toy so you can watch it choose:

which past frames reach the memory encodertoy 2D port of trajectory_fov.py
courtyard, top-down · generating chunk 17pavilionpondtreecoverage of the next four viewsshare of frustum sample points seen bythe latest frame plus eight retrieved frameslatest frame only45%similarity top-867%max-coverage (WorldCrafter)100%per target view (max-coverage)slot 2100%slot 4100%slot 6100%slot 8100%recalled from 6 distinct past chunksviews about to be generatedpoint no retrieved frame seeshistory, one cell per latent frame · the latest frame is always keptchunk 0nowgreen: slots 2, 4, 6, 8 of this chunk, the poses the memory is read out atcoloured: the eight frames retrieval picked · dark: the latest frame
A 2D port of WorldCrafter's history retrieval on a made-up walk. The percentages are this toy's geometry, not measurements of the model. Drag to the last chunk, where the camera turns back to the pavilion, and switch modes: similarity ranking spends its eight slots on near-copies of the most-overlapping views, while max-coverage keeps adding whichever frame lifts the worst-covered upcoming view.

On the last chunk of the toy walk, the camera turns back toward the pavilion from where it started. Similarity ranking spends all eight slots on the frames of the last two chunks. They overlap the upcoming views the most, and they are near-copies of each other. Max-coverage takes none of them beyond the latest frame, which is always in. It reaches back to the first two chunks, which faced the pavilion, and fills the rest from four other parts of the walk. In the toy, the union goes from 67% to 100% of the sample points. Those percentages are my toy's, not the model's. The measured version is the paper's ablation, below: swapping max-coverage for similarity ranking moves revisit LPIPS from 0.255 to 0.296.

One thing the code does not do is check occlusion. A point counts as seen if it falls inside a past frame's frustum, even with a wall in between. And the frustum is a fixed 100° by 71.13° from 0.1 m to 30 m, which matches the default camera but not every scene.

Step two: an encoder that learned 3D from view synthesis

The nine chosen latents go into a memory encoder the code calls RepEncoder. Its architecture and weights come from the LagerNVS encoder, with one surgical change: the image-processing front end is gone. A new InputLayer takes each 16×48×80 latent, un-standardises it, resizes it to 44×74 and runs a stride-2 convolution to a 22×37 grid of 1,024-wide tokens. That grid enters DINO at its third block: the patch embedding and the first two blocks are dropped, and the remaining 22 are kept. The paper's Figure 2 still labels the box "DINO layers", which is consistent with that: the shallow ones are replaced, the deep ones stay.

After DINO comes a VGGT-style backbone that alternates per-frame and cross-frame attention, with each frame's camera pose (expressed relative to the latest frame) entering as a camera token. The output is a scene representation of 814 tokens per source frame, 768 wide: 7,326 tokens for the nine frames, holding geometry and appearance without ever becoming a point cloud.

Pipeline diagram. Left, a video DiT with feed-forward, cross-attention, camera-conditioning and self-attention blocks generates the first chunk from noise. Along the top, a dashed box of history latent frames with a camera trajectory running under them; a shaded subset is labelled retrieved latent frames. These feed a memory encoder made of patch embedding, DINO layers and attention layers, which outputs a row of representation tokens. An orange box labelled current camera sends the upcoming poses into a memory readout box, which outputs memory tokens. Right, a second video DiT takes memory, recent history and noise and generates the current chunk, which is added back into the history.
The loop: retrieve past latents by camera coverage, encode them into representation tokens, read out fixed-size memory at the current camera, and denoise the next chunk with memory, recent history and noise in one sequence. The first chunk has no history and is generated from camera poses alone. (WorldCrafter paper, Figure 2.)

The parameter census, summed from the safetensors header of repencoder/model.safetensors:

partwhat it isparameters
input_layerlatent patch embedding, new148,480
dino_tail22 of DINO's 24 blocks, 1,024 wide300,237,824
vggtframe and global attention with camera tokens658,085,056
repfeaturepose-guided readout, 768 wide182,325,376
output_layer3×3×3 conv to 16 latent channels331,792
total1,141,128,528

That total matches the parameter_count the Fast package records in repencoder_frozen.json. 97,690,304 of it are unmerged rank-64 LoRA factors, which suggests the encoder was adapted with low-rank updates rather than fully fine-tuned. The paper does not say which; the file layout does. For scale, the DiT it feeds is 14,291,783,744 parameters.

Step three: read the memory out where you are going

The representation has 7,326 tokens and the DiT has room for 3,840. Something has to choose what survives. The paper compares two ways.

Pose-free readout maps the whole representation to 3,840 tokens and leaves the DiT's attention to find what is relevant. Pose-guided readout asks the representation a question: what would the scene look like from these four poses? WorldCrafter ships the second.

In code, the four query poses are the same slots 2, 4, 6 and 8 of the upcoming chunk. Each becomes a six-channel ray map at 384×640, cut into 8×8 patches: 48×80 = 3,840 query tokens per view. Nine bidirectional blocks cross-attend queries and scene tokens in both directions, a final block updates the queries, and a 3×3×3 convolution maps the result to 16 channels:

# worldcrafter/repencoder/model.py, forward_conditioned
input_features = self.input_layer(source_latents)      # [B, 9, 814, 1024]
dino_features  = self.dino_tail(input_features)
scene          = self.vggt(dino_features, source_camera_tokens)   # [B, 9, 814, 768]
target_features = self.repfeature(scene, target_rays)  # 4 target views
memory4        = self.output_layer(target_features)    # [B, 16, 4, 48, 80]

The readout is initialised from LagerNVS's shallow decoder layers, the part of LagerNVS that decodes a target view. So the memory is four latent-frame-shaped tensors, one per upcoming pose, produced by a network that began life as a view renderer. The paper is careful to say this conditions the DiT "without reconstructing target-view images", and nothing in the released code decodes memory4 or supervises it as an image. But its shape and lineage say what it is for.

The ablation says it matters. With the same inputs and the same token budget, pose-free readout gives revisit LPIPS 0.333 and rotation error 18.307; pose-guided gives 0.255 and 13.536. The authors attribute this to "a more effective allocation of the fixed memory budget to target-relevant information." A readout that knows where you are going can spend its tokens on what you will see.

Camera control, and getting to 16 fps

Camera control is a separate branch. The target trajectory gives a camera-to-world pose and intrinsics per frame. Following PRoPE, relative camera geometry enters self-attention as a positional transform, implemented as the parallel camera-attention branch from UCPE: its own query, key and value projections, added to the original attention through a zero-initialised projection. The Base package's camera_adapter.pth holds 400 BF16 tensors, ten per block across the 40 blocks, 1,050,777,600 bytes; at two bytes each that is about 525M parameters. That figure is my division, not a stated count.

Keyboard control compiles to that trajectory. The inference guide's actions are forward1, yaw_left30, pitch_up15 and so on, one action per 33-frame chunk, plus reverseN, which retraces the preceding N chunks. That is the revisit primitive, as a command.

Training is four stages, all on data whose camera poses come from Depth Anything 3 and whose captions come from Qwen2.5-VL:

stagetrainsdataiterationsGPUs, batch
1DiT, adapted to the new window760,000 Open-Sora-Plan videos5,00032, 32
2UCPE camera branch, DiT frozen40,000 filtered OSP + 6,000 DL3DVnot stated32, 128
3memory encoder, on VAE latentsDL3DV + filtered OSP5,00016, 16
4readout, encoder, DiT and camera jointlyDL3DV + filtered OSP, then MIND synthetic8,000 + 1,00032, 32

So "no depth" is true at inference and not in training: a depth model produced the pose labels the whole system learned from.

The real-time model, WorldCrafter-fast, is distilled with distribution matching over a coarse-to-fine pyramid: 3 spatial resolutions, 2 denoising steps each. It is two models. A high-noise one, distilled after the MIND synthetic data was added, runs every step but the last and keeps the subject-following that data taught. A low-noise one, distilled before it, runs the last step and keeps textures from smearing. The paper reports 16 fps on a 4-GPU machine and does not name the GPU. The repo's interactive demo is validated on a single H200 and carries the note "The interactive demo is currently being debugged."

What the numbers say

All the results are on a benchmark the authors built: 145 images (83 dynamic, object-centric scenes and 62 static ones), each with 5 metric camera trajectories, so 725 videos per method. The trajectories run 528 to 1,648 frames and include closed loops that return to earlier views. Memory is scored by comparing a revisit frame with its matched first-visit frame. Camera control is scored by recovering the trajectory from the generated video with VGGT-Ω and aligning it to the commanded one. Eight recent camera-controllable world models are compared.

revisit consistency · LPIPS (lower is better)725 videos per method · reported
WorldCrafter: 47.6% lower than Lyra 2.0WorldCrafter-fast0.186WorldCrafter0.255Lyra 2.00.487HY-WorldPlay0.515Matrix-Game 3.50.549SANA-WM0.553Alaya-EVOKE0.565Echo-WM0.582DreamX-World0.627LingBot-World 20.633
implicit 3D-aware memorydepth-based spatial memoryframes retrieved by camera similarityrecurrent state / sliding windownot described in the paper
Reported by the WorldCrafter authors on their own benchmark (arXiv:2609.24984, Figures 4 and 5). Memory families are as the paper describes each baseline. WorldCrafter-fast is the distilled model: it is the most consistent on revisits and third on every camera metric.

The paper's headline is "47.6% improvement relative to the strongest baseline". That is LPIPS: 0.487 for Lyra 2.0 against 0.255. PSNR goes from 14.050 to 18.016 dB, and MEt3R, a multi-view consistency score, from 0.334 to 0.166. On camera error the base model is first on all three metrics, though the margins there are smaller: TransErr 1.475 against Lyra's 1.538, CamMC 1.546 against 1.624.

The strongest baseline on memory is Lyra 2.0, and Lyra 2.0 reconstructs. It builds spatial memory from Depth Anything 3 depth and warps it. The other depth-based spatial memories, Alaya-EVOKE and Matrix-Game 3.5, sit mid-table. So the result is not "3D memory loses". It is that a learned memory with a view-synthesis lineage beat the best explicit one by a wide margin, on this benchmark.

And the distilled model is more consistent than the base: LPIPS 0.186 against 0.255, MEt3R 0.129 against 0.166. It is also worse on camera control, third on every camera metric. The paper does not explain the inversion. One reading, mine and untested: a model that moves the camera less than it is told, and keeps the scene stiller, has less to reconcile when it comes back.

On general video quality (VBench), WorldCrafter posts the highest overall score, by half a point:

subject consistencybackground consistencydynamic degreeoverall
WorldCrafter82.69590.58996.89381.910
WorldCrafter-fast81.36589.55996.50580.285
Alaya-EVOKE80.52288.99499.02981.406
SANA-WM79.41389.62598.83580.841

The column I would not skip is dynamic degree. The two WorldCrafter models have the two lowest scores in the table; every baseline is between 97.087 and 100.000. The gap is small, and it is the direction you would expect from a memory that pulls each chunk toward what was already there.

A grid of five columns labelled Ours, LingBot-World2, SANA-WM, Alaya-EVOKE and DreamX-World, and four rows labelled first visit, explore, revisit and point cloud. The first-visit row is the same Chinese garden pavilion over a pond in every column. In the revisit row, only the Ours column shows that pavilion again from the same angle; the others show a different pavilion, a different corridor, or a different pond. In the point-cloud row, Ours is a compact reconstruction of the garden with a coloured camera path; the others are diffuse or tangled clouds.
The same first frame, a long exploration, and a return. Only WorldCrafter's revisit is the pavilion it started from; the point clouds, reconstructed from each generated video with VGGT-Ω, show the others failing to line up. One scene chosen by the authors; the table above is the measured average. (WorldCrafter paper, Figure 3.)

Some context the numbers need. The benchmark is the authors' own, and neither it nor the evaluation code is released. Every video is resized to 640×384, which is WorldCrafter's native resolution, before scoring. Baselines run as their authors ship them: full-step models for SANA-WM (with its refiner), Lyra 2.0 and HY-WorldPlay, distilled models for the rest. That is a fair choice, but it means the table compares products, not architectures.

What each piece buys

The ablations run on the base model before distillation, one change at a time, at the same memory-token budget:

variantMEt3RLPIPSPSNRRotErrCamMC
context memory, 4 raw frames0.3820.49713.90726.5222.150
frozen memory encoder0.2270.30516.87315.4281.886
pose-free readout0.2510.33316.48618.3071.828
similarity-based retrieval0.2130.29617.12514.6571.664
WorldCrafter0.1660.25518.01613.5361.546

Every piece earns its place, and the encoder earns the most. Swapping it for raw frames costs more than any other single change, and it costs camera accuracy as well as memory: rotation error nearly doubles, from 13.536 to 26.522. Freezing the encoder in the final stage costs much less, which says the encoder is most of the way there after its warm-up on latents, and joint training closes the rest.

Three panels. a, Long-horizon memory: revisit LPIPS against revisit interval of 160, 360, 640, 960 and 1360 frames; the grey context-memory line rises steeply from about 0.27 to about 0.51, the green WorldCrafter line rises gently from about 0.22 to about 0.29. b, Joint optimization: validation LPIPS against training iterations from 0 to 8k; both start near 0.49, the frozen-encoder line flattens near 0.32, the joint line keeps falling to about 0.25. c, Memory-processing cost as horizontal latency bars: depth-based spatial memory takes 0.409 s for depth estimation and 0.937 s for warping, 1.346 s total; WorldCrafter takes 0.049 s for the memory encoder and 0.013 s for readout, 0.062 s total, annotated 21.7x faster.
(a) The gap between raw-frame memory and the learned memory widens with the distance between visits. (b) Training the encoder jointly with the DiT keeps improving where a frozen one stalls. (c) Per-chunk memory cost at 640×384, excluding VAE decoding and denoising, hardware not stated. (WorldCrafter paper, Figure 9.)

The cost panel is the other half of the argument for skipping the reconstruction. For depth-based spatial memory the authors measure 0.409 s of Depth Anything 3 depth and alignment plus 0.937 s of warping, 1.346 s per chunk. The memory encoder takes 0.049 s and the readout 0.013 s: 0.062 s, a 21.7× reduction. A chunk is 33 frames, just over two seconds of video at 16 fps. By my arithmetic on the paper's timings, depth-and-warp would use about two thirds of that before any denoising ran, and the memory encoder about 3%. The paper does not say what hardware timed either.

What ships

Code and weights are public. The paper does not state a parameter count; everything below is from the files.

The repository, at cff3e1c (24 September), has the diffusers pipeline, the memory encoder, the retrieval, the UCPE branch, an inference CLI and the keyboard demo, plus seven image-to-video and three text-to-video examples.

TencentARC/WorldCrafter-Base@d6b4731 · snapshot 2026-09-26
parameters
14.29B
repo size
59.46 GB
task
image-to-video
library
diffusers
safetensors
7 shards
largest file
9.99 GB
files
16
downloads
85
likes
7
parameters by dtype
F3214.29B
worldcraftertext-to-videocamera-control

The DiT is 14,291,783,744 parameters stored in F32 across six shards, plus a rank-128 LoRA (623,157,248 BF16 parameters) and the UCPE camera branch in a separate .pth. Base borrows the memory encoder, text encoder, VAE and scheduler from the Fast package, so it needs both downloads.

repo last modified 2026-09-22

TencentARC/WorldCrafter-Fast@51320c3 · snapshot 2026-09-26
repo size
147.20 GB
task
image-to-video
library
diffusers
safetensors
21 shards
largest file
9.99 GB
files
46
downloads
0
likes
11
worldcraftertext-to-videocamera-control

Two full F32 copies of the 14.29B DiT (high-noise and low-noise), each with its own rank-256 DMD LoRA of 1,251,737,600 BF16 parameters; the 1,141,128,528-parameter memory encoder; a 5,680,910,336-parameter UMT5 text encoder in F32; the Wan VAE.

repo last modified 2026-09-22

The sizes follow from shipping F32: 59.5 GB for Base, 147.2 GB for Fast. The model card's sampling budget is five high-noise steps and one low-noise step per chunk for image-to-video.

The licence is the constraint that matters most. WorldCrafter's own terms permit use "only for academic purposes" and forbid "any commercial or production purposes under any circumstances". The components it builds on are non-commercial anyway: VGGT-derived code under CC-BY-NC-4.0 and the LagerNVS-derived encoder under the FAIR Noncommercial Research License. Of the third-party components the licence file lists, only Helios-Base is Apache-2.0.

Not released: training code, the curated Open-Sora-Plan subsets, the 725-video benchmark and its evaluation scripts, and any ablation checkpoint. The headline tables can be read but not reproduced.

Where it breaks

The paper names two limits. Consistency "can still break down along particularly complex or extended trajectories". And re-encoding history at every chunk costs latency. The code confirms the second: the encoder runs from scratch on nine frames per chunk, with no state carried between chunks. The authors' proposed fix is a streaming encoder that folds each new chunk into the memory.

Three more, from reading the code, all reasoned rather than measured:

For a streaming world model, "3D memory" never had to mean a reconstruction. It has to mean something that can answer "what should I see from here?" quickly. WorldCrafter answers with a learned view synthesiser in latent space, chosen and queried with plain camera geometry. On the authors' benchmark, that was better and 21.7× cheaper than the depth-and-warp alternative. See also the argument for keeping world state separate from the renderer in XGEN-JING and DAO, and TencentARC's other bet on native geometry in GAE.

What would change my mind

5 claims above, and what would falsify each

  1. WorldCrafter's memory is four latent-frame-shaped tensors rendered at the next chunk's latent slots 2, 4, 6 and 8, occupying 3,840 of the DiT's 14,640 tokens per chunk.

    Read from repencoder/manifest.json (output_shape [16, 4, 48, 80], target_slots [2, 4, 6, 8]), the patch_memory, patch_mid and patch_short kernel shapes in the Base safetensors headers, and the window split in diffusers/pipeline.py. The token total is my arithmetic. A pipeline path that feeds the memory at another shape or patch size would overturn it.

  2. History retrieval maximises the worst-covered upcoming view first, not per-frame similarity, and it does no occlusion test.

    From select_trajectory_fov_history in trajectory_fov.py at cff3e1c: the lexicographic key leads with per-target coverage sorted ascending, and visibility is frustum containment only. A later commit that adds a depth or visibility test, or a different retrieval path used at inference, changes it.

  3. The memory encoder and readout are 1,141,128,528 parameters; the DiT is 14,291,783,744.

    Summed from safetensors headers fetched by HTTP range request, and matched against parameter_count in adapter_high_noise/repencoder_frozen.json. The header sum is 32 higher because it includes the input layer's latent mean and standard deviation buffers. Loading both modules and summing p.numel() would settle it.

  4. The revisit gains are real on the authors' benchmark but not independently reproduced.

    The benchmark, trajectories and evaluation code are unreleased, so every number in the results section is reported, not measured. A third-party run on a public revisit benchmark, with Lyra 2.0 on the same trajectories, would confirm or shrink the 47.6% LPIPS margin.

  5. The distilled model's better revisit scores come with worse camera following, and the paper does not explain the inversion.

    From Figures 4 and 5: fast wins all four memory metrics and is third on all three camera metrics. My guess, that under-following the camera makes revisits easier to match, is untested. A per-video correlation between camera error and revisit LPIPS would test it.

Cite this article

For attribution, please use the following reference or BibTeX:

Satyajit Ghana, "WorldCrafter: skipping the reconstruction, not the 3D", ai.thesatyajit.com, September 2026.

bibtex
@misc{ghana2026worldcrafter,
  author = {Satyajit Ghana},
  title  = {WorldCrafter: skipping the reconstruction, not the 3D},
  url    = {https://ai.thesatyajit.com/articles/worldcrafter},
  year   = {2026}
}
share