# Side Project Showcase Template — Research Brief

> **Day 30 of 365.** Single-page "things I've built" inventory for indie makers, hobbyists, and engineers. NOT a developer portfolio with case studies (Day 1), NOT an indie-hacker landing with MRR narrative (Day 14). The unit of content is the **project artifact** — what was built, what stack, what status, link out. No long-form write-ups, no revenue-transparency story arc.

---

## Audience & primary CTA

- **Who visits:** Potential employers or collaborators scanning for evidence of curiosity and range; fellow makers browsing a specific stack ("anything in Rust here?"); the maker themselves sharing the URL from a GitHub README, Twitter bio, or LinkedIn about section.
- **Primary CTA:** Click through to a live project (or its source). The template exists to route eyeballs to the work.
- **Secondary CTAs:** Follow on GitHub / X; contact (LinkedIn primary, email secondary per project convention); JSON feed embed for makers who want to pipe their project list into other bio tools.

---

## Reference sites (real businesses / makers)

- https://levels.io/projects/ — Reverse-chronological list, date-stamped, no status badges, no filtering, embedded tweets as social proof. Strength: radical transparency and completeness (1993–2022). Weakness: no visual hierarchy between live and dead projects, no filtering, last updated 2022.
- https://indiepa.ge/marclou — Single-column card list; each card: logo, product name, one-line description, "Acquired" or "Discontinued" badge, revenue figure inline. Strength: status badges + revenue signal. Weakness: no tech stack, no year, no filtering, third-party platform (not self-hosted).
- https://dvassallo.com/ — Extreme minimalism: name, bulleted product list (title + link only), no descriptions, no badges, no stack. Strength: fastest possible scan. Weakness: zero metadata — indistinguishable from a link-in-bio.
- https://www.coryzue.com/projects/ — Clean card grid: thumbnail, title, 1-line description. No status badges, no tech stack chips, no filtering. Strength: images give visual personality. Weakness: all projects look equivalent regardless of live/dead state.
- https://zenorocha.com/projects — Chronological by year (section headers per year), featured top block with user-count metrics ("1M+ users"), then full archive list. Strength: the year-grouping signals evolution over time; metrics on featured entries build trust. Weakness: no filtering, no tech stack, no status differentiation between active and archived work.
- https://swyx.io/ideas — Text-forward idea/essay archive with category filter chips (Essay, Note, Talk, etc.). 627 items, client-side filter. Strength: demonstrates that client-side filtering on a large static list is usable and fast. Directly informs our filter implementation approach.

---

## Existing templates surveyed

- **Astrofy** (github.com/manuelernestog/astrofy) — Strength: project section with card grid. Weakness: no status badges, no tech stack chips, no filter by status, no year grouping, generic visual treatment identical to developer portfolio.
- **RyanFitzgerald/devportfolio** (Astro + Tailwind) — Strength: modern stack. Weakness: project section subordinate to experience timeline — not a standalone inventory page.
- **astro-bento-portfolio** — Strength: bento grid is visually interesting. Weakness: bento tiles do not map well to a long tail of 8-12 projects — layout breaks after ~6 items.
- **AstroZen / Astrofolio (Vercel templates)** — Generic card grids, no status system, no filtering, no schema.org, light-mode-only without toggle.
- **Themeforest** — No standalone "side project showcase" category exists. Saturated: generic "portfolio with projects section" (usually subordinate to experience or blog). The niche of a pure, dense project inventory page is unaddressed.
- **Gap confirmed:** No free MIT template exists that ships (a) rich per-project metadata, (b) semantic status badges, (c) client-side filter by status and stack, (d) TypeScript data source, (e) GH Pages deploy, as a standalone single-page experience.

---

## Persona — Mira Kovač

**Name:** Mira Kovač  
**Bio:** Vienna-based backend engineer and weekend maker. Mostly Go, Postgres, and whatever frontend framework won't slow her down.  
**Handles:** GitHub · X · LinkedIn (uses canonical project convention — builder updates to their own)

**Projects (10 entries spanning all statuses):**

