Commit Graph
165 Commits
Author SHA1 Message Date
ZacharyZhang-NYandClaude Opus 5.5 b68f2bf1d5 Calendar · views on the clock keep moving
The week and day views read the clock once and handed that moment down
as given, which turned off the line's ticker: the line at now and the
lit day stood still. The owner's moment now goes down unchanged, and a
time grid, month view or year view on the clock keeps its own ticker,
so the line moves and today turns over at midnight, even on days that
are not today. A given moment holds them still.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 03:23:18 -04:00
ZacharyZhang-NYandClaude Opus 5.5 a41cb2f9c2 Calendar · Time grid: week and day views, drag to make and to resize
TimeGrid sets days side by side under a column of hours. Each event is
a card by its hours, clipped to each day it touches, and events that
overlap share the width in lanes. A drag on empty time makes an event
by quarter hours through forms::pen; a drag on an event's lower edge,
on the day it ends, moves its end, each drag checked against its
owner. The grid opens at half past seven, or an hour and a half
before now when today is shown and that is later.

CurrentTimeIndicator marks the minute now on today and moves with the
clock. TimezoneOverlay adds another zone's hours beside the grid's.
AllDayRow lays whole days across their columns in lanes.
CalendarWeekView and CalendarDayView are one view of seven days or
one: a header that steps and comes back to today, the days' names
stacked so they fit narrow columns, the whole days, then the hours.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 03:13:38 -04:00
ZacharyZhang-NYandClaude Opus 5.5 f316ab56ba Calendar · Months: a month view, a year view, event chips and cards
CalendarMonthView lays a month in week rows. An event across days lies
over them as a bar in the first free lane, cut at the week's edge;
the rest sit by the hour as chips, and a crowded day keeps the rest
behind "N more". Arrows move a day, Page keys turn the month, and
Enter or a double press opens the day; the cursor holds through the
owner's echo of a turn. Days sit at sevenths of their row, as the bars
do, so text never widens a column.

YearView shows twelve small months; a day with something on it wears a
dot in its first event's hue. EventChip is an event in a line and
EventCard a block with its hours and place. MiniCalendar points to
forms::Calendar. Palette::hue is now the one home for a chart color by
index, for mail labels and events alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 02:49:37 -04:00
ZacharyZhang-NYandClaude Opus 5.5 c1a5603184 Primitives · a raise keeps its state under its owner's id
A raise inside another was namespaced by its place in the layer's
queue, so one that came before it moved its id path and rebuilt its
keyed state and focus: an open date popup would lose its month when a
tip appeared. raise now takes its owner's id and draws under it, and
float and float_height pass the owner's id on from every call site.
A test holds a focused box in a raise while another comes before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 02:23:05 -04:00
ZacharyZhang-NYandClaude Opus 5.5 9abab5f2ba Primitives · raise: what opens inside a dialog lies over it
gpui 0.2.2 asserts on a deferred draw inside another, and every dialog,
sheet and popover draws inside one, so opening a date field in the
snooze or schedule dialog panicked, as would any list, menu or picker
opened in an overlay. primitives::raise replaces each deferred draw:
at the top it defers as before; inside something raised it leaves a
placeholder in the tree, and its layer lays it out on its own, then
draws it last. check.sh refuses gpui's deferred anywhere else.

The time dialog's rule is now times::ahead, tested for a moment
behind, now itself, a moment ahead and another zone; a gpui test picks
yesterday in the snooze dialog, sees that it has passed and that
nothing is sent, then picks two days ahead and hears that moment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 01:51:51 -04:00
ZacharyZhang-NYandClaude Opus 5.5 5b0a8443a7 Mail · Sorting: a label picker and a snooze menu
LabelPicker puts labels on a message: a field finds them by name,
arrows move and a press or Enter turns one on or off, each row with its
check and its hue. A name no label has can be made into one, and the
field starts over. Its rows are the option rows every list shares;
forms::marked_row leads one with a mark. The cursor shows only while
the field has focus.

