<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi" -->

---
title: ZERO: The Engineering Behind a Defiant Interactive Narrative
description: A detailed technical breakdown of ZERO, an immersive scroll-driven WebGL experience built with Three.js, GSAP, GLSL, and Vite. The post covers the full...
canonical: https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: ZERO: The Engineering Behind a Defiant Interactive Narrative | daily.dev
og:description: A detailed technical breakdown of ZERO, an immersive scroll-driven WebGL experience built with Three.js, GSAP, GLSL, and Vite. The post covers the full...
og:url: https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi
og:image: https://api.daily.dev/og/posts/W3Vf6GfvI.png
og:image:alt: ZERO: The Engineering Behind a Defiant Interactive Narrative
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# ZERO: The Engineering Behind a Defiant Interactive Narrative

**[Codrops](https://daily.dev/sources/codrops)** · 17 min read · 1 upvotes · 0 comments

## Summary

A detailed technical breakdown of ZERO, an immersive scroll-driven WebGL experience built with Three.js, GSAP, GLSL, and Vite. The post covers the full engineering pipeline: a virtual scroll architecture where one value drives all animations, aggressive asset optimization (DRACO geometry compression, KTX2/ETC1S GPU-compressed textures, texture atlases) that reduced 1GB+ of source assets to under 10MB, and strategies to eliminate texture upload stutters using createImageBitmap, requestIdleCallback, and chunked atlas uploads. Custom GLSL shaders are detailed for frost unlock, burning money, certificate shredding, tunnel pulse, and hexagonal text blur effects. An adaptive quality manager dynamically adjusts pixel ratio, blur samples, and geometry detail based on real-time frame timing to maintain 60fps on budget Android devices. The post also discusses shader precision pitfalls on mobile GPUs (mediump vs highp) and interaction design for press-and-hold gates.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://tympanus.net/codrops/2026/07/17/zero-the-engineering-behind-a-defiant-interactive-narrative>

## Questions this post answers

### How can I avoid GPU texture upload stutter in a Three.js WebGL scene?

Decode images off the main thread using createImageBitmap(), then queue GPU uploads to run only during idle time via requestIdleCallback, uploading a texture with renderer.initTexture() while deadline.timeRemaining() exceeds a small threshold. For very large atlases, split them into 256px tiles and upload one per frame so a single upload never exceeds the frame budget.

_Developers chasing smooth WebGL frame rates can find more rendering techniques like this on daily.dev._

### Why does a small PNG texture still use a lot of GPU memory in WebGL?

A PNG's file size on disk has no relation to its GPU memory footprint, because textures are fully decompressed once uploaded. A 2048x2048 texture occupies roughly 16MB of VRAM regardless of compression on disk, whereas KTX2 with ETC1S compression stays compressed on the GPU, using far less memory and uploading faster.

_Anyone optimizing texture pipelines for WebGL can track techniques like KTX2 compression on daily.dev._

### Why should I self-host DRACO and KTX2 decoders instead of loading them from a CDN?

Relying on a third-party CDN for DRACO and KTX2/Basis transcoders creates a single point of failure: a slowdown on gstatic or unpkg can cause every compressed asset to fail decoding even though the assets themselves are hosted locally. Bundling the decoders in a self-hosted vendor directory removes that external dependency entirely.

_Teams building resilient 3D web pipelines can keep up with asset-loading best practices on daily.dev._

## Similar posts on daily.dev

- [The Spark: Engineering an Immersive, Story-First Web Experience](https://daily.dev/posts/the-spark-engineering-an-immersive-story-first-web-experience-djgui8twi) · Codrops · 3 upvotes · 0 comments
- [Bypassing the DOM: How We Built a 60 FPS GPU Playground in React](https://daily.dev/posts/bypassing-the-dom-how-we-built-a-60-fps-gpu-playground-in-react-bjjoodryo) · Medium · 1 upvotes · 0 comments
- [WebGL for Designers: Creating Interactive, Shader-Driven Graphics Directly in the Browser](https://daily.dev/posts/webgl-for-designers-creating-interactive-shader-driven-graphics-directly-in-the-browser-tynmq00fd) · Codrops · 4 upvotes · 0 comments
- [Virtual Scroll-Driven 3D Scenes – Frontend Masters Blog](https://daily.dev/posts/virtual-scroll-driven-3d-scenes-frontend-masters-blog-ssxkgzbrm) · Frontend Masters · 2 upvotes · 0 comments

---

Tags: [#webdev](https://daily.dev/tags/webdev), [#performance](https://daily.dev/tags/performance), [#game-development](https://daily.dev/tags/game-development), [#threejs](https://daily.dev/tags/threejs)

[View this post on daily.dev](https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"ZERO: The Engineering Behind a Defiant Interactive Narrative","url":"https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi"},"datePublished":"2026-07-17T14:07:53.737Z","dateModified":"2026-09-14T06:00:44.816Z","description":"A detailed technical breakdown of ZERO, an immersive scroll-driven WebGL experience built with Three.js, GSAP, GLSL, and Vite. The post covers the full...","image":"https://media.daily.dev/image/upload/s--ZrL_HSsR--/f_auto/v1722860399/public/Placeholder%2006","thumbnailUrl":"https://media.daily.dev/image/upload/s--ZrL_HSsR--/f_auto/v1722860399/public/Placeholder%2006","isAccessibleForFree":true,"articleSection":"Codrops","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Codrops","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/codrops","url":"https://daily.dev/sources/codrops"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"webdev,performance,game-development,threejs","timeRequired":"PT17M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Codrops","item":"https://daily.dev/sources/codrops"},{"@type":"ListItem","position":3,"name":"ZERO: The Engineering Behind a Defiant Interactive Narrative"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/zero-the-engineering-behind-a-defiant-interactive-narrative-w3vf6gfvi#faq","mainEntity":[{"@type":"Question","name":"How can I avoid GPU texture upload stutter in a Three.js WebGL scene?","acceptedAnswer":{"@type":"Answer","text":"Decode images off the main thread using createImageBitmap(), then queue GPU uploads to run only during idle time via requestIdleCallback, uploading a texture with renderer.initTexture() while deadline.timeRemaining() exceeds a small threshold. For very large atlases, split them into 256px tiles and upload one per frame so a single upload never exceeds the frame budget. Developers chasing smooth WebGL frame rates can find more rendering techniques like this on daily.dev."}},{"@type":"Question","name":"Why does a small PNG texture still use a lot of GPU memory in WebGL?","acceptedAnswer":{"@type":"Answer","text":"A PNG's file size on disk has no relation to its GPU memory footprint, because textures are fully decompressed once uploaded. A 2048x2048 texture occupies roughly 16MB of VRAM regardless of compression on disk, whereas KTX2 with ETC1S compression stays compressed on the GPU, using far less memory and uploading faster. Anyone optimizing texture pipelines for WebGL can track techniques like KTX2 compression on daily.dev."}},{"@type":"Question","name":"Why should I self-host DRACO and KTX2 decoders instead of loading them from a CDN?","acceptedAnswer":{"@type":"Answer","text":"Relying on a third-party CDN for DRACO and KTX2/Basis transcoders creates a single point of failure: a slowdown on gstatic or unpkg can cause every compressed asset to fail decoding even though the assets themselves are hosted locally. Bundling the decoders in a self-hosted vendor directory removes that external dependency entirely. Teams building resilient 3D web pipelines can keep up with asset-loading best practices on daily.dev."}}]}
```

