Skip to main content

Documentation Index

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

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

SpellForm is used on the Contact (/contact) page, presented under the “Cast a Message” heading. It renders a max-w-lg form with three fields, an animated submit button, and a layered animation system tied to the message textarea: as the user types, Elder Futhark runic characters float upward above the form. On submission, the button shows a spinning Sparkles icon for 2 seconds, then switches to a success state with a 20-particle confetti burst. The component takes no props.
Form submission is simulated — there is no real backend or email service connected. After a 2-second delay the component sets a success state for 5 seconds, then resets. To make the form functional, replace the setTimeout logic in handleSubmit with a real API call (e.g. to a Formspree, SendGrid, or custom endpoint).

Usage

import { SpellForm } from './components/SpellForm';

// Used standalone on the /contact page
<SpellForm />

Form Fields

Your True Name

  • Input type: text
  • Required: yes
  • Placeholder: "e.g. Merlin"
  • Styling: border-b border-turquoise/30 (bottom border only) — a minimal underline style

Astral Address (Email)

  • Input type: email
  • Required: yes
  • Placeholder: "merlin@avalon.com"
  • Styling: same bottom-border treatment

The Incantation (Message)

  • Element: <textarea rows={4}>
  • Required: yes
  • Placeholder: "Speak your purpose..."
  • Styling: border border-turquoise/30 rounded-lg — a full border (unlike the inputs above)
  • The textarea value is bound to controlled state message — this is what drives the runic particle system
All fields share: w-full bg-ink/50 px-4 py-3 text-parchment focus:outline-none focus:border-turquoise transition-colors font-serif text-lg placeholder:text-parchment/20.

Submit Button States

StateVisual
Idle"Cast Spell"font-serif text-xl text-parchment tracking-wider group-hover:text-turquoise
SubmittingRotating Sparkles icon (lucide-react), animate: { rotate: 360 }, transition: { duration: 2, repeat: Infinity, ease: "linear" }
Success"Spell Cast Successfully"font-serif text-xl text-turquoise tracking-wider
The button is disabled during both submitting and success states (opacity-50 cursor-not-allowed). A shimmer gradient (bg-gradient-to-r from-transparent via-turquoise/20 to-transparent) sweeps across the button on hover via animate-[shimmer_1.5s_infinite].

Runic Particle System

As the user types in the message textarea, Elder Futhark runes float upward in the space above the form (absolute -top-32 h-32 pointer-events-none overflow-hidden). The full rune set used:
ᚠ ᚢ ᚦ ᚨ ᚱ ᚲ ᚷ ᚹ ᚺ ᚾ ᛁ ᛃ ᛇ ᛈ ᛉ ᛊ ᛏ ᛒ ᛖ ᛗ ᛚ ᛜ ᛟ ᛞ
The number of visible runes scales with the message length:
const visibleRunes = message.length > 0
  ? runeSet.slice(0, Math.min(message.length / 5 + 1, 10))
  : [];
  • At 0 characters: no runes
  • At 5 characters: 2 runes
  • At 45+ characters: 10 runes (maximum)
Each rune is an AnimatePresence-managed motion.div:
initial:    { opacity: 0, y: 20, x: Math.random() * 200 - 100 }
animate:    { opacity: [0, 1, 0], y: -100 }
exit:       { opacity: 0 }
transition: { duration: 2, repeat: Infinity, delay: index * 0.2 }
className:  "absolute bottom-0 left-1/2 text-turquoise font-serif text-2xl text-glow"
Runes start at the bottom of the container, drift upward 100 px, and fade in and out in a continuous loop. Each rune is staggered by 200 ms.

Submission Flow

1. User submits form
   → setSubmitting(true)
   → button shows rotating Sparkles icon

2. After 2000 ms (setTimeout)
   → setSubmitting(false)
   → setSuccess(true)
   → message field cleared ("")
   → button shows "Spell Cast Successfully"
   → 20-particle confetti burst fires

3. After 5000 ms (nested setTimeout)
   → setSuccess(false)
   → form resets to idle state

Confetti Burst Animation

On success, 20 motion.div particles are rendered via AnimatePresence (the outer motion.div fades out after 1 s with a 1 s delay):
// Each of 20 particles
initial:    { scale: 0, x: 0, y: 0 }
animate:    { scale: [0, 1, 0], x: (Math.random() - 0.5) * 400, y: (Math.random() - 0.5) * 400 }
transition: { duration: 1, ease: "easeOut" }
className:  "absolute w-2 h-2 bg-turquoise rounded-full shadow-[0_0_10px_#40E0D0]"
Each particle flies outward in a random direction within a ±200 px radius, shrinks back to zero scale, and dissolves — creating a starburst of glowing turquoise dots.

Form Container Styling

w-full max-w-lg mx-auto
bg-midnight/50 p-8 rounded-2xl
border border-turquoise/20
backdrop-blur-sm
relative z-10
The space-y-6 between fields and the relative z-10 (above the rune particle layer which is pointer-events-none) complete the layout.

Build docs developers (and LLMs) love