6.4500 Design for the Web: Languages and User Interfaces

↑ All studios

Studio 12

Transition exercise

We will work on making a popup that smoothly appears when you focus a text input above it is focused:

Start by forking this pen.

Step 1: Add a transition

As the code currently stands, the popup appears and disappears instantly. Use the transition property to make it animate smoothly. Note that display is not animatable, so the transition property will do nothing with the current code. You can use a tranform to scale it down to 0, then a transition from that will make it appear to grow. Do not use a very long duration as that can make a UI feel sluggish. As a rule of thumb, avoid durations longer than 400ms (0.4s)

Step 2: Fix the transform to make it grow from its pointer

The popup currently grows from its center, which looks a bit weird. Use the transform-origin property to make it grow from the tip of the pointer instead.

Do not eyeball this; look at the CSS creating the pointer and calculate what the offsets should be. The diagram below may be helpful:

where:

Keep in mind that when specifying a transform origin, that to go higher or to the left of the element, you need to use negative values.

Step 3: Make it bounce!

We currently have a pretty decent transition:

We can go a step further and make it bounce at the end, to make it feel more alive and playful.

Use cubic-bezier.com to create a bezier curve that bounces at the end (i.e. the y value goes beyond 100%, then comes back to 100%). The exact curve is up to you.

Step 4: Make it bounce only when it appears

Some of you will not have this problem, as it depends on how you wrote your CSS. In that case, you have nothing to fix!

Play a little with your transition. Especially if you use an intense bounce, you get a weird artifact when the popup disappears: it shrinks to 0, then grows a little bit on the other side of the screen, then disappears entirely. This is because your timing function is applied on both states: normally when growing, and in reverse when shrinking, so you get a "bounce" when shrinking too!

To fix this, you should only apply your timing function when the popup appears, not when it disappears. If input:not(:focus) + .popup hides our popup, what selector would select it only when it appears?

App Directory

In the last homework you all made profile editors. We are assuming all of you already include a name property in your profile objects, but if not please add one. If for some reason you explicitly do not want a name property, please talk to us.

Then, also add a generator property to your profile object that links to your application as shown below.

Finally, add an additional channel "designftw-2025-studio2" to your profile objects. This will ensure that profiles in your app gets added to our shared directory.

In total, make sure your profile objects look something like this:

{
	value: {
		name: "Your Name",
		generator: "https://username.github.io/your-app/",
		describes: this.$graffitiSession.value.actor,
		// your other properties...
	},
	channels: [
		"designftw-2025-studio2",
		// your other channels...
	],
}

After making those changes, make sure you are using GraffitiRemote() instead of GraffitiLocal(). This will ensure that you are actually posting data to the server.

createApp({
	// your app...
})
  .use(GraffitiPlugin, {
    // graffiti: new GraffitiLocal(), <- comment this line
    graffiti: new GraffitiRemote(), // <- uncomment this line
  })
  .mount("#app");

Once you are done, log out and log back in with a Solid account and create a profile. Make sure you can see it in this directory.

Other peoples' data

If you have not been working with GraffitiRemote you may notice that you are now seeing more data in your app made by other people. That other data can be very useful - it will populate your app with real data that can be valuable for testing and help you overcome the cold start problem.

However, you may also see some errors because your app is now receiving data that it does not understand. The best solution is to make sure you are using an appropriately strict JSON Schema in your discover calls. This will filter out any data that your app does not understand.

As a quick fix, or if you intentionally do not want your app to receive data from other your peers, you can change the channels you are getting data from. For example, if your name is Alice, you could append -alice to all the channels in your app to ensure that the channels you are using will not collide with the channels that other students are using.

Autopolling

Currently, when you send messages you will see them instantly, but if you want to see new messages from other users, you have to refresh the page. You can enable an autopoll setting on any discover operation you want to update automatically. All you need to do is add an autopoll attribute the <graffiti-discover> component:

<graffiti-discover autopoll :channels="[]" ... >
</graffiti-discover>
Due to some current technical limitations, do not overuse this feature as it can cause performance issues. Only use it to get new messages but do not use it to, say, update a person's profile, etc.

Confirm that autopoll is working by sending a message in one browser window and checking that it appears in another window. When you are done, make sure to push your changes to your Github pages site.

User Testing

Once you have all added yourselves to the directory, we are going to shuffle the directory and pair you up to do user testing and design critique of each other's apps. Start with user testing, similar to how we did with paper prototyping only now you no longer need to act as the computer. Instead, you can act as the user on the other end of the app! Make sure you can talk to one another through the app while you are doing this.

In addition to being a user, you must also be the facilitator and observer of your user study. As always be concious of which "hat" you are wearing.

When you are both done with user testing, you can start the design critique of each other's apps.