// Project brief
First Ship — start here
HTML · CSS · JavaScript · Git
New here? Do this one first. Five tiny tickets that teach you how everything works — branches, pull requests, code review, going live — and leave you with a page about yourself, live on the internet, that you built and shipped yourself. About an hour.

Work items
5
Story points
7
Est. effort
~1h
Top difficulty
2/10
// How it works
01
Enroll
Get your own private repo, generated from the project blueprint.
02
Ship work items
Pick up bugs, tasks, and stories — one PR each, run through CI and AI code review.
03
Earn story points
Merge to bank verified points and unlock the next item on the backlog.
// The backlog
5work items, unlocked in order as you ship. Open any of them to see exactly what you'd be doing — nothing here is hidden until you sign up.
TASK-001
XS · 1SPPut your name on the page
This is the ticket where you learn how everything here works. The code change is one word — the point is the journey it takes to get shipped.
How to do this ▾
Why it matters
This is the ticket where you learn how everything here works. The code change is one word — the point is the journey it takes to get shipped.
What you do
Your page currently says YOUR NAME HERE. Make it say your actual name.
Do this once
git clone <your repo url> cd <your repo folder> npm install npm run devOpen http://localhost:3000 — that's your page.
Now the actual work
1. Make a branch. A branch is your own copy of the code to experiment in, so you can't break anything:
git checkout -b task/TASK-001-your-name2. Make the change. Open
src/profile.jsand changenameto your real name.3. Check it.
npm test4. Save and send it.
git add . git commit -m "TASK-001: put my name on the page" git push -u origin task/TASK-001-your-name5. Open a pull request. GitHub will show a button for it. A pull request means "here's my change, please review it" — it's how every software team hands in work.
Then watch: the tests run automatically, a reviewer reads your change, and when it's approved it merges and your page goes live. That's the loop you'll repeat for the rest of your career.
Hints
Everything you need is in
src/profile.js. If a command fails, ask the mentor on this page — that's what it's for.Done when
namein src/profile.js is the student's own name, not the placeholder- Tests pass
BUG-002
XS · 1SPThe page says "Hello, undefined"
Someone visiting your page is greeted by the word "undefined" instead of your name. Not a great first impression.
How to do this ▾
Why it matters
Someone visiting your page is greeted by the word "undefined" instead of your name. Not a great first impression.
What you do
Your page should greet visitors with your name, but it says undefined instead.
Run the tests and read what they tell you:
git checkout main && git pull git checkout -b bug/BUG-002-hello-undefined npm testThe test message points at the problem. Look at the
greeting()function insrc/profile.js: it asks the profile for a piece of information — check whether that piece actually exists.A failing test is a good thing. It's not telling you off, it's telling you exactly where to look. Getting comfortable reading them is most of what debugging is.
Hints
One word is wrong in
greeting()insrc/profile.js. Compare it against the fields listed inPROFILEjust above.Done when
- greeting() returns "Hi, I'm <the name>" using the profile's real field
- Works for any profile passed in, not just the student's own name
- The fix is in the code, not in the test
- Tests pass
STORY-003
S · 2SPAdd your links
A page about you that nobody can follow up on is a dead end. Give visitors somewhere to go.
How to do this ▾
Why it matters
A page about you that nobody can follow up on is a dead end. Give visitors somewhere to go.
What you do
Add at least two links to your page — GitHub, LinkedIn, an Instagram, a blog, whatever you want people to find.
Two parts to this one:
1. The data. Add your links to the
linksarray insrc/profile.js:links: [ { label: "GitHub", url: "https://github.com/your-username" }, { label: "LinkedIn", url: "https://www.linkedin.com/in/you" }, ],2. The code that shows them.
renderLinks()currently returns nothing. Make it return one<a>tag per link, using each link'surlandlabel.This is the first ticket where you write something new rather than fix something. Take your time.
Hints
.map()turns a list of things into a list of other things, and.join("")glues them into one string. That's the whole trick.Done when
- At least two links with both a label and a url
- renderLinks() returns one
<a href="…">label</a>per link - The links appear on the rendered page
- Tests pass
BUG-004
XS · 1SPYour links take visitors away and they don't come back
Someone reading your page clicks your GitHub link, lands on GitHub, and your page is gone. You just lost them.
How to do this ▾
Why it matters
Someone reading your page clicks your GitHub link, lands on GitHub, and your page is gone. You just lost them.
What you do
Your links currently open in the same tab. Make them open in a new tab, so your page stays put.
Add two attributes to each
<a>tag you generate inrenderLinks():target="_blank"— open in a new tabrel="noopener noreferrer"— and do it safely
That second one matters: without it, the page you linked to gets a handle on yours and can interfere with it. Professional teams always write these two together, and now you know why.
Hints
You're editing the same
renderLinks()you wrote last ticket — just adding attributes inside the<atag.Done when
- Every rendered link has target="_blank"
- Every rendered link has rel containing noopener
- The links still point where they did before
- Tests pass
STORY-005
S · 2SPShow what you're learning
The last piece of your page: what you're actually working on. This is the bit a recruiter reads.
How to do this ▾
Why it matters
The last piece of your page: what you're actually working on. This is the bit a recruiter reads.
What you do
List at least three things you're learning, and show them on your page.
1. Add them to the
skillsarray insrc/profile.js:skills: ["JavaScript", "Git", "HTML & CSS"],2. Make
renderSkills()return one<li>per skill — sorted alphabetically, not in the order you typed them.Why sorted? Because then the page looks the same no matter what order anyone types things in. Output that doesn't depend on luck is easier to test and easier to trust — a small idea you'll meet again and again.
When this merges, your page is finished. Send the link to someone.
Hints
[...list].sort()sorts a copy, which leaves the original array alone. Sorting the original in place would work here too, but copying is the safer habit.Done when
- At least three skills listed
- renderSkills() returns one
<li>per skill - Output is sorted alphabetically regardless of the order in the array
- The skills appear on the rendered page
- Tests pass