Skip to main content

Documentation Index

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

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

The ProjectPanel and RuneTile components are the primary content-display units for the Projects and Skills pages respectively. Both pull from their corresponding data files and translate raw configuration objects into richly styled, animated cards that match the sys.witch cyber-occult aesthetic — neon glows, monospace type, and Framer Motion entrance animations throughout.

ProjectPanel

ProjectPanel renders the detail view for a single project. It sits in the right-hand column of the Projects page alongside the SummoningCircle selector grid. When a project is selected, Framer Motion animates the panel into view with a slide-and-fade transition; when no project is selected a placeholder projects sigil icon prompts the user to make a choice. The panel receives a single project prop — an object sourced directly from data/projects.js.

Props

PropTypeRequiredDescription
projectobjectYesA project entry from data/projects.js, or null to show the empty state

Rendered Sections

  1. Hero image — full-width, object-cover, rendered with filter grayscale contrast-125 and a magenta colour-overlay blended on top.
  2. Titlefont-display (Tektur), neon-magenta with text-glow.
  3. Tags — each tag from the tags array is rendered as a neon-magenta-bordered mono badge.
  4. Descriptionfont-sans body copy.
  5. Binding Notes — optional footer block rendered only when bindingNotes is present; displayed inside a neon-purple bordered annotation box with a rune-3 sigil icon.
  6. Action links — rendered as GlyphButton instances:
    • demoUrl → “Summon Demo” (solid magenta)
    • sourceUrl → “Reveal Source” (outline purple)
    • readmeUrl → “Inspect Readme” (outline cyan)
All three action link fields (demoUrl, sourceUrl, readmeUrl) are optional. Buttons only render when their corresponding URL is present in the project data.

Data Shape

Each project object in data/projects.js follows this shape:
// data/projects.js
const projects = [
  {
    id: "void-tracker",
    title: "VOID TRACKER",
    description:
      "A dark-mode first task management system utilizing local storage and a custom drag-and-drop interface. Built to organize chaos into structured data.",
    tags: ["React", "TypeScript", "Tailwind", "Zustand"],
    image: "https://images.unsplash.com/photo-1555949963-aa79dcee981c?auto=format&fit=crop&q=80&w=800",
    demoUrl: "#",
    sourceUrl: "#",
    bindingNotes: "Data persists locally. No external database summoned.",
  },
  {
    id: "nexus-dashboard",
    title: "NEXUS DASHBOARD",
    description:
      "Real-time analytics dashboard visualizing mock server metrics. Features custom D3.js charts wrapped in React components with glowing neon aesthetics.",
    tags: ["Next.js", "D3.js", "Framer Motion", "WebSockets"],
    image: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80&w=800",
    demoUrl: "#",
    sourceUrl: "#",
    readmeUrl: "#",
    bindingNotes: "Metrics are simulated via client-side generation.",
  },
  {
    id: "spell-checker-cli",
    title: "SPELL.CHK CLI",
    description:
      "A command-line tool for linting markdown files for specific terminology and style guide adherence. Written in Rust for maximum execution speed.",
    tags: ["Rust", "CLI", "Regex", "Markdown"],
    image: "https://images.unsplash.com/photo-1629654297299-c8506221ca97?auto=format&fit=crop&q=80&w=800",
    sourceUrl: "#",
    readmeUrl: "#",
    // no demoUrl — "Summon Demo" button is omitted
  },
  {
    id: "alchemy-ui",
    title: "ALCHEMY UI",
    description:
      "A component library of highly animated, accessible React components. Focuses on complex micro-interactions and keyboard navigability.",
    tags: ["React", "Storybook", "Radix UI", "CSS Modules"],
    image: "https://images.unsplash.com/photo-1507721999472-8ed4421c4af2?auto=format&fit=crop&q=80&w=800",
    demoUrl: "#",
    sourceUrl: "#",
    // no readmeUrl or bindingNotes
  },
];

JSX Usage

import { ProjectPanel } from "@/components/projects/ProjectPanel";
import { projects } from "@/data/projects";

export default function ProjectsPage() {
  const [activeProject, setActiveProject] = React.useState(null);

  return (
    <div className="flex gap-8">
      {/* Selector column — SummoningCircle grid renders here */}
      <ProjectPanel project={activeProject} />
    </div>
  );
}

SummoningCircle

SummoningCircle is the circular project-selector button that appears in the left-hand column of the Projects page. Each circle represents one project and, when active, triggers the corresponding ProjectPanel to animate in.

Props

