A modern, single-page developer portfolio built with React 18 via CDN and styled with a custom liquid-glass brutalist aesthetic. This project is intentionally lightweight: there is no bundler, no npm dependency tree, and no build step required to run the site.
- Overview
- Key Features
- Tech Stack
- Project Structure
- How It Works
- Getting Started
- Development Workflow
- Content Updates
- Deployment
- Customization Guide
- Accessibility and UX Notes
- Performance Notes
- Troubleshooting
- Roadmap Ideas
- License
Pitfolio is a personal portfolio SPA designed to present backend engineering work, technical writing, and professional experience in a highly visual and interactive format.
The app is loaded from a single HTML entry point (Portfolio/Portfolio.html) and composes UI from modular JSX files (app.jsx, components.jsx, pages.jsx, tweaks-panel.jsx) that are compiled in the browser through Babel Standalone.
This architecture makes the project:
- easy to clone and run,
- simple to deploy to static hosting,
- approachable for rapid iteration without toolchain setup.
- Single Page Application using hash-based routes.
- Project and company detail pages with dynamic slug-based navigation.
- Blog section with curated post metadata and full content blocks.
- Theme customization panel with persistent settings via
localStorage. - Keyboard shortcuts for fast route switching (
G+ shortcut key). - Animated visual layer (cursor blob, gradients, glass cards, motion effects).
- Data-driven content model centered around a single
resume.jsonsource.
- React 18 (CDN)
- ReactDOM 18 (CDN)
- Babel Standalone for in-browser JSX compilation
- Vanilla CSS with custom properties and grid-based layout
- Static JSON for resume/content data
- No package manager or build tooling required
pitfolio/
├─ README.md
├─ LICENSE
└─ Portfolio/
├─ Portfolio.html # App entrypoint (script imports + tweak defaults)
├─ app.jsx # Root app component and bootstrapping
├─ components.jsx # Shared components and custom hooks
├─ pages.jsx # Route-level pages + blog and transformation helpers
├─ tweaks-panel.jsx # Theme/tweak controls and persistence
├─ styles.css # Global styles, tokens, responsive rules
├─ vercel.json # Static-host routing config for Vercel
├─ assets/
│ ├─ Nr_Logo_png.png
│ └─ about_hero_img.png
└─ data/
└─ resume.json # Primary profile/work/content dataset
The app uses hash-based routing (#/work, #/blog, #/project/{slug}, etc.), enabling static hosting without server-side route handling for most paths.
Main route categories include:
#/(home)#/work#/blog#/blog/{slug}#/project/{slug}#/company/{index}#/about#/contact
At startup, app.jsx fetches data/resume.json and stores it in component state. Route pages consume this object to render:
- profile basics,
- experience timeline,
- project cards/details,
- education,
- skills,
- contact links.
window.TWEAK_DEFAULTS (defined in Portfolio.html) seeds initial display preferences such as:
- color palette,
- cursor blob visibility,
- decorative grain,
- grid overlays,
- background blobs.
useTweaks then persists user selections to localStorage, so preferences survive reloads.
Core content sources are split deliberately:
data/resume.json→ professional profile datapages.jsx→ route components + blog post metadata/content
Helper utilities transform raw content to presentation-ready structures (e.g., slug generation, tag inference, date formatting).
- Clone or download the repository.
- Open
Portfolio/Portfolio.htmlin your browser.
This works for visual checks, but data fetch behavior may vary due to browser CORS/file restrictions.
From inside the Portfolio/ directory:
python -m http.server 8080Then open:
http://localhost:8080/Portfolio.html
Alternative:
npx serve .Because there is no build step:
- Edit JSX/CSS/JSON files.
- Refresh the browser.
- Verify route behavior and responsive layout.
Recommended workflow:
- Keep browser devtools open for runtime warnings.
- Validate route transitions (
#/,#/work,#/blog, detail routes). - Confirm theme toggle persistence across reloads.
For most updates, edit only:
Portfolio/data/resume.json
Use this for:
- role/company updates,
- project details,
- skills,
- education,
- social/contact links.
Edit Portfolio/pages.jsx when you need to update blog posts, post metadata, or route-level copy not represented in the JSON model.
This project deploys cleanly on Vercel as a static site.
Recommended settings:
- Framework Preset: Other / Static
- Root Directory:
Portfolio - Build Command: (empty)
- Output Directory: (empty)
Because the entry file is Portfolio.html rather than index.html, keep a rewrite rule (already present in Portfolio/vercel.json) so root requests resolve correctly.
You can deploy the Portfolio/ directory on any static platform:
- GitHub Pages
- Netlify
- Cloudflare Pages
- S3 + CloudFront
- Render static hosting
If your host expects index.html, either:
- rename
Portfolio.htmltoindex.html, or - configure a rewrite/redirect rule.
To adapt this portfolio for a different person/brand:
- Replace content in
data/resume.json. - Swap assets in
Portfolio/assets/. - Adjust color tokens and gradients in
styles.css. - Tune defaults in
window.TWEAK_DEFAULTSinsidePortfolio.html. - Update blog entries in
pages.jsx.
Branding tips:
- Keep typography tokens centralized (
--serif,--sans,--mono). - Rebalance contrast when changing glass/background colors.
- Test both desktop and mobile breakpoints after visual edits.
Current UX includes high visual styling and motion; when customizing, consider:
- preserving text contrast ratios,
- reducing excessive motion for sensitive users,
- maintaining visible focus states,
- ensuring keyboard navigation remains clear,
- keeping tap targets mobile-friendly.
Even without a build toolchain, the project remains lightweight due to:
- static assets,
- no runtime API dependencies beyond local JSON,
- minimal external script count,
- simple deploy surface.
Potential optimizations (optional):
- convert images to optimized modern formats,
- lazy-load heavier non-critical sections,
- precompute frequently transformed content.
Run a local HTTP server from Portfolio/ instead of opening files with file:// paths.
Ensure host rewrite settings are configured for your entry point (Portfolio.html) or use hash routes consistently.
Check browser storage permissions and verify localStorage is available (private/incognito modes can vary by browser).
- Add optional light/dark mode presets.
- Extract blog content to markdown/JSON.
- Add contact form with serverless endpoint.
- Introduce image optimization pipeline (optional future build step).
- Add automated accessibility checks.
This repository is licensed under the terms in LICENSE.