Case Study 2: Responsive Portfolio Site in an Afternoon

Background

Marcus Chen was a computer science student finishing his junior year. He had solid Python skills from coursework, some experience with Flask from a web development class, and a collection of class projects he was proud of but that lived only in GitHub repositories. With summer internship applications approaching, his career advisor gave him blunt feedback: "Your resume is fine, but every serious candidate has a portfolio website. You need one."

Marcus had tried building a portfolio before. He had spent a weekend wrestling with a WordPress template, gave up, tried a drag-and-drop builder, found it too limiting, and then abandoned the project. This time, he decided to try a different approach: build it from scratch with AI assistance, using the vibe coding techniques he had been learning.

He set a goal: have a deployed portfolio site by the end of the day. Not perfect -- just professional enough to include on his resume and job applications.

Hour 1: Planning and Design Direction (9:00 AM - 10:00 AM)

Marcus started not with code, but with a clear specification. He had learned from Chapter 10 that specification-driven prompting produces better results than improvised requests. He wrote out what he wanted:

I need a personal portfolio website. Here are my requirements:

Content Sections:
1. Hero: Full-name, title ("Computer Science Student & Developer"),
   brief tagline, and links to GitHub, LinkedIn, and email
2. About: 2-3 paragraphs about my background and interests
3. Skills: Visual display of my technical skills with proficiency levels
4. Projects: Grid of 4-6 project cards with title, description,
   tech stack tags, screenshot, and links to GitHub/live demo
5. Experience: Timeline of education and work experience
6. Contact: Simple contact form (name, email, message)

