Field Notes

Jun 5, 2026 · Updated 9 days ago

We used to blog about how to code. Now it's time to blog the decision. I've been thinking about writing field notes for a long time. The term used to be observing other people, but this is about observing my own thoughts.

I'll share some revamping and improvement across projects I worked on here.

Chat Context Menu

This is a crucial part of LobeHub. It carries all context except the message. But with many things off.

Old context menu
Old context menu
  • Ambiguous function: what does Show Formatting Toolbar do? Will this open a new dialog? (It's actually a checkbox)
  • Icon color swap based on state: Information overload.
  • Mixed trailing arrow icons → / ▶︎
  • Progressive exposure: why is Add Skills parallel with Skills, while View More Files is not parallel with Upload File or Image.
  • Wording: "Upload File or Image" should be "Attachment".
  • File name truncation: only truncating the trailing part. Should truncate the middle part.

After all these problem fixed:

Revamped context menu
Revamped context menu

The rules are:

  • Consistant & clean wording
  • Information structure & progressive explosure
  • Consistency over tuning

Janky Transition

This is the major transition in Detail. People click on a detail card to see more about the detail.

0:00 / 0:00
Before

Originally I put layout on the card and it animates its own size and position. The contents drift along a slightly different path, arriving a beat early or late. Nothing is technically broken, yet the eye reads it as "off" instantly.

// DetailItem.tsx — the dialog frame
const layoutTransition = {
  layout: { type: "spring", stiffness: 320, damping: 32, mass: 0.6 },
};
<motion.article layout transition={layoutTransition} />

// DetailItemHeader.tsx — title on a near-but-different spring
const titleTransition = {
  layout: { type: "spring", stiffness: 320, damping: 30, mass: 0.7 }, // ← not the frame's
};
<motion.h3 layout transition={{ ...titleTransition, scale }} />

// ...and everything else just falls back to the default spring
<motion.p layout />              {/* summary */}
<motion.div layout />            {/* tags */}
<motion.div layout />            {/* media (DetailItemMedia.tsx) */}

The cause is that Framer Motion animates every layout element on its own independent spring. Leave the transition off and it falls back to the default; hand-tune each one, and they each run slightly different physics. The frame travels on one curve while its children travel on five others.

The fix is to make everything move on the same spring. So I pulled the spring out into a single constant and handed that exact transition to every animated element in the expand:

// animations.ts — one spring, shared by everything in the expandexport const DETAIL_LAYOUT_SPRING = {  type: "spring", stiffness: 320, damping: 32, mass: 0.6,};export const DETAIL_LAYOUT_TRANSITION = { layout: DETAIL_LAYOUT_SPRING };// DetailItem.tsx — the dialog frameconst layoutTransition = {  layout: { type: "spring", stiffness: 320, damping: 32, mass: 0.6 },};<motion.article layout transition={layoutTransition} /><motion.article layout transition={DETAIL_LAYOUT_TRANSITION} />// DetailItemHeader.tsx — title, summary, tagsconst titleTransition = {  layout: { type: "spring", stiffness: 320, damping: 30, mass: 0.7 },};<motion.h3 layout transition={{ ...titleTransition, scale }} /><motion.p layout /><motion.div layout />          {/* tags */}<motion.h3 layout transition={{ ...DETAIL_LAYOUT_TRANSITION, scale }} /><motion.p layout transition={DETAIL_LAYOUT_TRANSITION} /><motion.div layout transition={DETAIL_LAYOUT_TRANSITION} />  {/* tags */}// DetailItemMedia.tsx — media<motion.div layout /><motion.div layout transition={DETAIL_LAYOUT_TRANSITION} />

The revamped version feels like this:

0:00 / 0:00

The article frame, the media, the title, the summary, the tag row, and each tag chip now share one physics simulation, so they accelerate, travel, and settle together, riding the frame as a single object. The takeaway is small but general: for coordinated layout animations, consistency beats tuning.

Privacy Warning Dialog

The major problem here is wording.

Old version
Old version

The first time I saw the dialog, I almost immediately skipped it — no hook, no real reminder, just a warning that no one likes to read.

Revamped version
Revamped version

Chat Sharing

🚧 This section is WIP

My collegue handle this to me to "polish details". This feature allows people to select multiple messages and forward to another agent. At the first glance, I spotted many problems

  • The bottom toolbar is taking too much vertical space which is more important here becuase we hope people can see more messages in one screen
  • Agent title and avatar combo is repeating in every message, eating more vertical spaces
  • "Select to here" is ambiguous: from where to where?
  • Text hirechy error in the Forward panel
  • Calling people "User" and calling AI "Assistant"
Revamped version
Revamped version

IM Channel Configuration

🚧 This section is WIP

The constraints here:

  • We really need many boring fields per the platform's guideline

Usage Screen

🚧 This section is WIP

0:00 / 0:00
Before

Timeline Extension

Here we are showing a Twitter browsing history list.

0:00 / 0:00
Before

It used to be a one-column layout. I realized that one column is for focusing on each post, but people come here to quickly find a certain post, so I switched to a masonry layout.

The search bar was originally a show-off widget, back in 2022 when I was building it. So I reverted it to a common, familiar pattern.

The original icon is semantic but ugly: restore your Twitter home page. The revamped one kept the Twitter bird home element but added some offset.

Revamped version
Revamped version

More Before / After

Here are more comparisons. Try adjusting the handle to see what's changed.

LobeHub share card — afterLobeHub share card — beforeBeforeAfter
Share Screen of LobeHub
LobeHub login screen — afterLobeHub login screen — beforeBeforeAfter
Login Screen of LobeHub
Inbox
Inbox

If there's more works worth sharing, I'll write a second one.

No content is written by AI in this essay.