PropTypeRequiredDescription
projectobjectYesA project entry from data/projects.js
onClickfunctionYesCallback fired when the circle is clicked
isActivebooleanYesWhether this circle is the currently selected item

Behaviour

  • Two concentric dashed rings (outer magenta, inner purple dotted) rotate continuously via Framer Motion when isActive is true.
  • The inner content area shows a faint background image of the project, a projects sigil icon, and the project title in font-display.
  • Four cardinal-point rune icons orbit the ring edge at 0°, 90°, 180°, and 270°.
  • When active the title glows neon-magenta; when hovered it transitions from text-text-primary to neon-magenta.
import { SummoningCircle } from "@/components/projects/SummoningCircle";

<SummoningCircle
  project={projects[0]}
  isActive={activeId === projects[0].id}
  onClick={() => setActiveId(projects[0].id)}
/>

RuneTile

RuneTile renders a single skill card on the Skills page. Skills are sourced from data/skills.js and mapped to a grid of tiles, each receiving its skill object and a numeric index for staggered entrance animation delays.

Props

PropTypeRequiredDescription
skillobjectYesA skill entry from data/skills.js
indexnumberYesPosition in the rendered list; drives animation delay (index * 0.05s)

Mastery Colour Map

The mastery field controls the colour of the badge label in the top-right corner of each tile:
Mastery valueColour token
"Initiate"text-neon-cyan
"Adept"text-neon-purple
"Master"text-neon-lime
On hover the border transitions from neon-lime/20 to neon-lime/60 and a lime glow shadow appears. The sigil icon in the top-left gains a drop-shadow-glow-lime effect.

Data Shape

// data/skills.js
const skills = [
  {
    id: "ts",
    name: "TypeScript",
    category: "Languages",
    mastery: "Master",        // "Initiate" | "Adept" | "Master"
    description: "Strict typing rituals to banish runtime errors.",
    sigilId: "rune-1",
  },
  {
    id: "js",
    name: "JavaScript",
    category: "Languages",
    mastery: "Master",
    description: "The chaotic ancient tongue of the web.",
    sigilId: "rune-2",
  },
  {
    id: "python",
    name: "Python",
    category: "Languages",
    mastery: "Adept",
    description: "Serpentine scripts for automation and data binding.",
    sigilId: "rune-3",
  },
  {
    id: "react",
    name: "React",
    category: "Front-End",
    mastery: "Master",
    description: "Component conjuration and state alchemy.",
    sigilId: "rune-4",
  },
  {
    id: "tailwind",
    name: "Tailwind CSS",
    category: "Front-End",
    mastery: "Master",
    description: "Utility-first styling incantations.",
    sigilId: "rune-5",
  },
  {
    id: "framer",
    name: "Framer Motion",
    category: "Front-End",
    mastery: "Adept",
    description: "Breathing life into static DOM elements.",
    sigilId: "rune-6",
  },
  {
    id: "node",
    name: "Node.js",
    category: "Back-End/Data",
    mastery: "Adept",
    description: "Server-side runtime environments.",
    sigilId: "rune-7",
  },
  {
    id: "sql",
    name: "SQL",
    category: "Back-End/Data",
    mastery: "Adept",
    description: "Relational data extraction and manipulation.",
    sigilId: "rune-1",
  },
  {
    id: "debug",
    name: "Chrome DevTools",
    category: "Debugging",
    mastery: "Master",
    description: "Peering into the void to find the source of bugs.",
    sigilId: "rune-2",
  },
  {
    id: "jest",
    name: "Jest / Vitest",
    category: "Debugging",
    mastery: "Adept",
    description: "Automated wards against regressions.",
    sigilId: "rune-3",
  },
  {
    id: "git",
    name: "Git",
    category: "Git/GitHub",
    mastery: "Master",
    description: "Timeline manipulation and alternate reality branching.",
    sigilId: "rune-4",
  },
  {
    id: "figma",
    name: "Figma",
    category: "Design",
    mastery: "Adept",
    description: "Vector manipulation and interface pre-visualization.",
    sigilId: "rune-5",
  },
];

JSX Usage

import { RuneTile } from "@/components/skills/RuneTile";
import { skills } from "@/data/skills";

export default function SkillsPage() {
  return (
    <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
      {skills.map((skill, index) => (
        <RuneTile key={skill.id} skill={skill} index={index} />
      ))}
    </div>
  );
}
To add a new skill, append an entry to data/skills.js. Use one of the existing sigilId values (rune-1 through rune-7) and set mastery to "Initiate", "Adept", or "Master" to control the badge colour.

Build docs developers (and LLMs) love