Performance, with receipts
These are measured, disclosed-hardware numbers for Weft’s solver, not marketing claims. Every figure comes from a real Stopwatch run against the shipped code on one specific machine, printed right here. No competitor we surveyed publishes a disclosed-hardware, platform-segmented benchmark like this one, so treat the disclosure itself as part of the point, not only the numbers.
The machine. Intel Core i9-14900KF, 24 physical cores, 32 logical processors, 64 GB RAM, Windows 11 Pro (build 26200), Unity 6000.3.9f1, Burst 1.8.29. Measured 2026-07-12.
What Weft costs, in plain terms
Four scenes a buyer actually asks about, each shown as its cost on the disclosed machine above and its share of a 90 fps VR frame (11.11 ms). These are the shipped-build (IL2CPP) numbers, the honest ones to plan a scene against.
| Your scene | Weft solver cost | Share of a 90 fps VR frame |
|---|---|---|
| One hero avatar (hair plus a garment) | ~0.6 ms | ~5% |
| A room of 8 avatars, everyone resting | ~2.8 ms | ~25% |
| A room of 8 avatars, your hand on one | ~4 ms (p95) | ~35%, 0 dropped frames measured |
| A 10,000-vertex garment spawning in | ~4.5 ms one-time (with Bake Topology) | budget once per avatar join, not per frame |
A few honest caveats worth knowing. This is measured on one disclosed desktop machine, your own machine will differ. On-device (Quest, mobile) performance is not yet measured. The touched-room row comes through a lighter measurement harness than the resting-room row, so treat the two as not directly comparable frame for frame. The full disclosed tables and methodology are below the fold, this table is a plain-language front on top of them.
It scales the way you would hope
Each avatar steps its own independent world, so adding avatars adds cost close to linearly. No surprise cliff. The shipped release build (violet) comes in under the editor ceiling (pink) at every point.
The figures above solve each avatar one after another, the honest worst case. Weft can overlap them instead: a resting crowd of eight runs about twice as fast, and even an avatar someone is touching now overlaps the rest. The full numbers are below.
A resting crowd, solved all at once
Solving a resting room of 8 avatars together instead of one at a time cuts the cost roughly in half.
Each rig in this ladder is one hair group (35 strands, 210 particles) plus one 3,000-vertex garment, about 3,210 simulated points per avatar and 25,680 across all 8 rigs.
Weft can solve several avatars at the same time instead of one after another, as long as no one is touching them. The table below measures exactly that, on the same machine and under the same everyday conditions as the rest of this page.
Measured 2026-07-12 / 2026-07-13.
These numbers are for a resting crowd, avatars no one is touching. When someone grabs or pokes an avatar, Weft now solves it alongside the crowd instead of pausing for it, so touching an avatar no longer stalls the frame (apart from one rare case). The touched numbers are in the next section and were measured a different way, so do not compare them cell for cell against this table.
| Rigs | Sequential ms | Concurrent ms, batch off | Concurrent ms, batch on | Speedup, batch off | Speedup, batch on |
|---|---|---|---|---|---|
| 1 | 0.7027 | 0.5866 | 0.5986 | 1.1979x | 1.1739x |
| 2 | 1.4632 | 0.9016 | 0.8819 | 1.6229x | 1.6592x |
| 4 | 2.9021 | 1.6309 | 1.6059 | 1.7794x | 1.8072x |
| 8 | 5.7515 | 2.8688 | 2.8261 | 2.0049x | 2.0351x |
In plain terms: a resting crowd runs about 1.2x faster at one avatar and a little over 2x at eight, and batching makes no real difference either way. The bigger the resting crowd, the more the overlap helps.
The Sequential column is the same crowd solved one at a time, measured the same way, so the speedups compare like with like. It is not the plain multi-avatar figures from earlier on the page, which were measured a little differently, so do not equate the two.
The two speedup columns (batching on and off) land within measurement noise of each other, so treat them as the same result.
Numbers on a real phone and a real headset are not here yet. The work they were waiting on is done and both devices are on hand, they just have not been measured yet. They go up once that run happens.
When a hand is actually on an avatar
About 4 ms even with every avatar in the room grabbed, poked, and pressed at once.
Every world in this ladder has a held grab on both the garment and the hair, plus a genuinely intersecting collider giving real poke impulse on every avatar, from frame one.
The tables so far are resting crowds. This one is the opposite: every avatar is being grabbed, poked, and pressed from the very first frame. It shows what a scene actually costs when a player’s hand is on an avatar.
Measured 2026-07-13.
| Avatars | Typical ms | p95 ms | p99 ms | Frames over 90 fps |
|---|---|---|---|---|
| 1 | 0.8043 | 1.4329 | 1.6742 | 0 |
| 2 | 1.1817 | 1.4355 | 1.4836 | 0 |
| 4 | 2.0224 | 2.5007 | 2.6737 | 0 |
| 8 | 3.5850 | 3.9533 | 4.0940 | 0 |
No frame went over budget, even with eight avatars being touched at once. It is one run on one machine rather than an average, so take it as a good sign rather than a promise. Busier scenes cost more.
p95 and p99 are worst-case reads, not averages: the frame you would see slower only about one time in twenty, and one in a hundred. The last column counts hitches, frames slower than the 11.11 ms a 90 fps headset gives you, slow enough to visibly drop a frame.
One caveat: this was measured a little differently from the resting table above (the same solver work, without the rendering around it), so do not compare the two tables number for number.
The one-time cost when an avatar joins, and the shipped fix
Each rung below is a from-scratch World Build measured once at avatar instantiation, not a per-frame cost.
Everything above is the cost paid every frame. This is the one-time cost of building an avatar the moment it appears, like a player walking into a scene mid-session. It happens once, not every frame, and here is both the honest hitch and the fix Weft ships for it.
Measured 2026-07-13.
| Strands | Build ms |
|---|---|
| 35 | 0.0956 |
| 70 | 0.1847 |
| 140 | 0.3708 |
| 200 | 0.5938 |
Hair
| Vertices | Build ms |
|---|---|
| 3,000 | 23.0921 |
| 4,875 | 47.2207 |
| 7,200 | 95.5325 |
| 10,000 | 193.8801 |
Mesh garment
| Rigs | Build ms |
|---|---|
| 1 | 23.0552 |
| 2 | 46.0327 |
| 4 | 92.5230 |
| 8 | 189.2070 |
Multi-avatar
Hair is cheap to build. The clothing mesh is where the cost is: a realistic ten-thousand-vertex garment takes around 194 ms from scratch, a real hiccup of a few frames if it all lands the instant the avatar appears. These are the honest un-baked numbers. See the fix below.
Bake Topology, the shipped fix
One click cuts a from-scratch build at the ten-thousand-vertex rung from ~198 ms to ~4.5 ms, roughly 44x faster.
A "Bake Topology" button on the garment's inspector captures the expensive part of building a garment (which vertices connect, and how) once into a saved asset, instead of rederiving it from scratch on every avatar join. The non-hinge mesh ladder drops from ~198 ms to ~4.5 ms at the ten-thousand-vertex rung, roughly 44x. Hinge-enabled garments see a smaller but still large win, from ~500 ms to ~55 ms at the same rung, roughly 9 to 10x. Pose, scale, and tuning changes never invalidate a bake, only genuine authoring changes to the mesh or its topology settings do, and the result is proven byte-identical to an unbaked build.
A stale or mismatched bake is never used. Weft silently falls back to building from scratch instead, so a bake can never ship a wrong or corrupted result.
Zero allocation, and it is a gate
Weft’s solve allocates zero managed bytes per frame in steady state, across hair, mesh cloth, and multi-avatar alike. That is not a hope, it is a hard test gate that asserts an exact zero-byte delta with no tolerance. A nonzero delta fails the build loudly. It is never quietly tolerated.
The full ladders
Every rung, both columns, and the exact memory footprint. Median solver-step time in milliseconds. Percentages are the 90 fps line.
Hair A strand crowd, six particles per strand.
Cheap even at 200 strands, under half a millisecond.
| Strands | Particles | Editor ms | Build ms | 90 fps | Memory |
|---|---|---|---|---|---|
| 35 | 210 | 0.1262 | 0.1078 | 1.14% | 9,520 B |
| 70 | 420 | 0.2652 | 0.2388 | 2.39% | 19,040 B |
| 140 | 840 | 0.4644 | 0.3746 | 4.18% | 38,080 B |
| 200 | 1,200 | 0.4922 | 0.3792 | 4.43% | 54,400 B |
Bytes per particle stays flat across the whole ladder, exactly as a fixed per-particle struct with no per-rung overhead should.
Mesh garment A flat grid, two triangles per quad.
Even a realistic ten-thousand-vertex garment costs about 1.3 ms.
| Vertices | Particles | Editor ms | Build ms | 90 fps | Memory |
|---|---|---|---|---|---|
| 3,000 | 3,000 | 0.6794 | 0.5186 | 6.12% | 373,536 B |
| 4,875 | 4,875 | 0.8379 | 0.6218 | 7.54% | 610,656 B |
| 7,200 | 7,200 | 1.0314 | 0.7760 | 9.28% | 905,376 B |
| 10,000 | 10,000 | 1.2947 | 0.9183 | 11.65% | 1,260,896 B |
Bytes per particle rises a hair across the ladder because bend-hinge constraint density per vertex grows a little at larger grids, not from any per-rung fixed overhead.
Multi-avatar Each rig is one hair group plus one garment.
Eight full avatars solved one by one cost about 6.5 ms, the honest worst case a resting or touched crowd never has to pay in full.
| Rigs | Particles | Editor ms | Build ms | 90 fps | Memory |
|---|---|---|---|---|---|
| 1 | 3,210 | 0.8076 | 0.6086 | 7.27% | 383,056 B |
| 2 | 6,420 | 1.5975 | 1.2395 | 14.38% | 766,112 B |
| 4 | 12,840 | 3.2479 | 2.4832 | 29.23% | 1,532,224 B |
| 8 | 25,680 | 6.4776 | 5.0928 | 58.30% | 3,064,448 B |
Cost scales close to linearly with rig count, since each rig steps an independent world with no cross-rig sharing. A single rig sits comfortably under 10% of every budget line above.
Reference frame budgets: 60 fps 16.67 ms, 72 fps 13.89 ms, 90 fps 11.11 ms, 120 fps 8.33 ms. The 90 fps line is the primary PCVR budget.
How it was measured
The method is the differentiator, so none of it is hidden. Read it and you can decide for yourself how much to trust the numbers above.
A real Stopwatch, nothing else
Every figure is a Unity EditMode batchmode run with a Stopwatch wrapped around the solver’s own Step call. No rendering, no input, no scene load. Pure solver stepping, the same convention the rest of the cost-test suite already uses.
Median of medians
Each rung runs 5 warmup steps that are thrown away, then 20 timed steps, and the published number is the median of 5 independent runs of that window. A median shrugs off a single slow scheduler tick better than a mean would.
Memory is computed, not timed
The memory columns come straight from the compiled struct sizes times the real particle and constraint counts, so they carry no run-to-run noise and are exact by construction. The IL2CPP build produced byte-identical memory to the editor across all twelve rungs.
A normal machine, on purpose
These were measured on an everyday working machine with normal background apps open (recording or streaming, a browser, and chat or voice), not a sealed lab rig. That is deliberate. It is what a real buyer’s machine looks like. Background CPU load averaged roughly 4 to 5 percent across the window, and the earlier idle run is archived for comparison.
We publish the slower number
The editor column runs managed glue under Mono with the collections safety checks on, overhead a release build strips out. The build column is a real Windows x64 IL2CPP release player run in the same window, and every one of the twelve rungs came in faster than its editor control, never merely equal. The frame-budget percentages use the slower editor column on purpose, so they are a conservative ceiling a shipped build only beats.
DOTS speed, no Entities tax
Weft is built on the DOTS foundation of Burst, the C# Job System, Collections, and Mathematics, but uses no ECS and carries no Entities dependency. You get DOTS-class solver performance without adopting an Entities project layout.
Performance-quality and device-tier presets
Weft ships buyer-facing preset menus that bind the simulation rate, substep count, iteration count, and the scheduler settings above to a single named tier. Picking a tier is exactly equivalent to hand-setting those fields yourself, nothing else changes.
Find both menus at Weft / Performance Profile in the Unity menu bar.
Performance-quality tiers
| Tier | Simulation rate | Substeps | Iterations | Scheduling | Batch schedule |
|---|---|---|---|---|---|
| Performance | 60 Hz | 2 | 2 | Concurrent | On |
| Balanced | 60 Hz | 4 | 4 | Auto | Off |
| Cinematic | 60 Hz | 6 | 6 | Auto | Off |
| Crowd | 60 Hz | 4 | 4 | Auto | Off |
Device tiers
| Tier | Simulation rate | Substeps | Iterations | Scheduling | Batch schedule |
|---|---|---|---|---|---|
| Desktop | 60 Hz | 4 | 4 | Auto | Off |
| Quest-class mobile XR | 45 Hz | 3 | 3 | Concurrent | On |
Every value in both tables is provisional. The Quest-class mobile XR row in particular is an honest starting point pending a real on-device measurement, not an eyeball-tuned final number.
Crowd is the only tier that turns sleep on. A settled garment goes fully idle and costs near zero per frame, at the cost of waking a touch slower than the shipped default.
No preset ever silently touches self-collision. Disabling it changes visual behavior, so it stays a hand knob you set deliberately per component.
Where Weft runs
Weft is a Unity package for your own Unity application or game. Import it, target your own build (PC, PC VR, or a standalone platform your project already ships to), and it drops in like any native package. That is the whole supported surface, on purpose.
Live social and avatar sandboxes load user uploads in a way that strips custom solver code at the door. That is how they keep untrusted uploads safe to run on someone else’s client, and it applies to every native solver built this way, Weft included. So those platforms are out of scope, as a property of how they work, not a defect here.
Standalone Quest-class XR
We have not measured Weft on a standalone headset yet. The code runs on the right chips, so it is plausible, but plausible is not measured. A headset and a phone are on hand now, and the numbers will go up here once there is a real run. Until then we will not publish a figure we have not actually taken.
Determinism
Weft’s replay is exact only when the same build runs on the same platform. Matching bit-for-bit across different platforms is not something it does today.
The promise is same-build, same-platform, and same-settings. Changing the simulation rate, substep count, iteration count, or stiffness after a recording exists breaks bitwise replay of that recording, the same as changing any other build or platform detail would.
The simulation rate is an honest throughput lever too: running at half the frequency, 30 Hz instead of the shipped 60 Hz default, costs roughly half the total solver time per real second, since the solver steps half as often.