Skip to content

refactor: specimen-sheet portfolio rebuild — authentic, verified, minimal - #8

Merged
securitywithhem merged 26 commits into
Hemfrom
scenario-rebuild
Jul 22, 2026
Merged

refactor: specimen-sheet portfolio rebuild — authentic, verified, minimal#8
securitywithhem merged 26 commits into
Hemfrom
scenario-rebuild

Conversation

@securitywithhem

Copy link
Copy Markdown
Owner

Summary

Complete portfolio redesign from scenario-driven to specimen-sheet model.
Focus: authentic presence (no AI artifacts), verifiable content (all projects real, all metrics proven),
and recruiter-direct flow (email-first contact, no forms).

Changes

Content

  • Projects audited: Dharma (GRC), VaultIQ (AI Security), Network Recon Tool (Offensive)
    • Each grounded in real GitHub repos, verified live
    • Highlights: concrete metrics (98.3% detection accuracy) and capabilities
    • Private repos show "walkthrough on request" (no dead links)
  • Bio rewritten: Removed "zero-knowledge" overclaim → "client-side encryption + measured AI detection"
  • All claims verified: No marketing fluff; everything a recruiter can check

Design

  • Six-plate specimen layout:
    • Plate 1 (hero/paper): Positioning statement + proof stats
    • Plate 2 (approach/ink): Three beats (Break → Understand → Build) + lattice figure
    • Plate 3 (work/paper): Three projects, one per fold, asymmetric
    • Plate 4 (capabilities/paper-2): Arc diagram (offensive → GRC + AI)
    • Plate 5 (credentials/paper-2): Certificates + TryHackMe with build-time verification
    • Plate 6 (contact/close): Email-first, Copy button, links
  • Archivo variable font: Single family, width axis as hierarchy device (62–125 wdth)
  • OKLCH tokens: --paper, --ink, --close, --accent; accent variants for dark backgrounds
  • Contrast verified: All text/surface pairs ≥4.5:1 WCAG AA (15 pairs measured via culori)

Technical

  • Removed: Contact form backend, Resend dependency, rate-limiter, validation schemas
    • Saves 69 kB First Load JS (237 kB → 168 kB)
    • Rationale: recruiters email or copy address far more than forms
  • Added: Certificate file verification (build-time, no dead links ever)
    • Drop PDFs in public/certificates/ → "View ↗" links light up automatically
  • Added: Copy-to-clipboard for email (single client island, graceful fallback)
  • Cleaned: Removed old scenarios, journey timeline, skill cards, legacy folder

Test Plan

  • Type-check passes (npm run type-check)
  • Lint passes (npm run lint)
  • Tests pass (13 passing, 0 failing)
  • Build succeeds (npm run build)
  • Live rendering verified:
    • All three projects render with highlights
    • Dharma shows private repo note (not broken link)
    • Public repos link to real GitHub pages (verified 200 status)
    • Contact headline reads "Open to security roles."
    • Hero stats show 3 and 1 (no leading zeros)
    • Resume spelling consistent (no accents)
    • Contrast: email (13.96:1), subline (6.81:1), all AA
    • Certificate links hidden when folder empty (no 404s)
    • Form is completely gone (no orphan references)
  • Git history: 8 logical commits, each with descriptive message

Review Notes

  • All content claims traceable to public GitHub repos or real metrics
  • No AI-generated copy; bio, project descriptions, and claims read as human-written
  • Design system is constraint-based (tokens, contrast gates, type scale)
    • Future changes inherit consistency automatically
  • Accessibility built in, not bolted on (contrast measured, reduced-motion defaults)

🚀 Ready to merge to Hem and deploy

Hem Gabhawala and others added 26 commits July 19, 2026 13:34
…l telemetry)

True from-scratch rebuild toward the immersive scenario edition.

- Quarantine legacy rendered/logic layer into legacy/ (excluded from
  tsconfig + ESLint); content preserved for per-phase porting.
- Design System v3 (dark industrial telemetry): CRT substrate, white-phosphor
  fg, four per-scenario accent tokens (red-amber/blue/violet/teal), 2px radius
  ceiling, 1px hairline system, precision-grid + mono-label utilities.
