Skip to content

fix: picking Column Drop left the field blank - #18

Merged
DoodleBears merged 1 commit into
mainfrom
fix/column-drop-blank-field
Oct 1, 2026
Merged

DoodleBears merged 1 commit into
mainfrom
fix/column-drop-blank-field

Conversation

@DoodleBears

@DoodleBears DoodleBears commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Why

Reported as "Column Drop 这个效果似乎现在看不到". It was not faint — the stage came up with
zero cells.

Change outline

columns moves a highlight down a column; a per-dot animation-delay can only offset
a dot's phase, never move anything. So buildCss returns null for it — correct and
documented behaviour.

The playground computed cssAvailable correctly, disabled the CSS switch and printed the
reason — then passed renderer="css" anyway. The engine was asked for something it refuses,
and paintCss returned without painting anything.

Disabling a control without honouring it is the worst of the available answers: the switch
explains itself while the field shows nothing.

  • The toggle now records a preference the preset can overrule; what the field is painted
    with follows, so renderer is css only when cssAvailable.
  • The readout and the copied snippet say svg rather than claiming a mode the engine is
    not in — a paste saying renderer="css" handed consumers the same blank field.
  • The engine normalises it too (paintable()), for direct callers: handle.options.renderer
    reports what is actually painted. Deliberately in option resolution, not inside paintCss —
    a frame callback retrying a build it knows will fail does that once per frame, and
    cssGap() still reports why.

Special things to note

  • Reversibility: additive; no engine default changes. columns still has css: false —
    this makes the refusal visible rather than blank, which is the documented contract.
  • The second half was a lie, not dead weight. The stylesheet 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. Every consumer shipped a rule describing a
    static, fully-lit field for a motion the renderer had already refused. keyframesFor now
    applies the same preset.css rule buildCss does, and a test walks every renderable preset
    to prove none went missing.
  • Four new tests: the field is painted somehow; the readout says svg; the copy omits
    renderer="css"; and the switch becomes usable again for a motion CSS can express.
  • 215 tests (was 209), oxlint 0, registry ok, both changelog ledgers.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Unsupported motion presets now render with SVG when CSS animation isn’t available. The active renderer is reflected in the display and copied settings.
    • CSS keyframes are emitted only for presets supported by the CSS renderer.

Reported as "Column Drop 这个效果似乎现在看不到". It was not faint — the stage came up with
ZERO cells.

`columns` moves a highlight down a column, and a per-dot `animation-delay` can only OFFSET
a dot's phase, never move anything. So `buildCss` returns null for it, which is the correct
and documented behaviour. The playground computed `cssAvailable` correctly, DISABLED the CSS
switch and printed the reason — and then passed `renderer="css"` anyway. The engine was
asked for something it refuses, and `paintCss` returned without painting anything.

Disabling a control without honouring it is the worst of the available answers: the switch
explains itself while the field shows nothing. The toggle now records a preference that the
preset can overrule, and what the field is actually painted with follows: `css` only when
`cssAvailable`, and the readout and the copied snippet say `svg` rather than claiming a mode
the engine is not in. A paste that said `renderer="css"` would have handed a consumer the
same blank field.

The engine normalises the same thing for direct callers, which matters more than the site:
`paintable()` rewrites the renderer to `svg` when the preset is not expressible, so
`handle.options.renderer` tells the truth about what is on screen. Doing it in the option
resolution rather than inside `paintCss` is deliberate — a frame callback retrying a build
it knows will fail does that once per frame, and `cssGap()` still reports why.

SECOND, AND IT WAS A LIE RATHER THAN DEAD WEIGHT: the stylesheet 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 — gives full brightness at BOTH ends: a static, fully-lit field. Every consumer shipped
that rule, and it described a motion the renderer had already refused to draw. `keyframesFor`
now applies the same `preset.css` rule `buildCss` does, so the document only carries
motions that can actually run — and a test walks every renderable preset to prove none went
missing.

215 tests (was 209), oxlint 0, registry ok, both changelog ledgers.
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (3)
AGENTS.md — auto-discovered
CHANGELOG.zh.md — configured
CHANGELOG.md — configured

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 0b1a6c2c-a599-4adf-88a6-041c618b7559

📥 Commits

Reviewing files that changed from the base of the PR and between 4277ba4 and 01bc9ab.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • CHANGELOG.zh.md
  • apps/site/src/components/Playground.tsx
  • apps/site/test/playground.test.tsx
  • packages/core/src/dot-matrix/field.ts
  • packages/core/src/dot-matrix/matrix.ts
  • packages/core/test/dom.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The playground and dot-matrix engine now use SVG when a selected preset is not CSS-renderable. The CSS stylesheet no longer emits keyframes for unsupported presets.

Changes

Renderer eligibility

Layer / File(s) Summary
Normalize the active renderer
packages/core/src/dot-matrix/matrix.ts, apps/site/src/components/Playground.tsx, packages/core/test/dom.test.ts, apps/site/test/playground.test.tsx, CHANGELOG.md, CHANGELOG.zh.md
The engine and playground use SVG for unsupported presets. The playground readout, copied configuration, and renderer switch reflect the effective renderer. Tests cover switching between unsupported and supported presets.
Limit CSS keyframes to supported presets
packages/core/src/dot-matrix/field.ts, packages/core/test/dom.test.ts
keyframesFor returns null for unsupported presets. Tests check that unsupported presets have no keyframes and supported presets retain them.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 01bc9

Selecting an effect the CSS renderer cannot express, such as Column Drop, now falls back to SVG, so the field is no longer blank. The readout and copied snippet report the renderer actually in use. No remaining merge-blocking risk was found.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 01bc9

The fallback makes rendering and copied configuration consistent. The inspected paths show no new privilege or sensitive-data access, but assurance is limited for embedding environments outside the reviewed browser flow.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The resolved browser flow affects the rendering element, document-scoped generated styles, and user-initiated clipboard output. This bounds the inspected effects, but does not establish complete coverage of external consumers or embedding environments.

Trust Boundaries and Controls

  • observed — Preset eligibility is enforced both in the playground and independently at core creation and update boundaries. Copied configuration remains text passed to navigator.clipboard.writeText after a button click, with manual display on rejection; it is not executed by that copy path.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 5 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary fix: selecting the Column Drop preset no longer leaves the field blank. It is concise and directly matches the changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 5 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

@DoodleBears
DoodleBears merged commit b7a7c0d into main Oct 1, 2026
2 checks passed
@DoodleBears
DoodleBears deleted the fix/column-drop-blank-field branch October 1, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant