Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/spooky/llms.txt
Use this file to discover all available pages before exploring further.
GhostMascot is a decorative floating ghost that idles with a gentle up-and-down float animation, giving the portfolio a playful haunted quality. The ghost is drawn as an inline SVG and animates its own body shape using Framer Motion’s motion.path morph, making it feel alive even while at rest.
Float animation
The gentle vertical float is provided by theanimate-float CSS class, defined in main.css:
10px upward at the midpoint of each 4-second ease-in-out cycle, then returns to its baseline, looping indefinitely. The ease-in-out timing function makes the movement feel buoyant rather than mechanical.
In addition to the container-level float, the ghost’s body path itself is animated with Framer Motion between two slightly different d attribute values — the wavy bottom hem shifts slightly, so the ghost’s hem ripples in and out of phase with the vertical float:
Ghost anatomy
The SVG renders on an 80×100 px canvas (viewBox="0 0 100 120"). It consists of:
- Body — a
motion.pathwith a cubic-Bézier dome top and wavy hem, filled#f5f5f5(the--color-ghostCSS variable) - Eyes — two solid
<circle>elements atcx=35, cy=45andcx=65, cy=45with radius 5, filled#1a1a1d - Rosy cheeks — two
<circle>elements at the sides of the face, filled#ff7518(pumpkin orange) atopacity: 0.4 - Mouth — a small quadratic Bézier arc
M45 60 Q50 65 55 60stroked in#1a1a1dwithstrokeLinecap: round
Jump-scare context
GhostMascot consumes JumpScareContext via the useJumpScare() hook. It uses a setInterval that fires every 15 seconds; each tick has a 50% chance of triggering a visible state. When triggered, visible is set to true and the ghost enters from the right side of the screen via a Framer Motion spring (stiffness: 100, damping: 15), stays visible for 3 seconds, then exits. If scaresEnabled is false, the interval is never started.
Placement
GhostMascot is positioned fixed bottom-20 right-0 at z-40, rendering in the lower-right corner of the viewport. The outer container carries pointer-events-none so it never intercepts clicks. It is rendered via the Layout component and therefore appears on every page.
Customizing the mascot
- Float distance — change
-10pxin the@keyframes floatrule to increase or decrease how high the ghost rises on each cycle - Float speed — change
4sin.animate-floatto speed up or slow down the bob - Body morph — adjust the
darray values in the Framer Motionanimateprop to change how dramatically the hem ripples - Colors — the fill
#f5f5f5and rosy-cheek#ff7518colors are set directly on SVG elements; replace them to change the ghost’s appearance
The You should also guard the Framer Motion path morph animation by reading
animate-float animation can be disabled for users who prefer reduced motion using the same pattern as the flicker animation:useReducedMotion() from Framer Motion and setting the animate prop to the static initial value when it returns true.