Skip to main content

Documentation Index

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

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

All of Space Mission’s portfolio content is defined as plain TypeScript/JavaScript arrays inside the source files. There is no CMS, no database, and no external API — every project card, skill node, work history entry, and testimonial is a literal object in the source code. When you run npm run build, Vite compiles those arrays into assets/main.js, which is what the deployed site actually serves. To change any content, you edit the source TypeScript files and rebuild.
The GitHub Pages deployment in this repository contains pre-built outputindex.html, assets/, components/, and pages/. Content changes must be made in the original TypeScript source files and rebuilt with npm run build before committing the new dist/ output.

Mission Briefing

The home page opens with a “Mission Briefing” terminal block that types out four lines one after another using a TypewriterText component. Each line has its own text string and a delay in milliseconds controlling when it starts animating. The four lines currently configured are:
> INITIALIZING TELEMETRY... SUCCESS.
> SUBJECT: Senior Software Engineer / Navigator of Code.
> STATUS: All systems nominal. Caffeine levels stable. Currently orbiting the React/TypeScript sector with occasional deep-space probes into backend nebulae.
> DIRECTIVE: Explore the star map above to access mission logs, orbital parameters, and archived transmissions.
In the source file, each line is rendered as a <TypewriterText> element:
<p><TypewriterText text="> INITIALIZING TELEMETRY... SUCCESS." delay={500} /></p>
<p><TypewriterText text="> SUBJECT: Senior Software Engineer / Navigator of Code." delay={1500} /></p>
<p><TypewriterText text="> STATUS: All systems nominal. ..." delay={3000} /></p>
<p><TypewriterText text="> DIRECTIVE: Explore the star map above ..." delay={7000} /></p>
To change the briefing text, replace the text prop value. To adjust the timing, update the delay value (in milliseconds). The third and fourth lines have longer delays to let the earlier lines finish typing first — keep that stagger in mind when adding or reordering lines.

Projects (Star Map)

The Projects page renders a draggable, zoomable star map. Each project is a glowing circle positioned absolutely on a 200vw × 200vh canvas using percentage coordinates. Clicking a circle opens a slide-in panel with the project details.

Data shape

interface Project {
  id: string;       // Unique identifier string
  name: string;     // Display name shown below the circle
  type: string;     // Category label (e.g. "Design System", "Dashboard")
  x: number;        // Horizontal position, 0–100 (percentage of canvas width)
  y: number;        // Vertical position, 0–100 (percentage of canvas height)
  size: number;     // Circle diameter in pixels (30–60 recommended)
  color: string;    // Hex color for the glow and fill (e.g. "#22d3ee")
  desc: string;     // Short description shown in the detail panel
  stack: string[];  // Array of technology names displayed as tags
}

Current projects

NameTypeColor
Nebula UIDesign System#22d3ee
Quasar AnalyticsDashboard#14b8a6
Pulsar APIBackend Service#7c3aed
Void ExplorerWeb3 App#f43f5e
Comms RelayChat App#eab308

Adding a project

Append a new object to the projects array in the source file:
{
  id: "6",
  name: "Gravity Well",
  type: "Mobile App",
  x: 55,
  y: 45,
  size: 45,
  color: "#a855f7",
  desc: "A cross-platform fitness tracker that treats rest days as orbital decay.",
  stack: ["React Native", "Expo", "Supabase"],
},
Keep x and y values spread across the full 0–100 range so the star map isn’t cluttered. Projects that are too close together will overlap their label text. Aim for at least 15–20 units of separation between any two projects’ coordinates.

Skills (Constellations)

The Skills page renders a starfield overlay where each skill group forms a named constellation. Nodes are positioned as percentage values on the viewport, connected by animated SVG lines. Hovering a node highlights its constellation and shows experience in years.

Data shape

interface SkillNode {
  id: string;     // Unique ID used to reference this node in connections
  label: string;  // Skill name displayed below the node
  x: number;      // Horizontal position, 0–100 (viewport percentage)
  y: number;      // Vertical position, 0–100 (viewport percentage)
  years: number;  // Years of experience — controls the node's rendered size
}