SnoozePicker offers later today, tomorrow, this weekend and next week,
each with its day and hour, or a time picked in a dialog. It shares
mail::times with ScheduleSend: the names, the dialog, which now waits
for a time ahead of now, and a rule that a moment comes once, so on a
Sunday tomorrow morning no longer repeats as Monday morning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 01:16:24 -04:00
ZacharyZhang-NYandClaude Opus 5.5 154f7f2b46 Data display · a tag stays inside its container
A Tag is capped at its container's width, and its label ends in an
ellipsis beside a fixed remove mark, so a long name in a narrow tag
field stays inside the field instead of running past it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 00:38:30 -04:00
ZacharyZhang-NYandClaude Opus 5.5 84c3dc16de Mail · Writing: the composer, recipients that suggest, a signature, send later
MailComposer writes a message: To, and Cc and Bcc once asked for, as
tag fields that suggest contacts and mark what is not an address; the
subject and the words; the files, each with a way off; the signature
under the words. Send wakes once there is someone to send to and every
address is one; it hands over the draft now or at a time, and Discard
lets it go. A new start from the owner begins the draft over.

forms::TagInput now suggests: the rows that hold the typed words float
under it through the list Combobox uses; Up, Down and Enter pick, and
Escape sets them aside. RecipientInput points to it. ScheduleSend
offers tomorrow morning, tomorrow afternoon, Monday morning, or a day
and hour picked in a dialog. SignatureEditor writes the lines and shows
how they sit under a message; it tells the owner's echo from a new
signature, so the caret stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 00:27:23 -04:00
ZacharyZhang-NYandClaude Opus 5.5 48118499ae Mail · a folded message keeps focus as it opens, and gives way at 280px
Each message in a thread holds one focus handle, a Tab stop while
folded and tracked on the letter once open, so a keyboard open keeps
focus on the message and Tab goes on to its Reply. A press on a fold
leaves focus alone. A fold's name now gives way with its words, so a
long name beside a long date stays inside the row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 00:07:27 -04:00
ZacharyZhang-NYandClaude Opus 5.5 f946af6216 Mail · Reading: a message reader, a conversation, and quoted text
MailReader opens a message under its subject: the sender's picture,
name and address, who it went to, when it came, and Reply, Reply all
when it went to more than one, and Forward, each only with a handler;
then its words and its files, each downloadable. MailThreadView lays a
conversation oldest first: the newest stands open, the others fold to
a line of the sender, their first words and when, which a press, Enter
or Space opens. QuotedText folds words quoted from before behind a
small mark; open, they sit behind a rule. Long names give way at the
label width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:57:06 -04:00
ZacharyZhang-NYandClaude Opus 5.5 0a281d91ab Mail · a focused star keeps Space and Enter; so does Unpin
A button in a SelectableList row now stops Space and Enter at its box
on key down, so the list no longer toggles its selection before the
button acts. The mail star and the pinned messages' Unpin, which had
the same fault, both do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:45:22 -04:00
ZacharyZhang-NYandClaude Opus 5.5 b6b1224c27 Mail · Boxes and lists: mailboxes, folders and labels, the mail list, inbox zero
MailboxList sets mailboxes, folders and labels in sections: a press, an
arrow or Enter opens one, the open one lit; a box with mail unread
stands out with its count, and a label wears one of the theme's chart
hues. MailList holds messages in a multiple-select list: the sender
strong beside a dot while unread, the subject and first words under
it, the time today, the weekday this week, the date this year or with
its year, a paperclip for files, and a star whose press stays off the
row. InboxZeroState points to feedback::EmptyState.

Sections of selectable lists now have one home, lists::Sections, which
ChannelList and MemberList use too; ListItem gains a third line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:35:04 -04:00
ZacharyZhang-NYandClaude Opus 5.5 6f599803ce Messaging · GIF picker: a GIF focused past the fold scrolls into view
Each GIF holds its own focus handle, and a canvas around it, ring and
all, sets the results box's offset once per focus from its painted
bounds. layout::bring_into_view now works along either axis; the data
table's header and the video timeline pass their sideways one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:11:46 -04:00
ZacharyZhang-NYandClaude Opus 5.5 5ade2bed74 Messaging · Stickers and GIFs: a sticker picker and a GIF picker
StickerPicker shows stickers a pack at a time, chosen above with a
segmented control; a search spans every pack and keeps the stickers
whose names hold it. Arrows move, Enter or a press picks. It reuses the
glyph grid, now forms::picks, which takes its columns and cell size and
titles from the host, so emoji, icons and stickers share one searchable
grid; forms::glyphs keeps the emoji and icon pickers.

GifPicker packs host GIFs in two columns, each moving, under a search
it owns; the host hears the trimmed words only when they change, and
categories fill the search while it is empty. Waiting, it shows tiles
in GIF shapes; finding nothing, it says so. Each GIF is a Tab stop that
a press, Enter or Space picks.

The share toggle now shows its state, as the microphone and camera do.
The gallery ships line-drawn stickers and small GIFs made from its own
pictures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:00:15 -04:00
ZacharyZhang-NYandClaude Opus 5.5 48d02c4903 Messaging · Calls: controls, tiles, a grid, a shared screen, a bar, a ringing dialog, a huddle
CallControls holds the microphone, camera and a shared screen as
toggles, then Leave. ParticipantTile shows a camera's frame from the
host or the person's initials, their name with a mark when muted, and a
ring while they speak. VideoCallGrid lays tiles in even rows as far as
they fit across its measured width; a short last row centers at the
full rows' width. ScreenShareView names who presents and offers Stop
presenting for your own share, the call's tiles beside or below.
VoiceCallBar tells where a call is, how long it has run and who is in
it, with the microphone and Leave. IncomingCallDialog rings with the
caller's picture; Accept or Decline answers each ring once, and Escape
declines. HuddleIndicator rings while a huddle is live; a press joins.

The recorder's device toggle and the camera's name chip now have one
home in media. People: member names sort whatever their case, a
status's words save trimmed, and a profile card's local time ticks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 22:33:54 -04:00
ZacharyZhang-NYandClaude Opus 5.5 37e56c7ab7 Messaging · People: members, a profile card, online status and a status setter
MemberList sets members online and offline by name, each group a list
under its count. A press or an arrow chooses one; Enter or a double
press acts on them; offline members go quiet. UserProfileCard shows a
person's picture with presence, name and standing, title, status, the
time in their zone, and Message and Call, each only with a handler.
OnlineStatus draws a presence's dot and word; Presence now names itself
and gives its color, in data_display, its one home.

StatusSetter holds a draft seeded from the owner's status: an emoji
from a picker field, words in its own text field, and when they clear.
Suggestions fill all three; Save hands the status over and Clear status
removes it. The emoji field reuses the date pickers' field, whose
trigger ignores the Enter release after a pick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 22:08:25 -04:00
ZacharyZhang-NYandClaude Opus 5.5 5bbfdcd766 Messaging · Messages: messages in runs, threads, the unread line and receipts
ChatMessage sets a message under its author's picture, name and clock
time. The next by the same author within five minutes, on the same day,
joins the run: only its words, the time in the gutter on hover.
UnreadDivider marks where unread messages start. MessageThread tells who
replied, how many and when the last came; with a handler it opens on a
press, Enter or Space. ThreadPanel holds the first message, a rule
counting the replies, the replies and a composer, its body scrolling.
ReadReceipt says sending, sent, delivered or read, and who saw it in a
group. MessageReactions and TypingIndicator point to collab and motion.

gpui recolors nothing on hover: text takes its color at layout. The
gutter time rests invisible and turns visible through a group hover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 21:48:17 -04:00
ZacharyZhang-NYandClaude Opus 5.5 3c8a5a026c Messaging · Channels: the chat list, its rows, a channel's head and its pins
ChannelList sets chats down in sections, each a list: a press, an arrow
or Enter opens one, and the open chat is lit. A title names one section,
and a section holds a chat. ChannelItem shows a hash or a lock, its
unread count, a pin when pinned, and goes quiet when muted.
DirectMessageItem shows a person's initials with their presence. Unread
names stand out through ListItem's new strong; muted channels and
offline people go quiet through its quiet. ChannelHeader holds the name
and topic beside members, pins and a call, wrapping by the header rule.
PinnedMessages lists pins newest first; a press, an arrow or Enter opens
one, and Unpin lets one go. With none it shows a line and takes no Tab
stop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 21:30:17 -04:00
ZacharyZhang-NYandClaude Opus 5.5 eeeca67e55 Files: a press on a download's button stays with the button
gpui runs the click of every pressed element under the pointer, so a
press on a finished download's Show button also opened the file through
the pressable row. The actions' box stops the press on mouse down, so
the row starts no click of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 21:12:38 -04:00
ZacharyZhang-NYandClaude Opus 5.5 0fcde7dbbe Files · Transfers: file operations, a transfer queue, downloads and storage
A file on its way is a Transfer with a state: waiting, moving at a rate,
paused, done or failed with a reason. One row draws it for the queue and
the downloads: its icon, its way, a bar while it moves or waits paused, a
status with the time left, and only the actions its state allows.
TransferQueue counts what moves and waits. DownloadManager keeps the
finished below under Clear, opening on a press and showing their folder.
FileOperationProgress tells a copy or move with its bar, time left and
current file, its header wrapping by the header rule; a failure speaks in
the danger tone. StorageUsage points to data_display's UsageBar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 21:05:59 -04:00
ZacharyZhang-NYandClaude Opus 5.5 f324702c89 Files: recent and found files keep the cursor on the file, not its place
RecentFiles and FileSearch keyed their rows by place in the list, so when
an open moved a file to the top, the cursor stayed at the place and the
next Enter opened another file. Rows are keyed by the file's folder and
name, asserted once a list, so the cursor follows the file. A dotfile's
kind reads by its extension, as its icon does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:55:21 -04:00
ZacharyZhang-NYandClaude Opus 5.5 c5c35f90fc Files · Find and look: preview, recent files, search, duplicates and archives
FilePreview shows a file large: its picture in the host's shape, the first
lines of its text, or its kind's icon, over its name, kind, size and
change; the gallery opens it on Space as a quick look. RecentFiles lists
files newest first under a header a day, a list a day. FileSearch sits
over a field the host owns and lists what the host found with its folder.
DuplicateFinder marks copies to remove and keeps the last of each group,
its mark shut, with the bytes the marks free beside Remove. ArchiveViewer
draws an archive's entries as a tree with sizes and savings, from paths
gathered by the folder builder the file tree now shares. A checkbox's
label wraps inside its box instead of running past it. Favorites and the
hex viewer point to documents and debug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:42:06 -04:00
ZacharyZhang-NYandClaude Opus 5.5 78fc3f90c0 Files: a narrow listing keeps its names; a column starts fresh for a new folder
The directory listing's size and date columns are fixed, so at 280px the
name had no room and rows showed no names. The heading and rows now sit
in a sideways scroll box whose child keeps the least width: the name's
least, the fixed columns and each row's icon, gaps and padding. A column
of the explorer was keyed by its depth, so a new folder there inherited
the old list's cursor; columns and rows are keyed by their folder. The
explorer asserts each folder on its path is a folder in its parent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:22:12 -04:00
ZacharyZhang-NYandClaude Opus 5.5 f694f0d413 Files · Explorer: a folder as a list, tiles or columns, with one path and one order
FileExplorer shows the folder at the end of a path three ways: the
directory listing, a grid of tiles, or a column per folder along the
path with the next folder lit. Its name, its count and a switch of views
sit above one path bar that climbs. A folder opens in place; a file goes
to the host, which lists each folder it goes to. A pick in an earlier
column closes the columns past it, and a new deepest column scrolls into
view. The directory listing takes its pick from its owner and reports
it, so the pick carries across views; its path bar and its first order
are shared. The gallery walks a small file system and shows the tree,
the context menu, renaming in place and a drop zone in use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:07:33 -04:00
ZacharyZhang-NYandClaude Opus 5.5 906e6c8ac1 Files: a tile's name keeps its ends; the ellipses share one line cutter
gpui's line_clamp wraps once and lays the rest of a long name on the
second line, which a centered tile then clipped at both ends. A tile's
name is now one line, cut in the middle so the front and the extension
stay. MiddleEllipsis draws like Ellipsis: in the text style around it,
sized by its text, so a short name centers; the two share one cutter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:51:43 -04:00
ZacharyZhang-NYandClaude Opus 5.5 ebad5328ed Files · Items: one icon map, file icon, file row and file grid
The crate had two maps from a file's name to its icon, in chat and in the
file tree, and they disagreed. One map now lives in primitives, over the
Lucide file-* icons, and chat, agent, the file tree and the directory
listing use it. FileIcon draws it for a file or a folder. FileItem is a
file's row, a ListItem with its size and when it changed. FileList is the
directory listing. FileGrid lays tiles in the order given, with a cursor
seeded from the owner's pick: arrows by tile and by row, Home, End, Enter
and a double press to open. The count of what fits a width has one home,
layout's columns_for, and fit builds on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:40:10 -04:00
ZacharyZhang-NYandClaude Opus 5.5 9872adc5e9 Forms: an option list stays inside the window; media ratios are checked in one place
The floating list under a Select, Combobox or MultiSelect was at least its
trigger's width with no ceiling, so a long choice ran it past the window
and its rows never ellipsized. It now stops at the window's width less the
window margin on each side, so gpui snaps it inside. The camera preview
and the model viewer check their ratio through primitives::checked_ratio.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:17:52 -04:00
ZacharyZhang-NYandClaude Opus 5.5 7f1cfe8c3d Media · Capture and devices: recorder, camera, mic meter, device choice and 3D model viewer
ScreenRecorderControls holds a recording in one pill: Record, then a live
dot and the time it has run beside pause or resume and stop, with mic and
camera toggles. CameraPreview shows host frames in the camera's shape, or
the camera off. MicLevelMeter lights segments up to the level, amber and
red near the top, with tones shared from data_display. DeviceSelector
picks a microphone, camera or speaker through Select, which may now be
empty while shut. ModelViewer shows the host's frame for an orbit that a
drag, the arrows, Command-scroll, + and - and a reset move; the orbit is
seeded from the host so fast drags add up. The gallery draws a stone
torus per orbit and frees each replaced frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:05:23 -04:00
ZacharyZhang-NYandClaude Opus 5.5 235f059c8e Lists: a selectable list's cursor starts on the owner's pick; the waveform's fit is tested
SelectableList keeps the owner's last selection and the one it last
sent. A selection the owner makes, on first paint or later, moves the
cursor to its first row; the echo of the list's own pick leaves the
cursor where the pick put it. The playlist's keys start from the song
under way. The waveform's bar count and inset move into `fit`, tested
beside `resample`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 18:44:38 -04:00
ZacharyZhang-NYandClaude Opus 5.5 4b86283d69 Media · Audio and controls: player, waveform, spectrum, volume, speed, transport and playlist
AudioPlayer sets a song's cover, title and artist over a scrubber with
the time played and left, the transport and the volume. AudioWaveform
draws peaks gathered to the bars that fit, dark as far as it has played,
and seeks by press, drag and keys, with the time tip the scrubber shares.
AudioSpectrum shows levels by pitch. VolumeControl mutes from its speaker,
and moving its slider while muted unmutes. PlaybackSpeedControl picks from
a menu. MediaControls holds shuffle, back, play, forward and repeat.
Playlist builds on SelectableList: the song under way is lit with moving
bars, and Enter or a double press plays another.

The video player's bar now rests while the stage itself holds focus, a
key it takes wakes the bar, and a press on a resting bar only wakes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 18:32:45 -04:00
ZacharyZhang-NYandClaude Opus 5.5 fcb1b2d9df Media: the player's bar fades by elapsed time, so its scrubber and buttons keep their state
The fade restarted an animation id at each rest and wake, and gpui hands
that id to every descendant: the scrubber's drag, hover and focus handle
and the buttons' focus were rebuilt under it. The bar's opacity now reads
the time since the last change through motion::since_change. The stage
tracks focus even without key handlers, so a focused bar button keeps
the bar up. The player's tests move to their own file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 18:14:06 -04:00
ZacharyZhang-NYandClaude Opus 5.5 fbf99ed4f7 Media: the caption outlasts the bar; one Space per press; narrow boxes hold
Only the bar fades now, so the caption stays while the controls rest, and
the caption chip can shrink, so a long line wraps inside a narrow player.
A focused media button keeps Space to itself, since gpui presses it on
the release. The player and the strip let Command and Control letters
pass. The scrubber's tip splits the free width by the pointer's share and
stays over the track at both ends. An inline edit's label gives way with
an ellipsis beside fixed parts.

The player is a Tab stop only when a key does something, logs its
captions, keys its fade by its own id, and logs a failed wake.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:52:27 -04:00
ZacharyZhang-NYandClaude Opus 5.5 d0175edb7b T26c Media: video
Scrubber shows what has loaded, what has played and its chapters, names
the time under the pointer, seeks by press and gpui's drag, and steps by
the slider's keys; over_media lights it for a dark layer. VideoPlayer
shows the host's frame in its shape with a caption and a control bar over
it: the scrubber, play, the time, speed, captions, picture in picture and
full screen, each only with its handler; the bar rests after a still
pointer while it plays, on one wake from the executor's timer. Keys:
Space and K, J and L, the arrows, C and F. VideoThumbnailStrip lays frames
along the length under a playhead with a trim whose handles drag and whose
ends I and O set. SubtitleEditor edits cues in place: times as mm:ss.mmm,
kept in order, a time that does not read kept out with the reason shown.

