Skip to main content

Documentation Index

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

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

witch-dev is designed to be forked and personalized. The navigation routes, page content, color palette, and build path are all controlled by a small set of configuration files. This guide walks through each customization point and explains what to change to make the portfolio your own.
Tailwind CSS classes are scanned and compiled at build time. Any change to color tokens, font families, or custom utilities in tailwind.config.js requires a fresh npm run build (or a running npm run dev dev server) before you will see the effect. Edits to the minified files inside dist/ or assets/ are overwritten on the next build and should be avoided.
The sidebar navigation is driven by the ua array defined in components/Navigation.js. Each entry in the array is a route object:
{ path: '/my-new-page', label: 'My Label', icon: SomeLucideIcon }
The current default routes (as found in the source) are:
const ua = [
  { path: '/',         label: 'Summon',     icon: HomeIcon },
  { path: '/about',    label: 'Origins',    icon: UserIcon },
  { path: '/projects', label: 'Grimoire',   icon: BookIcon },
  { path: '/skills',   label: 'Affinities', icon: ZapIcon },
  { path: '/writing',  label: 'Scrolls',    icon: ScrollIcon },
  { path: '/contact',  label: 'Raven',      icon: MailIcon },
];
The icon property accepts any Lucide React icon component. Import it from lucide-react alongside the other icons at the top of Navigation.js. To add a new route:
  1. Add an entry to the ua array:
    { path: '/uses', label: 'Arsenal', icon: WrenchIcon }
    
  2. Create the corresponding page component and register it in your React Router configuration.
  3. Add a static HTML shell at pages/Uses.html following the same pattern as the existing shells (see the Build guide).
  4. Rebuild with npm run build.
To rename a route label — update the label string. The label appears in the tooltip on desktop hover and as the full-size menu item on mobile. To reorder routes — rearrange the objects in the ua array. The navigation renders them in array order.
pages/CaseStudies.html exists in the build output and sets window.__STATIC_PAGE_ROUTE__ = "/case-studies". The /case-studies route is not included in the default ua navigation array — it is a scaffolded shell ready to be activated. To enable it, add a { path: '/case-studies', label: '...', icon: ... } entry to ua and register the route in your React Router configuration.

Page content

Each page’s data is defined as a static array in the corresponding page component source file before the build. After running npm run build, this data is compiled into assets/main.js. To update content, edit the source arrays and rebuild.
PageArray nameShape
Projectsv{ id, title, desc, tags[], mocked, image }
Skillsp{ name, level, category }
Writingj{ id, title, excerpt, category, icon, date, featured }
About (timeline)ue{ id, title, icon, content, color, glow }
About (sidebar)gestring[]
Projects — each entry in the v array defines one project card:
{
  id: 'proj-01',
  title: 'My Project',
  desc: 'A short description of what this project does.',
  tags: ['React', 'TypeScript', 'Tailwind'],
  mocked: false,
  image: '/assets/project-screenshot.png',
}
Skills — each entry in the p array defines one skill bar:
{
  name: 'TypeScript',
  level: 90,          // 0–100, controls the progress bar width
  category: 'Languages',
}
Writing — each entry in the j array defines one post card:
{
  id: 'post-01',
  title: 'My Article Title',
  excerpt: 'A one-sentence summary of the article.',
  category: 'Engineering',
  icon: PenIcon,       // Lucide React icon component
  date: '2025-01-15',
  featured: true,
}
About timeline — each entry in the ue array defines one timeline event:
{
  id: 'timeline-01',
  title: 'Started at Acme Corp',
  icon: BriefcaseIcon,
  content: 'Led the frontend team building ...',
  color: 'coven-purple-400',  // Tailwind color token
  glow: 'box-glow-purple',    // Custom glow utility class
}
About sidebar — the ge array is a plain list of strings displayed as a skill/interest list in the About page sidebar:
const ge = [
  'Open source contributor',
  'Coffee-driven development',
  'Mechanical keyboards',
];

Tailwind colors

