You are going to make an account on the same site the games industry runs on, write a web page from nothing, and finish with a live, professional portfolio — your showreel, your first-year work, your name, on a real URL you can put on an application.
Short version: GitHub is where the world's code lives. It is a website that stores your project, remembers every version of it you have ever saved, lets other people work on it with you, and — the part you will use today — will host a website for you, free, forever.
You have done this. A folder that looks like this:
That is version control done by hand, and it fails in exactly the way you would expect: you cannot tell what changed between two of those files, you cannot get back a thing you deleted three days ago, and the moment a second person is involved it collapses entirely. Every industry has hit this problem. The software industry solved it properly, and the solution is called {{git|Git}}.
People use the names interchangeably and it causes real confusion, so get this straight now.
A program on your computer. It watches a folder and, whenever you tell it to, takes a permanent snapshot of everything in it. That snapshot is called a {{commit|commit}}. Git is free, it works offline, and it does not need the internet or any website to function.
A website that stores Git projects. It is a place to push your snapshots so they exist somewhere other than your laptop, so other people can see them, and so you have a link to send. Microsoft owns it. There are competitors — GitLab, Bitbucket — that do the same job.
An analogy that actually holds up: Git is the save system in your game. GitHub is the cloud save. The save system works fine with no internet. The cloud save is what means your progress survives the laptop being stolen, and what lets a friend load your file.
A project folder that Git is watching. Everyone says "repo". Your portfolio site will be one repo.
A saved snapshot with a note attached saying what you changed. "Add showreel section". You can return to any commit, ever.
Sending your commits up to GitHub. Until you push, your work exists on one machine only, which is the same as it barely existing.
GitHub has a feature called {{pages|GitHub Pages}}. If a repo contains a file called index.html, GitHub will serve it as a real, public website at https://yourusername.github.io/reponame/ — no hosting fees, no domain to buy, no server to configure. That is the whole trick behind what you are building today, and it is the same mechanism used by an enormous number of real developer portfolios.
Git is normally driven by typing commands, and in Save Point you learn to do exactly that for your Unreal projects, because a 40 GB game project needs it. A portfolio site is a handful of small text files, so today everything happens in the browser, on the GitHub website itself. You will still be making real commits to a real repository — just by clicking rather than typing.
This is not a web design exercise wearing a technical hat. Every studio you might ever work for runs on version control, and a GitHub profile is the single most-looked-at thing on a junior developer's application after the showreel itself.
A game is not made by one person saving files. Picture ten people on one project on a Tuesday afternoon: a gameplay programmer changing how the jump feels, a UI artist replacing every button, a designer tuning enemy health, an audio person adding footstep sounds. All four are editing the same project at the same time.
Version control is what makes that possible instead of catastrophic. Each person works in their own {{branch|branch}} — their own parallel copy of the project. When their work is done they open a {{pr|pull request}}, which is a formal "here is what I changed, please look at it before it goes in". Someone else reads it, comments on it, asks for a fix, and then it gets {{merge|merged}} into the main version. Nothing lands in the real project without going through that door.
The build broke this morning and nobody knows why. Git can tell you exactly which change did it, who made it, and when — and undo just that one thing without touching anything else.
Pull requests are where code review happens. This is how junior developers actually learn on the job: someone senior reads your work and tells you why there is a better way.
On a group project, the commit history is an unarguable record of who did what and when. That protects you, and it is why lecturers ask to see it.
Two honest caveats, because you will hear contradictory things and should know why.
Rockstar, Ubisoft, Epic and most large teams use Perforce rather than Git for the game project itself, because it handles enormous binary files — textures, meshes, audio, cinematics — better than Git does. But the concepts are identical: commit, history, branch, review, revert. Learn them in Git and you can use Perforce inside a week. Nobody will teach you what a commit is on day one of a job.
Tools, engine plugins, build scripts, backend services, websites, game jam entries, mods, and virtually every indie team. Unreal Engine's own source code is on GitHub. If you have ever downloaded a plugin, an asset script or a jam game, you have used GitHub already without noticing.
Be realistic about how a junior application gets read. Someone spends perhaps ninety seconds on it. A GitHub profile with a live portfolio site and a steady trickle of commits over the year says several things at once without you writing a word of it:
| What they see | What they read into it |
|---|---|
| A live site at a real URL | Finishes things. Can be shown a task and produce a working artefact. |
| Commits spread across months | Works consistently, not the night before a deadline. |
| Sensible commit messages | Can communicate about work in progress. Will not be painful to review. |
| A README on each project | Thinks about the person picking it up next. Rare, and immediately noticed. |
| No GitHub at all | Nothing bad — but nothing at all, next to five candidates who have one. |
Nobody is hiring you for your ability to write HTML. They are hiring you for evidence that you can produce finished work and operate the way a team operates. A portfolio you built and published yourself is that evidence, and it costs you one afternoon.
Beyond the industry argument, this site is where your course work lives for the year. One link that goes to your showreel and your best pieces, that you update as you go, that you can hand to a moderator, a university admissions tutor or a studio without rebuilding anything. Build it once now, add to it all year.
Ten minutes, free, and one decision — your username — that is genuinely worth thinking about for sixty seconds before you type it.
GitHub Pages gives you https://username.github.io/. Whatever you pick is on every link you send for the rest of the course, and quite possibly on a CV. xX_DarkSlayer_Xx is a genuinely bad look on a job application. Use your real name if it is free — jbell-dev, jamesbell-games, jamesbellni. Lowercase, hyphens rather than underscores, no birth year. Changing it later breaks every link you have given out.
jamesbell-dev beats jamesbell9471.Free professional software for students, including a free custom domain for a year, GitHub Copilot, and a long list of other tools. You need proof of enrolment. Search for GitHub Student Developer Pack and apply with your college email — it takes a few days to approve, so start it now.
GitHub is a social network as well as a filing cabinet. Following people means you see what they build, and starring a repository is a bookmark you can find again. It also makes the site feel considerably less intimidating.
Verification email never arrives: check spam, and check you typed the address correctly — you can edit it on the same screen. College mail filters are aggressive.
"Username is not available": it may be taken by an inactive account and there is no way to claim it. Pick a variant and move on; do not spend twenty minutes here.
Locked out because you lost the 2FA phone: this is what the recovery codes are for, which is why you saved them somewhere else. Without them, recovery is slow and sometimes impossible.
A repository is just a folder that GitHub is looking after. You are about to make one, and the name you give it decides what your website's address will be.
This confuses everybody once, so here it is up front.
username.github.ioYour user site. You get one. It lives at the short, clean root address:
https://jbell-dev.github.io/
This is the one you want for a portfolio. It is the address you put on a CV.
A project site. You get unlimited ones. It lives in a subfolder of your user site:
https://jbell-dev.github.io/coin-rush/
Right for individual games and experiments later. Not for the portfolio itself.
The repository must be named yourusername.github.io — your actual username, all lowercase, with .github.io on the end and nothing else. If your username is jbell-dev, the repo is jbell-dev.github.io. Not portfolio, not JBell-Dev.github.io. Get one character wrong and the site will not appear, with no error message to tell you why.
yourusername.github.io
Substituting your real username. GitHub will show a small green tick if the name is available.The repo page is the file list, and it is the same layout for a two-file portfolio and for the Linux kernel. The things worth knowing:
| Thing | What it does |
|---|---|
| Code tab | The files, as they are right now. Click any file to read it, click the pencil to edit it. |
| Commits (the clock icon above the file list) | Every version ever saved, newest first. Click one to see exactly what changed, line by line, green for added and red for removed. |
| Issues | A to-do list with a discussion attached to each item. Genuinely useful on group projects. |
| Settings | Where GitHub Pages is switched on. You want this in a minute. |
README.md | The front page of your repo. Whatever is in it renders underneath the file list. |
Click README.md, then the pencil icon. It is written in {{md|Markdown}} — plain text with a few symbols that turn into formatting. You have used it before if you have ever typed **bold** in Discord.
# James Bell Level 3 Games Development student at Belfast Metropolitan College. Unreal Engine, C++, game audio. **Portfolio:** https://jbell-dev.github.io/ ## What is in here The source for my portfolio site. Built with hand-written HTML and CSS, hosted on GitHub Pages. - `index.html` - the page itself - `style.css` - all the styling - `images/` - screenshots and thumbnails
Scroll down, and this is the important part: the box asking you to describe your changes. That is the {{commit|commit message}}. Type Write the README — a short, plain description of what you did — and click Commit changes. You have just made your first commit. It is now in the history permanently, and if you wreck the file tomorrow you can get this version back.
Say what changed, in a few words, as if finishing the sentence "This commit will…". Add showreel section. Fix broken image path on mobile. Update project descriptions.
Not update, not stuff, not asdf, not final FINAL. In six weeks you will be scrolling this list looking for the version before you broke something, and past-you writing "stuff" fourteen times will be no help at all.
Switching on GitHub Pages takes about forty seconds. Do it before you have written anything worth showing, because a live URL that says "coming soon" is far more motivating than a folder that says nothing.
main, folder: / (root), then Save
You are telling GitHub: take the files from the main branch, from the top-level folder, and serve them as a website.With no index.html in the repo, Pages falls back to rendering the README. That is not a bug — it means the whole pipeline is working. The moment you add a file called index.html, that becomes your homepage instead.
index.html
Lowercase. This exact name is the one every web server on earth looks for when someone visits a folder.<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>James Bell — Games Development</title> </head> <body> <h1>James Bell</h1> <p>Games Development student at Belfast Met. Portfolio going up shortly.</p> </body> </html>
Add holding pagehttps://yourusername.github.io/. Give it thirty seconds if it is not there immediately. That is a real website, on the real internet, that anyone in the world can now load.In the browser, on github.com. The pencil icon on any file.
Write a message, click the button. Saved forever, with a note.
Automatically, every commit. Nothing to click.
Refresh. Usually under 30 seconds.
That loop — edit, commit, live — is the whole workflow for the rest of this session. Everything from here is learning what to put inside the file.
index.html. Not Index.html, not index.htm, not index.html.txt. Web servers care about capital letters even when Windows does not.yourusername.github.io, exactly, all lowercase.main for a repo made today.Style.css and your HTML says style.css, it works on your Windows machine and fails on GitHub's Linux servers. Keep every filename lowercase, always.href="style.css" means "in the same folder as this HTML file". If you put the CSS in a folder called css, it is href="css/style.css".Screenshot.PNG is a different file from screenshot.png as far as the server is concerned. Rename everything to lowercase before you upload.my game.png causes trouble. Use my-game.png. Hyphens, always.A web page is text files. That is the whole secret. There is no special program, no project format, nothing binary — you could write a website in Notepad, and the first ones were.
Structure and content. What things are. This is a heading, this is a paragraph, this is an image, this is a link. Nouns.
Presentation. What things look like. Headings are orange, cards sit in a three-column grid, there is 40 pixels of space here. Adjectives.
Behaviour. What things do when poked. You do not need any today — a portfolio works perfectly without it.
The separation matters more than it looks. Because your content is in HTML and your appearance is in CSS, you can completely redesign your portfolio next year by editing one file, without touching a word of your actual work.
index.html and style.css — plain text, nothing else.
They go up to GitHub and Pages serves them.
Someone types your URL. The server sends the text.
Reads the HTML, applies the CSS, paints the page.
HTML is made of {{element|elements}}. An element is an opening {{tag|tag}}, some content, and a closing tag. The closing tag has a forward slash. That is nearly all of it.
<p>Opening tag. The p is the element name — paragraph.Hello there.The content. What the reader actually sees.</p>Closing tag. Same name, with a slash. Says "the paragraph ends here".Some elements carry extra information as {{attr|attributes}}, written inside the opening tag as name="value":
<aElement name — a is an anchor, meaning a link.href="https://…"Attribute. href is where the link goes.>End of the opening tag.My showreelThe clickable text.</a>Closes it.A few elements have no content, so they have no closing tag — they are called {{void|void elements}}. <img> and <br> are the ones you will meet.
Every HTML file you ever write starts like this. Learn the shape; you will type it hundreds of times.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Shown in the browser tab</title> <link rel="stylesheet" href="style.css"> </head> <body> <!-- everything the visitor sees goes here --> </body> </html>
| Line | What it is for |
|---|---|
<!DOCTYPE html> | "This is modern HTML." Always the first line. Leave it out and browsers switch to a bizarre 1998 compatibility mode that will waste an hour of your life. |
<html lang="en"> | Wraps the entire document. lang tells screen readers and search engines what language it is in. |
<head> | Information about the page. None of it is displayed. Title, character set, stylesheet links. |
<meta charset="utf-8"> | Lets you use any character — accents, arrows, emoji — without them turning into rubbish. |
<meta name="viewport"…> | Makes the page behave properly on phones. Without it, a mobile browser pretends to be a desktop and shrinks everything to unreadable. Non-negotiable. |
<title> | The browser tab text, and the blue line in Google results. Put your name in it. |
<link rel="stylesheet"> | "Also load this CSS file." How your HTML finds style.css. |
<body> | Everything visible. All your actual content. |
Type in the left box and the right box updates instantly. Nothing here is saved, nothing can break, and you cannot get it wrong in a way that matters. Break it deliberately: delete a closing tag and see what happens.
Try: change the text, add a second <p>, change <h1> to <h2> and see it shrink, then delete a </p> and watch the browser cope with your mistake rather than crashing.
Unlike C++, which refuses to compile if you miss a semicolon, HTML has no error messages. A browser handed broken HTML will guess what you meant and render something. That is friendly and it is also the reason your page will sometimes look bizarre with no clue as to why. When that happens, the culprit is nearly always a tag you forgot to close.
There are well over a hundred HTML elements. You need about fifteen, and you will use ten of them constantly. Here they are.
<h1>Biggest heading — one per page, usually your name</h1> <h2>Section heading — Showreel, Work, About</h2> <h3>Sub-heading inside a section</h3> <p>A paragraph. Ordinary text lives in one of these.</p> <p>You can put <strong>important text</strong> and <em>emphasised text</em> inside a paragraph.</p>
Do not pick <h3> because you want smaller text — pick it because it is a sub-heading of an <h2>. Size is CSS's job. Screen readers let blind users jump between headings to navigate a page, and skipping levels breaks that. Go h1, then h2, then h3, in order, and let CSS make them whatever size you like.
<ul> <!-- unordered: bullet points --> <li>Unreal Engine 5</li> <!-- li = list item --> <li>C++ and Blueprints</li> <li>Blender</li> </ul> <ol> <!-- ordered: 1, 2, 3 --> <li>Blocked out the level</li> <li>Built the movement</li> </ol>
Lists are the right tool for your skills and your tools-used lines. They are also, with CSS, how navigation menus are built.
<!-- to another website --> <a href="https://github.com/jbell-dev">My GitHub</a> <!-- open in a new tab (use for external links) --> <a href="https://youtube.com/@me" target="_blank" rel="noopener">YouTube</a> <!-- to another page in your own site --> <a href="about.html">About me</a> <!-- to a section further down this page --> <a href="#work">See my work</a> <!-- an email address --> <a href="mailto:me@example.com">Email me</a>
The #work link jumps to whatever element on the page has id="work". That is how a one-page portfolio's navigation bar works, and you will use it in the template.
rel="noopener" alongside target="_blank" is a small security habit. Type it without thinking about it.
Some elements exist purely to group other elements, so you can style or position them as a block. The generic one is <div>. But HTML also gives you named containers that say what the group is — these are called {{semantic|semantic}} elements, and using them costs nothing and helps everything.
<body>
<header>
<nav>
<a href="#work">Work</a>
<a href="#about">About</a>
</nav>
</header>
<main>
<section id="work">
<h2>My work</h2>
<article>
<h3>Coin Rush</h3>
<p>A small arcade game built in C++.</p>
</article>
</section>
</main>
<footer>
<p>© 2026 James Bell</p>
</footer>
</body>| Element | Use it for |
|---|---|
<header> | The top of the page — your name, the navigation. |
<nav> | A set of navigation links. |
<main> | The main content. One per page. |
<section> | A distinct chunk with its own heading — Showreel, Work, About. |
<article> | One self-contained thing — a single project card. |
<footer> | The bottom — copyright, contact, links. |
<div> | A group with no particular meaning. Use when none of the above fits. |
Elements go inside other elements, and they must close in the reverse of the order they opened. Like brackets in maths, or braces in C++.
<p><strong>Hello</strong></p>
Opened p, opened strong, closed strong, closed p. Inside stays inside.
<p><strong>Hello</p></strong>
The tags cross over. The browser will not complain, it will just do something you did not intend.
Indent every level by two spaces. It is not decoration — it is how you spot an unclosed tag by eye, and it is the difference between a file you can fix in ten seconds and one you rewrite.
These two attributes are how CSS finds things. They are the bridge between your HTML and your styling, so understand them before the next section.
<!-- class: a label. Reusable, as many as you like --> <article class="project-card">…</article> <article class="project-card">…</article> <article class="project-card featured">…</article> <!-- id: a unique name. Once per page, never repeated --> <section id="showreel">…</section>
Class = "this is one of these" — used for styling many similar things. Id = "this is the one" — used for jump links like href="#showreel". If you are unsure, use a class. An element can have several classes, separated by spaces.
<!-- like this -->. Invisible on the page. Use them to label the sections of a long file so you can find things.
Six starting points. Load one, then wreck it.
Challenge: starting from "Structure", add a third link to the nav, add a second project article, and give the page a footer with your name in it.
A games portfolio is mostly pictures of games and a video of games. These two elements carry most of the weight of your site, so get them right.
<img src="images/coin-rush.jpg" alt="Player collecting coins in a neon arena">
<imgNo closing tag — an image has no content to wrap.src="images/coin-rush.jpg"Where the file is, relative to this HTML file.alt="Player collecting…"A description, read aloud by screen readers and shown if the image fails to load.Write what the image shows, in a few words. "Player collecting coins in a neon arena", not "screenshot" and not "image1.jpg". It is how blind visitors experience your portfolio, it is what appears when a file path is wrong, and leaving it out is the single most common accessibility failure on the web. Assessors notice.
The src is a path — directions from the current file to the target file.
Same folder: just the filename. Inside a subfolder: folder/filename. Up one level: ../filename. Never start a path with C:/Users/… — that works on your machine and on nobody else's on earth.
Lowercase names, hyphens not spaces. boss-fight.jpg. GitHub's servers are case-sensitive even though Windows is not, and this catches people every single year.
Resize before you upload. A 4K screenshot straight from Unreal is 8 MB and roughly 4,000 pixels wide. Nobody's site needs that. Export at about 1600 pixels wide and your page will load in a second instead of thirty.
JPG for screenshots, PNG for anything with sharp edges or transparency. WebP is smaller than both and every current browser supports it.
Keep them in an images/ folder. Twenty loose files in the root is a mess by week three.
images/ at the start of the filename field, or just drag the whole folder in.Add project screenshots. The upload is not saved until you do this.You do not host video yourself. A video file is huge, GitHub Pages has limits, and it would load appallingly. You upload the reel to YouTube and {{embed|embed}} the player in your page — which is exactly what every professional portfolio does.
On YouTube: Share → Embed → Copy. You get something like this:
<iframe src="https://www.youtube.com/embed/VIDEO_ID" title="James Bell — First Year Showreel" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
An <iframe> is a window onto another website inside your page. The only part you need to change is VIDEO_ID — the string after v= in your video's normal URL.
youtube.com/watch?v=dQw4w9WgXcQThe normal URL you see in the address bar. The ID is the part after v=.youtube.com/embed/dQw4w9WgXcQThe embed URL. Same ID, different path. Use this one in the iframe.Pasting youtube.com/watch?v=… into an iframe gives you a blank grey box and a console error about refusing to connect. It is the single most common mistake on this section, and now you will recognise it in five seconds instead of forty minutes.
By default an iframe is a fixed 560×315 pixels, which looks broken on a phone and pathetic on a monitor. Wrap it in a div and let CSS do the work — this is in the template already, but here is why it exists:
<div class="video"> <iframe src="…" allowfullscreen> </iframe> </div>
.video {
aspect-ratio: 16 / 9;
}
.video iframe {
width: 100%;
height: 100%;
}aspect-ratio: 16 / 9 tells the box to always be widescreen shaped, whatever width it ends up. The iframe then fills it completely. Two rules, and your reel is correct on every device.
HTML gives you a page that looks like a 1994 university document. CSS is everything between that and a site you would put your name on.
h1Selector — what to style.{Opens the block.color: #FF5A1F;Declaration — property, colon, value, semicolon.font-size: 48px;Another one. As many as you like.}Closes it.h1 {
color: #FF5A1F;
font-size: 48px;
}Read it as a sentence: "every h1 on this page is orange and 48 pixels tall". Every semicolon matters — miss one and that declaration and the next one are silently ignored.
One line in the <head>:
<link rel="stylesheet" href="style.css">
Now every rule in style.css applies to that page. One stylesheet can serve a hundred pages, which is why changing your colour scheme is a one-file job.
Three of these cover almost everything you will ever write.
| Selector | Means | Matches |
|---|---|---|
p | Every element of this type | All paragraphs |
.project-card | Every element with this class. Dot for class. | <article class="project-card"> |
#showreel | The element with this id. Hash for id. | <section id="showreel"> |
.card h3 | Any h3 inside an element with class card | Headings within cards only |
a:hover | A link, but only while the mouse is over it | Hover effects |
body | The whole page — good for defaults | Background colour, base font |
.tools { background: #FFC93C; }<p class="lead">I build games.</p>
<p class="tools">Unreal, C++</p>
<p class="tools">Blender, Maya</p>
<p id="contact">Email me</p>
color: orange; /* a name — 140 of them exist */ color: #FF5A1F; /* hex — red, green, blue in pairs */ color: rgb(255, 90, 31); /* the same numbers, 0 to 255 */ color: rgba(255, 90, 31, 0.5); /* the last number is opacity */
Use hex. It is what every design tool gives you, and #FF5A1F is unambiguous in a way that "orange" is not. The pattern is #RRGGBB — two hex digits each for red, green and blue, 00 being none and FF being maximum.
Pick three and stop. One dark background, one light text colour, one accent for links and highlights. Every extra colour is a decision you will get wrong.
Dark backgrounds suit games work. Screenshots pop against near-black, and it is the visual language of the industry. #0E0E14 rather than pure #000000 — pure black next to bright images is harsh.
Contrast is not optional. Mid-grey text on a dark grey background looks sophisticated on your calibrated monitor and is illegible on a laptop in a bright room. If you have to lean in, it is wrong.
body {
font-family: "Inter", system-ui, sans-serif; /* fallbacks after commas */
font-size: 16px;
line-height: 1.6; /* 1.6 x the font size — the single biggest
readability win in all of CSS */
color: #E8E8F0;
}
h1 {
font-size: 56px;
font-weight: 800; /* 400 normal, 700 bold */
letter-spacing: -0.02em; /* tighten big headings slightly */
text-transform: uppercase;
}
a {
color: #FF5A1F;
text-decoration: none; /* removes the underline */
}font-family takes a list. The browser uses the first one it has. Ending with sans-serif guarantees something sensible on any machine. For a custom font, Google Fonts gives you a <link> to paste in your <head> — free, and one line.
If you change one thing in this section, change this. Default line spacing is cramped and makes any block of text look amateur. Set line-height: 1.6 on body and your site immediately reads as more considered than most student work.
Try: change the background colour, set line-height to 1 and then 2 to feel the difference, and make links change colour on hover.
Every single element on a page is a rectangle. Once you can see the rectangles, CSS stops being guesswork and starts being predictable — and this is the concept that separates people who fight CSS from people who use it.
| Layer | What it is | Remember it as |
|---|---|---|
| Content | The text or image itself. | The thing. |
| Padding | Space between the content and the border. Takes the background colour. | Stuffing inside the box. |
| Border | A line drawn around the padding. | The cardboard. |
| Margin | Space outside the border, pushing other elements away. Always transparent. | The gap to the next box. |
Padding or margin? If you want space inside a card — between its edge and its text — that is padding. If you want space between two cards, that is margin (or better, gap, which you meet next section).
.card {
padding: 20px; /* all four sides */
padding: 20px 30px; /* top+bottom, then left+right */
padding: 10px 20px 30px 40px; /* top, right, bottom, left — clockwise */
padding-top: 40px; /* just one side */
margin: 0 auto; /* 0 top and bottom, auto left and right
— this is how you centre a block */
border: 2px solid #2A2A38; /* width, style, colour */
border-radius: 8px; /* rounded corners */
}By default, width: 300px plus padding: 20px gives you a box that is 340px wide, because padding is added on top of the width. This is a famous piece of web history that everybody now overrides on line one:
* {
box-sizing: border-box;
}The * means "every element". Now width: 300px means the box is 300px wide, full stop, with padding taken out of the inside where you expected it to be.
Boxes come in two default flavours, and knowing which is which explains most "why won't this move" moments.
div, p, h1, section, article. Take the full width available and stack vertically. Width, height and vertical margins all work normally.
a, span, strong, em. Sit within a line of text, only as wide as their content. Setting width or height on these does nothing — the usual cause of an hour of confusion.
You can change either with display: block or display: inline-block — which is how you turn a link into a button-shaped thing you can give padding to.
| Unit | Means | Use for |
|---|---|---|
px | Pixels — fixed. | Borders, small precise gaps. |
% | Percentage of the parent element. | Widths that should flex. |
rem | Multiples of the page's base font size. 1rem is normally 16px. | Font sizes and spacing that should scale. |
vh / vw | Percentage of the viewport height / width. | Full-screen hero sections: height: 100vh. |
auto | "You work it out." | margin: 0 auto, image heights. |
Two properties worth knowing now: max-width stops a box growing past a size — max-width: 1100px; margin: 0 auto; is the standard centred-content pattern on nearly every website. And max-width: 100% on images stops a big screenshot bursting out of the page on a phone.
Try: set padding to 0, then 60px. Delete the box-sizing rule and watch the box get wider than you asked for. Change margin and see the gap between the boxes change.
Two tools. Flexbox arranges things in a line; Grid arranges them in rows and columns. Between them they build every layout on your portfolio, and both are far easier than the reputation CSS has.
Put display: flex on a container, and its children line up in a row. That is the entire idea.
nav {
display: flex;
gap: 24px; /* space between the items */
align-items: center; /* line them up vertically */
justify-content: space-between; /* push them to the edges */
}| Property | What it does |
|---|---|
display: flex | Turns this element into a flex container. Its children become a row. |
gap | Space between children. Replaces fiddling with margins — always use this. |
justify-content | Position along the row. flex-start, center, space-between, flex-end. |
align-items | Position across the row. center is the one you want 90% of the time. |
flex-direction: column | Stack vertically instead of horizontally. |
flex-wrap: wrap | Let items drop onto a new line rather than squashing. Add this to any flex row that holds more than three things. |
The joke about CSS is that centring things is impossible. It has not been true for years:
.hero {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}Your project cards are a grid. Use Grid.
.work-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}1fr means "one fraction of the free space". repeat(3, 1fr) is three equal columns. But there is a better version that needs no media queries at all:
.work-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}Read it as: "make as many columns as fit, each at least 280px wide, sharing the space equally". Three across on a laptop, two on a tablet, one on a phone — automatically, with no extra code. This one line is doing most of the work in your portfolio template, and it is worth understanding rather than copying.
Things go in one direction and their sizes vary. Nav bars, a row of tags, an icon beside text, a footer.
Things go in rows and columns and should line up. Project cards, image galleries, a two-column about section.
One more pattern you will want — text over an image, as on a project card:
.card {
position: relative; /* the parent becomes the reference point */
}
.card .caption {
position: absolute; /* now positioned against .card, not the page */
bottom: 0;
left: 0;
right: 0;
padding: 16px;
background: rgba(0, 0, 0, 0.7);
}Try: change minmax(180px, 1fr) to minmax(300px, 1fr) and watch columns disappear. Change gap. Swap justify-content between center and space-between.
Assume the person deciding whether to interview you opens your portfolio on a phone, on a train. More than half of all web traffic is mobile, and a site that needs pinching and dragging reads as unfinished.
<head>, on every page. Without it nothing else in this section works.
<meta name="viewport" content="width=device-width, initial-scale=1">
img {
max-width: 100%;
height: auto;
}.container {
width: 100%;
max-width: 1100px;
margin: 0 auto;
padding: 0 24px;
}For everything else there is the {{media|media query}} — a block of CSS that only applies at certain screen sizes.
/* normal rules first — these apply everywhere */
.hero h1 {
font-size: 72px;
}
/* then the exceptions for small screens */
@media (max-width: 700px) {
.hero h1 {
font-size: 36px;
}
nav {
flex-direction: column;
}
}"When the screen is 700 pixels wide or narrower, also apply these rules." Because they come later in the file, they win. Put every media query at the bottom of your stylesheet, together, so you always know where they are.
Pick breakpoints from your layout, not from device names. Do not hunt for "the iPhone 15 width". Narrow your browser window until your design looks bad, and put a breakpoint there. Most sites need one or two. 700px and 1000px will serve you fine.
Use clamp() and skip the query entirely. font-size: clamp(32px, 6vw, 72px) means "never smaller than 32, never bigger than 72, and 6% of the screen width in between". One line, smooth at every size, no breakpoints. This is what the heading on this page is doing.
1. A fixed width in pixels somewhere — use max-width. 2. An image with no max-width: 100%. 3. A flex row with no flex-wrap: wrap. 4. A long unbroken URL or filename in your text. If your page scrolls sideways on a phone, it is one of these four, every time.
Try: change the media query from 600px to 200px — the mobile styles stop applying, because the preview pane is wider than that. Media queries measure the window the page is in, which here is the little browser on the right.
Here is a complete, working, professional portfolio site. Every technique from the last seven sections is in it and nothing else is — no framework, no build step, no dependencies. Two files. Read it, understand it, then make it yours.
First-year Games Development student building games in Unreal Engine 5.
index.html on GitHub and click the pencil
Select everything that is in there (Ctrl+A) and delete it.Add portfolio template.style.css
Paste the CSS below in. Commit with Add stylesheet.images/ folder
Named project-1.jpg to project-6.jpg. Screenshots of your own work — section 15 covers what makes a good one.Every place you need to change something is marked with a comment. Read the structure before you paste it: header, hero, showreel, work, about, contact, footer — each one a <section> with an id that the navigation links to.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CHANGE THIS: your name goes in the browser tab and in Google results -->
<title>Your Name — Games Development Portfolio</title>
<meta name="description" content="Games Development student at Belfast Metropolitan College. Unreal Engine, C++, level design and game audio.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;700&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="site-header">
<div class="container header-inner">
<a class="logo" href="#top">Your Name</a>
<nav class="site-nav">
<a href="#showreel">Showreel</a>
<a href="#work">Work</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
</div>
</header>
<main id="top">
<!-- ============ HERO ============ -->
<section class="hero">
<div class="container">
<p class="kicker">Games Development · Belfast Met</p>
<h1>Your Name</h1>
<p class="tagline">
First-year Games Development student building games in Unreal Engine 5.
Gameplay programming in C++, level design, and game audio.
</p>
<div class="hero-actions">
<a class="btn btn-primary" href="#showreel">Watch the showreel</a>
<a class="btn" href="#work">See the work</a>
</div>
</div>
</section>
<!-- ============ SHOWREEL ============ -->
<section class="section" id="showreel">
<div class="container">
<p class="section-label">01 — Showreel</p>
<h2>First Year Showreel</h2>
<p class="section-intro">
Ninety seconds of everything I built this year: gameplay, levels,
models and audio. Full breakdowns of each piece are below.
</p>
<!-- CHANGE THIS: replace VIDEO_ID with the id from your YouTube URL.
youtube.com/watch?v=dQw4w9WgXcQ -> the id is dQw4w9WgXcQ
Use the /embed/ address, not the /watch address. -->
<div class="video">
<iframe
src="https://www.youtube.com/embed/VIDEO_ID"
title="Your Name — First Year Showreel"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
<p class="video-caption">
Music: <em>Track name</em> by Artist, used under licence.
<a href="https://www.youtube.com/watch?v=VIDEO_ID" target="_blank" rel="noopener">Watch on YouTube</a>
</p>
</div>
</section>
<!-- ============ WORK ============ -->
<section class="section" id="work">
<div class="container">
<p class="section-label">02 — Selected work</p>
<h2>What I built this year</h2>
<p class="section-intro">
Six projects from first year. Each one lists the tools, what I was
responsible for, and what I would do differently next time.
</p>
<div class="work-grid">
<!-- Copy one whole <article> block to add another project -->
<article class="project">
<img src="images/project-1.jpg" alt="Player character collecting spinning coins in a neon arena">
<div class="project-body">
<h3>Coin Rush</h3>
<p class="project-meta">Unreal Engine 5 · C++ · Solo · 2 weeks</p>
<p>
A timed arcade game written entirely in C++ with no Blueprints.
Twenty coins spawn at random positions and the player has thirty
seconds to collect them.
</p>
<p class="project-role">
<strong>My role:</strong> everything — gameplay classes, spawning,
scoring, HUD and the end-of-round state.
</p>
</div>
</article>
<article class="project">
<img src="images/project-2.jpg" alt="Greybox blockout of a warehouse level seen from above">
<div class="project-body">
<h3>Warehouse Blockout</h3>
<p class="project-meta">Unreal Engine 5 · Level design · Solo · 3 weeks</p>
<p>
A greyboxed stealth level built to a brief: three routes to the
objective, each favouring a different playstyle. Tested with six
classmates and re-cut twice after watching them play.
</p>
<p class="project-role">
<strong>My role:</strong> layout, pacing, sightlines, playtest notes
and iteration.
</p>
</div>
</article>
<article class="project">
<img src="images/project-3.jpg" alt="Low-poly sci-fi crate and barrel models on a turntable">
<div class="project-body">
<h3>Sci-Fi Prop Pack</h3>
<p class="project-meta">Blender · Substance Painter · Solo · 2 weeks</p>
<p>
Eight modular low-poly props under 1,500 triangles each, UV
unwrapped, textured, and imported into Unreal with correct scale
and collision.
</p>
<p class="project-role">
<strong>My role:</strong> modelling, UVs, texturing and engine import.
</p>
</div>
</article>
<article class="project">
<img src="images/project-4.jpg" alt="Audio editing session showing layered footstep waveforms">
<div class="project-body">
<h3>Footsteps and Foley</h3>
<p class="project-meta">Reaper · Unreal MetaSounds · Solo · 1 week</p>
<p>
A surface-aware footstep system: recorded foley on four surfaces,
layered and randomised so the same step never plays twice in a row.
</p>
<p class="project-role">
<strong>My role:</strong> recording, editing, and implementation in engine.
</p>
</div>
</article>
<article class="project">
<img src="images/project-5.jpg" alt="Two-dimensional platformer level with a character mid-jump">
<div class="project-body">
<h3>Skyline</h3>
<p class="project-meta">Unreal Engine 5 · Blueprints · Solo · 2 weeks</p>
<p>
A 2D platformer prototype exploring coyote time, jump buffering and
variable jump height — the small details that decide whether a jump
feels good.
</p>
<p class="project-role">
<strong>My role:</strong> movement system, camera, and level.
</p>
</div>
</article>
<article class="project">
<img src="images/project-6.jpg" alt="Game jam entry title screen with three team member names">
<div class="project-body">
<h3>48-Hour Game Jam: Signal Lost</h3>
<p class="project-meta">Unreal Engine 5 · Team of 3 · 48 hours</p>
<p>
A first game jam, built to the theme "no way back". Finished and
submitted with ten minutes to spare, which taught me more about
scoping than any lecture has.
</p>
<p class="project-role">
<strong>My role:</strong> gameplay programming and build packaging.
</p>
</div>
</article>
</div>
</div>
</section>
<!-- ============ ABOUT ============ -->
<section class="section" id="about">
<div class="container">
<p class="section-label">03 — About</p>
<div class="about-grid">
<div>
<h2>About me</h2>
<p>
I am a first-year Games Development student at Belfast Metropolitan
College, Castlereagh campus. I came to the course from playing games
and taking them apart, and I am here to learn to build them properly.
</p>
<p>
I am most interested in gameplay programming — the systems that decide
how something feels to control. This year I have worked in C++ and
Blueprints, modelled and textured my own assets, and recorded and
implemented my own audio.
</p>
<p>
Next I want to go deeper into C++ and take on a longer team project.
</p>
</div>
<div>
<h3>Tools</h3>
<ul class="skill-list">
<li>Unreal Engine 5</li>
<li>C++ and Blueprints</li>
<li>Blender</li>
<li>Substance Painter</li>
<li>Reaper and Audacity</li>
<li>Git and GitHub</li>
</ul>
<h3>Strengths</h3>
<ul class="skill-list">
<li>Gameplay programming</li>
<li>Level blockout and pacing</li>
<li>Sound design and implementation</li>
<li>Finishing things on a deadline</li>
</ul>
</div>
</div>
</div>
</section>
<!-- ============ CONTACT ============ -->
<section class="section section-contact" id="contact">
<div class="container">
<p class="section-label">04 — Contact</p>
<h2>Get in touch</h2>
<p class="section-intro">
Open to work experience, collaborations and game jams.
</p>
<!-- CHANGE THESE: your real links -->
<div class="contact-links">
<a class="btn btn-primary" href="mailto:you@example.com">you@example.com</a>
<a class="btn" href="https://github.com/yourusername" target="_blank" rel="noopener">GitHub</a>
<a class="btn" href="https://www.youtube.com/@yourchannel" target="_blank" rel="noopener">YouTube</a>
<a class="btn" href="https://yourusername.itch.io" target="_blank" rel="noopener">itch.io</a>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<p>© 2026 Your Name · Games Development · Belfast Metropolitan College</p>
<p>Built by hand with HTML and CSS. Hosted on GitHub Pages.</p>
</div>
</footer>
</body>
</html>The top of this file is a block of colour and font variables. Change those seven values and the entire site changes with them — that is the whole reason to use var() rather than typing #FF5A1F in thirty places.
/* =========================================================
Portfolio stylesheet
Change the colours and fonts here at the top; everything
below uses these values, so one edit updates the whole site.
========================================================= */
:root {
--bg: #0E0E14; /* page background — near black, not pure black */
--surface: #16161F; /* cards and panels */
--line: #2A2A38; /* borders and dividers */
--text: #E8E8F0; /* body text */
--muted: #9A9AB0; /* secondary text */
--accent: #FF5A1F; /* links, highlights, the one loud colour */
--accent-2: #00D6D6; /* a second accent, used sparingly */
--display: "Space Grotesk", system-ui, sans-serif;
--body: "Inter", system-ui, -apple-system, sans-serif;
--radius: 10px;
--max: 1100px;
}
/* ---- reset ---- */
* {
box-sizing: border-box;
}
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--body);
font-size: 16px;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
}
img {
max-width: 100%;
height: auto;
display: block;
}
a {
color: var(--accent);
}
h1, h2, h3 {
font-family: var(--display);
font-weight: 700;
line-height: 1.1;
letter-spacing: -0.02em;
margin: 0 0 16px;
}
:focus-visible {
outline: 3px solid var(--accent-2);
outline-offset: 3px;
}
/* ---- the centred column everything sits in ---- */
.container {
width: 100%;
max-width: var(--max);
margin: 0 auto;
padding: 0 24px;
}
/* ---- header ---- */
.site-header {
position: sticky;
top: 0;
z-index: 10;
background: rgba(14, 14, 20, 0.85);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--line);
}
.header-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding-top: 16px;
padding-bottom: 16px;
}
.logo {
font-family: var(--display);
font-weight: 700;
font-size: 18px;
color: var(--text);
text-decoration: none;
letter-spacing: -0.01em;
}
.site-nav {
display: flex;
gap: 26px;
flex-wrap: wrap;
}
.site-nav a {
color: var(--muted);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: color 0.15s;
}
.site-nav a:hover {
color: var(--text);
}
/* ---- hero ---- */
.hero {
padding: 110px 0 90px;
border-bottom: 1px solid var(--line);
background:
radial-gradient(900px 400px at 15% -10%, rgba(255, 90, 31, 0.16), transparent 65%),
radial-gradient(700px 400px at 90% 10%, rgba(0, 214, 214, 0.10), transparent 60%);
}
.kicker {
font-family: var(--display);
font-size: 12px;
font-weight: 500;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--accent);
margin: 0 0 18px;
}
.hero h1 {
/* never smaller than 40px, never bigger than 88px, fluid in between */
font-size: clamp(40px, 9vw, 88px);
margin: 0 0 20px;
}
.tagline {
font-size: 19px;
color: var(--muted);
max-width: 56ch;
margin: 0 0 34px;
}
.hero-actions {
display: flex;
gap: 14px;
flex-wrap: wrap;
}
/* ---- buttons ---- */
.btn {
display: inline-block;
padding: 13px 26px;
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--surface);
color: var(--text);
font-weight: 600;
font-size: 15px;
text-decoration: none;
transition: transform 0.15s, border-color 0.15s, background 0.15s;
}
.btn:hover {
transform: translateY(-2px);
border-color: var(--accent);
}
.btn-primary {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.btn-primary:hover {
background: #ff6f3d;
}
/* ---- sections ---- */
.section {
padding: 90px 0;
border-bottom: 1px solid var(--line);
}
.section-label {
font-family: var(--display);
font-size: 12px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--accent-2);
margin: 0 0 14px;
}
.section h2 {
font-size: clamp(28px, 5vw, 44px);
}
.section-intro {
color: var(--muted);
max-width: 60ch;
font-size: 17px;
margin: 0 0 40px;
}
/* ---- showreel ---- */
.video {
aspect-ratio: 16 / 9;
width: 100%;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius);
overflow: hidden;
}
.video iframe {
width: 100%;
height: 100%;
border: 0;
display: block;
}
.video-caption {
color: var(--muted);
font-size: 14px;
margin: 14px 0 0;
}
/* ---- project grid ---- */
.work-grid {
display: grid;
/* as many columns as fit, each at least 300px wide */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 26px;
}
.project {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius);
overflow: hidden;
display: flex;
flex-direction: column;
transition: transform 0.18s, border-color 0.18s;
}
.project:hover {
transform: translateY(-4px);
border-color: var(--accent);
}
.project img {
width: 100%;
aspect-ratio: 16 / 10;
object-fit: cover;
border-bottom: 1px solid var(--line);
}
.project-body {
padding: 22px 22px 24px;
}
.project h3 {
font-size: 21px;
margin: 0 0 6px;
}
.project-meta {
font-family: var(--display);
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--accent-2);
margin: 0 0 14px;
}
.project p {
font-size: 15px;
color: var(--muted);
margin: 0 0 12px;
}
.project-role {
font-size: 14px;
color: var(--text);
border-top: 1px solid var(--line);
padding-top: 12px;
margin: 16px 0 0;
}
.project-role strong {
color: var(--accent);
}
/* ---- about ---- */
.about-grid {
display: grid;
grid-template-columns: 1.4fr 1fr;
gap: 50px;
}
.about-grid p {
color: var(--muted);
margin: 0 0 16px;
}
.about-grid h3 {
font-size: 15px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--accent-2);
margin: 0 0 14px;
}
.about-grid h3 + ul + h3 {
margin-top: 34px;
}
.skill-list {
list-style: none;
margin: 0;
padding: 0;
}
.skill-list li {
padding: 9px 0;
border-bottom: 1px solid var(--line);
font-size: 15px;
}
/* ---- contact ---- */
.section-contact {
text-align: center;
}
.section-contact .section-intro {
margin-left: auto;
margin-right: auto;
}
.contact-links {
display: flex;
gap: 14px;
flex-wrap: wrap;
justify-content: center;
}
/* ---- footer ---- */
.site-footer {
padding: 40px 0 60px;
color: var(--muted);
font-size: 14px;
}
.site-footer p {
margin: 0 0 6px;
}
/* =========================================================
Small screens. Keep every media query together, at the
bottom of the file, so you always know where they are.
========================================================= */
@media (max-width: 760px) {
.hero {
padding: 70px 0 60px;
}
.section {
padding: 60px 0;
}
.about-grid {
grid-template-columns: 1fr;
gap: 34px;
}
.header-inner {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.site-nav {
gap: 18px;
}
}
@media (prefers-reduced-motion: reduce) {
* {
transition: none !important;
}
}| Find | Replace with | Where |
|---|---|---|
Your Name | Your actual name | index.html — title, logo, hero, footer |
VIDEO_ID | Your YouTube video id | index.html — twice in the showreel section |
you@example.com | Your email | index.html — contact section |
yourusername | Your GitHub username | index.html — contact links |
The six <article class="project"> blocks | Your own projects — delete any you do not need, copy one to add more | index.html — work section |
| The About text and the two skill lists | You, honestly. Three short paragraphs. | index.html — about section |
--accent: #FF5A1F | A colour that is yours | style.css — line 9 |
Paste the template, commit, check it loads. Change the names, commit, check. Add the video, commit, check. If something breaks you then know exactly which change did it, and you can look at the previous commit to see what you had. Twelve small commits are worth far more to you — and to whoever assesses this — than one enormous one.
The template is deliberately restrained, because restrained is what looks professional. But it is a starting point, not a finish line, and an assessor can tell the difference between a template you pasted and one you understood. Things worth doing:
Swap the two accent colours in :root for something that suits your work. Keep the dark background — screenshots sit better on it.
Pick two on Google Fonts, paste their link into the <head>, and update --display and --body.
Make coin-rush.html with the same header and CSS, write it up properly, and link the card to it. This is the single most impressive addition.
Upload cv.pdf to the repo and link it from the contact section.
A 32×32 PNG called favicon.png, plus <link rel="icon" href="favicon.png"> in the head. Small detail, immediately noticed.
Blockout, greybox, final. Showing how you got there is more interesting than the result.
The reel is the most important thing on your portfolio. It is what gets watched first, and often it is the only thing that gets watched. Ninety seconds, on YouTube, linked from your site — and every one of those three constraints is there for a reason.
Size. A minute of decent-quality video is 100–300 MB. GitHub asks you to keep repos under 1 GB and blocks single files over 100 MB. Your reel does not belong in a Git repository.
Delivery. YouTube re-encodes your video into six resolutions and streams the right one to every device on every connection. A raw MP4 on GitHub Pages does none of that and will buffer on a phone.
Reach. It is searchable, shareable, and it works when someone opens it on a train. And you can send the link on its own, without the site, which you will do more often than you expect.
The mistake that costs students most is showing team or tutorial-based work without saying which parts were theirs. An assessor or an employer looking at an unattributed clip assumes the least, or worse, wonders. One line of on-screen text — "team of 3 — I built the movement and the audio" — turns an ambiguous clip into evidence.
Play in a new window rather than in the editor viewport so there is no UI in shot. For clean camera moves use Sequencer and render with Movie Render Queue — it produces far better output than screen capture and it does not drop frames.
OBS Studio is free and records at 1080p60 without breaking a sweat. Windows Win+G works in a pinch. Record at 60fps if the game runs at 60 — a stuttery capture makes good work look bad.
Do not use a commercial track. YouTube will detect it, and the outcomes range from ads on your reel to it being muted or blocked in some countries — which is discovered by the person who could not watch it, not by you.
Free, cleared, built into YouTube Studio. The easiest correct answer.
Incompetech, Free Music Archive. Free with attribution — so put the attribution in your video description.
If you made the sound design, let it carry the reel. For an audio-focused student this is the stronger choice anyway.
Your Name — Games Development Showreel 2026. Your name first. This is a professional document, not a video called final_reel_v3.From the video's URL, take the id — the characters after v=:
https://www.youtube.com/watch?v=dQw4w9WgXcQYour video's normal address. The id is the highlighted part.→https://www.youtube.com/embed/dQw4w9WgXcQWhat goes in the iframe src.In your index.html, find VIDEO_ID — it appears twice, once in the iframe and once in the "Watch on YouTube" link — and replace both. Commit with Add showreel. Reload your site. Your reel is on your portfolio.
youtube.com/watch?v=… refuses to load in an iframe. It must be youtube.com/embed/…. This is the cause about half the time.& and everything after it — delete from the & onwards.Six project cards, each with a screenshot, three sentences and a line saying what you did. This is where you turn a year of coursework into something that reads as a body of work.
Finished things. Even small ones. A complete two-week project beats an ambitious abandoned one every time.
Range. One piece of code, one level, one art asset, one audio piece. It shows you can work across a pipeline.
Anything you can talk about. If you could explain every decision in it for five minutes, it belongs here.
Tutorial results with nothing added. Everybody has the same third-person template. If you followed a tutorial and then built something on top, show and say that instead.
Half-finished experiments. Unless you frame them as experiments and say what you learned.
Ten variations of one thing. Pick the best one.
Six good pieces beat twelve mediocre ones. A portfolio is judged on its weakest item, because that is the one that makes a reviewer wonder about your standards. Cut anything you feel you need to apologise for.
The image is the card. Most people look at six pictures and read one description.
High Resolution Screenshot from the viewport menu gives you a clean, large frame.project-1.jpg — lowercase, no spaces.Four parts, in this order, and no more than about sixty words in total. The template card is built around exactly this.
The project's name. Not "Assignment 2".
Engine, language, solo or team, how long it took.
Two sentences. What the thing does and one interesting decision you made.
Exactly what you were responsible for. Non-negotiable on team projects.
"Coin Rush
This was a game I made for my assignment. It was quite hard but I learned a lot and I'm happy with how it turned out."
Says nothing about the work. Could describe any project by anyone.
"Coin Rush — Unreal Engine 5 · C++ · Solo · 2 weeks
A timed arcade game written entirely in C++ with no Blueprints. Twenty coins spawn at random positions and the player has thirty seconds to collect them all. Spawning re-rolls any position that lands too close to the player, so no round starts with a free point.
My role: everything — gameplay classes, spawning, scoring, HUD."
Specific, honest, and shows a decision that was actually thought about.
"What I would do differently." One sentence. "The spawn logic runs on every tick when it only needs to run once — I would move it to BeginPlay." It costs you nothing, it shows you can look at your own work critically, and in an interview it is very often the thing they ask you about.
Say plainly what was yours. "Team of 3 — I wrote the movement and packaged the builds." "Built following a tutorial series, then extended with my own inventory system." Nobody minds a student following a tutorial; everyone minds finding out later that unattributed work was not yours. It is the one thing that can turn a good portfolio into a problem, and being straightforward costs you nothing.
Work down this list. When everything is ticked, send the link — and then keep using the repo for the rest of the year, because a portfolio that stops in October is worth much less than one that grows.
Ten minutes when the work is fresh and you still remember the decisions. Come June, you will not.
Upload a new one and swap the id. Keep the old one unlisted rather than deleting it — progress is worth being able to show.
Your Unreal projects, with Git LFS, as set out in Save Point. Link them from the portfolio cards.
What it is, how to run it, what you did. It takes five minutes and almost nobody does it, which is exactly why it stands out.
The contribution graph on your profile is a year-long record of consistency. It is not a score to game — but a flat one says something too.
The Student Developer Pack includes one free for a year. yourname.dev, pointed at the same repo. One settings field.
| Next | Why bother |
|---|---|
| Learn Git on the command line | The browser workflow does not scale past a few small files. Save Point takes you through it with Unreal projects, which is where you actually need it. |
| Branches and pull requests | How real teams work. Make a branch on your own portfolio, change the colours, open a pull request on yourself and merge it. Ten minutes, and the idea sticks for good. |
| VS Code plus the GitHub extension | Editing files on github.com gets old fast. Edit locally with a live preview, commit from the sidebar. |
| A dedicated page per project | Process, iterations, what broke, what you would change. This is what turns a portfolio into a case study, and it is what higher education admissions actually read. |
| JavaScript, eventually | Not needed for this, but it is the next step if you want a portfolio that does things rather than just showing them. |
Send your lecturer two links: your portfolio URL (https://yourusername.github.io/) and your GitHub profile (https://github.com/yourusername). The second one matters — it shows the commit history behind the first, which is the evidence that you built it.
Ten questions. Every one of them is something that will actually come up — either in an assessment, in an interview, or at half past eleven the night before a deadline when your site has stopped working.
Every term used in this guide, in plain English. Dotted underlines throughout the site pop these up where they appear.