DEV Community

Cover image for 👻 "Someone Is Watching" - Psychological Horror WebGL Experience with Real-time Camera Manipulation
sneh1117
sneh1117

Posted on

👻 "Someone Is Watching" - Psychological Horror WebGL Experience with Real-time Camera Manipulation

This is a submission for the DEV April Fools Challenge

What I Built

"Someone Is Watching" - A psychological horror webpage that pranks users by convincing them they're being haunted... by themselves.

It starts innocently: "This experience requires camera access." Once granted, users see themselves on screen. Then things get weird. Their own face from 5 seconds ago starts appearing as a ghost behind them. A creepy pale face emerges from the darkness. Messages like "IT'S RIGHT BEHIND YOU" flash across the screen with RGB glitch effects.

The ultimate April Fools prank: making someone genuinely creeped out by their own webcam feed. It's completely harmless—just clever camera frame buffering and canvas manipulation—but it feels supernatural.

After 70 seconds of escalating terror, it ends with: "I saw everything."

Perfect for pranking friends who think they're just testing your "cool web project."

Demo

🔗 Try it if you dare (Warning: Actually creepy. Use headphones in a dark room for maximum effect)

What to expect:

  • Phase 1 (0-15s): Awareness building - "You've been here for 3 seconds..."
  • Phase 2 (15-30s): Creepy face starts appearing faintly in background
  • Phase 3 (30-50s): Your "ghost" from past frames manifests beside you
  • Phase 4 (50-70s): Full terror - glitching text, ghost at max opacity, face staring
  • Phase 5 (70s): The reveal

Pro tip: Send this to a friend at 11 PM and watch them freak out 👻

Code

https://github.com/sneh1117/someone-is-watching

Key files:

  • index.html - The entire experience in one self-contained HTML file
  • Vanilla JavaScript, no dependencies
  • Works on desktop and mobile (with camera permission)

How it works technically:

// Capture video frames and store them
function captureGhostFrame() {
  const tempCanvas = document.createElement('canvas');
  const tempCtx = tempCanvas.getContext('2d');
  tempCtx.drawImage(video, 0, 0);
  ghostFrames.push(tempCanvas); // Store for later
}

// Draw old frame as "ghost" behind current feed
function startGhostEffect() {
  const randomFrame = ghostFrames[Math.floor(Math.random() * ghostFrames.length)];
  ghostCtx.globalAlpha = ghostOpacity;
  ghostCtx.filter = 'blur(4px) brightness(1.5)';
  ghostCtx.drawImage(randomFrame, offsetX, offsetY);
}

// Procedurally draw creepy face
function drawCreepyFace() {
  // Pale oval face
  faceCtx.fillStyle = '#ddd';
  faceCtx.ellipse(faceX, faceY, faceSize * 0.7, faceSize, 0, 0, Math.PI * 2);

  // Hollow black eyes
  faceCtx.fillStyle = '#000';
  faceCtx.ellipse(leftEyeX, eyeY, eyeSize, eyeSize * 1.3, 0, 0, Math.PI * 2);
  // ... with occasional tiny white pupils for extra creep factor
}
Enter fullscreen mode Exit fullscreen mode

How I Built It

Tech Stack:

  • Pure HTML/CSS/JavaScript - No frameworks, no libraries, just almost 900 lines of vanilla code
  • Canvas API - For compositing ghost frames and drawing the creepy face
  • getUserMedia API - For camera access (with explicit permission)
  • Web Audio API - For ambient horror soundscape

Architecture:

  • 3 canvas layers: video feed (background) → ghost overlay → creepy face
  • Phase-based timeline system triggering effects at specific timestamps
  • Frame buffer storing 5 most recent video captures
  • RGB glitch shader effect using text-shadow offsets
  • Procedural face generation (different each flicker)

Design choices:

  • Grayscale desaturated feed - Gives that found-footage horror vibe
  • Courier New font - Feels like surveillance system text
  • Slow burn pacing - 70 seconds is perfect; not too long, but enough to build dread
  • Your own face as the monster - The uncanny valley of seeing yourself delayed

What made it delightfully useless for April Fools:
It serves absolutely no practical purpose. It's pure psychological torment disguised as a "web experience." The joke is that people willingly give camera access thinking it'll be cool, then immediately regret it as they watch their ghost materialize.

Prize Category

Community Favorite

This project embodies the spirit of April Fools: it's a harmless prank that genuinely gets a reaction. Unlike jump-scare websites that last 2 seconds, this is a slow-burn psychological experience that makes people question if their webcam is malfunctioning or haunted.

Why it deserves Community Favorite:

  • Shareable prank potential - "Hey check out this cool camera effect I made" 😈
  • Technical creativity - Uses standard web APIs in unexpected ways
  • Genuine reactions - The ghost effect actually works and is genuinely unnerving
  • Safe scare - No jump scares, no malware, just creative code
  • Cross-platform - Works on any device with a camera

The best April Fools pranks are the ones that make you laugh after you realize you've been had. This one makes you laugh nervously while checking over your shoulder.


Built with insomnia, too much horror movie research, and a questionable amount of "testing on friends at midnight."

Camera permissions are real and required by browsers—no secret surveillance here! Just creative illusions. 👁️

Top comments (0)