Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ If Astro ships TS 7 support, wire `astro check` back in rather than leaving this
- **Preserve the size algebra.** `cell = size / ((n - 1)(1 + gap) + dotSize)` is solved, not clipped, which is what
keeps the field landing exactly on the box at any `dotSize` — including above 1, where the dots touch. If you
change it, the invariant tests in `packages/core/test/dot-matrix.test.ts` are the specification.
- **Verify layout in a browser, not in jsdom.** jsdom computes no layout at all — `getComputedStyle(el).gridTemplateColumns` on a real grid rule returns the empty string — so no unit test here can catch a box that has collapsed. A stage whose controls column was an `auto` track (sized by max-content) grew from 264px to 602px on a single long caption and squeezed the field's track to zero; the stage is `overflow: hidden`, so the field was clipped out of existence while the DOM still held all 25 cells and every source-level check passed. Drive Chrome over CDP (`--remote-debugging-port`, `Runtime.evaluate`, `Page.captureScreenshot`) with a **dedicated `--user-data-dir`** — reusing the default one makes the instance exit immediately — and assert on measured geometry and on screenshots. Regexing the stylesheet for the rule is not a substitute: a test written that way matched a different component's `repeat(auto-fill, …)` and stayed green with the bug present.
- **Direction is per-order AXES, not a global "reverse".** `direction` is a list of axis tokens
(`["counterClockwise", "insideOut"]`), and each order reads only its own — `ORDER_DIRECTION_AXES` is the
contract a UI reads to know what to offer. Offer from that table and never from a hardcoded list: a
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@

### Fixed

- **Fixed: `Column Drop` still showed nothing, and this time the field was being clipped rather than missing.** The previous fix made the motion render, and it _was_ rendering — 25 cells, animating, one column lit at a time. The stage's controls column was an `auto` track, and `auto` is sized by max-content, so the refusal caption ("this motion is a highlight moving down the field…", shown only when the CSS renderer refuses the chosen motion) grew that track from **264px to 602px** and squeezed the field's own track to **zero**. The stage is `overflow: hidden`, so the field was not squashed — it was clipped out of existence. The tracks are capped now, and the caption wraps inside the cap instead of widening it.
- **This one has no automated test, on purpose.** jsdom computes no layout, so no test in this repo can catch a collapsed track, and the first attempt at one was worse than nothing: it regexed the stylesheet, matched a **different** component's `repeat(auto-fill, …)`, and stayed green with the bug present. A test that asserts about the wrong rule is not a slow test, it is a wrong one. `AGENTS.md` now records that this class of check needs a real browser over CDP, with the `--user-data-dir` detail that cost the most time to work out.

- **Fixed: picking `Column Drop` left the field blank.** A motion the CSS renderer cannot express — one that MOVES a highlight down a column, which a per-dot `animation-delay` cannot do — was still being rendered through it, and `buildCss` returns null for exactly those. The playground disabled the CSS switch and said so, then passed `renderer="css"` anyway, so the stage came up **empty**. Disabling a control without honouring it is the worst of both answers: the switch explains itself while the field shows nothing. The field now renders the one way it can, and the readout and the copied snippet say `svg` rather than claiming a mode the engine is not in. The engine normalises the same thing for direct callers, so `handle.options.renderer` reports what is actually painted instead of leaving the element empty.
- **The CSS renderer no longer publishes keyframes it cannot honour.** It emitted `@keyframes botui-dm-columns`, and that rule animated _nothing_: `spike` is a gaussian centred on the cycle seam, so sampling it at the two positions its stop table names — 0 and 1 — yields full brightness at both ends, i.e. a static fully-lit field. Shipping that in every consumer's stylesheet was a lie about what the motion looks like, not merely dead weight. Only presets the renderer actually accepts get a rule, which is the same rule `buildCss` applies.

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@

### 修复

