Documentation 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.
All content in Systems Witch is stored as plain JavaScript data arrays and strings at the top of their respective page components in assets/main.js. There is no CMS, no external database, and no config file to manage — just find the array, edit the entries, and rebuild. The components are purely presentational: they read the data and render it; the shape of the data determines what appears on screen.
Projects
The projects array, defined just before the ProjectsView component, drives the /projects grid. Each object in the array becomes one project card:
{
id: "01", // Two-digit string shown as a large ghost number on card hover
title: "PROJECT_NAME", // All-caps monospace title displayed in the card header
description: "...", // One-sentence description shown in IBM Plex Sans below the title
tags: ["--frontend", "--webgl"], // Must match values in the filters array (see below)
link: "https://..." // URL opened by the [ run.exe ] button in the card footer
}
The current project entries are:
| id | title | tags |
|---|
"01" | NEURAL_WEAVE | --frontend, --webgl |
"02" | VOID_PROTOCOL | --backend, --crypto |
"03" | GRIMOIRE.UI | --frontend, --design |
"04" | ECHO_CHAMBER | --creative, --hardware |
The filter buttons above the grid are generated from a separate filters array:
const filters = ["--all", "--frontend", "--backend", "--design", "--creative"];
"--all" is a special value that bypasses tag filtering and shows every project. All other values are matched against each project’s tags array. If you add a new tag to a project entry, add the same value to the filters array — otherwise no filter button will exist for it.
Skills
The skills array, defined just before SkillsView, populates the portrait-orientation skill cards on /skills. Cards are rendered in array order:
{
name: "React / Next.js", // Displayed in Cinzel serif italic at the card center
level: 90, // Integer 0–100; drives the animated progress bar width
category: "Frontend" // Shown in the top-right corner of the card in small monospace
}
The current six entries are React / Next.js (90), TypeScript (85), Node.js (75), WebGL / Three.js (60), Tailwind CSS (95), and System Architecture (80). The progress bar width animates from 0 to ${level}% on scroll-into-view using a Framer Motion whileInView transition.
Articles
The articles array, defined just before ArticlesView, populates the ls-style file listing on /articles. Each entry represents one row in the table:
{
name: "article-slug.md", // Shown in the NAME column; also used by the grep filter
size: "14K", // Shown in the SIZE column
date: "May 20", // Shown in the DATE column
perms: "-rw-r--r--" // Shown in the PERMS column
}
The grep input at the top of the page filters rows in real time by matching against name. The current five entries are:
| name | size | date |
|---|
architecting-the-void.md | 14K | May 20 |
css-as-incantation.md | 8.2K | May 15 |
state-management-rituals.md | 21K | Apr 30 |
the-death-of-clean-code.md | 12K | Apr 12 |
webgl-sigils-tutorial.md | 45K | Mar 28 |
Article names currently link nowhere — the NAME cell renders plain text. To add links, extend each entry with a link field and update the <td> for the name column to render an <a> tag:
<td className="py-2 px-4 text-bone group-hover:text-acid ...">
<a href={article.link} target="_blank" rel="noopener noreferrer">
{article.name}
</a>
</td>
Testimonials
The testimonials array, defined just before TestimonialsView, populates the encrypted-message feed on /testimonials. Each entry is one transmission card:
{
id: "TRX-001",
sender: "CTO @ Nexus Corp",
timestamp: "2026-05-26T14:32:01Z", // ISO 8601; displayed verbatim in the card header
message: "...", // The testimonial body, rendered in quotation marks
status: "DECRYPTED" // Status label shown bottom-right; any string works
}
The three current entries carry IDs TRX-001, TRX-002, and TRX-003. Each card animates in from the left on scroll using whileInView. The pulsing > Awaiting incoming transmission... line below the cards is hardcoded in the component.
About bio
The bio text lives as inline JSX inside AboutView, rendered inside a terminal-style bg-graphite/30 block. There are five text nodes to update:
- Intro line —
# I am a full-stack developer and digital occultist. — the <span className="text-acid"> prefix renders as #.
- Work philosophy sentence — the paragraph describing the intersection of “hard logic” and “creative chaos”.
- Philosophy body — the
Code is incantation... paragraph explaining the approach to interfaces.
- Background section header —
## Background.
- Background paragraph — replace the two placeholder tokens with real values:
[REDACTED_AGENCY] → your previous employer or agency name
[STARTUP_NAME] → the startup you scaled infrastructure for
Also update the four ENVIRONMENT_VARIABLES entries in the sidebar info block:
| Key | Default value | Notes |
|---|
LOCATION | "Cyberia" | Your actual location or preferred alias |
FOCUS | "Design_Engineering" | Your current primary focus area |
AVAILABILITY | true | Set to false when not taking contracts — the value renders in text-acid green |
CAFFEINE_LEVEL | 0.89 | A float between 0 and 1.0 |
Hero status line
In HomeView, after the hero tagline, there is a one-line status indicator rendered in monospace:
<div className="pt-8 flex gap-4 justify-center font-mono text-sm">
<span className="text-graphite">//</span>
<span className="text-acid">STATUS:</span>
<span className="text-bone">ACCEPTING_CONTRACTS</span>
</div>
Change ACCEPTING_CONTRACTS to any status string that reflects your current availability, for example:
| String | Meaning |
|---|
ACCEPTING_CONTRACTS | Open for new client work |
HEADS_DOWN | Focused on an ongoing project |
OPEN_TO_HIRE | Looking for a full-time role |
ON_SABBATICAL | Temporarily unavailable |
Profile image
The About page sidebar contains a placeholder where a profile photo should go. The current markup renders a dot-grid background and the text [ IMAGE_DATA_MISSING ]:
<div className="w-full h-full bg-graphite flex items-center justify-center overflow-hidden relative">
{/* dot grid overlay */}
<span className="font-mono text-acid text-xs opacity-50">
[ IMAGE_DATA_MISSING ]
</span>
</div>
Replace the inner contents with a real <img> tag to display your photo:
<div className="w-full h-full bg-graphite flex items-center justify-center overflow-hidden relative">
<img
src="/path/to/your-photo.jpg"
alt="Profile"
className="w-full h-full object-cover"
/>
</div>
The outer wrapper already handles the aspect-square ratio, border border-acid frame, and the four corner accent squares — those remain unchanged.
All data arrays are defined at module scope immediately before their page component in assets/main.js. The quickest way to locate them is to search for the array name: const projects, const skills, const articles, const testimonials.