The Contact page merges a standard contact form with a generative art canvas. As the user types their message, a sigil is drawn in real time on aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/systems-witch/llms.txt
Use this file to discover all available pages before exploring further.
250×250 canvas to the right of the form — each character’s ASCII code determines the angle and radius of a point in a closed path, producing a unique geometric glyph for every message. The form advances through three states (idle, casting, sent) and clears after a simulated transmission.
Layout
The page uses a two-column grid onmd+ screens:
Form fields
The form has two inputs and a submit button, all inside aspace-y-6 font-mono form element:
placeholder:text-graphite — placeholders are nearly invisible until the user focuses, maintaining the terminal aesthetic. The disabled prop locks both fields once submission begins.
Submit button states
The single<button type="submit"> cycles through three text values based on state:
| State | Button text | Button style |
|---|---|---|
idle (message non-empty) | [ CAST_SIGIL ] | border-acid text-acid hover:bg-acid hover:text-black shadow-glow |
idle (message empty) | [ CAST_SIGIL ] | border-graphite text-graphite cursor-not-allowed |
casting | TRANSMITTING... | border-graphite text-graphite cursor-not-allowed |
sent | TRANSMISSION_SUCCESS | border-graphite text-graphite cursor-not-allowed |
shadow-glow class (box-shadow: 0 0 10px rgba(164,255,61,.5)) is only active in the idle+ready state, creating a subtle acid aura around the active button.
Form submission handler
if (!message) return provides a second layer of protection beyond the disabled attribute. In the default build, the 2-second setTimeout simulates a network request. When state reaches "sent", setMessage("") clears the textarea and triggers a useEffect re-run that clears the canvas (because the message length drops to 0).
Canvas sigil algorithm
The canvas is a250×250 <canvas> element accessed via useRef. A useEffect dependent on [message] redraws the sigil every time the message string changes:
- Angle:
charCode % 36 * 10°— divides the full circle into 36 discrete positions (every 10°) - Radius:
(charCode % 100) / 100 * maxRadius— normalizes to 0–100% of the available canvas radius
#A4FF3D) with shadowBlur: 10 and shadowColor: "#A4FF3D" — the canvas shadowBlur property creates the neon glow effect natively without CSS.
Canvas container
The canvas sits inside arelative w-64 h-64 border border-graphite box. A subtle linear-gradient grid (10% opacity, 20px × 20px cells) covers the entire box as an absolutely-positioned background layer:
state === "casting", the container gains animate-pulse-glow border-acid. When state === "sent", the canvas fades to opacity-0 and an overlay text block appears in its place:
State machine summary
sent back to idle in the default implementation — the page effectively becomes read-only after one successful submission. To allow re-submission, add a “Send another” button that calls setState("idle").
The email input has
type="email" and required, so the browser’s native form validation will block submission if the address is malformed. The textarea is also required. These validations fire before handleSubmit is called.