interface Constellation {
  id: string;                    // Unique ID for the constellation
  name: string;                  // Display name (e.g. "LYRA (Frontend)")
  color: string;                 // Hex color for nodes and connecting lines
  nodes: SkillNode[];            // Array of skill nodes
  connections: [string, string][]; // Pairs of node IDs to connect with lines
}

Current constellations

ConstellationColorSkills
LYRA (Frontend)#22d3eeReact, TypeScript, Tailwind, Next.js
CYGNUS (Backend)#7c3aedNode.js, PostgreSQL, Redis, GraphQL
ORION (Tools)#14b8a6Git, Docker, AWS

Adding a skill node to an existing constellation

To add a new node to LYRA, append to its nodes array and add a connection:
{
  id: "frontend",
  name: "LYRA (Frontend)",
  color: "#22d3ee",
  nodes: [
    { id: "react",   label: "React",      x: 20, y: 30, years: 5 },
    { id: "ts",      label: "TypeScript", x: 35, y: 20, years: 4 },
    { id: "tw",      label: "Tailwind",   x: 45, y: 40, years: 3 },
    { id: "next",    label: "Next.js",    x: 25, y: 50, years: 3 },
    // New node:
    { id: "vite",    label: "Vite",       x: 38, y: 55, years: 2 },
  ],
  connections: [
    ["react", "ts"],
    ["ts", "tw"],
    ["react", "next"],
    ["next", "tw"],
    // Connect to the new node:
    ["next", "vite"],
  ],
},
Node size scales with years — a node with years: 6 renders noticeably larger than one with years: 1, giving viewers an at-a-glance sense of depth.

Work History (Mission Logs)

The Work page displays a vertical timeline of mission patches — one per role. Each entry has a status badge (ACTIVE or COMPLETED) and a patchColor Tailwind class string that tints the border and label text.

Data shape

interface WorkEntry {
  id: number;
  role: string;       // Job title, displayed as the patch heading
  company: string;    // Employer name
  stardate: string;   // Date range in free-form text, e.g. "2022.4 - PRESENT"
  status: "ACTIVE" | "COMPLETED";
  patchColor: string; // Tailwind class string, e.g. "border-space-turquoise text-space-turquoise"
  debrief: string;    // Role description / achievements paragraph
  tech: string[];     // Technologies used, rendered as tags
}

Current entries

RoleCompanyStatus
Senior Navigator (Frontend)Stellar TechACTIVE
Flight Engineer (Fullstack)Nebula SystemsCOMPLETED
Cadet DeveloperOrbit MediaCOMPLETED

Adding a new entry

{
  id: 4,
  role: "Principal Engineer",
  company: "Horizon Labs",
  stardate: "2024.1 - PRESENT",
  status: "ACTIVE",
  patchColor: "border-purple-400 text-purple-400",
  debrief:
    "Spearheading the migration of a decade-old monolith into a distributed micro-frontend architecture. Reduced time-to-deploy from two weeks to under four hours.",
  tech: ["React", "Module Federation", "Kubernetes", "TypeScript"],
},
The patchColor field accepts any valid Tailwind border + text class pair. The value is applied directly to the patch element, so make sure both classes exist in your Tailwind configuration.

Case Studies (Archive)

The Case Studies page lists mission debriefs as clickable cards. Each entry links to a detail page at /case-studies/:slug.

Data shape

interface CaseStudy {
  id: string;
  codename: string;   // Internal mission codename
  client: string;     // Client or project name
  status: string;     // Mission status label, e.g. "CLASSIFIED", "ARCHIVED"
  sector: string;     // Industry or domain area
  summary: string;    // Short description shown on the card
  outcome: string;    // Key result or metric from the engagement
  tags: string[];     // Technology / domain tags
}

Current entries

CodenameSlug
Project Apolloproject-apollo
Data Nebuladata-nebula
Shield Generatorshield-generator

Adding a case study