Design Requirements:
- Clean, modern, minimalist design
- Color scheme: dark navy (#0f172a) and white with an accent color
  (suggest one that looks professional)
- Smooth scroll navigation
- Subtle animations on scroll (elements fade in as they enter viewport)
- Professional typography (suggest a Google Fonts pairing)

Technical Requirements:
- Pure HTML, CSS, and vanilla JavaScript (no React -- I want simplicity)
- Mobile responsive (looks good on phone, tablet, desktop)
- Fast loading (no heavy libraries)
- Deployable to GitHub Pages
- SEO-friendly meta tags
- Accessible (keyboard navigable, screen reader friendly)

He then asked the AI to suggest a design direction before writing any code:

Before generating code, describe the visual design you would create
for this portfolio. Include:
- Suggested accent color and why
- Font pairing suggestion
- Layout approach for each section
- Animation ideas
- Overall mood/feel

I want it to feel professional but not boring, modern but not trendy.

The AI suggested an amber/gold accent color (#f59e0b) against the dark navy for warmth and energy, the font pairing Inter for body text and Space Grotesk for headings, and a layout where sections alternated between full-width backgrounds to create visual rhythm. Marcus liked the direction and moved to code.

Lesson Learned: Spending time on design direction before writing code is not wasted time -- it is an investment. Marcus could have jumped straight to "generate a portfolio website" and gotten something generic. By specifying his design preferences, he got something that felt intentional and personal.

Hour 2: HTML Structure (10:00 AM - 11:00 AM)

Marcus prompted the AI for the complete HTML structure:

Generate the full HTML for my portfolio with these content sections.
Use this actual content:

Name: Marcus Chen
Title: Computer Science Student & Developer
Tagline: "Building things that matter with clean code and curiosity."

About: [He provided two paragraphs about himself]

Skills:
- Python: 90%
- JavaScript: 65%
- SQL/PostgreSQL: 75%
- Flask: 80%
- Git: 85%
- Data Structures & Algorithms: 80%
- Machine Learning (scikit-learn): 60%
- Linux/Command Line: 70%

Projects:
1. StudyBuddy - AI-powered study group matching platform (Python, Flask,
   PostgreSQL, OpenAI API)
2. EcoTrack - Carbon footprint tracker with data visualization (Python,
   pandas, matplotlib, Streamlit)
3. GameOfLife - Conway's Game of Life with custom rule editor (JavaScript,
   HTML Canvas)
4. SortViz - Sorting algorithm visualizer for CS education (Python, Pygame)

[He provided descriptions, GitHub URLs, and screenshot filenames for each]

Experience:
- BS Computer Science, State University (2022-2026)
- Teaching Assistant, Intro to CS (Fall 2024-Present)
- Software Engineering Intern, LocalTech Inc (Summer 2024)

Use semantic HTML5 elements. Include proper meta tags for SEO.
Include Open Graph tags for social media sharing.
Do NOT include CSS or JavaScript -- just the HTML structure.

The AI produced a well-structured HTML document with approximately 200 lines. Marcus reviewed it carefully, checking that: - All his content was included accurately - Semantic elements were used appropriately (<section>, <article>, <nav>) - Each section had a unique id for scroll navigation - Images had descriptive alt text - The contact form had proper labels and input types

He made two corrections: a misspelled project name and a missing GitHub URL. The whole review took 15 minutes.

Hour 3: CSS Styling (11:00 AM - 12:00 PM)

This was the most intensive hour. Marcus built the CSS in stages:

Stage 1: Base Styles and Typography

Write CSS for my portfolio HTML. Start with:
- CSS custom properties (variables) for colors, fonts, spacing
- CSS reset/normalize
- Typography: Inter for body (400, 500, 600 weights),
  Space Grotesk for headings (700 weight)
- Base styles: smooth scrolling, box-sizing border-box
- Color scheme: dark navy #0f172a, white #ffffff, accent #f59e0b,
  light gray #94a3b8 for secondary text

Mobile-first approach. Base font size 16px, line-height 1.6.

Stage 2: Layout and Sections

Now add layout CSS for each section:

Navigation:
- Fixed at top, transparent initially, gets dark background on scroll
  (I will add the JS for this later)
- Horizontal links, right-aligned, with smooth hover underline effect
- Mobile: hamburger menu (I will add JS for toggle)

Hero:
- Full viewport height
- Content centered vertically and horizontally
- Name in large heading, title in smaller text, tagline in accent color
- Social links as icon buttons in a row
- Subtle gradient or pattern on the background

About:
- Max-width 800px, centered
- Clean paragraphs with good readability

Skills:
- Grid of skill bars
- Each skill shows name on left, percentage bar on right
- Bar is dark navy background with accent fill
- Two columns on desktop, one on mobile

Projects:
- Responsive grid: 2 columns on desktop, 1 on mobile
- Card: image on top, title, description, tech stack tags, links
- Hover effect: slight scale up and shadow increase

Experience:
- Vertical timeline with alternating sides on desktop
- Single column timeline on mobile
- Dots and connecting line

Contact:
- Centered form, max-width 600px
- Styled inputs with bottom border that animates to accent on focus
- Submit button with accent background, white text, hover effect

The CSS came to about 450 lines. Marcus found this surprisingly reasonable -- he had expected CSS to be thousands of lines. The mobile-first approach meant the base styles handled phones, and the media queries at 768px and 1024px added refinements for larger screens.

He previewed in the browser and was immediately pleased with the result. The color scheme was cohesive, the typography was readable, and the layout was clean. He made several adjustments through AI prompts:

  • "The hero section gradient looks too strong. Make it more subtle."
  • "The skill bars need rounded corners. And animate them filling up from zero when they scroll into view."
  • "The project cards need more padding and the tech tags should be smaller pill shapes."

Each adjustment took one prompt and produced accurate CSS changes.

Hour 4: JavaScript Interactions (12:00 PM - 1:00 PM)

After a quick lunch at his desk, Marcus tackled the JavaScript. He needed four interactive features:

Write vanilla JavaScript (no libraries) for my portfolio:

1. Navigation scroll effect: Add a "scrolled" class to the nav when the
   user scrolls past 100px (I will use this to change nav background
   from transparent to dark)

2. Smooth scroll: When clicking nav links, smooth scroll to the target
   section with an offset for the fixed nav height

3. Mobile menu toggle: Hamburger button toggles a mobile menu overlay.
   Close when a link is clicked. Close when clicking outside.
   Add aria-expanded attribute for accessibility.

4. Scroll animations: Elements with a "reveal" class should fade in and
   slide up slightly when they enter the viewport. Use IntersectionObserver
   for performance.

5. Skill bar animation: When the skills section scrolls into view,
   animate the skill bars from 0% to their target width.

Keep the code clean and well-commented. No jQuery, no libraries.
Use modern JavaScript (ES6+).

The AI produced approximately 120 lines of JavaScript. Marcus was able to read and understand most of it because the AI had commented each section. He had two questions:

  1. "What is IntersectionObserver? We do not have anything like that in Python." The AI explained it as an efficient way to detect when an element becomes visible in the viewport, analogous to a Python observer pattern that triggers a callback when a condition is met.

  2. "What does the spread operator ... do in element.classList.add(...classes)?" The AI explained it as similar to Python's *args unpacking.

Everything worked except the mobile menu, which had a z-index issue (the menu appeared behind the hero section). Marcus described the problem, the AI suggested adding z-index: 1000 to the mobile menu overlay, and it was fixed.

Hour 5: Contact Form and Polish (1:00 PM - 2:00 PM)

The contact form needed to actually send messages. Since Marcus was deploying to GitHub Pages (static hosting with no backend), he could not use a server-side form handler. He asked the AI for options:

My portfolio is hosted on GitHub Pages (static site, no backend).
How can I make the contact form actually send me emails?
Compare the options in terms of cost, complexity, and reliability.

The AI presented three options: Formspree (free tier, 50 submissions/month), EmailJS (free tier, 200 emails/month), and Netlify Forms (free, but requires Netlify hosting). Marcus chose Formspree for its simplicity -- it required only changing the form's action attribute to a Formspree endpoint URL.

He then added form validation:

Add client-side validation to my contact form:
- Name: required, minimum 2 characters
- Email: required, valid email format
- Message: required, minimum 10 characters

Show validation errors below each field in red.
Disable the submit button while submitting.
Show a success message after successful submission.
Show an error message if submission fails.
All in vanilla JavaScript, no libraries.

Final Polish

Marcus spent the last portion of this hour on polish:

Add these finishing touches to my portfolio:
1. A "back to top" button that appears when scrolled past the hero
2. Proper focus styles for keyboard navigation (visible focus rings)
3. A print stylesheet that hides navigation and formats nicely for paper
4. Preload the Google Fonts to prevent flash of unstyled text
5. Add a simple CSS loading animation that shows while fonts load
6. Meta description, Open Graph image, and favicon references

Hour 6: Testing and Deployment (2:00 PM - 3:00 PM)

Cross-Device Testing

Marcus tested on three devices: - His laptop (1440px) -- everything looked great - His phone (375px, iPhone SE) -- the hero text was slightly too large - A tablet simulation in Chrome DevTools (768px) -- the project grid needed adjustment

He described each issue to the AI and got CSS fixes:

  • "On a 375px screen, the hero heading overflows. Scale it down."
  • "At 768px, the project cards are too narrow in a 2-column layout. Switch to single column below 900px instead of 768px."

Accessibility Testing

Marcus ran the Lighthouse accessibility audit and scored 94. The two issues: 1. The social media links in the hero had no accessible names (they were icon-only) 2. The color contrast on the secondary text (#94a3b8 on #0f172a) was slightly below the 4.5:1 ratio

He fixed both:

Fix these accessibility issues:
1. Add aria-label to social icon links: "GitHub profile", "LinkedIn
   profile", "Send email"
2. The secondary text color #94a3b8 on dark navy #0f172a fails WCAG AA
   contrast. Suggest a lighter gray that passes while still looking
   subtle and secondary.

The AI suggested #cbd5e1 (slate-300), which passed contrast checks and still looked appropriately subdued.

Deployment

Marcus deployed to GitHub Pages:

# Create a new repository on GitHub called "marcuschen.github.io"
git init
git add .
git commit -m "Initial portfolio site"
git remote add origin https://github.com/marcuschen/marcuschen.github.io.git
git push -u origin main

Within minutes, the site was live at https://marcuschen.github.io. He added the URL to his resume, LinkedIn profile, and GitHub bio.

Performance Results

Final Lighthouse scores: - Performance: 97 (fast load, no heavy JavaScript frameworks) - Accessibility: 100 (after the fixes) - Best Practices: 100 - SEO: 100

The entire site was approximately 35KB of HTML, CSS, and JavaScript (excluding images), with a load time under 1 second on a 3G connection.

The Complete Timeline

Time Activity Prompts Used
9:00-10:00 Planning, design direction 3
10:00-11:00 HTML structure 2
11:00-12:00 CSS styling (3 stages) 6
12:00-1:00 JavaScript interactions 3
1:00-2:00 Contact form, polish 4
2:00-3:00 Testing, fixes, deployment 5
Total 6 hours 23 prompts

Aftermath

Marcus received positive feedback from three interviewers who mentioned his portfolio. One interviewer commented that the site was "clean and clearly built by someone who cares about quality." He did not mention that AI had helped build it -- the quality of the prompts and the review process were his contributions, and the result spoke for itself.

Over the following weeks, Marcus made several improvements: - Added a dark mode toggle (1 additional AI prompt plus 15 minutes of refinement) - Added his new projects as they were completed - Wrote a blog post about building the site, which he linked from the portfolio - Added analytics with a privacy-respecting tool (Plausible) to track visitor behavior

Six months later, Marcus had customized the site enough that it felt entirely his own. The AI-generated foundation had given him a starting point; his iterative improvements had made it personal.

Key Takeaways

  1. Specification before code. Marcus spent a full hour planning before writing any code. This investment meant his AI prompts were specific, his design was coherent, and he did not waste time on major revisions.

  2. Static sites are underrated. For a portfolio, Marcus did not need React, a build system, or a JavaScript framework. Plain HTML, CSS, and JavaScript produced a faster, simpler, and more reliable result than any framework-based approach would have.

  3. Build in layers. HTML structure first, then CSS styling, then JavaScript interactions. This layered approach let Marcus verify each stage independently and made debugging straightforward.

  4. AI handles CSS remarkably well. The styling was the area where AI provided the most value. Marcus described visual intent ("subtle gradient," "pill-shaped tags," "animated skill bars"), and the AI translated it into precise CSS. This is the workflow where vibe coding shines brightest.

  5. Test on real devices early. Browser DevTools device simulation is useful but imperfect. Marcus caught issues by testing on his actual phone that DevTools did not reveal, particularly around touch target sizes and text readability.

  6. Lighthouse is your quality checklist. Running Lighthouse after the initial build identified specific, actionable issues. Fixing them was fast because the AI could directly address each Lighthouse recommendation.

  7. Six hours is enough for version 1. The portfolio was not perfect, but it was professional, functional, and deployed. Perfectionism is the enemy of deployment. Ship version 1, then iterate.

  8. Your review process is your contribution. AI generated the code, but Marcus made the design decisions, reviewed every line, tested on multiple devices, fixed accessibility issues, and iterated until the quality was right. The judgment, taste, and quality standards were entirely his.