Nightshade’s UI is assembled from six focused React components, each responsible for a distinct layer of the interface. They are defined in theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/nightshade/llms.txt
Use this file to discover all available pages before exploring further.
components/ directory as individual ES modules and loaded into the browser ahead of the main bundle via <link rel="modulepreload"> in index.html. This section describes each component, how they depend on one another, and how the module preload strategy improves cold-start performance.
The Six Core Components
1. Layout
Layout is the application shell. It renders the full-screen dark-background container and composes <FamiliarCursor>, <SmokeLayer>, and <Navigation> as persistent layers. The page content passed as children is rendered inside a motion.main element that animates opacity and brightness on each route change:
components/Layout.js
2. Navigation
Navigation renders the fixed top bar. It maps over a navItems array to produce icon + label links and uses AnimatePresence to animate a flame indicator (activeFlame) that follows the active route using Framer Motion’s shared layoutId:
components/Navigation.js
incantation is a Latin phrase that appears below the icon as a tooltip on hover. The active route is detected with useLocation() — a nav item is considered active when location.pathname matches its path exactly, or starts with it for non-root paths.
3. Candle
Candle is an SVG-based decorative component used throughout the interface wherever a flame visual is needed — in the home page candle-selection UI, alongside blog post cards, in the testimonials section, and on case study entries. It accepts height, width, delayIndex, isLit, and className props:
components/Candle.js
isLit is true, a motion.div flame element with a radial gradient and the CSS animate-flicker class appears above the wax body. The delayIndex prop selects one of four flicker-delay CSS utility classes (flicker-delay-1 through flicker-delay-4) to stagger the animation between multiple candles on screen.
4. FamiliarCursor
FamiliarCursor replaces the browser’s default cursor with a two-part custom cursor: a small dot that snaps to the pointer with a quick tween transition, and an SVG witch-familiar icon whose position follows with spring physics (stiffness 150, damping 25, mass 0.5):
components/FamiliarCursor.js
mousemove to update both elements and to mouseover to detect when the cursor hovers an interactive element (<a>, <button>, or [role="button"]), scaling up the dot on hover. On touch-only devices (pointer: coarse) the component returns null — no custom cursor is rendered.
5. SmokeLayer
SmokeLayer is a fixed, full-screen atmospheric background layer set behind all page content. It renders three motion.div blobs with blurred, semi-transparent fills in the app’s teal, plum, and turquoise palette colours. Each blob animates continuously on a long loop (25–35 seconds), drifting and scaling in a looping keyframe sequence:
components/SmokeLayer.js
<filter> element applies fractal noise displacement via <feTurbulence> and <feDisplacementMap>, with the turbulence base frequency itself animated to create a slow, organic drift effect. The layer uses mix-blend-screen and 30% opacity to integrate naturally with the dark background.
6. Sigils
Sigils exports nine SVG icon components, one per navigation route. They are used exclusively by Navigation as the icon value in each navItems entry. Each sigil is a stateless functional component that accepts size and className props and renders a thematic SVG path design:
| Export | Used for |
|---|---|
SanctumIcon (S) | / — The Sanctum |
WitchIcon (a) | /about — The Witch |
SummoningsIcon (b) | /projects — Summonings |
ArcanaIcon (c) | /skills — Arcana |
PactsIcon (d) | /work — Pacts |
WorkingsIcon (e) | /case-studies — Workings |
JournalIcon (f) | /blog — Journal |
WhispersIcon (h) | /testimonials — Whispers |
CommuneIcon (g) | /contact — Commune |
Module Preload Strategy
Each component module is declared as a<link rel="modulepreload"> in index.html, listed in dependency order before assets/main.js executes:
index.html
import() requests that would otherwise occur as each component is evaluated for the first time, reducing perceived cold-start latency on the initial page load.
All components import JSX utilities from
../assets/proxy.js for Framer Motion bindings — motion, AnimatePresence, useSpring, and related APIs are re-exported from there. React JSX itself (jsx, jsxs, and Fragment) comes from ../assets/jsx-runtime.js. Neither file contains application logic; they exist solely to bundle shared dependencies once and share them across every component module.