Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/v-doom/llms.txt

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

ParticleBackground is a purely decorative, full-viewport canvas element that renders a field of softly drifting particles behind all page content. It creates the subtle atmospheric depth that gives v-doom its dark, otherworldly aesthetic — small luminous dots slowly ascending through the midnight background, like embers rising from an unseen flame.

Behavior

Particles are drawn onto an HTML5 <canvas> element using a requestAnimationFrame render loop. On each frame every particle’s position is updated and repainted, producing smooth continuous motion. Key visual properties of each particle:
PropertyRangeNotes
Colorrgba(237, 230, 211, opacity)Bone/parchment white — matches the --color-bone theme token
Size0.5 – 2.5 px radiusVaried for a natural depth-of-field feel
Opacity0.1 – 0.4Semi-transparent; never harsh or distracting
Horizontal drift±0.25 px/frameGentle lateral waver
Vertical driftUpward, 0.1 – 0.6 px/frameAlways rising; wraps back to bottom when off-screen
Particle count is viewport-aware: the component seeds one particle per 15 000 px² of screen area, so the density stays visually consistent across screen sizes.
The canvas also listens to window.resize and reinitializes the particle field whenever the viewport changes, so the effect remains correctly sized after browser zoom or orientation changes.

Positioning

The canvas is rendered with the following CSS, keeping it locked behind every other element at all times:
position: fixed;
inset: 0;          /* covers the full viewport */
z-index: 0;        /* behind all page content */
pointer-events: none;  /* never intercepts clicks or hovers */
opacity: 0.4;      /* global canvas opacity, stacked on top of per-particle opacity */
Because the element is position: fixed (not absolute), it stays anchored to the viewport even as the user scrolls — the particle field fills the entire screen at all times.

Usage

ParticleBackground is automatically mounted by Layout. You do not need to add it to individual pages.
// Already included in Layout — no manual usage needed
import { ParticleBackground } from './components/ParticleBackground';

// Layout renders it automatically before Navigation,
// so it sits below every other element in the stacking context:
<ParticleBackground />
Inside Layout.js the render order is:
1

CustomCursor

The custom cursor overlay (topmost interactive layer).
2

ParticleBackground

The particle canvas at z-0, rendered before all other content.
3

Navigation

The site-wide nav bar at a higher z-index.
4

Page content

Animated page body at z-10, floated above the particle layer.

Performance Considerations

The canvas render loop runs on the main thread via requestAnimationFrame. Modern browsers composite canvas frames on the GPU, so the animation is smooth on mid-range and high-end devices. However, on low-powered or thermal-throttled devices the continuous repaints may compete with scroll performance.

Disable entirely

Remove <ParticleBackground /> from Layout.js. The rest of the page renders correctly without it — the midnight background colour alone still looks complete.

Reduce density

In ParticleBackground.js, change the divisor in Math.floor(width * height / 15000) to a larger number (e.g. 30000) to halve the particle count.
Removing <ParticleBackground /> from the Layout is the only supported way to disable the effect. Do not try to hide it with visibility: hidden or display: none — the requestAnimationFrame loop will keep running in the background and consume CPU even when invisible.
ParticleBackground accepts no props. To change particle colors, speeds, or size ranges, edit the initialization block inside the component’s useEffect directly:
// ParticleBackground.js — particle seed inside useEffect
n.push({
  x:       Math.random() * t.width,
  y:       Math.random() * t.height,
  size:    Math.random() * 2 + 0.5,          // radius in px (0.5 – 2.5)
  speedX:  (Math.random() - 0.5) * 0.5,      // horizontal drift
  speedY:  (Math.random() - 1) * 0.5 - 0.1,  // vertical: always negative = upward
  opacity: Math.random() * 0.3 + 0.1,        // 0.1 – 0.4
});
// Paint color per particle:
i.fillStyle = `rgba(237, 230, 211, ${e.opacity})`; // bone/parchment

Build docs developers (and LLMs) love