Name the file size you need and get it. Drop a GLB, GLTF, FBX, OBJ, DAE, STL, PLY, VOX or VRM — or a zipped model folder — and the page works down a list: dead weight first, then the mesh bytes, then the textures, and only then the triangles. In your browser, no file size limit.
Batch processing runs this exact tool over a whole folder and hands back one zip — no file limit, still nothing uploaded.
Every other compressor hands you dials and lets you find out afterwards whether you hit your budget. This one takes the budget. Type the number — 2 MB, 5 MB, whatever the page you are building can afford — and the tool works down its list, measuring the actual file after every move rather than predicting it, and stops as soon as it is under.
The order it works in is the order of what each step costs you. First the weight that is doing nothing at all: maps that are one flat value, UV sets no texture reads. Then the mesh bytes, which shrink without a single triangle being removed. Then the textures, which is the first step you could ever see. Triangles come last, and only if you leave that switch on — turn it off and the tool will tell you the smallest it could get without touching your mesh instead of quietly cutting it.
It also reports what it spent. A compressor that hits your number and will not say how is asking you to trust it about the one thing you can check.
A GLB is a mesh and a stack of images, and every guide on the internet — including the earlier version of this page — will tell you the images are where the weight is. That is true right up until you resize them, at which point a generated model is suddenly 70% mesh and no texture setting moves the number again.
Vertex data is stored as 32-bit floats by default, which is far more precision than any of it needs: a position has to be right to a fraction of a millimetre on a model measured in metres, and a UV has to land on the right texel of a 4096px map. Stored compactly instead, it is a fraction of the size and lands within about one part in 130,000 of the model — a hundredth of a millimetre on a two-metre character. Your file says so in the standard way, through KHR_mesh_quantization and EXT_meshopt_compression, which is what tells your engine how to read it.
Measured, on a 55 MB Meshy character: 30.1 MB of mesh and animation data becomes 8.6 MB — 3.5× smaller with every one of its triangles still there. The same pass on a 13 MB rigged character takes 13.1 MB of mesh down to 3.7 MB. This is the step that makes "get it under 5 MB" reachable without deleting anything.
It is not free of consequences, which is why the page asks where the file has to open. The integer form loads anywhere that reads a ratified glTF extension, Blender included. The compressed form needs a decoder on the other side — three.js, Babylon, PlayCanvas, <model-viewer>, Unity and Unreal all have one; Blender does not. Pick "anywhere" and you keep the first half of the saving and stay openable in a DCC.
Generated models routinely ship a roughness map that is a flat grey square and a metalness map that is flat black — full-resolution images encoding one value. A 1024px greyscale PNG carrying "0.5" is not a texture, it is a float that took a wrong turn, and it is costing you a texture slot, a download and a GPU upload.
The tool samples every map, and where the whole image is genuinely one value it folds that value into the material constant the map was multiplying and drops the image. The render is unchanged — not approximately unchanged, unchanged — because the number the shader multiplies by is the same number. Images that are byte-identical to another image in the file are merged, and UV sets nothing reads any more are dropped with them.
This is the only step here with no downside at all, so it always runs, in both modes.
AI generators ship 2K and 4K maps by default — a croissant arrives wearing a 4096×4096 albedo. Resizing those to a sane maximum costs you nothing you can see at normal viewing distance. A Meshy croissant, 18.4 MB: its textures are 7.8 MB of that, and a 1024px cap takes them to 421 KB, a 95% cut.
Textures are written back as JPEG, or PNG where the image genuinely uses its alpha channel. Both are glTF core image types, so the output opens in Blender, Unity, Godot, three.js and every viewer that reads GLB. WebP would be roughly another 30% smaller but requires the EXT_texture_webp extension to be declared, and a file that omits it is invalid — it would open here and fail elsewhere. A smaller file that does not load is not a smaller file.
In target mode you do not choose the cap: the tool starts at 1024px and balanced quality, and moves up to sharper textures if your budget has room or down if it does not. What it landed on is in the report.
Compression without a target is just fiddling, so here are the numbers worth typing into the box. A model on a web page that should feel instant: under 2 MB. A product viewer someone will wait a beat for: 5 MB. A character in a WebGL game, loaded behind a progress bar: 10–15 MB. An asset for <model-viewer> or a similar embed: under 5 MB, because it competes with the rest of the page for the same connection.
One hard limit is worth knowing because it fails loudly rather than slowly: iOS AR Quick Look rejects USDZ over roughly 25 MB, and a GLB converted for it inherits that ceiling. If your model is destined for an AR link, that number is not a preference.
A raw AI-generated model — 4K textures, 300,000 triangles — lands somewhere between 15 and 60 MB. Every one of these targets is reachable from there, and on most models without removing a triangle.
Four rows, and between them they are the whole diagnosis. File size before and after. Textures, before and after, so you can see how much of your file was images. Mesh data, before and after, which is everything an accessor points at — positions, normals, UVs, skin weights, animation curves. And triangles, which only appears if triangles were actually cut.
If the mesh row is the big one and the tool still could not reach your target, the model is genuinely dense and the honest fix is fewer triangles — the dedicated polygon reducer gives you the full range with a before-and-after count, and baking the detail into a normal map keeps the look at a fraction of the geometry.
And if the file is small but the page is still slow, the weight was never the issue. Load time and render time are different problems with different fixes — this guide walks the distinction.
A JPEG shrinks the download but not the GPU: the moment it is sampled it unpacks to raw RGBA, so a 2048px texture takes 16 MB of VRAM however small the file was. The optional KTX2 mode, on the manual side of the page, re-encodes every texture to Basis Universal, which the GPU samples in its compressed form — the VRAM cost drops to a fraction and upload stalls shrink with it.
It is off by default for one honest reason: Blender cannot open KTX2 textures yet. Engines are fine — three.js (KTX2Loader), Babylon, PlayCanvas, Unity and Unreal all read KHR_texture_basisu — so turn it on when the file ships to a renderer rather than a DCC.
In this order, because it is the order of what each step costs you. First remove the weight that is doing nothing: maps that hold a single value, images duplicated under two names, UV sets no texture reads. Then pack the mesh data, which is 3–4× smaller with every triangle intact. Then resize the textures, which is the first step you could ever see. Only then remove triangles. Most guides start at step three and never mention step two, which is why so many models end up decimated when they did not need to be. This page runs that order for you, and will run it against a file size you name.
Stop before the lossy steps and you keep everything: dead weight removal changes nothing on screen, and mesh packing keeps every triangle — it stores the same surface in fewer bytes rather than throwing surface away. On a generated model those two alone are usually a 3–5× cut. Texture resizing is the first genuinely visible step, and triangle removal the only one that changes the shape; both are switches you control, and the report says which ones were used.
Yes — that is the default mode. Type the number (2 MB, 5 MB, whatever your page can afford), and the tool measures the real file after every step and stops as soon as it is under. If your target cannot be reached without removing triangles, it tells you rather than quietly removing them; and if you have left triangle-cutting switched off, you get the smallest lossless result plus a note saying how far it landed.
On a generated model, usually between 5× and 10× without removing a single triangle — and if you name a target the tool will tell you whether it reached it rather than leaving you to check. Measured examples: a 55 MB Meshy character has 30.1 MB of mesh data, which packs to 8.6 MB; its 4K textures lose 90%+ at a 1024px cap. A model with no textures and a small mesh loses little, and the report says so rather than pretending.
The output declares EXT_meshopt_compression and KHR_mesh_quantization, so any engine that reads those opens it — that is the pair to enable in your loader. Not Draco: it needs a heavier decoder and decompresses more slowly. If your pipeline specifically requires Draco, take the plain output from here and run Draco afterwards.
Choose "anywhere, Blender included" and yes — the file stays inside what every conformant glTF importer reads. Choose the engine option and Blender will refuse it, because that form needs a decoder Blender does not carry. The page says so next to the choice rather than letting you find out downstream.
Positions land within about one part in 130,000 of the model’s size — a hundredth of a millimetre on a two-metre character — and normals and UVs stay below what any renderer resolves. It is not lossless in the bit-for-bit sense and it is not visible in any renderer, at any zoom you would use on the asset.
At a 1024 px cap and balanced quality, not in any way you will notice in a game or a web viewer. If the model is a hero asset that fills the screen, ask for a larger target — the tool spends the headroom on sharper textures before it spends it anywhere else.
No. Decoding, resizing, re-encoding, quantizing and compressing all happen in your browser tab.
Two causes, and it is worth knowing which one you have. Textures: a GLB embeds every image it uses, and generators default to 2K or 4K maps — a single 4096×4096 albedo is several megabytes, and a PBR material carries four or five. Geometry: a few hundred thousand triangles is roughly 10 MB of float32 vertex and index data. The old advice was that only the first is fixable; that is no longer true, because packing the mesh shrinks the second by 3–4× without deleting anything. The report separates the two for you.
Under 2 MB for something that should appear instantly, under 5 MB for a viewer someone is waiting on deliberately, and 10–15 MB is acceptable behind a progress bar in a game. If the model is headed for iOS AR Quick Look, stay under about 25 MB — that one is a hard rejection rather than a slow load.
Yes as an input — drop an .fbx and you get a compressed GLB back, with the conversion happening on the way through. Textures survive only if they were embedded in the FBX; loose images sitting beside the file cannot be reached from a browser tab. There is no FBX output.
No. A rigged character comes out rigged, bound to the same skeleton, with every animation clip still on it and the skin behaving as it did — that is checked on real rigged models before anything ships. Compression here never touches the skeleton, and it only removes triangles if you asked it to.