Assignment 10
Due
Submitting your homework
We are going to use Github Classroom for this assignment. You need to have an account on GitHub and be logged in. Authorize Github Classroom here and accept the assignment, then follow the instructions there. Please follow the structure and naming of the starter repo, though you can add any additional files if you need them.
To submit the assignment, please visit Canvas
and submit the URL to your final commit that you want us to grade.
A commit URL looks like https://github.com/designftw-YEAR/hw10-username/commit/b59f14ba05869b3067724aa6d2006667a54c8e7d.
You can submit as many times as you want.
This is important. Your homework is not submitted and is accruing slack hours until you do this!
To make sure your homework is graded correctly, please follow the following:
- Please make sure each of your exercise directories are self contained, i.e. that you don't reference any files outside of the directory (e.g. from your repo root or other exercises). While having a common assets directory for all your exercises might be a good idea in general, we extract each exercise directory separately (as it may be graded by different people), and that will result in your pages not working correctly.
- Do not use root-relative URLs (URLs that start with
/) or absolutelocalhostURLs, as these require the grader to run a local server at a specific directory within your repo. If for some reason you cannot avoid it, please document it in a README otherwise links may be broken for whomever is grading your homework.
If you submit after the deadline, it will count towards your slack hours.
Assignment Updates:
April 16, 5:30pm
- 3A: Added AI guidance
- 3B: Added specific Cursor features to try
Exercise -N: HW4 Retrogrades (Optional)
Now that you've received feedback on some of your assignments, we are offering a (completely optional) opportunity to improve some of your past work and resubmit it for a retrograde. Your final grade on an exercise will then be the average of the original grade and the retrograde. For example, if you got 10 points on the original exercise and 20 points on the retrograde, the final grade we'd put down for the exercise would be 15 points. We will never give you a lower grade than you got originally.
Not all exercises are eligible for retrogrades, either because they are part of multi-week assignments already or because we don't think fixing up that exercise provides a good learning opportunity.
This week, you may request retrogrades for any or all of:
- HW6 Ex1: Build a Scraper (30%)
- HW7 Ex1: Make your homepage more universal (30%)
- HW7 Ex3: Drag & Drop to reorder your to-do list (40%)
- HW8 Ex2: Create a bookmarklet that allows you to hide undesirable content (50%)
To submit a regrade, simply commit and push additional changes to the relevant exercise in that week's repo. Retrograde submissions are due with the assignment where they are offered.
Exercise 1: User testing of Figma mockup of your Chat App (30%)
For this part of the assignment you will do a user testing session of your Figma Chat App mockup from HW9. The structure of this assignment is just like HW8 Exercise 1:
- Choose three tasks (the same as HW8 or different if your design has evolved)
- Run a user study with two participants (since you only have one prototype this will not be a between-subjects experiement like HW8)
- Follow the same user testing procedure as in HW8
Deliverable: An HTML page in user-testing with a short clips of your users performing tasks, and a write up with your three tasks, insights from the user testing, plans for changes, and raw user testing notes in an appendix at the end.
Exercise 2: Improve Color on your website (10%)
Use what we learned this week to improve color on (or add color to) your personal website from past homeworks. Make at least 3 improvements and point them out in a short writeup (~1 sentence for each improvement).
AI Usage: You should think through what kinds of changes you want to make on your own, but you are free to use AI to implement those changes.
Deliverable: Entire website in homepage. Short writeup in homepage/writeup.html.
Exercise 3: Starting Your Chat App (60%)
In this exercise you will start to implement your own chat application, starting from the basic chat apps you've been working on in studio. You will focus on implementing the base functionality:
- Creating/joining a chat
- Chatting
This does not need to include all the special design features you have been designing in your prototypes, but it should be a step towards your design and usable as an intermediate. Feel free to include "fake" functionality for some of your specialty features---much like the paper prototypes and figma mockup this should be just one more step of fidelity, but not the final product.
Part A: What, Where, and Who
AI Usage: For this part of the assignment, you should think about the design on your own. However, you may use AI to implement it and to help you generate JSON schema.
Before getting to the look and feel of your app, the first thing you are going to do is specify how chats in your application are created, found, joined, and participated in. This is your app's "information hierarchy" and it is crucial to work out how this is going to be translated into code before working out the rest of your app.
You are going to break apart the flow of creating, finding, joining, and participating in a chat into a series of actions. For this homework focus on three to four actions that get you to basic chatting functionality---you will have several weeks to continue iterating to create your full chat app, this is just a first rough draft. For each action you are going to ask the questions "What", "Where", and "Who":
- What action needs to be persisted and/or shared? Each of these actions will need to be represented with a Graffiti object.
- "Where" should each of the action take place? This will determine what channels to use to store/find the object.
- Who should be able to "see" each action? This will determine what allowed list to use for the object.
For example, in studio 10 (which we strongly recommend finishing it if you have not already) there are only two actions that need to be persisted/shared: "Create Chat" and "Send Message". We can describe those as follows:
Create Chat:
- What: Create a new chat with a specific title. This is represented with a Graffiti object with the following value:
{
activity: "Create",
type: "Chat",
title: "My chat title",
channel: crypto.randomUUID(), // The "Where" for sending chat-specific messages
published: Date.now() // timestamp
}
- Where: New chats should be findable by anyone in the DesignFTW class so we use the hardcoded channel
"designftw-26". - Who: Anyone in the class can see the created chats, so there is no allowed list.
Send Message:
- What: Send a text message. This is represented with a Graffiti object with the following value:
{
content: "My message",
published: Date.now() // timestamp
}
- Where: Chat messages occur in a random chat-specific channel. This channel is created with
crypto.randomUUID()and persisted/shared in the the "Create Chat" object above. - Who: Anyone who visits a chat can see all the messages, so there is no allowed list.
What Tips
Since Graffiti objects can include arbitrary JSON in their value fields they can represent many actions. In studio you've seen how objects can be used to represent sending messages and creating chats. In your tracker homework you used Graffiti objects to perform "updates" to tracker entries. Here are some other examples of actions and corresponding objects you might want in your app.
To add someone to a group chat you could create an object like:
// Add someone to a group chat
{
activity: "Add",
object: "did:plc:zd7szk2575bygcrlt2m35zj6", // The actor ID of the person being added to the chat
target: "d222491b-d6d0-4c21-aadd-45ed9bc21566" // The chat channel
}
You could change "Add" to "Remove" to create an action for remove someone from a group chat.
You can also use objects to represent explicitly joining a particular chat:
// Join to a group chat
{
activity: "Join",
target: "d222491b-d6d0-4c21-aadd-45ed9bc21566" // The chat channel
}
You could change "Join" to "Leave" to create an action for leaving a group chat.
You can also use objects to follow/friend another person:
// Follow someone
{
activitiy: "Follow",
object: "did:plc:zd7szk2575bygcrlt2m35zj6", // The actor ID of the person being followed
}
You can also use an object to create a profile which could be useful to discover to find other people to message/add/friend:
// A profile
{
name: "David Karger",
bio: "A professor at MIT",
pronouns: "he/him",
describes: "did:plc:zd7szk2575bygcrlt2m35zj6", // The actor ID of the person whose profile it is
}
See the Activity Vocabulary standard for more inspiration and some common vocabulary terms, but don't feel constrained by it. You can come up with whatever actions/objects you'd like.
Where Tips
So far you have seen examples of hardcoded channels for representing static places ("designftw-26" representing the DesignFTW class) and random channels for representing user-generated places (crypto.randomUUID() for representing chats). These cover many cases but some other cases to consider:
- Where = "your inbox": Many chat apps involve direct messaging where you want to be able to send messages to someone's "inbox". You can use someone's actor ID to represent "their inbox". We did this in your tracker apps where your tracker data is stored in the channel "
[your actor ID]/tracker". An object can be in multiple channels at once so it can be in both someone's inbox (their actor ID) and your outbox (your actor ID). - Implicit where: Some chat apps might involve chatting about things that have an existing naming convention. For example, MIT classes have numbers, so if you were making an app for MIT students to discuss classes people might not need to explicitly "create" a class chat but could instead simply type in the class number. Under the hood this "where" would be encoded as a channel string that includes the class number, like
mit:class:6.4500. Similarly there are existing naming conventions for media (ISBNs for books, MBID for music), locations (states, zip codes, other area standards), and websites (URLs), all of which could be used to implitly describe "where" an action occurs.
Who Tips
So far we have only shown you public actions. But many chat apps involve private messages that only certain people can see. You can specify an allowed list to mark who specifically you want to see any particular action---this is your "who". This might be members of a group chat, the target of a direct message, etc. In your code allowed lists are specified like this:
graffiti.post({
value: { youValue: "something" },
channels: ["yourchannel"],
// The allowed list contains the actor IDs of who you want to be able to see the object
allowed: ["did:plc:zd7szk2575bygcrlt2m35zj6", "did:plc:zd7szk2575bygcrlt2m35zj6"]
}, session.value)
Some actions you just want to persist but you don't want to share at all; the "who" is just "the logged in user". For example, you might want you app to remember which chats the user has "joined" but you don't want to make that information available to anyone but the user. In that case, your object can include an empty allowed list and only the user who created it will be able to see it.
graffiti.post({
value: { youValue: "something" },
channels: ["yourchannel"],
allowed: [] // empty array => only you can see it
}, session.value)
Putting this together
Once you have constructed a What, Where, Who for each action, you can translate those descriptions into code: a function for posting an action as well as code to discover those actions, just like you've done in studio. Then use these functions and signals to build out the base functionality of creating, finding, joining, and participating in chats.
Again this does not need to be all the functionality of your chat app. You will be building out your chat apps over the next couple weeks. Focus on 3-4 primary actions that are crucial to being able to chat within your app. If you have questions about scoping, please ask on Piazza.
Part B: Vibe Coding Crash Course w/ Cursor
AI Usage: For the rest of this assignment, you are not just allowed, but encouraged to use AI to generate code.
As usual, while you may delegate tasks to AI, you are still ultimately responsible for the quality of your code and website.
AI can augment, but should not replace, thinking carefully about your design. In general, please avoid giving vague prompts to AI such as "build me a chat app."
Instead, use more precise prompts like "I want a main screen with a list of chats on the left, a chat window in the middle, and settings on the right."
or "the message box should be pink with a purple border"
You may also find that including Figma mockups or images of sketches may lead to better results. Precise prompting tends to lead to better model output!
In this part of the exercise, you will use Cursor, an AI-powered code editor.
Why Cursor?
Cursor provides a generous free plan to students, and has all the features found in other modern coding environments like Claude Code, Codex, Lovable, and Antigravity.
You are welcome to use those tools if you wish, but we will only be providing guidance for using Cursor in this homework.
Follow these steps to get started:
- Get student access. Sign up at cursor.com/students for a free year of Cursor Pro.
- Watch the tutorial video. Watch this video for an overview of Cursor's main features.
- Play around with AI code generation in Cursor. These are ordered by the size of code change
they support. Try them out in part C!
- single-line autocompletion: useful for coding with AI's help
- multi-step tab completion: useful for small refactors with AI's help
- quick edits (cmd+K): useful for adding chunks of code, e.g. functions, blocks of HTML
- agent mode (cmd+I): useful for multi-file edits, large refactors, large chunks of code generation
- plan mode: useful for ensuring AI is adhering to your prompt for large changes
- ask mode: useful for understanding code. Doesn't edit code.
There are no deliverables for this part. It's just a checkpoint to make sure you're familiar with agentic coding before you do part C.
Part C: Look and feel
In addition to the basic data flow from part A, the chat app should begin to look and feel like a real chat app and so change the look and feel appropriately. Keep the following usability goals in mind:
- Are appropriate loading signals displayed for async operations?
- Does the chat interface feel consistent with other chat apps you've used? Or is there a design reason why you are intentionally breaking the norm?
- Can mistakes be recovered from easily? Deleting messages, leaving groups, etc.
- Are the names you choose for certain interactions clear and understandable? The names you display to the user do not necessarily need to exactly match technical jargon you use in your code ("channels", "signals", etc.)
Deliverable: Your basic chat app in chat-app/ and a writeup in chat-app/writeup.html describing your what/where/who and other design decisions as appropriate.
Exercise N: HW10 feedback
Since this is a new class, we need your constructive feedback about every aspect of it: lectures, homeworks, labs etc.
Please fill in your feedback about HW10 in this form. You can edit it as many times as you like until the survey closes (48 hours after the homework deadline). Since this is part of your participation grade, it does not affect your slack hours, but failing to submit the form on time, could result in a lower participation grade.