Back to Newsroom
guides25 min read

Why Your 3D Models Are Too Large for the Web - and How to Fix It

Why 3D files from DCC tools are too large for web delivery, what the right size targets are, and the three techniques that get a 35 MB GLB down to under 3 MB.

May 28, 2026Updated May 24, 2026
VT

Vectreal Team

Founding Contributors

Building open infrastructure for practical 3D on the web.

The Number That Shows Up in DevTools

Open the Network tab on a page that embeds a 3D model. Sort by size. The GLB is almost always the largest single asset on the page - often by an order of magnitude. A product model from a professional 3D artist can arrive at 25, 40, or 80 MB. For context, a fully-loaded marketing homepage with images, fonts, and JavaScript commonly comes in under 3 MB total.

This is not a problem with the model. It is a problem with the file format's defaults when used as a delivery artifact. The same file sizes that are unremarkable inside a studio pipeline - where everything runs on gigabit local storage - are untenable for browser delivery over consumer networks.

The gap between "file created by a DCC tool" and "file ready for a web embed" is wide. Three culprits drive it. Each has a corresponding fix.


Why 3D Files Are Large by Default

Culprit 1 - Geometry precision

A typical product model exported from Blender, Maya, or Cinema 4D carries 200,000-800,000 triangles. That precision is appropriate when the model is rendered in a film or used for downstream CAD work. It is far more than a web viewer needs. A browser viewer rendering at standard screen resolutions is drawing each triangle at an average size of a few pixels. Triangle counts above 200,000 contribute details that sub-pixel rasterization discards entirely.

The geometry itself is also uncompressed in a raw glTF or GLB. Vertex positions, normals, UVs, and tangents are stored as full-precision float32 arrays. For web delivery, quantized integer encoding achieves the same visual result in 30-50% fewer bytes per attribute.

Culprit 2 - Texture resolution and format

Textures are almost always the dominant contributor to file size, and the problem compounds with the number of materials in the scene. A standard PBR material set - albedo, normal, roughness, metallic, ambient occlusion - typically produces five textures per material. At 2K resolution in PNG format, that is roughly 10-20 MB per material slot. A scene with three materials ships 30-60 MB of textures before any geometry is counted.

The format problem is separate from the resolution problem. PNG and JPEG are 2D image formats designed to be decompressed and displayed on a flat screen. A GPU rendering a 3D scene needs the texture in a different state: held in compressed GPU memory, mipmapped, sampled at arbitrary UV coordinates. When a browser loads a PNG into a WebGL scene, it decompresses the PNG to raw RGBA pixels in CPU memory, then uploads those raw pixels to the GPU. A 2K PNG that ships as 6 MB on disk decompresses to 16 MB in GPU memory. The network saving from PNG compression does not carry through to GPU memory pressure.

Culprit 3 - Scene graph overhead

A glTF file is a JSON-described graph of nodes, meshes, materials, textures, cameras, animations, and accessors. DCC tools typically export everything in the scene - including objects marked as reference geometry, animation clips replaced by later versions, duplicate materials consolidated in the DCC but not in the export, and unreferenced buffer views that point to nothing. A real-world glTF from a production pipeline often contains 10-25% of data that no viewer ever touches.


What "Web-Ready" Means, in Numbers

Before running any optimization pass, establish the target. The right target depends on context.

ContextTarget file sizeTriangle budget
Hero embed (landing page, above fold)Under 5 MB150,000-250,000
Product detail pageUnder 2 MB100,000-150,000
Grid or card (multiple embeds on one page)Under 500 KB30,000-80,000
Mobile-first (LTE or slower)Under 1 MB50,000-100,000

These are not aspirational targets. They are the numbers at which time-to-first-frame on a mid-range device over a typical consumer connection lands under three seconds. Above these thresholds, visible bounce events start accumulating. A model that takes eight seconds to load is, for most practical purposes, a model that does not load.

Triangle counts above budget do not directly increase file size - individual triangles are compact. They increase GPU load, which affects sustained frame rate. A scene that loads fast but runs at 20 fps on mobile is a solved load problem with an uncovered runtime problem.


The Three Techniques

Technique 1 - Mesh simplification

Mesh simplification reduces triangle count while preserving the visual shape of the model. The standard algorithm is quadric error metric simplification: each vertex is assigned a cost representing how much the surface would distort if it were removed. Vertices in flat, featureless regions have low cost and get merged first. Vertices on silhouette edges, sharp features, and high-curvature areas have high cost and are kept. The algorithm runs until the target triangle count is hit.

In practice, removing 30% of triangles on a typical product model produces a visual difference that requires side-by-side comparison at high magnification to detect. Removing 50% produces a visible difference on close inspection of organic geometry; on hard-surface mechanical models, it often produces no visible difference at all. Simplification savings vary by model type - an organic character model with smooth surfaces simplifies well; a CAD model with precise flat faces may simplify less aggressively without introducing visible faceting.