| Name | Description (≤100 chars) | Year | Status | Stack | Metric |
|------|--------------------------|------|--------|-------|--------|
| **Shuttlr** | Simple background job queue for Postgres — no Redis needed | 2021→ongoing | Live | Go, Postgres, Docker | 4.2k GitHub stars |
| **Logpilot** | Tail and search logs from multiple servers in one terminal | 2022→ongoing | Live | Go, SSH, TUI | 1.1k active installs |
| **Taskline** | Minimal Kanban board that runs from a single SQLite file | 2023→ongoing | Live | Go, HTMX, SQLite | ~320 users |
| **Mirrorcast** | Self-hosted screen-share tool, P2P via WebRTC | 2022→2023 | Archived | TypeScript, WebRTC | Worked well, not maintained |
| **Flashform** | Opinionated form builder for Go HTTP servers | 2021→2022 | Archived | Go, HTML | Superseded by Huma/Chi patterns |
| **NoteVault** | Encrypted personal notes sync — end-to-end, self-hosted | 2023→2024 | Sold | Go, AES-256, SQLite | Acquired by small team, $6k |
| **Planify** | Team standup scheduler with Slack + email digest | 2022→2023 | Sold | Go, Postgres, Slack API | Sold for $3.2k on Acquire.com |
| **GoBench** | Micro-benchmarking harness for Go HTTP handlers | 2024→ongoing | WIP | Go | Early dev, no release |
| **Crontab.dev** | Visual cron expression builder and tester | 2024→ongoing | WIP | TypeScript, Astro | Beta, feedback welcome |
| **pg-jobs** | Lightweight job queue library for Go + Postgres (MIT) | 2023→ongoing | OSS | Go, Postgres | 780 GitHub stars |

---

## Layout recommendation — Hybrid: featured row + compact grid

**Recommendation: Hybrid layout.** Top row: 2–3 "featured" cards at full width (or 2-col), larger thumbnail area, description, metrics. Below: uniform 3-col card grid for the full inventory. Below that (optional): a tight 2-col "link list" for the 1-2 archived projects that don't deserve card real estate.

**Justification:**
- Bento-style fails at 10+ items — tile-size decisions become arbitrary busy-work for the operator.
- Pure uniform grid (all cards equal) makes a "Sold for $6k" project look identical to a dead weekend experiment.
- Pure tabular list (spreadsheet) is high-density but loses visual personality; better for 30+ items.
- Pure timeline obscures the living/dead distinction — zenorocha.com demonstrates this.
- Hybrid solves all of the above: featured cards signal the maker's "best bets"; the grid below is fast to scan; compact tail rows handle stale/archived entries gracefully. The swyx.io pattern proves client-side filters work elegantly on the full list.

**Filter bar** sits above the grid, persistent on scroll (sticky). Shows: **All · Live · Archived · Sold · WIP · OSS**. Stack filter is a secondary multi-select dropdown rather than a chip row (avoids chip row growing to 20+ items as stack diversity grows). Text search input with `/` keyboard shortcut. Year sort toggle (newest first / oldest first).

**Filter implementation recommendation:** Status chips only as primary filter (5 chips max). Stack filter as a `<select multiple>` or popover dropdown — too many stacks for chip row. Text search optional but recommended. Skip "sort by name" — not useful for this register. Newest-first default.

---

## Must-have sections (in order)

1. **Header** — Name, 1-line bio, social strip (GitHub, X, LinkedIn), "Last updated" timestamp (compile-time).
2. **Filter bar** — Status chips (All / Live / Archived / Sold / WIP / OSS) + stack dropdown + search input. Sticky.
3. **Featured projects** — 2–3 top projects in 2-col larger cards. Each: name, description, status badge, stack chips (3 max), year range, primary metric, "Visit →" or "Source →" button. Optional screenshot/icon.
4. **All projects grid** — Uniform 3-col (2-col on tablet, 1-col on mobile) for the rest. Same metadata at smaller density. Filtered by status chips in real time. Each card has a permalink anchor (`#shuttlr`).
5. **Footer** — Social row, "Built with Astro · MIT licensed", TemplateInfo bar.

No hero image. No long bio paragraph. No newsletter section (that's Day 14's register). No revenue stats band (also Day 14). Persona speaks through the project list itself.

---

## Design conventions — observed from reference sites

- **Typography tendency:** Makers skew sans-serif, clean, readable at list density. zenorocha, dvassallo, levels.io all use system/sans stacks. Marc Lou's Indie Page is the cleanest with a single geometric sans. No serif anywhere in the reference set — the content is metadata-forward, not editorial.
- **Color tendency:** Light-default (all references except levels.io, which is famously raw dark). Accent is typically a single bold hue used only for active state and CTAs.
- **Imagery:** Project icons or screenshots — never full-bleed photography, never illustration. Many references use no images at all (dvassallo, levels.io). We use small square icons (64×64 SVG/PNG) per project — optional — falling back to a colored initial letter.
- **Density:** Medium-high. More data-forward than a marketing landing, less dense than a spreadsheet. Cards have visible padding but no generous whitespace margins.

---

## Palette & typography — Day 30 pick

**Palette: Copper / warm off-black on warm cream**

```
--bg:           #FAF7F2   /* warm cream — distinct from Day 29's cool #F9F9FB */
--surface:      #FFFFFF
--surface-muted:#F3EFE8   /* warm gray — filter bar, inactive chips */
--accent:       #B5541C   /* copper-rust — warm, crafty, "leather-bound notebook" energy */
--accent-light: #FDF0E8   /* copper tint — active chip fill */
--text:         #1C1510   /* very warm near-black */
--text-muted:   #7A6A5A   /* warm gray-brown */
--border:       #E8DFD0   /* warm beige border */
```

Dark mode: `--bg: #161210`, `--surface: #1F1A17`, `--accent: #D4713A` (lightened copper), borders warm gray-brown. System-preference toggle.

**Justification:** Copper/rust on warm cream is entirely absent from Days 1–29. It reads as "maker's workbench" — warm, handcrafted, confident without being corporate. Pairs naturally with project metadata (stack chips, status pills) because the accent only appears on interactive elements and the Live badge — everything else is neutral. Not the terracotta of Day 15 (coral/light-warm) nor Day 23 (terracotta-rust/parchment) — copper is more orange-brown and richer, not the sandy red of terracotta.

**Typography: Epilogue + JetBrains Mono**

- **Display / UI:** **Epilogue** — a geometric sans with strong variable weight axis. At weight 800 the condensed titling reads bold without aggression. At 400 it is clean body text. Available via Fontsource (OFL). Not used in Days 1–29 (which use Inter, Geist, DM Sans, Newsreader, IBM Plex, Manrope, Outfit, Source Serif 4, Lora, Fraunces, Bricolage Grotesque, Plus Jakarta Sans, Archivo Black, Playfair Display, Spectral, Syne, Cormorant Garamond, Libre Baskerville, Raleway, Space Grotesk, DM Serif Display, Inter Tight, Satoshi).
- **Monospace (year ranges, stack chips, metrics):** **JetBrains Mono** weight 500. Used in Days 13, 14, 28, 29 — but always as a data accent in narrow context. Here: year ranges (`2021 → ongoing`) and optional metric numbers. Acceptable reuse because the template type and palette are fully distinct.

---

## Status badge color system

| Badge | Bg | Text | Contrast ratio | WCAG AA |
|-------|----|------|----------------|---------|
| **Live** | `#D1FAE5` (emerald-100) | `#065F46` (emerald-900) | 8.1:1 | ✓ |
| **Archived** | `#F3F4F6` (gray-100) | `#374151` (gray-700) | 7.0:1 | ✓ |
| **WIP** | `#FEF3C7` (amber-100) | `#92400E` (amber-800) | 7.3:1 | ✓ |
| **Sold** | `#EFF6FF` (blue-50) | `#1E40AF` (blue-800) | 8.4:1 | ✓ |
| **OSS** | `#F5F3FF` (violet-50) | `#5B21B6` (violet-800) | 7.9:1 | ✓ |

Five statuses only. "Discontinued" maps to "Archived" — same visual weight. Rationale: five pills = fast scan, zero ambiguity. More than five and the filter bar becomes a legend quiz.

---

## Tech stack chip system