- Fonts Geist -> Inter + JetBrains Mono (doc-mandated two-typeface system).
- Add PRODUCT.md + DESIGN.md (impeccable-init equivalent) locking audience,
  brand lane, palette, typefaces, motion law.
- lint-staged: add --no-warn-ignored so staged legacy/ files don't fail the hook.
- Minimal server-rendered Phase 1 skeleton page; build passes (static
  prerender, 113 kB First Load JS), typecheck + lint clean.

Direction set with taste-skill brutalist (Tactical Telemetry) lens; three
deliberate overrides where 03_UI_UX.md wins (4 accents, 2px radius, restraint).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Sticky navbar with IntersectionObserver scroll-spy and per-scenario active
  highlight (App Flow: nav reflects which of the 4 scenarios is in view, not a
  lump "Scenarios"); condensed desktop nav + full mobile panel; resume download.
- Hero: fully server-rendered/crawlable copy with a reduced-motion-aware
  entrance (Reveal honors prefers-reduced-motion at the call site); primary CTA
  targets the first scenario anchor; résumé download; focus-area telemetry row.
- Footer: contact affordances, social links, back-to-top, telemetry framing.
- Skip-to-content link; global scroll-padding-top for the sticky-nav offset.
- Data/types layer: Profile + ScenarioMeta (nav meta only), navigation contract
  (navLeaves single source of anchor ids), accent scope helpers, data accessors.
- Industrial Button primitive (buttonVariants, no Slot dep).
- A11y: full palette + all 4 accents WCAG-AA verified via culori; routed real
  small text to fg-muted, nudged fg-dim #5A5A60 -> #71717A (4.09:1) for
  decorative separators.

Verified: typecheck + lint clean; build passes (static, 167 kB First Load);
SSR DOM contains hero copy, all 13 anchors, nav, skip link, résumé — no
hydration warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (both tiers)

The de-risking gate. Builds SC-01 end-to-end across both render tiers from one
content object, and proves the two-tier model holds.

Capability + data:
- lib/capability: WebGL2 / deviceMemory-hardwareConcurrency / reduced-motion /
  <768px detection, decided once and session-cached; SSR-safe fallback default
  (no hydration mismatch). prefers-reduced-motion and mobile always force fallback.
- Full Scenario type (Backend Schema); Offensive Security scenario data
  (recon -> exploit -> report beats, "trace" interactive moment, network-topology
  environment, non-null fallback with 1:1 animationBeats); projects + skills.
- Build-time integrity gate (lib/scenarios): throws on parity/reference
  violations at import -> fails `next build`.

Rendering (components/scenarios):
- Fallback tier (design-first): 2D SVG network topology, Framer Motion, reacts
  to active beat + trace, reduced-motion-aware at the call site.
- Full tier: R3F procedural topology, GSAP ScrollTrigger scroll-scrubbed camera,
  subtle bloom; dynamically imported (ssr:false) so the ~1.2 MB three.js chunk
  is code-split out of the initial load.
- Stage orchestrator: tier selection, IntersectionObserver beat tracking,
  keyboard-accessible interactive trace; Suspense falls back to the 2D visual
  while the 3D chunk loads (no blank state). Both tiers consume identical data.
- Server section wrapper renders unit/title/summary in SSR DOM always.

Gate evidence: typecheck + lint clean; build static-prerenders; SSR DOM contains
all 3 beats + summary + payoff + interactive trigger (content parity); three.js
absent from initial HTML and its 1.2 MB chunk is lazy (fallback tier stays
172 kB First Load). Automated Lighthouse deferred to Phase 6 (no CLI in env).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hero <h1> is the LCP element; animating it from opacity:0 kept it invisible
until hydration, delaying Largest Contentful Paint. Add a transform-only "slide"
mode to Reveal (opacity stays 1) and use it for all above-the-fold hero content.

Prod Lighthouse (mobile): LCP 7.1s -> 2.8s, FCP 0.9s, Speed Index 0.9s. SSR HTML
now emits zero opacity:0 inline styles. Transforms don't affect layout, so no CLS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- About: server-rendered bio, pull quote, focus areas.
- Journey: vertical timeline of the VAPT -> GRC & AI Security arc (sorted
  ascending), per-item reveal, semantic <time>.