Mesh simplification alone typically reduces total file size by 10-30%, depending on how much of the original file is geometry versus textures.

Technique 2 - Texture compression and format conversion

This is where the large savings happen. Textures in a typical DCC export are PNG or JPEG. Converting them to a web-optimized format - WebP for broad compatibility, or KTX2/Basis Universal for GPU-native delivery - has an outsized effect on total file size because textures represent the majority of the bytes.

WebP is the practical choice for server-side pipelines. It achieves 25-40% smaller file sizes than JPEG at comparable visual quality, with broad browser support. A PBR material set that ships as 18 MB of PNG arrives as roughly 4-6 MB of WebP at 85% quality - a reduction that dwarfs any mesh simplification savings on a typical scene.

KTX2 / Basis Universal is the GPU-native option. Unlike PNG or WebP (which are decompressed before the GPU sees them), KTX2 stays compressed in GPU memory, transcoding at load time to whatever format the local GPU supports best - BC7 on desktop, ASTC on mobile, ETC2 as a broad fallback. The result is faster upload to the GPU, lower sustained memory pressure, and better frame rate at high texture density. The Vectreal Publisher uses this path in its browser-side optimization pipeline.

The quality tradeoff is real but manageable. High-quality conversion (quality setting around 85-90%) is visually indistinguishable from the source texture for the vast majority of materials. Medium quality (70-75%) introduces faint compression artifacts on close inspection of high-frequency detail - fine weaves, brushed metal, text rendered as a texture. The right quality setting is the lowest one that still looks correct for the specific scene, evaluated at the specific viewing distance and device profile that matters.

Texture compression is typically responsible for 60-80% of the total size reduction in an optimization pass. On a 35 MB model, converting PNG textures to WebP at high quality commonly drops the file to 5-8 MB before any mesh changes are made.

Technique 3 - glTF graph cleanup

Graph cleanup removes data from the glTF JSON and binary buffer that nothing in the scene actually references. Specifically: duplicate accessors, unused buffer views, unreferenced animation clips, orphan nodes, redundant materials, and duplicate textures. It also normalizes common inconsistencies - coordinate axis mismatches, unit scale assumptions, missing color space declarations - that cause renderers to add overhead at load time.

Graph cleanup is the smallest individual contributor to size reduction - typically 5-15% - but it compounds with the other two techniques. A model that has been mesh-simplified and texture-compressed still carries all of its dead graph weight until cleanup runs. Running cleanup as part of every pass ensures the binary buffer reflects the actual state of the optimized mesh and textures.


The Manual Path - gltf-transform CLI

glTF-Transform is the standard open-source library and CLI for programmatic glTF manipulation. Installing the CLI requires Node.js:

npm install --global @gltf-transform/cli

Start by inspecting the file to understand what you are working with before touching anything:

gltf-transform inspect input.glb

This prints a breakdown of mesh count, triangle count, texture count, texture resolutions, buffer sizes, and any issues the validator detects. Run this before and after any optimization pass to see exactly what changed.

Texture compression first - this is where the size is:

# KTX2 with ETC1S encoding - best compression ratio
gltf-transform etc1s input.glb output-etc1s.glb
 
# KTX2 with UASTC encoding - better quality, larger file
gltf-transform uastc input.glb output-uastc.glb

ETC1S is appropriate for most diffuse and roughness textures. UASTC is worth the larger output for normal maps and high-frequency detail textures where its quality advantage is visible.

Mesh simplification - target the triangle budget:

# Retain 70% of original triangle count
gltf-transform simplify input.glb output.glb --ratio 0.7
 
# Aggressive: retain 50%
gltf-transform simplify input.glb output.glb --ratio 0.5

Graph cleanup - remove dead weight:

# Deduplicate accessors and textures
gltf-transform dedup input.glb output.glb
 
# Remove unused nodes, materials, and animation clips
gltf-transform prune input.glb output.glb

The full pipeline, chained:

# Inspect first - establish the baseline
gltf-transform inspect source.glb
 
# Simplify → dedup → prune → compress textures
gltf-transform simplify source.glb stage1.glb --ratio 0.75
gltf-transform dedup stage1.glb stage2.glb
gltf-transform prune stage2.glb stage3.glb
gltf-transform etc1s stage3.glb output-optimized.glb
 
# Inspect the result - verify what changed
gltf-transform inspect output-optimized.glb

Running inspect before and after gives a precise accounting of what changed. A well-tuned pass on a typical product model moves the file from 30-80 MB to 2-6 MB with no visible quality difference at normal viewing distances.

What the CLI leaves to you: it optimizes the file you give it, then stops. It does not host the result, version it, manage access by API key, or give a non-developer a way to re-optimize without running terminal commands. For a personal project with a single static model, that is fine. For a team with evolving 3D content and non-developer contributors, those gaps add up.


