Back to Devlog
    v0.8.6
    RendererJanuary 4, 2026Release notes

    One Command Loads a Map

    A djb2-hashed PK3 index cached in localStorage, and a loadMap pipeline that resolves every dependency a map needs before it draws anything.

    The Index

    A djb2 hash of `pk3name:size` pairs for cache invalidation, saved to localStorage. PK3Index answers findFile(path), findShader(name), findMap(name), findPK3sForTextures(paths), getMapNames() and getShaderNames().

    Index build is ~2-5s for 20+ PK3s. Size is 100-500KB in localStorage.

    Hashing name and size rather than modification time is a deliberate choice: file mtimes are not stable across a download, and an index that invalidates itself on every fresh copy of the same game is an index nobody trusts.

    The Pipeline

    text
    loadMap(name)
      -> findMap -> loadBsp -> resolveMapDependencies -> loadRequiredPK3s
      -> loadShaders -> buildMesh -> applyTextures -> applySkybox -> applyLightmaps

    Commands: map <name>|list|current|reload|unload, pk3 index build|stats|clear, shader deps <path>.

    The Fixes

    Flare halos became transparent (GL_ONE GL_ONE_MINUS_SRC_COLOR), skybox paths stopped double-prefixing env/, filter/multiply decal shaders got depthWrite = false, and BSP command state stayed in sync with map-loaded maps.

    Known Limitations

    • Requires pk3_manifest.json in the game folder for PK3 discovery, or falls back

    to pattern matching.

    • Local .map file loading not yet integrated (BSP only).
    • Decal z-fighting — polygonOffset decals still have z-fighting issues with

    underlying geometry. "Needs proper decal rendering with depth sorting or stencil buffer."

    That decal line survives all the way to v0.8.10 and is still, four years and thousands of commits later, the honest answer for textures/decals/plasterworn0030.