- **修复:`Column Drop` 仍然什么都看不到,而这次场是被裁掉了而不是缺失。** 上一个修复让这个动效真的渲染出来了,而且它**确实**在渲染 —— 25 个格子、在动、每次点亮一列。舞台的控件列是 `auto` 轨道,而 `auto` 按 max-content 定尺寸,于是那条拒绝提示("这个动效是高亮沿着场移动…" —— 只在 CSS 渲染器拒绝当前动效时显示)把该轨道从 **264px 撑到 602px**,把场自己的轨道挤到 **0**。舞台是 `overflow: hidden`,所以场不是被压扁,而是被整个裁掉。轨道现在设了上限,提示在上限内换行,而不是把列撑宽。
- **这一条故意没有自动化测试。** jsdom 完全不算布局,所以本仓库里没有任何测试能抓住塌掉的轨道;而我写的第一版比没有更糟:它用正则去匹配样式表,匹配到了**另一个**组件的 `repeat(auto-fill, …)`,于是在 bug 存在时依然全绿。能断言到错误规则的测试不是慢的测试,是错的测试。`AGENTS.md` 现在记下了这类检查需要用 CDP 驱动真实浏览器,并写下了最耗时间才弄明白的 `--user-data-dir` 细节。

- **修复:选中 `Column Drop` 后场是空白的。** CSS 渲染器无法表达的动效 —— 那种把高亮**移动**到下一列的动效,而每格 `animation-delay` 做不到这件事 —— 仍然被交给它渲染,而 `buildCss` 对这些 preset 恰好返回 null。Playground 把 CSS 开关禁用了并说明了原因,**然后照样传 `renderer="css"`**,于是舞台**什么都没有**。禁用一个控件却不遵守它是最糟的答案:开关解释了自己,而场什么也不显示。现在场会用它唯一能的方式渲染,readout 和复制出的片段都如实写 `svg`,而不是声称一个引擎并未处于的模式。引擎侧对直接调用方做同样的归一化,于是 `handle.options.renderer` 报告真正被绘制的东西,而不是留一个空元素。
- **CSS 渲染器不再发布自己无法兑现的 keyframes。** 它一直在输出 `@keyframes botui-dm-columns`,而那条规则**什么都不动**:`spike` 是一个以周期接缝为中心的 gaussian,所以按它的 stop 表所列的两个位置 —— 0 和 1 —— 采样,两端都是全亮度,也就是一块静止的全亮场。把这个规则塞进每个使用者的样式表里,是对那个动效外观的**谎称**,而不只是无用代码。现在只有渲染器真正接受的 preset 才有规则,与 `buildCss` 用的是同一条判据。

Expand Down
20 changes: 19 additions & 1 deletion apps/site/src/styles/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,15 @@ h3 {
grid-template-columns: 1fr;
gap: 6px;
font-size: 13px;
/* without this the caption's intrinsic width is what the track is sized from */
min-width: 0;
}

.stage-toggle-label em {
/* the refusal caption is a sentence, not a control label: let it wrap inside the
controls column instead of pushing the column wider */
display: block;
line-height: 1.5;
}

.stage-controls label {
Expand Down Expand Up @@ -632,7 +641,16 @@ footer {

.playground-stage {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
/* Bounded, not `auto`. The controls column holds a sentence — "this motion is a
highlight moving down the field…" — and an `auto` track is sized by max-content, so
that one caption grew the track from 264px to 602px and squeezed the field's own track
to ZERO. The stage has `overflow: hidden`, so the field was not squashed, it was
clipped out of existence: the DOM had all 25 cells and the page showed nothing.

An `auto` track cannot express "as wide as it needs, but never at the field's
expense", and `minmax(0, auto)` is the same thing. The track is capped instead, and
`min-width: 0` lets the caption wrap inside that cap rather than widening it. */
grid-template-columns: minmax(0, 264px) minmax(0, 1fr);
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--card);
Expand Down
Loading