Skip to main content
← Blog

The Day the Star Got a Face

VauDium·

We drew eyes and a mouth on fecit's assistant star. We made it chubbier, let its expressions fade instead of snap, and gave it a serious face for interruptions — sulking once on the way. A day spent making the star feel alive.

The Day the Star Got a Face

There’s a star floating in the middle of fecit’s assistant screen. It tilts side to side while thinking, spins once when it finishes talking, and nods or breathes every few seconds when idle. The gestures have been there for a while. The face hasn’t. It was a well-animated shape, not a someone.

Today we drew eyes and a mouth. Then we spent the rest of the day working on that face.

1. Two eyes, one small mouth

There were several candidates, and we picked the one with the least in it. Two dot eyes and a small smile. No eyebrows, no cheeks, no highlights. The star is small (56px) and spins often, and the more you draw on it the messier it gets mid-spin.

One constraint shaped everything. This star rotates during its gestures, and the silhouette has to keep reading as a star while it turns. So the features live only inside the inner diamond of the star. Push them out into the arms and the face swallows the star mid-spin.

There are five expressions, each paired with a gesture the star already had.

  • Idle: the default smile
  • Thinking about an answer: eyes closed
  • A task just completed: smiling eyes
  • Tapped: a surprised mouth
  • Speaking up at a gate: a wink

Closing the eyes while thinking was the one that changed everything. With gestures alone it was “spinning”; with the eyes shut it became “thinking.”

Ink color is chosen automatically from the star’s brightness. White eyes on a blue star, black eyes on a yellow one. The gate modals use different star colors, so this mattered.

2. A little chubbier

With a face on it, the star looked thin. The inner diamond was narrow enough that two eyes barely fit, and it was too sharp to be a mascot.

Changing the shape would be easy, except that this star was the same file used as an icon in 64 places across the app. The point-color star in lists, the template star in the library, all one SVG. Fatten the mascot and 64 icons fatten with it.

So the mascot got its own star. Outer points unchanged, the four inner points pushed further from center. The original value was 2.5. We started at 3.2, went “a little more” to 3.8, tried “a little less” at 3.5, and came back to 3.8. It’s the kind of number you can’t settle without putting the candidates side by side. Chubbier is definitely cuter.

A wider body made the face look small. Eye spacing and mouth width went up 1.3×. All five expressions were scaled from the same center at the same ratio, so they still line up when layered.

3. Expressions should fade, not snap

Up to here, everything was still images. When thinking starts the eyes close, but they close in a single frame. The gestures are smooth and the face wasn’t, which made the face look like a sticker sitting on top rather than part of the body.

On mobile the five expressions are stacked and only their opacity is chosen. That opacity used to be written as 0 or 1; now it interpolates over 160ms. It runs on the animation thread in the same frame as the gestures, so a busy JS thread can’t make it stutter. The eyes close now. They don’t switch off.

Opening the desktop, we found the assistant star had no face at all. When the face was drawn that morning it went into the three gate modals, and the assistant star was skipped. It got the same expression layers, and the rAF loop that drives the gestures now picks the expression too. A CSS transition handles the fade at the same 160ms. Both platforms share one constant.

4. A serious face, and one sulk

There are two gates. One steps in when you start a hard task (“Want to plan first?”); the other when you complete one (“Want to leave a retrospect?”). Both are blue speech bubbles. There’s a third, yellow bubble that invites you to do a review.

That morning all three winked. But the blue two are interruptions asking for confirmation, and the yellow one is an invitation. Winking while interrupting felt flippant. The blue gates needed a slightly more serious face.

The first attempt was a flat line for a mouth. Same eyes, smile removed. The answer came the moment it hit the screen: it sulked. It didn’t read as serious; it read as negative. On a face with no eyebrows, the mouth carries the entire tone, and a flat line sits far too close to “no”.

The default smile has a curve depth of 1.45. We brought it down to 0.55 and narrowed it slightly. Not a smile, not a sulk. A mouth that is listening.

One thing came out along the way. The retrospect gate used to burst completion particles when the star appeared, because it is the moment of completion. But particles going off next to a serious face had the face and the body saying different things. The particles are gone. The celebration still plays at the actual moment of completion, so nothing is lost.

5. The completion sound played twice through the gate

One thing unrelated to faces got caught as well. Tapping outside the retrospect gate to just complete the task made the completion sound cut off midway and start again.

Obviously the completion handler was firing twice. Closing the gate and completing come from the same hand. Except that logging a call stack inside the sound function showed it was called once.

The cause was the player. The rewind (seekTo) is asynchronous, and playback started without waiting for it. Normally the rewind finishes first and nothing shows. But tapping the gate backdrop overlaps with the modal’s closing animation, the rewind lands late, and a sound already playing gets yanked back to the start. Awaiting the rewind before playing fixed it.

From the symptom alone, “called twice” looked certain. One log line cut one assumption.

What today taught

One: the less you draw, the better it moves. Two dot eyes and one mouth are enough for the star to think, startle, and listen. Anything more would smear every time it spins.

Two: a mascot needs its own body. As long as it shares a file with the icons, you can’t touch it. Sixty-four places move with it.

Three: the transition is part of the expression. Swap it in one frame and it’s a sticker; fade it over 160ms and it’s a face.

Four: a flat mouth isn’t serious, it’s sulky. With no eyebrows the mouth carries all the tone. Removing a smile and reducing a smile are different expressions.

Five: “it plays twice” doesn’t have to mean “it was called twice.” Count the calls with a log before fixing anything.

The star is still a star. It just closes its eyes when it thinks, startles when you tap it, and holds back a little of its smile when it interrupts you. In one day a shape became a someone.