- Skills: narrative-grouped catalogue (grouping is the signal, no fabricated
  scores). Expanded flat Skill[] across all categories — offensive ids stay
  intact for the SC-01 integrity gate and Phase 4 scenarios reference the rest.
- Data: TimelineEvent + SkillGroup types; data/timeline.ts; skillGroups view model.
- Page now renders About/Journey/Skills in App Flow order; scenarios 2–4 and
  certifications/tryhackme/github/blog/contact remain wired placeholders.

Verified: typecheck + lint clean; build static; SSR DOM contains all three
sections' content. A11y: routed the journey category label off fg-dim (4.09:1)
to fg-muted (5.77:1) for AA on small text.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Scenario-visual registry: stage now resolves Fallback + code-split Scene by
  scenario id (decoupled from the offensive scenario).
- SC-02 data: audit-ledger environment, blue accent, capture/chain/verify beats,
  "trace the hash chain" interactive moment, Dharma payoff, 1:1 fallback beats
  (integrity gate passes).
- Fallback tier: 2D hash-chained ledger (SVG), reduced-motion-aware verify sweep.
- Full tier: descending 3D ledger blocks, GSAP scroll-scrubbed camera pan,
  verification pulse on trace; code-split (three.js absent from initial HTML).

Verified: typecheck + lint clean; build static; SSR DOM has all 3 beats +
summary + payoff + trigger; GRC scene chunk is separate. Blue accent AA-verified
(7.09:1). Awaiting 3D spot-check before SC-03.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- GRC camera: pulled back to z~8.6 with a 4th keyframe so the full chain frames
  without clipping, gentle S-curve descent.
- Both scenes: GSAP scrub true -> 0.8 (inertial catch-up) and eased look-at
  target (lerp), so orientation no longer snaps. Noticeably smoother scrubbing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SC-03 data: encrypted-vault environment, violet accent, encrypt/classify/
  zero-knowledge beats, "reveal an encrypted field" interactive moment (type
  reveal), VaultIQ payoff, 1:1 fallback beats (integrity gate passes).
- Fallback tier: 2D grid of encrypted panels (SVG) — ciphertext -> plaintext on
  reveal, lock indicator, reduced-motion-aware crossfade.
- Full tier: 3D vault grid, panels light per beat + lock bar dims on reveal,
  GSAP scrub 0.8 + eased look-at; code-split (three.js absent from initial HTML).

Verified: typecheck + lint clean; build static; SSR DOM has all 3 beats +
summary + payoff + trigger; 3 scenario anchors. Violet accent AA (6.29:1).
Awaiting 3D spot-check before SC-04.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Scenario schema: payoffProjectId nullable + optional payoffSummary, so a
  cert/capability-backed scenario (App Flow: SC-04 payoff is AWS-cert-backed
  skills, not a project) is first-class. Integrity gate updated accordingly.
- SC-04 data: cloud-architecture environment, teal accent, containerize/deploy/
  secure beats, "inspect the security layer" moment (type inspect), capability
  payoff, 1:1 fallback beats.
- Fallback tier: 2D architecture diagram (SVG) with inspect callout on the IAM
  node; reduced-motion safe.
- Full tier: 3D service graph, nodes/edges light per beat, inspect focuses IAM
  (scale + rotating ring), GSAP scrub 0.8 + eased look-at; code-split.
- Stage renders a capability payoff (summary + beat skills) when no project.
- A11y: techStack chips fg-dim -> fg-muted (AA on small text) across payoffs.

Verified: typecheck + lint clean; build static; SSR has all beats + capability
payoff; 4 scenario anchors; three.js lazy. Teal AA (10.63:1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Certificate type; data/certificates.ts + data/tryhackme.ts (ported), sorted
  newest-first; shared lib/format.ts date helper.
- Certifications: grid of credential cards (issuer/title/date, verify link when
  present).
- TryHackMe: headline stats (Top 2% · 175+ labs · paths) + completed learning
  paths + profile link.

Completes the scenario spine + credentials. Remaining placeholders: GitHub,
Blog, Contact (Phase 5). Verified: typecheck + lint clean; build static; both
sections in SSR DOM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Contact: hardened API route (server-side Zod validation, HTML/control-char
  sanitization, escapeHtml email body, honeypot + timing trap, IP rate-limit
  3/hr, Resend delivery). Fixed legacy bug: sends to owner email, not the site
  hostname. 503 when RESEND_API_KEY absent (no silent pretend-success).
  Client form uses native validation + server error display — no zod/RHF in the
  client bundle (First Load 255kB -> 177kB).
- GitHub: server component fetches project repos (ISR 1h, GITHUB_TOKEN optional),
  graceful fallback to static data when API/repo unavailable.
- SEO: full metadata (title/desc/canonical/OG/Twitter), JSON-LD Person + WebSite
  (scenarios as parts), dynamic OG image (next/og), sitemap, robots — all in the
  server-rendered DOM. Dropped Blog (unscoped by the plan) from nav.
- CSP: enforcing in production, unsafe-eval dropped (dev-only for HMR), narrowly
  scoped; unsafe-inline retained for Next's static hydration scripts (documented
  tradeoff vs nonce-based dynamic rendering). env module + rate-limit + github
  client re-derived and re-reviewed.