witch-dev uses a custom coven-* color palette defined in tailwind.config.js. These tokens are referenced throughout every component via Tailwind utility classes (text-coven-green-400, bg-coven-purple-900, border-coven-magenta, etc.). The full palette, with hex values extracted from the compiled CSS:
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        'coven-black': '#050308',   // Deepest background — body bg
        'coven-dark':  '#0a0612',   // Navigation sidebar and card backgrounds

        'coven-purple': {
          400: '#c026d3',           // Accent borders and active icon tint
          500: '#a855f7',           // Primary purple — nav links, scrollbar
          800: '#2d1b4e',           // Muted purple — glass panel borders
          900: '#1a0b2e',           // Dark purple — active nav bg, card bg
        },

        'coven-green': {
          300: '#bef264',           // Hover text on nav items (mobile)
          400: '#a3e635',           // Active nav icon, glow accents
          500: '#84cc16',           // Button fills, selection highlight bg
        },

        'coven-magenta': '#d946ef', // Accent for magenta glow effects
      },
      fontFamily: {
        creepster: ['Creepster', 'cursive'],   // Decorative display font
        mono:      ['JetBrains Mono', 'monospace'], // Code and monospace UI
        space:     ['Space Grotesk', 'sans-serif'], // Body text
      },
    },
  },
};
To change the accent color — replace the coven-green hex values with your chosen palette. For example, swapping to amber:
'coven-green': {
  300: '#fcd34d',   // amber-300
  400: '#fbbf24',   // amber-400
  500: '#f59e0b',   // amber-500
},
Then rebuild: npm run build. Tailwind regenerates the CSS with the new values. To add a new custom utility — add it to the plugins array or inside an addUtilities call in tailwind.config.js, following the same pattern as box-glow-green, box-glow-purple, and glass-panel:
// Example custom plugin utility
const plugin = require('tailwindcss/plugin');
module.exports = {
  plugins: [
    plugin(({ addUtilities }) => {
      addUtilities({
        '.box-glow-amber': {
          boxShadow: '0 0 15px rgba(251,191,36,0.3), inset 0 0 10px rgba(251,191,36,0.2)',
        },
      });
    }),
  ],
};

Vite base path

If you are deploying to a subdirectory URL — for example, GitHub Pages at https://username.github.io/witch-dev/ rather than a custom apex domain — you must tell Vite what the base path is. Without this, all asset URLs in the HTML output (/assets/main.js) will be absolute and will 404 on the subdirectory host. Set the base option in vite.config.js:
// vite.config.js
export default {
  base: '/witch-dev/',
};
Replace /witch-dev/ with the exact subdirectory path of your deployment. After changing this value, rebuild:
npm run build
Vite will prefix all asset paths in every generated HTML file with /witch-dev/, matching the deployment URL.
If you set base to a subdirectory but deploy to a root domain (or vice versa), all JavaScript and CSS assets will return 404 errors and the site will render a blank page. Double-check that base matches your actual deployment URL before publishing.

canvas.manifest.js

The file canvas.manifest.js (output to dist/canvas.manifest.js) maps internal screen identifiers to route paths. The current manifest registers one screen:
const e = {
  screens: {
    scr_4sn1by: { name: 'Home', route: '/' }
  }
};
export { e as m };
If you add new pages that should appear in the screen manifest — for example if you are integrating a visual canvas editor — add a new entry using a unique ID:
const e = {
  screens: {
    scr_4sn1by: { name: 'Home',   route: '/' },
    scr_7xk2pq: { name: 'Uses',   route: '/uses' },
    scr_9mf3wz: { name: 'Resume', route: '/resume' },
  }
};
export { e as m };
Adding a screen to canvas.manifest.js alone is not enough to create a working route. You must also:
  1. Create the page component in your source.
  2. Register the route in your React Router configuration.
  3. Create the corresponding HTML shell in pages/YourPage.html with the window.__STATIC_PAGE_ROUTE__ redirect script.
  4. Rebuild with npm run build.

Build docs developers (and LLMs) love