**Recommendation: Simple text pills, uniform warm-gray tint.** No shields.io — too much visual noise for a 10+ item list. Single color family (`--surface-muted` bg, `--text-muted` text) keeps chips subordinate to status badges. No per-language color-coding — color-by-language means adding new colors for every new language, and the status badge system already carries the visual differentiation load. Chips are small (font-size 11px, padding `2px 8px`, border-radius full), max 3 per card (truncate to "+2 more" tooltip if needed).

---

## SEO / schema.org

- **Type:** `Person` (the maker) wrapping an `ItemList` of `SoftwareApplication` (web apps / tools) and `SoftwareSourceCode` (OSS libraries).
- **Required properties on `Person`:** `name`, `url`, `sameAs` (GitHub, X, LinkedIn), `description` (bio), `knowsAbout` (stack tags).
- **Per-project `SoftwareApplication`:** `name`, `description`, `url`, `applicationCategory`, `dateCreated`, `keywords` (stack array), `offers` (for live products — type `Offer`, `price: "0"` or omit if paid).
- **Per-project `SoftwareSourceCode` (OSS):** `name`, `codeRepository` (GitHub URL), `programmingLanguage`, `license` (MIT URL).
- **OG image direction:** Warm cream background, maker name in Epilogue 800 at ~72px warm near-black, below: count of projects ("10 side projects · Go · TypeScript · Postgres"), bottom strip copper accent band with GitHub handle. 1200×630 SVG committed as static asset.

---

## Static-only fit

No concerns. Everything is static:
- **Project data:** `src/data/projects.ts` — TypeScript array, not MDX content collection. At 10–15 projects, a typed array is faster to edit and requires no frontmatter tooling. The operator opens one file, edits one object, pushes. Recommend a `Project` interface with `status: 'Live' | 'Archived' | 'Sold' | 'WIP' | 'OSS'`, `stack: string[]`, `year: { start: number; end: number | 'ongoing' }`, `metric?: string`, `url?: string`, `source?: string`, `icon?: string`.
- **Filter / sort:** Client-side JS on the static DOM — same approach as Day 29 changelog filter chips. No server needed.
- **"Last updated" timestamp:** Injected at build from `new Date().toISOString()` in the Astro layout. Updates on every deploy.
- **JSON feed of projects:** Generate a `public/projects.json` endpoint at build time via an Astro `src/pages/projects.json.ts` endpoint — zero config, pure static. Useful for makers who want to embed their list elsewhere.
- **No booking flow, no payments, no real-time data.** This template is a pure static read.

---

## Differentiation — what we'll do better

- **Status semantics are first-class.** No existing free template has a semantic status system (Live / Archived / Sold / WIP / OSS) with verified WCAG AA badge colors, filter chips, and a data schema that enforces the type.
- **TypeScript-typed project data.** The `Project` interface at `src/data/projects.ts` makes the template self-documenting. The operator can't accidentally misspell a status — TypeScript catches it at build.
- **Hybrid layout for realistic project volumes.** Featured cards for the best work, compact grid for the tail — the only surveyed approach that works elegantly at 8–15 projects without operator layout decisions.
- **JSON feed endpoint out of the box.** `/projects.json` is unique in this template space — it lets makers embed their project list in their GitHub README, Notion, or other bio tools via a single URL.
- **Permalink anchors per project.** `#shuttlr` deep links are present on every card — the maker can link directly to one project from a tweet or email.
- **GH Pages one-click, zero Vercel lock-in.** None of the reference sites are distributable templates. Every alternative surveyed requires Vercel or Next.js. We ship a wired `pages.yml`.
- **Dark mode + warm palette.** All reference makers use light-only. We offer both, designed-first.

Sources:
- [levels.io/projects/](https://levels.io/projects/)
- [indiepa.ge/marclou](https://indiepa.ge/marclou)
- [dvassallo.com](https://dvassallo.com/)
- [coryzue.com/projects/](https://www.coryzue.com/projects/)
- [zenorocha.com/projects](https://zenorocha.com/projects)
- [swyx.io/ideas](https://www.swyx.io/ideas)
- [indiepa.ge (Indie Page platform)](https://indiepa.ge/)
- [Astro Themes Directory](https://astro.build/themes/)
- [Vercel Portfolio Templates](https://vercel.com/templates/portfolio)
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
