Make the media pool a list you can actually read

Every row is one line now — a thumbnail at the stage's own 16:10, the name,
and the one number you need before dragging it somewhere — at the timeline's
own row height. Two always-open folders cost eight headings before the first
row in a pane 210px wide; they are two tabs, and a search counts its hits in
the scope you are not looking at so nothing can hide behind the one you did
not pick.

Symbols draw their own first frame, through the resolver and rasteriser the
stage uses. A PLACED symbol is drawn where it is placed, with the rest of its
host isolated away: rooting at a symbol renders its DRAWING, and a rotoscoped
face is head-local in units of one image height, so the source-to-stage scale
that makes it pixels lives on the :face group of whatever places it. Rendered
rooted at itself a face is correct and under a pixel across. Thumbnails are
smoothly downscaled for the same kind of reason the preview is not: at a tenth
of the stage's size nearest neighbour samples one pixel in a hundred, and the
silhouette is the whole of what makes a thumbnail recognisable.

Names are editable, and that is two operations behind one pencil. A symbol's
name is a field of this document, so it is an undoable edit and blank gives it
back its id. Footage and sounds live beside projects rather than inside one,
so theirs is a server write shared by every project using the row — PATCH on
the existing Footage.label, and a new Sound.label kept separate from the
filename, which is a fact about the upload and not somebody's name for it.

No TIMELINES section beside a SYMBOLS one: every symbol here IS a timeline, so
that pair named one thing twice. What is true is that exactly one of them is
where the work happens, and clip/opens-on already answers which — it leads the
pane as PROJECT, drawn at a size you can read a pose off, with the library
under it. Still not :main being special; rename it or place it inside
something else and the pool follows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-10-01 00:56:39 -04:00
parent 815ce449ea
commit 7e34d0c704
11 changed files with 924 additions and 160 deletions

View file

@ -416,67 +416,249 @@ button.share-button:hover, button.share-button.on { filter: brightness(1.1); }
.peer.guest { background: var(--dim); }
/* --------------------------------------------------------------------------
media pool */
media pool
/* Two folders, THIS PROJECT and ALL ASSETS, each holding groups. */
.pool-folder { margin-bottom: 8px; }
.pool-folder > summary {
cursor: pointer;
padding: 2px 0 4px;
font-weight: 600;
color: var(--fg);
A FILE LIST, AND IT IS 210px WIDE. Every row is one line — a picture at the
stage's own proportions, a name, one number — because the pane under this one
is the timeline and a row that costs two lines costs timeline rows. The row is
--row tall, which is a timeline row, so a pool of symbols and the rows they
end up on are the same size object.
One exception, deliberately: the main timeline. See `.pool-row.main`. */
/* The search strip, between the pane head and the tabs. Its own band rather
than crowded into the head, which is one line and already holds the + . */
.pool-find {
position: sticky;
top: 21px;
z-index: 2;
display: flex;
align-items: center;
gap: 4px;
padding: 3px 5px;
background: var(--chrome);
border-bottom: 1px solid var(--hair);
}
.pool-folder > .pool-group { padding-left: 8px; }
.pool-project { margin-bottom: 2px; }
.pool-project > summary { cursor: pointer; color: var(--dim); padding: 1px 0; }
.pool-project > .pool-item { margin-left: 10px; width: calc(100% - 10px); }
.pool-group { margin-bottom: 9px; }
.pool-search {
flex: 1;
min-width: 0;
height: 17px;
padding: 0 5px;
font: inherit;
color: var(--fg);
background: var(--pane);
border: 1px solid var(--line);
border-radius: 2px;
}
/* The one-line gloss under a group heading. Small and quiet: it answers "what
is this list" once, for someone who has not read the model. */
.pool-group > h2 + .dim { margin-bottom: 4px; }
/* Safari draws its own clear button inside a search input, in its own idiom and
at its own size. The one next to it is this file's. */
.pool-search::-webkit-search-decoration,
.pool-search::-webkit-search-cancel-button { -webkit-appearance: none; }
.pool-group > h2 {
margin: 0 0 3px;
.pool-clear {
flex: 0 0 auto;
width: 17px;
height: 17px;
padding: 0;
border: 0;
border-radius: 2px;
background: none;
color: var(--dim);
cursor: pointer;
}
.pool-clear:hover { background: var(--hair); color: var(--fg); }
/* The scope tabs, in the vocabulary `ui/tabs` already established for symbols —
the same object, so two rows of tabs on one screen read as one idea. */
.pool > .tabs { top: 45px; position: sticky; z-index: 2; }
/* A tally, shown only on the tab you are NOT looking at and only while a search
is running: it says "what you asked for is over here". */
.tab .count {
padding: 0 4px;
border-radius: 7px;
background: var(--sel-bg);
color: var(--sel);
font-variant-numeric: tabular-nums;
}
/* MEDIA, SOUNDS, TIMELINES. A heading is one line and it sticks, so scrolling a
long list never leaves you looking at rows with no idea what kind they are. */
.pool-section { margin-bottom: 7px; }
.pool-section > h2 {
position: sticky;
top: 69px;
z-index: 1;
margin: 0 0 2px;
padding: 1px 5px;
font: inherit;
font-weight: 600;
color: var(--dim);
text-transform: uppercase;
letter-spacing: .07em;
background: var(--pane);
}
.pool-item {
display: block;
width: 100%;
text-align: left;
padding: 2px 6px;
.pool-section > .dim { padding: 0 5px 2px; }
.pool-rows { display: flex; flex-direction: column; }
/* What a search found nothing to say. */
.pool-empty { padding: 6px 5px; color: var(--dim); }
.pool-project { margin: 0 0 1px 5px; }
.pool-project > summary { cursor: pointer; color: var(--dim); padding: 1px 0; }
.pool-project > .pool-rows { margin-left: 8px; }
/* THE ROW IS THE BUTTON. Click selects, double-click opens, and drag starts
anywhere across it — the whole strip, not the few characters of the name. The
wrapper carries the state classes and the frame; the button inside it fills
that frame edge to edge, so there is no dead strip anywhere along the row. */
.pool-row {
display: flex;
align-items: center;
gap: 2px;
min-width: 0;
height: var(--row);
padding: 0 4px;
border: 1px solid transparent;
border-radius: 2px;
}
.pool-row:hover:not(.disabled) { background: #fff; }
.pool-row.on { background: var(--sel-bg); border-color: var(--sel); }
/* WHICH ONE IS OPEN, as a mark and not as the word "open" — a list this narrow
cannot spend twenty pixels of every name on a word that is true of one row.
The accent, because selection is the only thing it is ever used for and the
open symbol is what the rest of the screen is showing. */
.pool-row.open { box-shadow: inset 2px 0 0 var(--sel); }
.pool-item {
display: flex;
align-items: center;
gap: 5px;
flex: 1;
min-width: 0;
padding: 0;
text-align: left;
border: 0;
background: none;
color: inherit;
font: inherit;
cursor: grab;
}
/* Shrinks to the name, so the pencil sits against the end of the word rather
than out at the edge of the pane — and ellipses rather than pushing the
number off the row. */
.pool-item .text { display: flex; flex-direction: column; flex: 0 1 auto; min-width: 0; }
.pool-item .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The number, at the far edge and never moving: `auto` on the left is what
pushes it there, and tabular figures are what stop it shuffling as the rows
scroll past. */
.pool-item > .sub {
flex: 0 0 auto;
margin-left: auto;
padding-left: 4px;
color: var(--dim);
font-variant-numeric: tabular-nums;
}
/* Every row leads with a picture, and they are all this box, so the names line
up down the list whatever is beside them. 16:10 is the stage's own ratio at
320x200 — a thumbnail that is not the picture's shape is a thumbnail you have
to think about. */
.pool-item .thumb {
flex: 0 0 32px;
width: 32px;
height: 20px;
object-fit: cover;
background: var(--stage);
border-radius: 1px;
pointer-events: none;
}
.pool-item .thumb.sound {
display: flex;
align-items: center;
justify-content: center;
color: #d9d9d9;
}
/* THE MAIN TIMELINE, under the PROJECT heading and at the top of the pane.
`clip/opens-on`'s answer: the longest symbol nothing else places, which is
where the work happens. The one row in the pane given size, a second line and
a surface of its own — spent here rather than spread over every row, which is
what keeps the list below it a list. */
.pool-row.main {
height: auto;
margin-bottom: 5px;
padding: 4px;
background: var(--sunk);
border-color: var(--hair);
}
.pool-row.main .thumb {
flex: 0 0 64px;
width: 64px;
height: 40px;
}
.pool-row.main .name { font-weight: 600; }
/* Both facts on one line under the name. Beside a 64px picture there is room,
and this is the one row where a person wants more than the length before
they click. */
.pool-row.main .detail {
color: var(--dim);
font-variant-numeric: tabular-nums;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pool-item:hover:not(:disabled) { background: #fff; }
.pool-item.on { background: var(--sel-bg); border-color: var(--sel); }
.pool-item .sub { display: block; color: var(--dim); }
.pool-item .text { display: block; overflow: hidden; text-overflow: ellipsis; }
/* The pencil. A span and not a button — see `ui/pool`'s `row` — so it needs its
own centring and cursor rather than inheriting a control's.
/* A media row leads with one frame of the video. */
.pool-item.media { display: flex; align-items: center; gap: 6px; }
.pool-item .thumb {
flex: 0 0 40px;
width: 40px;
height: 30px;
max-width: 40px;
max-height: 30px;
object-fit: cover;
background: var(--stage);
Hidden until the row is under the pointer or holds focus, because a column of
twenty pencils is a column of twenty pencils; `visibility` rather than
`display`, so it keeps its width and the name beside it does not reflow as the
pointer crosses the list. */
.pool-rename {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 15px;
width: 15px;
height: 15px;
border-radius: 2px;
color: var(--dim);
line-height: 1;
cursor: pointer;
visibility: hidden;
}
.pool-row:hover .pool-rename,
.pool-row:focus-within .pool-rename { visibility: visible; }
.pool-rename:hover { background: var(--hair); color: var(--fg); }
/* Renaming. The input REPLACES the row at the same height, so a list does not
jump while you type in it. */
.pool-name {
flex: 1;
min-width: 0;
height: 17px;
padding: 0 4px;
font: inherit;
color: var(--fg);
background: #fff;
border: 1px solid var(--sel);
border-radius: 2px;
pointer-events: none;
}
/* The whole pane is the drop target, so the cue has to be the pane and not a