Verified: typecheck + lint clean; build static (home 177kB, ISR 1h); SSR has
contact + github + JSON-LD; robots/sitemap/og-image 200; contact API validation
+ honeypot + rate-limit exercised.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 3D scenes rendered geometry with no text, so full-tier viewers couldn't tell
what each node/block/panel/service was — only the 2D fallback showed labels.

- Add drei <Html> labels to all four 3D scenes (SceneLabel), using the site mono
  font (no font asset, CSP-safe), colored by active/accent state. SC-03 labels
  even reflect the ciphertext->plaintext reveal.
- Fix SC-04 2D fallback: reposition data/iam nodes to fit the viewport without
  overlap, shrink node label font so "ECS · Docker" etc. no longer clip.

Content parity intact (labels already in SSR DOM via fallback + beats). Verified:
typecheck + lint clean; build static.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… overlap

- SC-02 ledger: 3D tag now uses a concise, meaningful `short` label
  (e.g. "Access policy", "Audit verified") instead of "#a1f3 policy.access.updated".
  2D fallback keeps the log-style dotted names.
- SC-03 vault: 3D tag shows the field name (doc.title -> Q3 Financials on reveal)
  instead of "doc.title · 8a3f9c2e" — much shorter.
- SceneLabel: smaller (10px), with a translucent background chip + border so
  crowded labels stay individually readable.

Verified: typecheck + lint clean; build static.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ccents)

- profile.name -> "Hem Nikesh Gabhawala" (propagates to hero, footer, metadata,
  title, JSON-LD Person, OG alt).
- "Résumé"/"résumé" -> "Resume"/"Download resume" in hero + navbar (desktop +
  mobile).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaced the four-paragraph "most people who say..." bio with tighter,