The Platform Path - Publisher Presets and @vctrl/core

Vectreal's optimization pipeline runs the same gltf-transform operations the CLI runs above. The difference is the interface and the infrastructure around it.

Via the Publisher (no code required)

Open the Vectreal Publisher. Upload the GLB or glTF. The platform runs the inspect pass automatically and displays the before stats: file size, triangle count, texture sizes. Switch between the four optimization presets - Raw, High, Medium, Low - and the viewport re-renders from the original uploaded file each time. The stats panel updates with the after numbers. When the right tradeoff is found, publish.

The presets are pre-tuned recipes on top of the same three-technique pipeline. High applies 90% mesh ratio and 90% texture quality. Medium applies 70% and 75%. Low applies 50% and 60%. The specific tradeoffs behind each preset, including when to override the defaults for specific material types, are covered in Optimization Presets Demystified.

No account is required to upload, optimize, and preview. Sign in to save and publish. The non-destructive architecture means switching presets re-processes from the original - the original file is never overwritten and no choices are permanent until publish.

Via @vctrl/core (Node.js pipeline)

For teams that run server-side optimization - build pipelines, automated asset processing, CI/CD workflows - @vctrl/core exposes the same optimization operations as a Node.js module:

npm install @vctrl/core
import { ModelOptimizer } from '@vctrl/core/model-optimizer'
 
const optimizer = new ModelOptimizer()
 
// Load from file
await optimizer.loadFromFile('./source.glb')
 
// Run the full optimization pass
await optimizer.optimizeAll({
  simplify: { ratio: 0.75 },
  textures: {
    targetFormat: 'webp',
    quality: 85,
    resize: [2048, 2048]
  }
})
 
// Export the result
const optimizedGlb = await optimizer.export()
 
// Inspect what changed
const report = await optimizer.getReport()
console.log(
  `${report.originalSize} → ${report.optimizedSize} bytes`,
  `(${report.stats.triangles.before} → ${report.stats.triangles.after} triangles)`
)

optimizeAll runs mesh simplification, deduplication, quantization, and texture compression in sequence. Individual operations can also be called separately - optimizer.simplify(), optimizer.deduplicate(), optimizer.compressTextures() - for pipelines that need selective control.

@vctrl/core is the same package that runs inside the platform. The source is open under AGPL-3.0 and available in the Vectreal repository.


A Realistic Before/After

To make the numbers concrete: a representative product model - a consumer electronics item with three PBR materials, exported from Blender at standard settings - typically passes through these states:

StageFile sizeTriangle countNotes
Raw Blender export38.4 MB412,000PNG textures, full-precision geometry
After graph cleanup36.1 MB412,000Orphan nodes and unused animation clips removed
After mesh simplification (75%)33.8 MB309,000Quadric error simplification, no visible change at viewing distance
After texture compression (WebP, 85%)4.6 MB309,000Three PBR material sets at 2K, visual quality intact
Publisher Medium preset (all three techniques)3.1 MB288,000Combined pass at Medium settings

The final 3.1 MB file loads in under two seconds on standard broadband and under four seconds on LTE. The original 38.4 MB file does not reliably finish loading before a typical visitor's patience expires.


Format Matters Before Optimization

One factor the size table above does not include: the choice of input format before any optimization pass runs. Some formats carry structural overhead that limits how much gltf-transform can compress.

GLB is the right starting point for any web optimization pass. It is binary-packed and self-contained, with all external texture and buffer references resolved into a single file. Multi-file glTF (JSON + separate texture files) should be packed to GLB before optimizing. USDZ and OBJ files need conversion to GLB first.

The distinction between glTF and GLB, what each actually contains, and why it matters for the optimization step is covered in glTF vs GLB - What Actually Matters When You Ship to the Web.


Starting Point

If you have a model and want to see the numbers without writing any code: the Publisher is free to use without an account. Upload the file, switch through the four presets, read the stats panel. The meaningful decisions - quality tradeoffs, file size targets, triangle budgets - are all visible in that workflow before any account or commit is needed.

For the CLI path:

npm install --global @gltf-transform/cli
gltf-transform inspect your-model.glb

The inspect output shows where the bytes are. Start with texture compression - that is almost always where the majority of the size lives.

For the Node.js pipeline path:

npm install @vctrl/core

The API documentation is in the repository. The ModelOptimizer source is readable and the operations map directly to the gltf-transform functions they wrap.

Built for makers shipping in 3D

Ready to publish your first interactive scene?

Start free to upload, optimize, and embed your first scene with the same workflows featured in this newsroom.

No credit card requiredFree plan availableEmbed in minutes

Continue Reading

Previous Article

How to Add a 3D Model to Any Website - The Complete Options Map

Go to previous article

More from the newsroom