← Back to Blog news

Meta's $300K Three.js jam bans CDNs — here's your zip budget

By BitSoul Team8/28/20265 min read5 views
Meta's $300K Three.js jam bans CDNs — here's your zip budget

Meta's Horizon Creator Competition: Game Prototype closes September 8, 2026 at 1:00pm PDT, and 451 developers are already registered for a share of $300,000 across three genres. The three-week build window isn't what trips people up — it's the submission format. Every entry ships as one .zip file, capped at 35MB, with `index.html` at the top level, Three.js and any decoders self-hosted in a `vendor` folder, and zero external network requests once the build runs. No CDN script tags, no hotlinked textures, no assets pulled from a CMS at runtime. Whatever the game touches has to already be sitting inside that zip when a judge unzips it.

That single rule — no network access while running — changes how you budget every model, texture, and audio file you put in the build. Here's the actual math, and where teams building for Survival & Resource Management, Simulation & Management, or Tower Defense & Strategy burn their budget without noticing.

What the no-network-access rule bans

What the no-network-access rule bans — illustrated

The rules state builds that load resources from external URLs, including content delivery networks, fail validation outright. That means the usual jam shortcut — a script tag pointing at a CDN copy of Three.js — is disqualifying, not just slow. Three.js itself, GLTFLoader, DRACOLoader, KTX2Loader, and their supporting WASM decoders all have to live in your `vendor/` folder and load via relative paths. Your own game code goes in `index.html`, unminified and readable — judges are checking that an AI tool actually generated the logic, per the Build Log requirement, so obfuscating or bundling it defeats the point.

Where the 35MB actually goes

Before a single game asset gets packed, the vendor folder already has a tax:

| Zip contents | Typical size | Notes |
|---|---|---|
| `index.html` (your code) | 20-150KB | Unminified, single file |
| `vendor/three.module.min.js` | ~650-700KB | Self-hosted, not imported from a CDN |
| `vendor/DRACOLoader.js` + decoder.wasm | ~250-300KB | Only needed if meshes are Draco-compressed |
| `vendor/KTX2Loader.js` + transcoder.wasm | ~300-350KB | Only needed if textures are Basis/KTX2 |
| Models, textures, audio, fonts | Remaining ~33-34MB | Your actual game content |

On paper that leaves over 33MB for content, which sounds generous. It isn't, once you account for the real constraint: this is a portrait-orientation mobile web build, judged by people opening a .zip on whatever device they have, on whatever connection they have. A build that technically fits under 35MB but takes 20 seconds to parse and decode on a mid-range Android phone loses on the Playability criterion (25% of the score) before a judge sees the core loop. Treat 35MB as the hard ceiling and 8-12MB as the actual target for anything you want to load fast.

A tower-defense budget, concretely

Say you pick Tower Defense & Strategy. A tight scope is 4-6 turret variants, 3-4 enemy types, a handful of terrain tiles, and UI icons. Reusing meshes via instancing (the same approach covered in our piece on scattering GLB props with GPU instancing) means you need maybe 10-14 unique GLBs total, not one per placed object. Budget each finished, texture-baked turret or enemy GLB at 300-800KB and you land around 6-8MB for the whole roster — comfortably inside both the zip cap and the mobile-load target, with room left for a music loop and a few SFX.

The low-poly name means nothing until you check

The low-poly name means nothing until you check — illustrated

The gotcha that actually kills submissions: source files lie about their own weight. Take a model in our own catalog, the Low-Poly Villager — the name says low-poly, the spec sheet says 1,982,036 triangles and a 54.9MB GLB. That single file is bigger than your entire zip allowance by itself. It's a hero-shot asset meant for decimation before real-time use, not a drop-in prop, and nothing in a filename tells you that. Before anything goes near your assets folder, open it and check the actual triangle count and file size — don't trust the tag. A poly-reduce pass in 3D Studio runs on your own GPU in the browser, so you can decimate a source file like that down to something in the 5-15K triangle range and re-export as GLB without a Blender round trip.

Loading compressed assets without a CDN

If you compress meshes or textures to hit that 8-12MB target, the decoders still have to be local. Point loaders at your own `vendor/` path, not a hosted one:

```js
import { DRACOLoader } from './vendor/three/DRACOLoader.js';
import { GLTFLoader } from './vendor/three/GLTFLoader.js';

const draco = new DRACOLoader();
draco.setDecoderPath('./vendor/draco/'); // local wasm, not a CDN URL
const loader = new GLTFLoader();
loader.setDRACOLoader(draco);
loader.load('./assets/turret.glb', (gltf) => scene.add(gltf.scene));
```

That's the same self-hosting pattern our Draco-compressed GLB engine support piece walks through for native engines — the difference here is there's no fallback CDN copy to lean on if your local path is wrong, because the validator blocks the network call before it even fails gracefully.

Check every GLB before you zip

The fastest way to blow the budget is packing a placeholder you forgot to optimize. Run a quick pass over your assets folder before packing:

```bash
for f in assets/*.glb; do
size=$(du -h "$f" | cut -f1)
echo "$f -> $size"
done
```

Anything over a couple megabytes is worth opening back up — either it's carrying an unbaked high-res texture set or it's a source file that never got decimated. Catching that on day 10 of a three-week build is a lot cheaper than catching it the night of September 8.

Renderer choice still matters

Nothing in the rules requires WebGPU specifically — a plain WebGL2 Three.js build clears validation fine. But since judges' devices are unknown and there's no CDN fallback to fetch a polyfill from, the automatic WebGPU-to-WebGL2 fallback covered in our piece on what still breaks in Three.js's production WebGPURenderer is worth reading before you commit to one renderer path — a build that only runs on WebGPU-capable browsers is a build that fails on some judges' phones before the core loop even starts.

A free BitSoul account's two monthly downloads cover pulling reference assets to test this pipeline; commercial use of any model in a shipped or monetized entry needs a paid membership — check pricing before you submit anything built on downloaded assets.

---

*This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.*

Tags: workflow optimization indie-game-dev game-assets 3d-models

Skip the modelling — download it instead

A free BitSoul account gets you 2 models every month plus 25 AI Engine credits to generate one of your own, no card required. Clean topology, PBR textures, and GLB downloads that drop straight into Unreal, Unity, Godot or Blender — plus OBJ and 3D-printable STL export.

Create a free account → Browse 846 models