Spooky Spectral Ghost

Spooky Spectral Ghost

A spectral ghost following your cursor, with glowing eyes, particles, fireflies, and an analog VHS-style decay effect. Includes a spooky preloader and quote.

  • Built with Three.js + Tweakpane
  • Custom preloader & ghost shader
  • GPU-accelerated WebGL canvas

HTML

<!-- Spooky preloader -->
<div id="preloader" class="preloader">
  <div class="preloader-content">
    <div class="ghost-loader">
      <svg class="ghost-svg" viewBox="0 0 512 512">
        <path class="ghost-body" d="..." />
        <circle class="ghost-eye left-eye" cx="208" cy="225" r="22" />
        <circle class="ghost-eye right-eye" ... />
      </svg>
    </div>
    <div class="loading-text">Summoning spirits</div>
  </div>
</div>

<!-- Quote + ghost canvas -->
<div id="main-content" class="content">
  <h1 class="quote">
    Veil of Dust<br />Trail of Ash<br />Heart of Ice
  </h1>
  <span class="author">
    Whispers through memory
  </span>
</div>
CSS

@import url("https://fonts.googleapis.com/css2?family=Boldonse&display=swap");

html, body {
  margin: 0;
  height: 100%;
  background: #111;
  color: #e0e0e0;
}

.preloader {
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: linear-gradient(135deg, #0a0a0a, #1a1a1a);
  transition: opacity 1s ease-out;
}

.preloader.fade-out {
  opacity: 0;
  pointer-events: none;
}

.content {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 20px;
  opacity: 0;
  transition: opacity 1.5s ease-in;
}

.content.fade-in {
  opacity: 1;
}

.quote {
  font-family: "Boldonse", system-ui;
  font-size: clamp(2.2rem, 5vw, 4.8rem);
  line-height: 1.15;
  text-transform: uppercase;
}

canvas {
  opacity: 0 !important;
  transition: opacity 2s ease-in;
}

canvas.fade-in {
  opacity: 1 !important;
}
JavaScript

// Import Three.js + post-processing utilities
import * as THREE from "https://esm.sh/three";
import { Pane } from "https://cdn.skypack.dev/tweakpane@4.0.4";
// + EffectComposer, RenderPass, UnrealBloomPass, ShaderPass...

// 1) Preloader controller (updates progress bar + fade in/out)
class PreloaderManager {
  constructor() { ... }
  updateProgress(step) { ... }
  complete(canvas) { ... }
}

// 2) Three.js scene: ghost mesh, fireflies, particles, atmosphere plane
const scene    = new THREE.Scene();
const camera   = new THREE.PerspectiveCamera(...);
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });

// 3) Post-processing: bloom + custom analogDecay shader
const composer   = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
const bloomPass  = new UnrealBloomPass(...);
const analogPass = new ShaderPass(analogDecayShader);

// 4) Ghost group + glowing eyes + fireflies + particle trail
const ghostGroup = new THREE.Group();
const ghostBody  = new THREE.Mesh(ghostGeometry, ghostMaterial);
ghostGroup.add(ghostBody);
// createEyes(), createFireflies(), createParticlePool()...

// 5) Mouse tracking makes the ghost follow your cursor
window.addEventListener("mousemove", (event) => {
  // convert mouse position into scene coordinates
  ...
});

// 6) Animation loop: update ghost, eyes, fireflies, particles, shaders
function animate(time) {
  requestAnimationFrame(animate);
  // easing, wobble, scale, analog noise & scanlines
  composer.render();
}

animate(0);