A rewritten, responsive portfolio covering all 13 projects in Sample-Portfolio and all 12 original portfolio entries. The site includes searchable/filterable project cards, grid and list layouts, 25 individual project pages, an about section, experience and education, and an email-draft contact form.
Runtime: static HTML, CSS, and vanilla JavaScript. No framework, automatic third-party requests, server API, or runtime npm dependency is needed. The interactive Google Map connects only when the visitor chooses to load it.
Open index.html in a browser, or use the included local server:
cd Portfolio.io
npm run devVisit http://127.0.0.1:4173. No package installation is needed just to preview or regenerate the static site. The server also emulates the GitHub Pages path at /Portfolio.io/.
Each entry has a real screenshot of its deployed demo, a project overview, implementation highlights, scope notes, and links to its demo and GitHub repository. Repository URLs come from the local Git remotes; demo URLs were retrieved from the repositories’ public homepage metadata and successfully opened during the rewrite.
Source folder in Sample-Portfolio |
Project | Visual direction |
|---|---|---|
bento-grid |
Orbit | Bento grid |
Claymorphism |
Doodle Math | Claymorphism |
Dark-mode |
Synapse | Dark mode / neon |
Editorial |
The Long Field | Editorial |
Glassmorphism |
Lumen | Glassmorphism |
hand-drawn |
Wildroot | Organic / hand-drawn |
Immersive-scoll-storytelling |
Vela | Immersive storytelling |
Kinetic |
PULSE 27 | Kinetic typography |
Maximalism |
Loud House | Maximalism |
Minimalism |
Atelier Nord | Minimalism / Swiss |
Neo-brutalism |
Stackd | Neo-brutalism |
Neumorphism |
Thermo | Neumorphism |
Retro |
Static FM | Retro / Y2K |
The original collection is also preserved: Receipthy, FundProHK, Hansgieng AI SaaS, ILLUSTIFY, AuraWave+, TraderJournalGPT, Web POS, Interior Design, Management Dashboard, Not Only Tea, Snapchat Clone, and WeWa — Whack-a-mole.
Sample brands are clearly identified as fictional concepts. Original entries retain their optimized and full-resolution screenshots; no unverified live URLs, technical stacks, client claims, or results have been invented. The sample applications themselves remain in their original repositories rather than being copied into this static site.
index.html Main page; includes generated gallery markup
404.html GitHub Pages recovery page
assets/css/style.css Shared responsive design system
assets/css/outfit-latin.woff2 Existing self-hosted font (license alongside)
assets/js/script.js Progressive enhancements and contact validation
assets/images/projects/ 13 screenshots captured from real deployed demos
assets/images/ Preserved original portrait and project assets
data/projects.json Project content, source folders, links, image metadata
data/preview-sources.json Screenshot source URLs, titles, and capture timestamps
projects/*.html 25 generated, directly addressable project pages
scripts/build-projects.mjs Dependency-free static project-page generator
scripts/build-site.mjs Assembles the deployable Vercel artifact in public/
scripts/serve.mjs Dependency-free local preview server
scripts/capture-previews.mjs Optional Playwright screenshot refresh tool
tests/portfolio.test.mjs Browser, content, interaction, and accessibility tests
vercel.json Vercel build command and output directory
- Edit
data/projects.json. Each project has a stableslug, category, title, style, description, highlights, scope note, and local preview image. - For a design exploration, include its original
folder, verifieddemoandrepo, and documentedstack. - For a screenshot-only original, keep
stack: []when undocumented; includefullImage,imageSize, andfullSizefor the supplied assets. - Run:
npm run build
npm run checkThe generator updates only the marked gallery/style regions and count fields in index.html, and generates the individual project pages. Do not edit projects/*.html directly. Main-page copy and layout are edited in index.html outside those markers.
npm run build regenerates the project pages and then assembles the deployable public/ folder. npm run check verifies that the committed pages match data/projects.json; it does not touch public/.
When the sibling Sample-Portfolio folder exists, the generator checks that every project directory is represented. It also checks unique slugs, required content, asset existence, and HTTPS URLs. npm run check verifies that committed output matches the data.
This is an optional, network-dependent maintenance step, not part of the build or page load:
npm install
npx playwright install chromium
npm run capture # all 13 demos
npm run capture -- orbit vela # selected slugsCaptures use a 1440 × 1000 viewport and reduced motion, and are stored as local JPEGs. Vela uses /configure to show the actual bike instead of the type-only opening. Capture URLs and timestamps are recorded in data/preview-sources.json. Inspect refreshed images before committing; deployments can change or become unavailable.
npm install
npx playwright install chromium
npm run check
npm testTests start their own server on an available local port and cover:
- All 25 entries and generated pages, with complete 13-folder source coverage.
- Every category and design-style filter, search, empty states, reset, and grid/list controls.
- Shareable URL state, reload, and browser Back/Forward.
- Layout overflow at 320, 390, 768, 1024, 1280, 1440, and 1920 pixels.
- Mobile accessibility scans on all 25 detail pages, plus mobile and desktop homepage scans.
- Contact errors, draft encoding, and invalidation after editing.
- The exact supplied Google Maps place link, accessible interactive-map controls, and no Google request before an explicit load.
- Keyboard skip/navigation links, legacy bookmarks, nested-path 404 recovery, no-JavaScript content, and direct-file browsing.
- Browser runtime errors and failed local-resource requests.
Screenshots and axe results are written to ignored .test-artifacts/. These are automated local checks, not a substitute for manual assistive-technology or real-device testing.
The site is static and deploys to two hosts from the same main branch:
- Vercel (production): https://portfolio-io-ivantangs-projects.vercel.app
- GitHub Pages: https://ivantang26.github.io/Portfolio.io/
Every push to main triggers both. Vercel runs npm run build and serves public/; GitHub Pages publishes the repository root unchanged.
Publish the repository root as a static site. Generated pages and previews are already present; no build command is required for GitHub Pages. Do not publish node_modules, public, or .test-artifacts.
For a different public hostname/path, update:
- The absolute Open Graph image URL in
index.html. - The Open Graph URL prefix in
scripts/build-projects.mjs, then regenerate. - The
<base href="/Portfolio.io/">in404.html.
Relative project, font, stylesheet, script, and image URLs already work at either the domain root or a repository subpath.
Vercel requires a build output directory, which is why a build that only rewrites files at the repository root fails with No Output Directory named "public" found after the Build completed. npm run build therefore ends with scripts/build-site.mjs, which:
- Copies
index.html,404.html,assets/, andprojects/intopublic/. - Rewrites the
404.html<base>from the GitHub Pages subpath to/, since a Vercel deployment serves the domain root. - Fails the build if any local link, project page, or preview image would be missing — so a broken artifact never reaches the CDN.
vercel.json pins that contract:
{
"buildCommand": "npm run build",
"outputDirectory": "public"
}public/ is generated and git-ignored: never edit or commit it. Import the repository in Vercel and leave the dashboard's Output Directory on public (its default) or let vercel.json set it. No runtime npm dependency, serverless function, or environment variable is needed, and every deployment serves the domain root, so the relative asset URLs work without the /Portfolio.io/ prefix.
To inspect the artifact before deploying, run npm run build and serve public/ with any static server.
Contact: ivantang26official@gmail.com.
The form prepares a mailto draft. It does not send a message or claim success on a server. The visitor opens the draft, reviews it, and sends it using their email app. Search/filter state is kept in the URL. The portfolio uses no analytics or first-party tracking cookies; the Google Map makes no third-party request unless the visitor activates it. Google may process connection data or set cookies when the interactive map or external Google Maps link is opened.
MIT — see LICENSE. Existing font licensing is in assets/css/OFL-Outfit.txt. Project names and third-party materials remain the property of their respective owners.