Workshop: from Figma to app¶
Exercise workshop-figma-to-app-annex.pdf · PDF
So far you have followed NoteBox, step by step. What happens when the design is yours and nobody has typed it first? How many of your own frames are really the same screen in another state? Which screen would you show your family if you had ten seconds?
This workshop has no new content. You take your own Figma design and build its main flow, with everything from this unit. In Unit 1 you were the architect. Now you are on site with your own plans, and the plans are not allowed to change just because building is hard.
What you will learn
- Plan an implementation from a design: screens, routes, files, data, state, events
- Build the main flow of your own app from your own frames, with tokens and a responsive layout
- Wire every visible control of that flow to an action
- Check your work against explicit criteria, and review a classmate's app with the same criteria
- Leave the project in a state anyone can run: it installs, it builds, it is pushed
- The trap: a smaller app that works beats a bigger one that does not
The rules of the site¶
- You work on your app, alone. Ask a neighbour before you ask the teacher, and the teacher before the internet.
- The course rule on AI: only cs50.ai, to explain things, never to write your app.
- There are four checkpoints. At each one, you show the app running, not the code.
- At the end, you review a classmate's app and they review yours.
If you fall behind, cut screens, never checkpoints.
From a drawing to a plan¶
Before you write code, you translate the design.
flowchart LR
S["<b>Screens</b><br>the frames"] --> R["<b>Routes</b><br>the addresses"]
R --> F["<b>Files</b><br>+page.svelte"]
F --> D["<b>Data</b><br>where it comes from"]
D --> ST["<b>State</b><br>what can change"]
ST --> E["<b>Events</b><br>what the user does"]
A handoff sheet is a table that turns a design into a plan: one row per screen, with its route, file, data, state and events.
Duplicate the workshop's Figma file from Classroom and fill in the sheet in frame 1 · Handoff sheet. Write one row per screen of your main flow, from three to five rows. A row for NoteBox's list could look like this:
| Screen | Route | File | Data | State | Events |
|---|---|---|---|---|---|
| Notes | / |
src/routes/+page.svelte |
GET /api/notes, through load |
query; visible is derived. States: with notes, empty, error |
Type in search → filter. Click a card → /notes/{id} |
Check your sheet against these four mistakes:
| The mistake | The fix |
|---|---|
| Rows that are states ("list empty", "list with error") | One row. The states go in the State column |
| An empty Data column | Every screen shows something, so where does it come from? "A JSON file" is a fine answer |
| Events with no action ("click on card"), or actions with no event ("the total updates") | Name the action. A total that updates is derived, not an event |
| Ten rows | Which three make the app worth opening? Those are today |
Then mark one row with a star: your main screen. Checkpoints 2 to 4 are about that screen.
Checkpoint 1: skeleton¶
Every screen of your sheet has its route and file. The header navigation reaches all of them and marks the current page. Your tokens are in
src/app.css.
Look out for:
- Tokens still called
--nb-...in an app that is not NoteBox. Rename them: they are your design decisions. - A navigation that does not mark the current page. See Routing and navigation.
- Dynamic routes written as
product-detailinstead ofproducts/[id].
Checkpoint 2: one honest screen¶
Your main screen matches your Figma frame at 390 px: same spacing, sizes and colours, through tokens. And it does not break at 1280 px.
Here is how to check it. Put the browser on the left with the device toolbar at 390, and the Figma frame on the right at 100 %. Go region by region, top to bottom. For each region, compare size, space, colour, type.
- "More or less the same." Find one number. What is the padding of this card in Figma? And in your CSS? If the two answers differ, that is the work.
- Hex colours and loose pixels. Every colour is a token, and repeated spacings should be too.
- No desktop version in the design. It does not need one, it needs not to break. A centred
max-widthcolumn is an honest answer; a card grid withauto-fillis a better one. See Layout with CSS. - A frame that is impossible or ugly in the browser. You may change the Figma file first, then the code. Design and code must agree; which one moves is your call.
If it works but does not look like the Figma, the plan and the building disagree. Change one of them, on purpose.
Checkpoint 3: it reacts¶
One interaction with state and a derived value: a filter, a counter, a toggle. One form with at least two validation rules and visible error messages.
This is mostly connecting your earlier homework to the main screen: your event-action table from Events and actions and your form from Forms and validation.
- A counter kept by hand, with
count++in three handlers. What happens when a fourth handler forgets? Use$derived. - Buttons that still do nothing. A control with no action either gets one or leaves the screen.
- Errors that only appear in the console. Who is the message for?
- A form copied from NoteBox, with NoteBox's rules. Your rules come from your data: a price cannot be negative, a date cannot be in the past.
Checkpoint 4: it has data¶
Your main screen takes its data from a JSON file or an endpoint, through
load.npm run buildpasses. Committed and pushed.
The minimum that counts is a JSON file in src/lib, a GET endpoint that returns it, a +page.js with load, and data in the page. See Consuming data. Do not leave it until the end: the data decides the markup, and a screen built on fake text gets built twice.
Then, in the terminal:
Careful: dev forgives, build is the truth
A project can run with npm run dev and still fail to build. A failed build prints the file and the line, so read the first error, not the last. The usual causes are an import of a renamed file, a {#each} block left open, or a variable used in the markup and never declared.
Peer review¶
Swap seats, not laptops. Sit in front of your classmate's running app and their copy of the Figma file, at frame 3 · Review criteria. Give each criterion a tick or a comment:
- It runs:
npm installandnpm run devwork on a clean clone, andnpm run buildpasses. - The main screen looks like the Figma frame at 390 px: spacing, type sizes, colours.
- No hex colour inside a component: colours come from the tokens in
app.css. - It does not break between 390 and 1280 px: nothing overflows, nothing overlaps.
- Every route in the sheet opens, and the current page is marked in the navigation.
- Every button and link does something. List any dead control you find.
- The form refuses wrong data and says why, next to the field, in plain words.
- Something on screen is calculated with
$derived, not typed by hand: a counter, a filter, a total. - The data comes through
loadfrom a JSON file or an endpoint, and an unknown URL shows an error page. - With the keyboard only (Tab, Enter, Space) you can complete the main task.
Every comment says where, what, and what you expected. "The form is bad" is not a comment. "New product: I typed a price of -5 and it was accepted" is.
Back in your own seat, read your review and write the one comment you will fix first at the top of the sheet. Do you think your classmate got something wrong? Maybe. But a user who misunderstood your screen is still a finding.
How the workshop is marked¶
This session counts as class work, which is 30 % of the mark for the learning outcome. A checkpoint reached late still counts in full: what matters is where your app is at the end, not how fast it got there.
| Item | Points | Full marks |
|---|---|---|
| Handoff sheet | 1 | 3+ screens with route, file, data, state and events |
| Checkpoint 1: skeleton | 2 | All routes reachable from the header, your own tokens in app.css |
| Checkpoint 2: one screen | 2 | Matches at 390 through tokens, holds at 1280 |
| Checkpoint 3: it reacts | 2 | State + derived interaction, and a form with 2+ rules and visible messages |
| Checkpoint 4: it has data | 2 | Through load, the build passes, pushed |
| Review given | 1 | Ten criteria answered, and comments say where, what and expected |
"How did we do that?"¶
You have already written all of this. Go back to it:
| I need... | Look at |
|---|---|
| Tokens and global styles | Component syntax, src/app.css |
| A component with props | Component syntax, NoteRow.svelte |
| A filter, a counter | Reactivity, query and visible |
| Remembering something in the browser | Reactivity, commit "Session 3" |
| A click that changes something, a child telling its parent | Events and actions, commit "Session 4" |
| A form with rules and messages | Forms and validation, NoteForm.svelte |
| Two columns, a card grid, breakpoints | Layout with CSS, commit "Session 6" |
| A new page, a page per item, navigation | Routing and navigation, src/routes/notes/[id]/ |
| Data from a file or endpoint, an error page | Consuming data, +page.js, +error.svelte |
Can I use a UI library?
Not this term. Unit 4 is about building your own components, and it starts from this code. You need to have felt the need first.
After the workshop¶
- Fix the one comment you picked, and commit it as "Fix after review".
- For your project, you can bring every screen of your sheet up to Checkpoint 2.
- Keep your copy of the Figma file: the handoff sheet is the first page of your project documentation later in the course.
Key takeaways¶
- Plan first: a handoff sheet turns frames into screens, routes, files, data, state and events.
- One row per screen, not per state. Pick one main screen and make it honest.
- Four checkpoints, each shown running: skeleton, one screen, it reacts, it has data.
- Compare with numbers, not "more or less": size, space, colour, type, through tokens.
npm run buildis the truth. Read the first error.- A useful review comment says where, what and what you expected, and a smaller app that works beats a bigger one that does not.
Quick check¶
1. Your design has the frames “Cart”, “Cart empty” and “Cart with error”. How many rows do they take in a handoff sheet?
- Three rows, one for each of the frames
- One row, with the states in its State column
- Two rows, one for the cart and one for errors
- No rows, since states do not belong on the sheet
They are the same screen in different states. A handoff sheet has one row per screen, and the states go in the State column.
2. Which of these is a derived value and not an event?
- Clicking the card to open the product
- Submitting the form to add a product
- The total, recalculated as items change
- Typing a word into the search box
A total that updates by itself is derived from other state. The others are things the user does: events, each of which needs an action.
3. You are checking your main screen against your Figma frame. What is the most useful way to do it?
- Compare the whole screen at a glance, and decide if it feels right
- Read your CSS file, and look for values that seem too large
- Ask a classmate whether they like how the screen looks now
- Compare region by region: size, space, colour and type, at 390 px
Put the browser at 390 next to the frame at 100 %, and compare numbers, region by region. "More or less the same" hides exactly the differences that are the work.
4. npm run dev works, but npm run build fails with several errors. What do you do first?
- Read the first error, which names a file and a line
- Read the last error, which is the most recent one
- Delete the project and clone it again from GitHub
- Ignore it, because the dev server is working fine
Dev forgives, and build is the truth. A later error is often caused by the first one, and the message gives you the file and the line.
5. Which of these is a useful peer review comment?
- The form is bad and should be done again
- New product: a price of -5 was accepted, I expected an error
- I would have used different colours for this app
- Everything looks fine to me, so well done on this
A useful comment says where, what, and what you expected, so the author can reproduce it and fix it.
6. You have 45 minutes left and a design with eight screens, and only two of them work. What do you do?
- Start the other six, so that every screen at least exists
- Skip the checkpoints, to have more time for writing code
- Cut screens, and bring the ones you keep through every checkpoint
- Hand in the Figma file, and leave the code for another day
A smaller app that works beats a bigger one that does not. You can cut screens, but not the checkpoints, because they are what make a screen actually work.
7. In your bookshop app, a “Wishlist” button on the main screen does nothing yet, and you will not have time to build it. What should happen to it?
- It stays, because the Figma design has it
- It stays, but with an error in the console
- It leaves the screen, and the design is updated
- It stays, but with a different colour on hover
A control with no action either gets one or leaves the screen. And design and code must agree, so you update the Figma file too.
The app you built here is big. The next step is a much smaller rehearsal of the same skills, alone and against the clock: Review and exam preparation.