{
  id: "cs-004",
  codename: "Dark Satellite",
  client: "Meridian Finance",
  status: "ARCHIVED",
  sector: "FinTech",
  summary:
    "Rebuilt the transaction reporting pipeline to handle 10× peak load without vertical scaling.",
  outcome: "99.98% uptime maintained through three consecutive quarter-end surges.",
  tags: ["Node.js", "Kafka", "PostgreSQL", "AWS"],
},
The slug used in the URL is derived from the codename field — use lowercase kebab-case to match the React Router pattern at /case-studies/:slug.

Blog Posts (Transmissions)

The Blog page lists posts in reverse-chronological order. Each post has a signal value (1–5) that renders as a signal-strength bar graphic. Clicking a post navigates to /blog/:slug, which loads the static detail view.

Data shape

interface BlogPost {
  id: number;
  title: string;
  slug: string;     // URL-safe kebab-case identifier — used in the route path
  date: string;     // Display date string, e.g. "2023.10.15"
  category: string; // "Paper", "Essay", or "Dispatch" — controls the icon
  signal: number;   // Signal strength 1–5, rendered as a bar graph
  excerpt: string;  // One-sentence summary shown on the list page
}

Current posts

TitleSlugCategorySignal
State Management in Zero-Gstate-management-in-zero-gPaper5
The Dark Matter of CSSthe-dark-matter-of-cssEssay4
Dispatch from the Edge (Computing)dispatch-from-the-edgeDispatch3

Slug naming convention

Slugs must be lowercase, hyphen-separated, and match exactly what the router will receive as :slug. A post with slug: "typescript-generics-deep-dive" must be navigated to at /#/blog/typescript-generics-deep-dive.

Adding a post

{
  id: 4,
  title: "Async/Await at the Speed of Light",
  slug: "async-await-speed-of-light",
  date: "2024.03.10",
  category: "Paper",
  signal: 4,
  excerpt:
    "Why blocking the event loop is the engineering equivalent of parking in a wormhole.",
},
The three category values map to specific Lucide icons in the source: "Paper"FileText, "Essay"MessageSquare, and "Dispatch"Radio. Any other string falls back to Radio.

Testimonials (Signals)

The Testimonials page floats quote cards at absolute positions on the screen with a slow vertical bobbing animation. Cards are staggered in time using the delay field so they don’t all bob in sync.

Data shape

interface Testimonial {
  id: number;
  name: string;    // Reviewer's name
  role: string;    // Title and affiliation, e.g. "Lead Architect @ Skynet"
  text: string;    // The testimonial body text
  x: number;       // Horizontal position, 0–100 (viewport percentage)
  y: number;       // Vertical position, 0–100 (viewport percentage)
  delay: number;   // Stagger delay in seconds for the bobbing animation
}

Current testimonials

NameRolePosition (x, y)
Sarah ConnorLead Architect @ Skynet10, 20
Ellen RipleyProduct Manager @ Weyland50, 10
David BowmanMission Commander @ Discovery20, 60
CooperPilot @ Endurance60, 50

Adding a testimonial

{
  id: 5,
  name: "HAL 9000",
  role: "Systems Analyst @ Discovery One",
  text: "I am putting myself to the fullest possible use, which is all I think that any conscious entity can ever hope to do — especially after this engineer refactored my state machine.",
  x: 75,
  y: 25,
  delay: 1.5,
},
Position testimonial cards with x and y values spread across the viewport so cards don’t overlap. Cards are w-80 (320 px) wide on mobile and w-96 (384 px) on larger screens — keep at least 30 percentage-point horizontal gaps between cards at similar y values to prevent collisions. Also avoid placing cards near y: 0 or y: 100 since the header and footer consume that space.

Rebuilding After Edits

After modifying any data array in the source TypeScript files, run the following to compile the changes and verify the output:
# Compile the updated source into dist/
npm run build

# Preview the built output locally before deploying
npm run preview
The preview server starts at http://localhost:4173 by default and serves the exact same static files that GitHub Pages (or any other host) would serve. Use it to confirm that new entries appear correctly before pushing to the deploy branch.

Build docs developers (and LLMs) love