punchier copy: shorter sentences, a standalone one-line transition ("That
offensive mindset is what I now apply to defensive security."), and a closing
paragraph that states the thesis directly instead of hedging ("not pivoting
away" -> "not moving away... I'm building on it").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… nodes

The Journey section read as a plain static list. Upgraded using ui-ux-pro-max
(scroll-reveal/stagger guidance) and the established taste-skill direction:

- JourneyRail (client wrapper): accent progress line drawn over the static
  rail via useScroll+useSpring, filling as the visitor reads through; wraps
  the server-rendered <ol> as children so SSR content is untouched.
- JourneyAmbientScene: capability-gated (full tier only) R3F canvas behind the
  list — a soft glowing chain with a light pulse traveling top-to-bottom
  (chronological progress), low bloom, low opacity, autoplay-only (no GSAP
  scrub — Journey isn't a Scenario, so it doesn't need the full two-tier
  apparatus). Dynamically imported, code-split like the four scenario scenes.
- Reveal: new `inView` mode (whileInView, viewport once) so per-item entrances
  trigger on scroll instead of a fixed mount delay, matching gsap scroll-reveal
  guidance (small y-offset, no re-trigger on scroll direction change).
- Node markers: pure-CSS pulsing ring (.node-pulse), stripped entirely under
  reduced-motion rather than just paused.

Verified: typecheck + lint clean; build static; SSR DOM content unchanged
(all timeline text present); three.js still absent from initial HTML; home
First Load JS 177kB -> 182kB (+5kB, the ambient scene chunk stays lazy).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nt language

Design review: 3D + bloom is exclusively the four Scenarios' device per the
brief's two-tier immersive layer — it's what makes SC-01-04 feel like the
payoff. Grafting a glowing WebGL canvas + a novel pulse-ring motif onto Journey
(a plain section before the scenarios) borrowed that vocabulary out of context,
which is why it read as forced and disconnected from the rest of the site.

Removed entirely: journey-ambient-scene.tsx (R3F canvas + bloom), the
mix-blend-screen mount, capability-tier gating for it, and the invented
.node-pulse CSS ring.

Replaced with the language already used everywhere else on the site (nav dot,
scenario STEP labels): accent color = active/reached, nothing else.
- JourneyRail: kept only the scroll-linked accent fill on the existing rail
  line (a color transition on an element already there, not a new visual).
- JourneyNode: node marker goes from hollow/muted to solid accent fill once
  scrolled into view — same "reached" treatment scenario nodes use.

Verified: typecheck + lint clean; build static; Journey SSR content unchanged;
three.js still absent from initial HTML.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… caption labels

SC-02/03/04 panels were filling large surfaces with full-saturation accent
color + high emissive + bloom stacked together -> neon pastel slabs instead of
technical panels. The AI vault's separate "lock bar" mesh was a harsh floating
glow blob. Labels were boxed chips centered ON the shape face, reading as a
redaction bar rather than an annotation.

- All three scenes: panel/node surface stays dark (#111114) always; state now
  reads through a thin drei <Edges> outline (accent when reached, brighter/
  thicker when verified/revealed/focused) plus a LOW emissive tint (0.08-0.24,
  down from 0.9-2.4) — signal, not fill.
- AI vault: removed the separate glowing lock-bar mesh entirely; unlock state
  is carried by the edge outline plus the label flipping cipher->plaintext.
- Cloud inspect ring: emissiveIntensity 2.4 -> 0.8 (reads as a focus ring, not
  a flare).
- SceneLabel: dropped the background chip/border; plain mono caption with a
  text-shadow, repositioned BELOW each shape (negative offsetY) instead of
  centered on its face.
- Bloom tuned consistently across all four scenes: intensity 0.55->0.3,
  luminanceThreshold 0.25->0.5, so only genuinely bright accents (pulse/reveal
  markers) bloom, not the whole surface.

Verified: typecheck + lint clean; build static.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Contact: "Looking for..." → "Open to security roles."
  Confident availability, specifics in subline
- Hero: Drop leading zeros on stats (03/01 → 3/1)
  Reads cleaner alongside "Top 2%" and "175+"
- Spelling: Résumé → Resume (no accents)
  Consistency across both hero and contact sections

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add verified credential links with zero dead links:
- lib/certificate-files.ts: fs-based verification helper
  Reads public/certificates/ at build time; links appear only when files exist
- components/sections/credentials.tsx: new Credentials plate
  Shows "View ↗" affordance next to each entry with a verification target
  (issuer URL or local file; plain text if neither)
- public/certificates/README.md: naming convention guide
  Names like cert-google-cybersecurity.pdf trigger "View" link automatically
- components/contact/copy-email.tsx: new client island
  Clipboard copy for email address (recruiters copy far more than mailto)

No dead links ever; the feature is self-documenting. Drop a file, get a link.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Remove unused contact form and its entire backend chain:
- Delete: app/api/contact/route.ts, lib/validations/contact.ts, lib/rate-limit.ts
- Remove: RESEND_API_KEY, GITHUB_TOKEN from lib/env.ts (orphaned)
- Remove: contactFormSchema, ContactFormInput from lib/types.ts
- Remove: resend npm dependency
- Prune: .env.local.example documentation

Rationale: recruiters email or copy address far more than forms. Email is simpler,
clearer, and requires no backend. Removing form shaves 69 kB from First Load JS
(237 kB → 168 kB). Contact plate now leads with email as sole primary action,
with Copy button + links as the full contact surface. No functionality lost.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Rewrite all project descriptions grounded in real GitHub repos:
- Dharma (GRC): Local AI, tamper-evident ledger, private repo
  Highlight: "Runs on local AI — sensitive data never leaves the org"
- VaultIQ (AI Security): 98.3% AI detection, client-side encryption
  Highlight: "98.3% AI-content detection · ROC-AUC 0.997" (verified metric)
- Network Reconnaissance Tool (Offensive): Nmap automation, real public repo
  Highlight: "Offensive tooling — the practice behind the defensive work"

Fix overclaims sitewide:
- Profile bio: "zero-knowledge" → "client-side encryption + measured AI detection"
- Profile aboutBio: Same correction + accurate Dharma/VaultIQ descriptions
- Approach Build beat: Remove "even platform can't read it" → add 98.3% accuracy
- Timeline: Update milestone date (2026-01 → 2026-06), accurate description
- Skills: Rename "Zero-Knowledge Architecture" → "Client-Side Encryption (AES-256)"

Result: every claim is now verifiable, all metrics are real, projects are live.
Recruiters can check source code; no vague marketing language remains.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Update root layout.tsx:
- Swap Instrument Serif + Inter → single Archivo variable font
- Add root className: archivo.variable (variable font registration)
- Mount SiteHeader + SiteFooter chrome

Update app/opengraph-image.tsx:
- Reframe for specimen aesthetic
- Use accent-on-ink colors for text

Update app/page.tsx:
- Wire all new section components (Hero, Approach, Work, Capabilities, Credentials, Contact)
- Remove old sections (scenarios, about, timeline, projects, certifications)

components/layout/site-header.tsx:
- Sticky, transparent over hero, gains wash on scroll
- Text inverts on dark plates (approach/contact)
- Smooth transition between light/dark text color

components/layout/footer.tsx:
- Brief attribution, anchored to close plate
- Spec-compliant, no design clutter

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
styles/globals.css (complete rewrite):
- OKLCH token definitions: --paper, --ink, --close, --accent
- Accent variants: --accent-on-dark for contrast on ink
- Muted text variants: --ink-dim, --on-close-muted (WCAG AA verified)
- Type scale: .type-statement, .type-plate, .type-body, .type-data, .type-figure
- Keyframes: @Keyframes transit-fall (animation band motion)
- All contrast ratios documented in comments (15 pairs, all ≥4.5:1)

lib/types.ts (extend Project interface):
- Add highlight?: string (one outcome a recruiter retains)
- Add sourceNote?: string (shown for private repos instead of dead link)
- Remove ContactFormInput (form is gone)

lib/seo/jsonld.ts + config.ts:
- Update for current profile + project structure
- Canonical site URL handling

data/navigation.ts:
- Navigation structure for scroll-spy and header links

Result: consistent type hierarchy across all plates, contrast verified at build,
no orphaned styles or unused tokens.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
PRODUCT.md (complete rewrite):
- Register: brand (portfolio/presence, not app)
- Audience: recruiters, startup founders, technical decision-makers
- Core principle: authentic specimen sheet, not AI-generated site
- Visual language: Archivo variable font, OKLCH tokens, specimen typography
- Content strategy: grounded claims, verifiable projects, no marketing fluff

DESIGN.md (complete rewrite):
- Token definitions and contrast gates
- Six-plate structure: paper (hero) → ink (approach) → paper (work) →
  paper-2 (capabilities) → paper-2 (credentials) → close (contact)
- Type scale and hierarchy rules
- Motion principles: easeOut, reduced-motion, reveal pattern
- Hard rules: no viewBox/preserveAspectRatio in contact band (learned from guilloche fail)
- Accessibility: WCAG AA, 4.5:1 body text, measured via culori

Docs/:
- Update 01_PRD.md: specimen sheet positioning
- Update 03_UI_UX.md: plate structure, asymmetric layout
- Update 06_App_Flow.md: section-by-section narrative flow

Result: documentation is current, architectural decisions are recorded,
future changes have a foundation to build on.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Clean up from design rebuild:
- Delete old sections: about, certifications, github, journey-timeline, skills, tryhackme
- Delete scenario system: all 4 scenario types + registry (replaced by simple project list)
- Delete old UI components: button, journey-rail
- Delete scenario data files: scenario-{ai,cloud,grc,offensive}.ts, scenarios.ts
- Delete legacy folder: entire old codebase snapshot for reference

The new specimen-sheet design renders six clean plates (hero, approach, work,
capabilities, credentials, contact) with no scenario system. Old code kept in git
history; can be recovered if needed, but won't ship.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@securitywithhem
securitywithhem merged commit 6fdbc34 into Hem Jul 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant