Iron Man HUD GitHub Portfolio
Build a JARVIS-themed portfolio that fetches your GitHub repos live.
Introduction
30 Second Summary
Portfolios are often boring lists of links on a plain white page. What if yours felt like stepping inside Tony Stark's helmet, with glowing animations and live data streaming in every time someone visits?
In this project, you will build a dark, JARVIS-inspired single-page portfolio that pulls your GitHub repositories in real-time using HTML, CSS, and JavaScript, then deploy it to the web with Vercel.
What You'll Build
The moment someone opens your page, a cinematic boot sequence plays ("Initializing J.A.R.V.I.S..."), then the HUD fades in to reveal your repos displayed as glowing cards that link directly to your GitHub projects.
By the end of this project, you'll have:
- A live portfolio URL that anyone can visit to watch your Iron Man HUD boot up with a cinematic progress bar and reveal your latest repos.
- A real-time GitHub API connection that automatically displays your latest repositories every time the page loads, with no manual updates needed.
- Handcrafted CSS animations and glow effects including a pulsing arc reactor, spinning ring, scanline overlay, and hover-activated repo cards that lift and glow.
- Secret Mission: Add a search bar that filters your repos by name or programming language in real-time.
Are there any prerequisites?
You need a GitHub account (with at least a few public repos to display), a free Vercel account, Git installed on your machine, and VS Code. Step 1 walks you through confirming everything is ready.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters. This step is your chance to set your intention before writing any code.
Set Up the Project
For Vercel to deploy your portfolio, it needs to pull your code from a GitHub repository. That means you need a local project structure connected to a remote repo.
In this step, you will create the project folder and its three files, initialize Git, and push everything up to GitHub so Vercel has something to deploy from later.
In this step, get ready to:
- Create the ironman-portfolio folder with three project files.
- Initialize Git and push your first commit to GitHub.
- Verify the project structure in VS Code.
Create the project folder and files
Every web project starts with a folder to hold your files. You will create three files that form the skeleton of any static website: one for structure, one for style, and one for behaviour.
- Press Ctrl+Alt+T to open a terminal window.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create the project folder and move into it by running these commands:
mkdir ironman-portfolio
cd ironman-portfolio
- Create the three project files by running:
touch index.html style.css script.js
- Confirm the files exist by running:
ls
You should see index.html, style.css, and script.js listed in the output.
Don't see three files?
Make sure you ran the touch command from inside the ironman-portfolio folder. Run pwd to check your current location. It should end with ironman-portfolio.
Help me find my files
- Open the folder in VS Code by running:
code .
VS Code opens with the ironman-portfolio folder loaded. You should see the three files in the Explorer sidebar on the left.
VS Code didn't open?
If you see a "command not found" error, open VS Code manually, then click File in the top menu bar. Click Open Folder and select the ironman-portfolio folder on your Desktop.
Help me open my project in VS Code
Initialize Git and push to GitHub
With the files in place, you need version control so you can track changes and connect to GitHub. Vercel watches your GitHub repo and redeploys automatically on every push.
- Open the integrated terminal in VS Code by pressing Ctrl+`.
- Initialize Git and make your first commit by running these commands:
git init
git add .
git commit -m "Initial commit: project structure"
What do these commands do?
- git init creates a new Git repository in your folder.
- git add . stages all three files for the commit.
- git commit -m "..." saves a snapshot of your files with a descriptive message.
You should see output confirming the commit, including the message Initial commit: project structure and a count of 3 files changed.
Now you need a GitHub repository to push to.
- Open your browser and go to github.com.
- Click the + icon in the top-right corner.
- Select New repository.
- Enter ironman-portfolio as the repository name.
- Leave the repository set to Public.
- Do NOT check any of the initialization options (no README, no .gitignore, no license).
- Click Create repository.
Why skip the initialization options?
You already have a local Git repo with a commit. If GitHub adds its own files (like a README), you will get a conflict when you try to push. Keeping the remote empty lets you push cleanly.
GitHub shows a quick-setup page with your repository URL. You will use this to connect your local repo.
- Back in VS Code's terminal, connect to GitHub and push by running these commands:
git branch -M main
git remote add origin https://github.com/[[GITHUB_USERNAME="your GitHub username"]]/ironman-portfolio.git
git push -u origin main
What do these commands do?
- git branch -M main renames your default branch to main.
- git remote add origin tells Git where your GitHub repo lives.
- git push -u origin main uploads your commit to GitHub and sets main as the default push target.
You should see output showing the push succeeded, with a line like Branch 'main' set up to track remote branch 'main' from 'origin'.
Push failed or asked for credentials?
If Git asks for your username and password, GitHub no longer accepts passwords for HTTPS pushes. You need a personal access token or SSH key. Check your GitHub authentication settings and make sure your credential helper is configured.
If you see an error about the remote already existing, run git remote remove origin then re-run the git remote add origin command with the correct URL.
Help me troubleshoot my push
Verify the project structure
Everything should now be in place: three files locally, one commit in history, and a matching copy on GitHub.
- In VS Code's Explorer sidebar, confirm you see index.html, style.css, and script.js listed.
Before you run the next command, what do you think git log --oneline will show?
- Verify your commit history by running:
git log --oneline
You should see a single line with a short commit hash followed by Initial commit: project structure. That confirms Git is tracking your files and the push to GitHub succeeded.
Your project skeleton is in place and backed up on GitHub. Next up, you will build the Iron Man HUD shell with HTML and CSS so you can see the dark, glowing interface in your browser.
Build the HUD Shell
Your project files are ready and linked to GitHub. But right now they're completely empty.
Without a visual structure, there is nothing to display data in. This step creates the full Iron Man HUD aesthetic so you immediately see a dark, glowing interface in your browser.
In this step, get ready to:
- Write the HTML structure with a header, stats bar, and repo grid.
- Style everything with CSS custom properties, glow effects, and keyframe animations.
- Open the page in your browser and see a pulsing arc reactor with the J.A.R.V.I.S. title.
Write the HTML page structure
The HTML defines every element on the page. You will build the document head, a header with an arc reactor graphic, and placeholder sections for data that arrives later.
- In VS Code, click on index.html in the Explorer sidebar to open it.
- Paste the following code into the empty file to create the document head and header section:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JARVIS // GitHub Portfolio</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Scanline overlay for retro HUD feel -->
<div class="scanlines"></div>
<main class="hud-container">
<!-- Header with arc reactor and title -->
<header class="hud-header">
<div class="arc-reactor">
<div class="reactor-core"></div>
<div class="reactor-ring"></div>
</div>
<div class="header-text">
<h1>J.A.R.V.I.S.</h1>
<p class="subtitle">GitHub Repository Interface</p>
</div>
</header>
What does this code do?
The <head> loads your stylesheet and sets the page title. The <body> starts with a scanlines div (a visual overlay you will style later) and a hud-container that centers everything.
The header holds two nested divs (reactor-core and reactor-ring) that CSS will turn into a glowing, spinning arc reactor.
- Directly below the code you just pasted (after the closing </header> tag), paste the stats bar, repo grid, and closing tags:
<!-- Stats bar showing repo count and status -->
<section class="stats-bar" id="statsBar">
<div class="stat">
<span class="stat-label">REPOS</span>
<span class="stat-value" id="repoCount">--</span>
</div>
<div class="stat">
<span class="stat-label">STATUS</span>
<span class="stat-value online">ONLINE</span>
</div>
<div class="stat">
<span class="stat-label">LAST SCAN</span>
<span class="stat-value" id="lastScan">--</span>
</div>
</section>
<!-- Grid where repo cards will appear -->
<section class="repo-grid" id="repoGrid">
<p class="loading-text">Scanning repositories...</p>
</section>
</main>
<script src="script.js"></script>
</body>
</html>
What does this code do?
The stats-bar section displays three data points: repo count, online status, and last scan time. The id attributes (repoCount, lastScan) let JavaScript update these values later.
The repo-grid section is where repository cards will be injected by JavaScript. For now it shows a blinking "Scanning repositories..." placeholder.
- Save index.html with Cmd+S (macOS) or Ctrl+S (Windows).
- Open index.html in your browser by right-clicking the file in the VS Code Explorer sidebar and selecting Open with Live Server. If you do not have Live Server installed, double-click the index.html file in your system file manager instead.
You should see unstyled black text on a white background. The header text, stat labels, and "Scanning repositories..." are all visible but plain.
Seeing a blank page?
- Make sure you pasted both code chunks into the same file, with the second chunk directly after the first.
- Check that the file is saved (look for a dot or circle on the index.html tab in VS Code, which indicates unsaved changes).
- Confirm you opened index.html and not style.css or script.js in the browser.
Still stuck? Help me debug why my index.html shows a blank page in the browser.
Style the page with CSS custom properties and layout
Now you will transform that plain text into a dark, glowing HUD. The CSS uses custom properties (variables) so every glow colour and panel shade is defined in one place.
- Click on style.css in the VS Code Explorer sidebar to open it.
- Paste the following base styles to set up the colour palette, reset defaults, and style the body:
:root {
--hud-cyan: #00d4ff;
--hud-cyan-dim: rgba(0, 212, 255, 0.3);
--hud-bg: #0a0a0f;
--hud-panel: rgba(0, 212, 255, 0.05);
--hud-border: rgba(0, 212, 255, 0.2);
--hud-text: #e0e0e0;
--hud-glow: 0 0 10px rgba(0, 212, 255, 0.5), 0 0 20px rgba(0, 212, 255, 0.2);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--hud-bg);
color: var(--hud-text);
font-family: 'Courier New', monospace;
min-height: 100vh;
overflow-x: hidden;
}
What does this code do?
The :root block defines CSS custom properties (variables). Every colour, border, and glow in the project references these variables so you can tweak the entire palette from one place.
The * selector resets all default browser margins. The body sets a near-black background (#0a0a0f) and a monospace font to establish the Iron Man terminal look.
- Save style.css and refresh your browser.
The page is now dark with light grey text. The scanlines overlay and layout come next.
- Below the code you just pasted in style.css, add the scanlines overlay, container, and header layout:
/* Scanlines overlay for retro CRT effect */
.scanlines {
position: fixed;
inset: 0;
background: repeating-linear-gradient(
to bottom,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.1) 2px,
rgba(0, 0, 0, 0.1) 4px
);
pointer-events: none;
z-index: 999;
}
/* Main container centers content */
.hud-container {
max-width: 1000px;
margin: 0 auto;
padding: 2rem;
}
/* Header layout */
.hud-header {
display: flex;
align-items: center;
gap: 1.5rem;
margin-bottom: 2rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid var(--hud-border);
}
What does this code do?
The .scanlines class creates a fixed full-screen overlay with thin horizontal lines that mimic a CRT monitor. The pointer-events: none ensures you can still click through it.
The .hud-header uses flexbox to lay the arc reactor and title side by side, separated by a subtle cyan border.
- Save style.css and refresh your browser.
You should see faint horizontal lines across the page and the header text arranged in a row. The arc reactor is not visible yet because it has no size or colour.
- Continue adding to style.css with the arc reactor structure and its inner elements:
/* Arc reactor container */
.arc-reactor {
position: relative;
width: 60px;
height: 60px;
}
/* Glowing reactor core */
.reactor-core {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 20px;
height: 20px;
background: var(--hud-cyan);
border-radius: 50%;
box-shadow: 0 0 15px var(--hud-cyan), 0 0 30px var(--hud-cyan), 0 0 60px rgba(0, 212, 255, 0.3);
animation: pulse 2s ease-in-out infinite;
}
/* Spinning outer ring */
.reactor-ring {
position: absolute;
inset: 0;
border: 2px solid var(--hud-cyan-dim);
border-radius: 50%;
animation: spin 8s linear infinite;
border-top-color: var(--hud-cyan);
}
What does this code do?
The .reactor-core is a small circle centered inside the 60px container. The box-shadow property stacks three cyan glows at different radii to create the iconic arc reactor bloom.
The .reactor-ring is a full-size circle with a brighter top border. Combined with animation: spin, it creates a rotating ring effect around the core.
- Next, add the keyframe animations that power the pulse and spin, plus the header text styles:
@keyframes pulse {
0%, 100% {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
50% {
opacity: 0.7;
transform: translate(-50%, -50%) scale(0.9);
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Title text with glow */
.header-text h1 {
color: var(--hud-cyan);
font-size: 1.8rem;
letter-spacing: 3px;
text-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
}
.subtitle {
font-size: 0.75rem;
letter-spacing: 2px;
opacity: 0.6;
margin-top: 0.25rem;
}
What does this code do?
The pulse keyframe gently shrinks and dims the core, then returns it to full size. This makes the reactor look like it is breathing with energy.
The text-shadow on h1 adds a soft cyan glow behind the "J.A.R.V.I.S." text, matching the reactor.
- Save style.css and refresh your browser.
You should now see a pulsing blue circle with a spinning ring, and the glowing "J.A.R.V.I.S." title beside it.
- Add the stats bar and repo grid styles to finish style.css:
/* Stats bar layout */
.stats-bar {
display: flex;
gap: 2rem;
margin-bottom: 2rem;
padding: 1rem;
border: 1px solid var(--hud-border);
background: var(--hud-panel);
}
.stat-label {
font-size: 0.6rem;
letter-spacing: 2px;
opacity: 0.5;
display: block;
}
.stat-value {
font-size: 1rem;
color: var(--hud-cyan);
}
.stat-value.online {
color: #00ff88;
text-shadow: 0 0 8px rgba(0, 255, 136, 0.5);
}
/* Repo grid layout */
.repo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
/* Blinking loading text */
.loading-text {
color: var(--hud-cyan);
opacity: 0.6;
animation: blink 1s step-end infinite;
}
@keyframes blink {
50% {
opacity: 0;
}
}
What does this code do?
The .stats-bar uses flexbox with a semi-transparent panel background and a subtle border. The .online class gives the STATUS value a green glow to signal a live connection.
The .repo-grid uses CSS Grid with auto-fill so cards wrap responsively. The blink animation makes the loading text flash on and off like a terminal cursor.
- Save style.css and refresh your browser.
The stats bar now appears with cyan values and a green "ONLINE" indicator. Below it, "Scanning repositories..." blinks.
Arc reactor not spinning or glowing?
- Make sure all six CSS chunks are in style.css in order, top to bottom. Missing one breaks the chain.
- Check that your <link rel="stylesheet" href="style.css"> in index.html matches the exact filename. The browser cannot find a misnamed file.
- Look for red underlines in VS Code. A missing closing brace } will break every rule below it.
Still stuck? Help me debug why my CSS animations are not working.
Confirm the full HUD shell renders
Before you run this final check, what do you expect the page to look like based on all the HTML and CSS you just wrote?
- Refresh your browser one more time to confirm the complete HUD.
You should see a dark page with faint scanlines, a pulsing blue arc reactor with a spinning ring, the glowing "J.A.R.V.I.S." title, a stats bar showing "--" placeholders and a green "ONLINE" status, and "Scanning repositories..." blinking at the bottom.
✔️ I see the glowing HUD
Your HUD shell is complete. Double check your full code matches below, then move on.
ⓧ I'd like to double check the full code
Your index.html should contain these sections, in order:
- Document head with charset, viewport, title (JARVIS // GitHub Portfolio), and stylesheet link.
- A scanlines div.
- A hud-container main with the header (arc reactor + title).
- A stats-bar section with three stat divs.
- A repo-grid section with loading text.
- A <script src="script.js"></script> before the closing </body> tag.
Your style.css should contain these sections, in order:
- The :root custom properties block, universal reset (*), and body styles.
- The .scanlines overlay, .hud-container, and .hud-header layout.
- The .arc-reactor, .reactor-core, and .reactor-ring styles.
- The @keyframes pulse and @keyframes spin animations, plus .header-text h1 and .subtitle.
- The .stats-bar, .stat-label, .stat-value, and .stat-value.online styles.
- The .repo-grid, .loading-text, and @keyframes blink styles.
Scroll up and confirm each section is present in order. If anything is missing, paste the missing chunk into the correct position in your file.
Your HUD shell is alive. The page already looks like Tony Stark's helmet display, but it shows no real data. Next up, you will connect it to the GitHub API so your actual repositories appear as glowing cards.
Fetch and Display GitHub Repos
Your HUD shell looks fantastic, but it is showing placeholder data. The "--" values in the stats bar and the blinking "Scanning repositories..." text need to be replaced with real information from your actual GitHub account.
In this step, you will connect your portfolio to the GitHub REST API so it fetches your repositories and displays them as styled, glowing cards. This is where your HUD goes from a static mockup to a live data interface.
In this step, get ready to:
- Write a JavaScript function that fetches your repos from the GitHub API.
- Render each repo as an interactive card in the HUD grid.
- Style the repo cards with glow effects and hover animations.
Write the fetch logic in script.js
GitHub provides a free public API that returns data about any user's repositories as JSON. Your JavaScript will call this API, parse the response, and update the stats bar with live numbers.
- In VS Code, open script.js (currently empty) and paste the following code:
const GITHUB_USERNAME = 'your-username-here';
async function fetchRepos() {
// Get references to the DOM elements we need to update
const repoGrid = document.getElementById('repoGrid');
const repoCount = document.getElementById('repoCount');
const lastScan = document.getElementById('lastScan');
try {
// Call the GitHub REST API for this user's repos
const response = await fetch(
`https://api.github.com/users/${GITHUB_USERNAME}/repos?sort=updated&per_page=30`
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const repos = await response.json();
// Update the stats bar with live data
repoCount.textContent = repos.length;
lastScan.textContent = new Date().toLocaleTimeString();
repoGrid.innerHTML = '';
} catch (error) {
repoGrid.innerHTML = `<p class="error-text">ERROR: Failed to connect to GitHub API. ${error.message}</p>`;
}
}
What does this code do?
This function does three things when called:
- GITHUB_USERNAME stores the username the API will look up. You will replace 'your-username-here' with your own GitHub username in a moment.
- fetch() sends a request to GitHub's public API. The sort=updated parameter returns your most recently changed repos first.
- The try/catch block handles network failures gracefully by displaying an error message instead of crashing silently.
- In script.js, find the line that says 'your-username-here' and replace it with your actual GitHub username.
- Save script.js.
The function is defined but not called automatically yet. You will call it from the browser console to test it.
- Open index.html in your browser (double-click the file, or right-click in VS Code and choose Open with Live Server if you have it installed).
- Open the browser console by pressing Cmd+Option+J (macOS) or Ctrl+Shift+J (Windows).
- Type the following into the console and press Enter:
fetchRepos()
Your stats bar should update. The REPOS value changes from "--" to a number (your repo count), and LAST SCAN shows the current time. The "Scanning repositories..." text disappears because the grid clears.
Stats bar still showing "--"?
- Make sure you replaced 'your-username-here' with your actual GitHub username (case-sensitive, no spaces).
- Check the console for red error messages. A 404 means the username was not found on GitHub.
- Confirm you saved script.js before refreshing the page.
help me debug why fetchRepos() is not updating my stats bar
Render repos as cards
The fetch logic works, but the grid is empty after clearing. Now you will loop through the repos array and create a styled card element for each one.
- In script.js, find the line that says repoGrid.innerHTML = ''; inside the try block.
- Directly below that line, paste the following code (still inside the try block, before the } catch line):
repos.forEach(repo => {
const card = document.createElement('div');
card.className = 'repo-card';
card.innerHTML = `
<a class="repo-name" href="${repo.html_url}" target="_blank" rel="noopener">
${repo.name}
</a>
<p class="repo-description">
${repo.description || 'No description provided.'}
</p>
<div class="repo-meta">
<span class="repo-language">${repo.language || 'Unknown'}</span>
<span>${repo.stargazers_count} stars</span>
</div>
`;
repoGrid.appendChild(card);
});
What does this code do?
- repos.forEach() loops through every repository returned by the API.
- For each repo, it creates a div with class repo-card and fills it with the repo name (as a clickable link), description, programming language, and star count.
- repo.html_url links each card directly to the repo on GitHub, so visitors can click through to your code.
- Save script.js.
- In the browser console, type fetchRepos() and press Enter again.
You should see plain white text appearing in the grid area. Each entry shows a repo name, description, and language. They look unstyled because the CSS does not exist yet.
Cards not appearing?
- Check the console for syntax errors. A missing backtick or unescaped quote inside the template literal will break the loop.
- Verify the new code is placed after repoGrid.innerHTML = ''; and before } catch (error). Order matters.
- If you see "ERROR: Failed to connect to GitHub API" in red, your username is likely misspelled.
help me fix my forEach loop that renders repo cards in my Iron Man HUD portfolio
✔️ Awesome, I've got everything!
Great. Make sure you saved script.js and confirmed the cards appear (unstyled) in the browser.
ⓧ I'd like to double check the full code
Scroll up and confirm your script.js contains these sections, in order:
- A GITHUB_USERNAME constant with your username.
- An async function fetchRepos() with three DOM references (repoGrid, repoCount, lastScan).
- A try block with the fetch() call, response check, JSON parse, stats update, grid clear, and repos.forEach() loop creating repo-card elements.
- A catch block that sets repoGrid.innerHTML to an error message with class error-text.
Add repo card styles to style.css
The cards render but they are unstyled text on a dark background. Time to give them the HUD treatment with borders, glow effects, and hover animations.
- Open style.css and add the following at the bottom of the file (after the @keyframes blink rule):
/* Repo card container and hover effects */
.repo-card {
border: 1px solid var(--hud-border);
background: var(--hud-panel);
padding: 1.25rem;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.repo-card::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 3px; height: 100%;
background: var(--hud-cyan);
opacity: 0;
transition: opacity 0.3s ease;
}
.repo-card:hover {
border-color: var(--hud-cyan);
box-shadow: var(--hud-glow);
transform: translateY(-2px);
}
.repo-card:hover::before { opacity: 1; }
What do these styles do?
- Each card gets a semi-transparent panel background with a subtle border, matching the HUD aesthetic.
- The ::before pseudo-element creates a hidden 3px cyan accent line on the left edge. It reveals itself on hover, giving a slick activation effect.
- On hover, the card glows cyan (via box-shadow) and lifts slightly with translateY(-2px).
- Still in style.css, add the card content styles directly below:
/* Card content styles */
.repo-name {
color: var(--hud-cyan);
font-size: 0.9rem;
margin-bottom: 0.5rem;
text-decoration: none;
display: block;
letter-spacing: 1px;
}
.repo-name:hover { text-shadow: 0 0 8px rgba(0,212,255,0.5); }
.repo-description { font-size: 0.75rem; opacity: 0.6; margin-bottom: 0.75rem; line-height: 1.4; }
.repo-meta { display: flex; gap: 1rem; font-size: 0.65rem; opacity: 0.5; letter-spacing: 1px; }
.repo-language { color: #00ff88; }
.error-text { color: #ff4444; text-shadow: 0 0 8px rgba(255,68,68,0.5); }
What do these styles do?
- Repo names glow cyan and gain a text-shadow on hover, making them feel interactive.
- Descriptions are dimmed to 60% opacity so they do not compete with the name.
- The language badge uses green (#00ff88) to stand out from the cyan palette, mimicking a terminal's status indicators.
- Save style.css.
- Switch to your browser, open the console (Cmd+Option+J on macOS or Ctrl+Shift+J on Windows), and type:
fetchRepos()
Before you press Enter, predict what you will see. Will the cards still be plain text, or will they look different now?
Your repo cards now appear as styled panels with cyan borders, dimmed descriptions, and green language tags. Hover over a card to see it glow and lift. The stats bar shows your actual repo count and the current time.
Cards still look unstyled?
- Confirm you saved style.css and refreshed the page before running fetchRepos() in the console.
- Check that your new CSS is placed after the @keyframes blink rule. If it is inside another rule block by accident, the styles will not apply.
- Right-click a card, choose Inspect, and confirm it has the class repo-card. If the class is missing, check your JavaScript template literal.
help me figure out why my repo card CSS styles are not applying
✔️ Awesome, I've got everything!
Great. Make sure you saved style.css and confirmed the cards glow on hover.
ⓧ I'd like to double check the full code
Scroll up and confirm your style.css additions (after @keyframes blink) contain these sections, in order:
- .repo-card with border, background, padding, transition, position, and overflow.
- .repo-card::before with the 3px cyan accent (opacity 0).
- .repo-card:hover with cyan border-color, box-shadow glow, and translateY(-2px).
- .repo-card:hover::before with opacity 1.
- .repo-name in cyan with letter-spacing. .repo-name:hover with text-shadow.
- .repo-description dimmed. .repo-meta as flex row. .repo-language in green. .error-text in red.
Notice how the experience feels right now. The page sits empty, then after a moment the repos suddenly pop into the grid with no transition. It works, but the jump from blank to loaded breaks the HUD immersion.
Your portfolio is now pulling live data from GitHub and displaying it beautifully. Next up, you will add a cinematic boot sequence that masks the loading time and makes the interface feel like it is powering up.
Add the Boot Sequence
Your HUD now pulls live data from GitHub and displays your repos as glowing cards.
The problem is the experience feels abrupt. When someone visits your page, repos just appear out of nowhere after a brief blank moment. A boot sequence animation solves this by masking the API loading time, making the interface feel like it is powering up. Think Tony Stark's helmet activating.
In this step, get ready to:
- Add a boot screen overlay with system-initialization text.
- Animate a progress bar that fills and then fades the screen away.
- Sync the repo fetch timing so data appears the moment the boot screen fades.
Add the boot screen HTML
The boot screen is a full-viewport overlay that sits on top of everything else. It needs to be the first visible element in the page so it covers the HUD while it loads.
- In index.html, find the opening <body> tag.
- Add this boot screen markup as the first child of <body>, above the existing <div class="scanlines">:
<div class="boot-screen" id="bootScreen">
<div class="boot-text">
<p>STARK INDUSTRIES</p>
<p class="boot-status">Initializing J.A.R.V.I.S...</p>
<div class="boot-bar">
<div class="boot-bar-fill"></div>
</div>
</div>
</div>
What does this code do?
- The outer boot-screen div becomes a fixed overlay covering the entire viewport.
- "STARK INDUSTRIES" and "Initializing J.A.R.V.I.S..." give the cinematic system-boot feel.
- The boot-bar-fill div will animate from 0% to 100% width to create the progress bar effect.
- Save index.html.
- Refresh your browser. You should see the raw text "STARK INDUSTRIES" and "Initializing J.A.R.V.I.S..." at the top of your page, unstyled.
Don't see the boot text?
- Make sure the boot-screen div is above the scanlines div, not below it.
- Check you saved the file. Unsaved changes will not show in the browser.
- Confirm the closing </div> tags match the opening ones. There are three nested divs.
Why isn't my boot screen HTML showing up?
✔️ Awesome, I've got everything!
Great. Save your file and move on to styling the boot screen.
ⓧ I'd like to double check the full code
Your index.html should now have the boot-screen div immediately after the opening <body> tag, followed by the scanlines div, then the hud-container main element. Scroll up and confirm the boot-screen markup matches the code block above.
Add boot screen CSS
The boot screen needs to cover the entire viewport with a dark background, center the text, and sit above everything else.
- In style.css, find the body rule (right after the * { margin: 0; ... } reset).
- Add this block directly below the body rule, before the existing .scanlines rule:
/* Boot Screen */
.boot-screen {
position: fixed;
inset: 0;
background: var(--hud-bg);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
animation: boot-fade 0.5s ease-out 2.5s forwards;
}
.boot-text { text-align: center; }
.boot-text p {
color: var(--hud-cyan);
font-size: 1.2rem;
letter-spacing: 4px;
margin-bottom: 1rem;
}
.boot-status { font-size: 0.8rem; opacity: 0.7; }
What does this code do?
- position: fixed with inset: 0 stretches the overlay across the full viewport.
- z-index: 1000 places it above the scanlines (z-index 999) so it hides everything underneath.
- The boot-fade animation will fire after a 2.5 second delay, fading the overlay out. It will not work yet because the keyframes are not defined.
- Save style.css and refresh your browser.
- You should see a dark overlay covering the entire page, with "STARK INDUSTRIES" centered in cyan text. The overlay stays permanently because the fade-out keyframes are not defined yet.
Still seeing unstyled text?
- Confirm style.css is saved. The file name in your VS Code tab should not show a dot or circle indicator.
- Make sure the new CSS rules are between the body rule and the .scanlines rule, not inside another block.
Why isn't my boot screen overlay appearing?
Now add the progress bar styles and the keyframe animations that make the bar fill and the screen fade out.
- In style.css, add this code directly below the .boot-status rule you just wrote:
.boot-bar {
width: 200px;
height: 2px;
background: var(--hud-border);
margin: 1rem auto 0;
border-radius: 1px;
}
.boot-bar-fill {
height: 100%;
width: 0%;
background: var(--hud-cyan);
border-radius: 1px;
animation: boot-load 2s ease-out forwards;
box-shadow: var(--hud-glow);
}
@keyframes boot-load { to { width: 100%; } }
@keyframes boot-fade { to { opacity: 0; pointer-events: none; } }
What does this code do?
- boot-load animates the progress bar from 0% to 100% width over 2 seconds.
- boot-fade makes the overlay invisible after 2.5 seconds (0.5s fade triggered by the delay in .boot-screen).
- pointer-events: none ensures the faded overlay does not block clicks on the HUD underneath.
- Save style.css and refresh your browser.
- You should see the dark overlay appear with a glowing cyan progress bar that fills over 2 seconds. After about 2.5 seconds the entire boot screen fades away, revealing your HUD underneath.
Boot screen not fading away?
- Check that the @keyframes boot-fade block is present and not accidentally inside another rule.
- Verify that .boot-screen has animation: boot-fade 0.5s ease-out 2.5s forwards with forwards at the end. Without forwards, the animation resets after playing.
- Do a hard refresh (Cmd+Shift+R on macOS or Ctrl+Shift+R on Windows) to clear cached CSS.
Why is my boot screen stuck and not fading?
✔️ Awesome, I've got everything!
Great. Save your file and move on to syncing the JavaScript timing.
ⓧ I'd like to double check the full code
Your boot screen CSS should include these blocks in order, all between the body rule and the .scanlines rule:
- .boot-screen (fixed overlay with z-index 1000 and boot-fade animation).
- .boot-text (centered text-align).
- .boot-text p (cyan color, letter-spacing).
- .boot-status (smaller font, reduced opacity).
- .boot-bar (200px wide, 2px tall container).
- .boot-bar-fill (cyan fill with boot-load animation and glow).
- @keyframes boot-load (width 0% to 100%).
- @keyframes boot-fade (opacity to 0, pointer-events to none).
Scroll up and confirm each block is present in your file.
Sync the fetch timing with the boot animation
Right now, the boot screen fades after 2.5 seconds. But your repo fetch runs at unpredictable timing. You need to delay the fetch so repos load while the boot screen is visible and appear the instant it fades.
- In script.js, scroll to the very end of the file (after the closing } of the fetchRepos function).
- Add this code at the bottom of the file:
// Wait for the page to load, then fetch repos after the boot animation finishes
document.addEventListener('DOMContentLoaded', () => {
setTimeout(fetchRepos, 2800);
});
What does this code do?
- DOMContentLoaded fires once the HTML is fully parsed and ready.
- setTimeout(fetchRepos, 2800) waits 2800 milliseconds before calling the fetch. This is slightly longer than the boot animation (2.5 seconds) so repos appear right as the boot screen finishes fading.
Before you run this, what do you think the page will look like on refresh? Will you see the boot screen first, or the repos?
- Save script.js and refresh your browser.
You see "STARK INDUSTRIES / Initializing J.A.R.V.I.S..." with a glowing progress bar that fills over 2 seconds. The boot screen fades away to reveal your HUD with repos already loaded. Hover over a repo card and it glows and lifts.
Repos not appearing after the boot fades?
- Check that you still have the GITHUB_USERNAME constant set to your actual GitHub username at the top of script.js.
- Open DevTools (Cmd+Option+I on macOS, Ctrl+Shift+I on Windows) and check the Console tab for errors.
- Verify you typed fetchRepos (no parentheses) inside setTimeout. Writing setTimeout(fetchRepos(), 2800) with parentheses calls it immediately instead of waiting.
Why aren't my repos showing after the boot animation?
✔️ Awesome, I've got everything!
Great. Double check you have saved script.js.
ⓧ I'd like to double check the full code
Your script.js should have these sections in order:
- The GITHUB_USERNAME constant at the top.
- The async function fetchRepos() with the full try/catch logic.
- The DOMContentLoaded event listener with setTimeout(fetchRepos, 2800) at the bottom.
Scroll up and confirm each section matches the code blocks above.
Your portfolio now boots up like Tony Stark's helmet powering on. Next up, you will deploy it to the internet so anyone can visit your live HUD.
Deploy to Vercel
Your Iron Man HUD portfolio works perfectly on your local machine. But nobody else can see it yet.
Deploying to Vercel puts your site on the internet with a public URL. Every time you push changes to GitHub, Vercel automatically rebuilds and redeploys your site.
In this step, get ready to:
- Push your final code to GitHub.
- Import your project on Vercel and deploy it.
- Verify your live site is accessible to the world.
Push your final code to GitHub
Your GitHub repo still has the empty files from the initial commit. You need to push all of the code you have written across the previous steps.
- Stage, commit, and push all your changes by running these commands in the VS Code terminal:
git add .
git commit -m "Complete Iron Man HUD portfolio"
git push
What do these commands do?
- git add . stages every changed file in your project folder.
- git commit -m "..." saves a snapshot of those changes with a message.
- git push uploads the snapshot to your GitHub repository.
- Confirm your push succeeded by running:
git log --oneline
You should see your commit message at the top of the log.
Push rejected or authentication error?
- If you see a permission error, make sure you are signed in to GitHub in your terminal. Run git remote -v to confirm the remote URL matches your repository.
- If the push is rejected because of non-fast-forward errors, pull first with git pull --rebase origin main then push again.
help me fix a git push error to my GitHub repository
Import the project on Vercel
With your code on GitHub, Vercel can pull it down and serve it as a live website. Since this project is plain HTML, CSS, and JavaScript with no build step, the setup is straightforward.
- Open your browser and go to vercel.com.
- Log in with your Vercel account.
- Click the Add New... drop-down button, then select Project.
- Find your ironman-portfolio repository in the list and click Import.
- On the configuration page, find the Framework Preset dropdown and select Other.
- Leave all other settings at their defaults.
- Click Deploy.
Why select Other as the framework?
Vercel supports many frameworks like Next.js and React. Your project is plain HTML, CSS, and JavaScript with no build tool or package manager. Selecting Other tells Vercel to serve the files directly from your repo without running any build commands.
Don't see your repository in the list?
Vercel connects to GitHub through a GitHub App. If your repo is missing, click Configure GitHub App on the import screen and make sure the ironman-portfolio repository has access granted.
help me connect my GitHub repository to Vercel
Vercel builds and deploys your site in seconds. You will see a success screen with a confetti animation and a preview of your live site.
Verify the live deployment
Before you click the generated URL, what do you think you will see when the page loads? Will it show repos immediately, or will something else happen first?
- Click the URL that Vercel generated (it looks like ironman-portfolio.vercel.app or similar).
- Watch the boot sequence play. You should see "STARK INDUSTRIES" and "Initializing J.A.R.V.I.S..." with a glowing progress bar.
- After about 3 seconds, the HUD fades in and your GitHub repos load as glowing cards.
- Hover over a repo card to confirm it glows and lifts.
Your Iron Man HUD portfolio is now live on the internet. Anyone with the link can see your repos loading in real-time.
What about automatic redeployment?
Vercel watches your main branch on GitHub. Every time you push new code, Vercel automatically pulls the latest commit, rebuilds, and redeploys. You never need to visit the Vercel dashboard to update your site.
Boot sequence plays but no repos appear?
- Open your browser's DevTools console (press F12) and check for a red error. If you see a 404, make sure the GITHUB_USERNAME value in script.js matches your actual GitHub username exactly.
- If you see a 403 rate limit error, wait a few minutes and refresh. The GitHub API allows 60 requests per hour for unauthenticated calls.
help me debug why my GitHub repos are not loading on my deployed Vercel site
Secret mission
Add a Search and Filter Bar
Your portfolio looks amazing, but what happens when you have 20+ repos? Visitors have no way to quickly find a specific project. In this secret mission, you will add a real-time search bar that filters repos by name or programming language as the visitor types.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on free services, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- GitHub repository (ironman-portfolio, free, no ongoing cost).
- Vercel deployment on the Hobby plan (free, no ongoing cost).
- Local project folder (ironman-portfolio on your Desktop).
Keep everything running
No action needed. Choose this if you want your portfolio to stay live and continue showing your latest repos to visitors.
- Your Vercel site stays live indefinitely on the free Hobby plan.
- Your GitHub repository remains available for future edits.
- Your local project folder stays on your Desktop for development.
Pause - I'll come back to this later
Both services are free, so there is nothing to pause. Your site costs nothing to keep running.
- Leave everything as-is. There are no charges accumulating.
- When you return, open the ironman-portfolio folder in VS Code and pick up where you left off.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below.
- Delete the Vercel project:
- Delete the GitHub repository:
- Delete the local project folder:
Nice Work!
Nice Work!
You just built a full Iron Man HUD-themed portfolio from scratch and deployed it live to the internet. Anyone can visit your Vercel URL and see your latest GitHub repos displayed in a cinematic, glowing interface that updates automatically.
You learned how to:
- Consumed the GitHub REST API with the JavaScript fetch function to display live repository data on every page visit.
- Created CSS animations including a pulsing arc reactor, spinning ring, scanline overlay, and a cinematic boot sequence.
- Deployed a static site to Vercel via GitHub integration with automatic redeployment on every push.
- Secret Mission: Added real-time search and filtering across your repository collection.
Ready to quiz yourself?