Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hetari/creative-coding/llms.txt

Use this file to discover all available pages before exploring further.

An animated loading screen overlays the entire viewport with a solid black plane. Clicking the “click to start” prompt triggers a GPU-accelerated dissolve: a Three.js ShaderMaterial applied to a full-screen PlaneGeometry erases the overlay outward from the center, driven by a uTransition uniform that GSAP advances from 0 to 1 over roughly 2.2 seconds. A retro Perlin-noise pixelation effect and a volumetric blue glow pulse around the dissolving edge as it expands. Once the transition completes, the loader element is hidden and the underlying page content appears.

Registry Entry

This sketch is registered in src/config/sketches.ts as:
{
  id: 'gsap-loading-reveal-loader',
  title: 'Reveal Loader',
  category: 'gsap/loading',
  path: '/gsap/loading/reveal-loader',
  order: 30,
  previewMode: 'iframe',
}

Tech Stack

LayerTool
ComposableuseGsap — provides gsap instance and useGsapContext helper
RendererThree.js WebGLRenderer with alpha: true
ShaderTHREE.ShaderMaterial with inline vertex + fragment GLSL
NoiseClassic 3D Perlin noise (cnoise) — self-contained GLSL implementation
AnimationGSAP gsap.to() on the uTransition uniform object
LifecycleVue onMounted / onUnmounted for renderer setup and cleanup

Concept

Loading animations are one of the most common creative coding patterns on the web. This sketch demonstrates how to drive a WebGL shader transition entirely from GSAP, treating a uniforms object as the animation target. The approach keeps animation logic in JavaScript while the GPU handles per-pixel rendering:
  1. State lives in uniforms — the uTransition value is a plain JavaScript number that Three.js reads each frame.
  2. GSAP animates the numbergsap.to(uniforms.uTransition, { value: 1.0, ... }) advances the uniform smoothly without any manual requestAnimationFrame counter.
  3. The shader interprets the value — the fragment shader uses uTransition to compute a radial dissolve with noise-displaced edges and a glowing border.

Shader Uniforms

UniformTypeDescription
uTransitionfloatTransition progress from 0.0 (fully opaque black) to 1.0 (fully transparent). Animated by GSAP
uResolutionvec2Viewport dimensions. Updated on resize via handleResize()
uTimefloatElapsed seconds from a THREE.Clock. Drives the pulsing glow color and noise animation
uBorderColorvec3Base glow color. Default: #3b82f6 (blue). Controls both the deep midnight tone and the rich glowing highlight

Key Shader Patterns

Pixelation Grid

The fragment shader snaps continuous UV coordinates onto a 10 × 10 pixel block grid to create a retro digital-glitch look:
float pixelSize = 10.0;
vec2 grid = uResolution / pixelSize;
vec2 pixelatedUv = floor(vUv * grid) / grid;

Perlin Noise Displacement

The pixelated UVs are displaced by a 3D Perlin noise field before computing the dissolve, giving the edge an organic, non-circular shape:
vec2 displacedUv = correctedUv + cnoise(vec3(correctedUv * 5.0, uTime * 0.1));
float strength = cnoise(vec3(displacedUv * 5.0, uTime * 0.2));

Radial Dissolve

A radial gradient from the center drives the transition boundary. The formula ensures the screen starts fully opaque and dissolves outward as uTransition rises:
float d = length(correctedUv - 0.5);
float normalizedDistance = d / maxDistance;

float radialGradient = normalizedDistance * 12.5
  + (1.0 - uTransition) * 2.0
  - 15.0 * uTransition;

strength = clamp(rawStrength, 0.0, 1.0);

Volumetric Glow Edge

A smoothstep band around the dissolve boundary produces a wide, soft glow ring that pulses with uTime:
float edge = smoothstep(0.0, 0.7, rawStrength) * smoothstep(2.5, 0.7, rawStrength);
edge *= min(uTransition * 5.0, 1.0);

vec3 deepMidnightColor = uBorderColor * 0.015;
vec3 richGlowingColor  = uBorderColor * 1.5;
vec3 edgeColor = mix(deepMidnightColor, richGlowingColor, sin(uTime * 1.5) * 0.5 + 0.5);

GSAP Animation

When the user clicks, handleStart() runs a two-part GSAP animation: the “click to start” text fades out immediately, then the transition uniform advances over 2.2 seconds:
function handleStart() {
  if (isStarted.value) return
  isStarted.value = true

  // Fade out the prompt text
  gsap.to(textRef.value, {
    opacity: 0,
    scale: 0.85,
    duration: 0.4,
    ease: 'power2.out',
  })

  // Advance the shader's transition uniform
  gsap.to(uniforms.uTransition, {
    value: 1.0,
    duration: 2.2,
    ease: 'power2.inOut',
    onComplete: () => {
      if (loaderRef.value) {
        loaderRef.value.style.pointerEvents = 'none'
        loaderRef.value.style.display = 'none'
      }
    },
  })
}

Lifecycle & Cleanup

The Three.js renderer, geometry, and material are created on onMounted and fully disposed on onUnmounted to prevent memory leaks:
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  if (animationFrameId !== null) {
    cancelAnimationFrame(animationFrameId)
  }
  geometry?.dispose()
  material?.dispose()
  renderer?.dispose()
})

useGsap Composable

The useGsap() composable provides a scoped gsap instance. For sketches that use ScrollTrigger or many tweens, pair it with useGsapContext() to automatically call ctx.revert() on unmount.

Three.js Shader Material

THREE.ShaderMaterial with transparent: true, depthTest: false, and depthWrite: false renders an overlay plane in front of all scene geometry without interfering with depth sorting.
Use useGsap’s useGsapContext(rootRef, ...) for all GSAP animations inside sketch components — it automatically calls ctx.revert() when the component unmounts, killing every tween and ScrollTrigger registered within the context and resetting any inline styles GSAP has written. This prevents animation state from leaking between route navigations in the sketch dashboard.

Build docs developers (and LLMs) love