InlineEdit is a Tab stop with the ring; it hands focus back after Enter or
Escape and keeps its text on Enter's release. overlays::media_button is
shared by the lightbox and the player's bar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:07:26 -04:00
ZacharyZhang-NYandClaude Opus 5.5 f7f20b5146 Reviews: T26b passes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:46:40 -04:00
ZacharyZhang-NYandClaude Opus 5.5 cb28c0e305 Media: a shaped corner follows the pointer up and down; the fitted crop is told once
With an aspect, a corner drag sizes the crop by whichever side the pointer
moved further, so a drag straight up or down resizes it too. The upload
tells the host the fitted crop once per file, whether the host keeps it or
not; a host that dropped it had set off a loop of reports. The annotator's
Escape stops only when it lets a chosen mark go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:38:22 -04:00
ZacharyZhang-NYandClaude Opus 5.5 7d86c804d7 T26b Media: crop and annotate
ImageCropper crops a picture by a box in shares of it: a press holds a
corner, a side or the body (crop::grip_at), a drag through gpui's drag
moves them (crop::dragged), kept inside the picture with a least side;
with an aspect only the corners size it and the box keeps its shape; the
arrows move it. The picture sits inset by half a handle, the focus border
outside it, so handles on its edge stay whole and it keeps its shape.
ImageUpload (T06e) takes pictures only, from a drop or the dialog
(forms::taken, DropZone::kinds), decodes the file for its shape, and with
no crop yet reports the largest centered box of its aspect once. The
annotator draws boxes, arrows, lines and numbered pins in chart colors
through forms::pen; Select chooses a mark, Delete removes it, and Cmd-Z
and Shift-Cmd-Z undo and redo through forms::History. theme.media() holds
their sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:16:29 -04:00
ZacharyZhang-NYandClaude Opus 5.5 0cf1d3679c Reviews: T26a passes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:58:02 -04:00
ZacharyZhang-NYandClaude Opus 5.5 12f0baab15 Media: the viewer's picture moves; a viewer with no picture takes no Tab
The stage's picture carries an id, so gpui keeps its frame and asks for
the next: an animated picture plays, turned or not. A viewer whose picture
has not loaded or cannot open is no Tab stop. AGENTS.md: img() moves an
animated picture's frames only with an id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:51:03 -04:00
ZacharyZhang-NYandClaude Opus 5.5 f8a51a5352 T26a Media: images
A new chapter, src/media. ImageViewer fits a picture to its stage and
zooms by the document steps, by keys, buttons and Cmd-scroll about the
pointer; a drag through gpui's drag, a scroll or the arrows pan it once it
overhangs; R turns it a quarter at a time. gpui paints pictures without a
transform, so media::turn turns the decoded frames off the main thread,
an asset keyed by the picture and the turn; `image` 0.25, which gpui
already decodes with, is now a dependency. ImageThumbnail shows a picture
in its own shape with a corner label and a ring when chosen, and is a Tab
stop only with a handler. Lightbox / Gallery Viewer points to
overlays::Lightbox, which the gallery opens from the thumbnails.

T26 splits into T26a–e. AGENTS.md: the drag rule says drags that pan,
turn or slide go through gpui's drag; pictures turn by their pixels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:34:45 -04:00
ZacharyZhang-NYandClaude Opus 5.5 4678773383 Reviews: T25f passes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:22:31 -04:00
ZacharyZhang-NYandClaude Opus 5.5 54e0384582 Generative: the embedding turns by drag past its edge; version diffs are tested
The turned embedding turns through gpui's drag, marked with its view, so a
drag keeps turning past the plot's edge. What a chosen version is set
against, and its heading, move into versions::compared, with a test. A
hidden legend entry dims its key and not its ring, and an embedding refuses
a group named twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:17:45 -04:00
ZacharyZhang-NYandClaude Opus 5.5 98b1a6416c T25f Generative: data and prompts
DatasetViewer is tables::DataTable with row detail; the gallery pages
through a dataset and opens a sample whole. EmbeddingVisualizer scatters
points by group, flat or turned in three dimensions: lens.rs holds the
projection, where a turned view keeps the unit ball's scale and fits any
point past it at every turn. A drag or the arrow keys spin it, the
pointer names a point, and the legend hides a group. PromptPlayground
gives each {name} of a template a field, marks the blanks, and runs once
every value is in. PromptDiff shows word changes inline, a space parting
a word taken out from the word put in; PromptVersionHistory lists
versions to choose from and restore.

ChartLegend entries that toggle are Tab stops with the focus ring. Each
capture pass starts its page fresh, so dark runs the script from the same
start as light.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 14:57:55 -04:00
ZacharyZhang-NYandClaude Opus 5.5 d196aa1e26 Reviews: T25e passes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 14:02:23 -04:00
ZacharyZhang-NYandClaude Opus 5.5 85f13b5455 Description rows wrap; the fine-tune share is tested
A DescriptionList row drops its value under its label once the value has
less than half a label's width beside it, so a 280px model card no longer
breaks its facts mid-word. FineTuneJobCard's bar share and its epoch line
move into tuning::progress, with a test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 13:57:14 -04:00
ZacharyZhang-NY 164d033ad3 T25e Generative: models
ModelCard sets a model's maker, what it does, its facts and tags, and
Use unless it is in use. ModelDownloadManager lists downloads with how
much of how much, speed and time left, and Pause, Resume, Cancel,
Retry and Delete by state. ModelStatus marks a model idle, loading,
loaded with its GPU memory, or failed. HardwareMonitor sets a meter per
part beside its history. FineTuneJobCard shows a job's phase, its
epochs and its loss on training and held-out data.

AGENTS.md: after each item, cargo clean -p ely-gpui-component too;
old builds of the crate had filled the disk. The reveal rule names
layout::bring_into_view.
2026-09-26 13:45:17 -04:00
ZacharyZhang-NY 092d125eda Reviews: T25d passes
Round 2 of the Claude reviewer found no defects.
2026-09-26 13:37:25 -04:00
ZacharyZhang-NY cb1b1ca90a Generative: the video strip scrolls and reveals; tags wrap in their row
The timeline's scroll box is the flex row itself, so its reach is its
shots; a focused shot brings itself whole into view through
layout::bring_into_view, which table headers now share; Extend sits
with the caption under the strip. A voice's tags cap at the row's
width and wrap inside it.
2026-09-26 13:32:44 -04:00
ZacharyZhang-NY 2266b4e367 T25d Generative: sound and motion
AudioGenerationPlayer shows a generated sound's prompt, model and
length, a bar while it is made, then chat::AudioMessage to play it;
Regenerate and Download wait for it. TTSVoicePicker lists voices with a
sample to play, the chosen one washed with a check, tags dropping below
when narrow. VideoGenerationTimeline lays shots along their time under
a ruler, with posters, placeholders, a playhead and Extend.

AudioMessage's waveform is one Tab stop where Left and Right seek, and
it gives way at 280px. debug::ruler serves the timeline's ruler. A mask
shown to read no longer follows the pointer.
2026-09-26 13:16:42 -04:00
ZacharyZhang-NY 6bfd53baee Reviews: T25c passes
Round 2 of the Claude reviewer found no defects.
2026-09-26 13:09:53 -04:00
ZacharyZhang-NY d5129675c9 Generative: a mask shown to read takes no pen; strokes fail loud
InpaintCanvas is a Tab stop with the focus ring only when on_brush
serves its keys, and takes the pen, the crosshair and the ring only
with on_stroke. new() asserts each stroke's radius within REACH and
its points on the picture. The settled strokes' cells stay cached, so
a drag paints only the stroke under the pen over a copy. The canvas
keeps square corners, so the wash fits the picture. The gallery drags
with moves.
2026-09-26 13:05:34 -04:00