Skip to content

Polish selection with filters

Read as Markdown

Give the selected card one coherent typed drop shadow while keeping every card’s original click and focus geometry.

Put the filter value on the card’s outer Group, not on its individual rectangles or labels. A nonempty filter captures that Group and all of its recursive output as one combined silhouette, so the body, text, and ports share one shadow. Nested filter boundaries resolve inside out; an ordered filter list runs forward in the order you declare it.

An empty [] means the unselected card remains on Pibbl’s direct path. It needs no filter capability. A nonempty list needs browser OffscreenCanvas and native Canvas filter support. Filter output changes pixels only: it does not enlarge layout, measurement, cursor, hit testing, focus bounds, or navigation geometry.

Use one typed filter value at the card boundary and keep the direct path explicit for every other card.

import { dropShadow } from "@pibbl/core/filters";
<Group
style={{
translateX: node.x,
translateY: node.y,
filter: selected
? dropShadow({
offsetX: 6,
offsetY: 8,
blurRadius: 10,
color: "rgb(23 33 29 / 35%)",
})
: [],
}}
>
{cardPaint}
</Group>;

The filter type reference lists every supported typed filter value and its validation rules. Style and draw explains the complete local composition model.

Import brightness and dropShadow from @pibbl/core/filters, and type PibblFilter from @pibbl/core. Use these filter values for the selected branch:

const bright = brightness({ amount: 1.08 });
const shadow = dropShadow({
offsetX: 6,
offsetY: 8,
blurRadius: 10,
color: "rgb(23 33 29 / 35%)",
});
const selectedFilters: readonly PibblFilter[] = [bright, shadow];
<Group
style={{
translateX: node.x,
translateY: node.y,
filter: selected ? selectedFilters : [],
}}
>
{cardPaint}
</Group>;

Run it once, then reverse the array to [shadow, bright]. Predict the difference: the two operations receive different inputs, so brightness-before-shadow and shadow-before-brightness do not produce the same pixels.

Sketch begins selected and receives one shadow around its complete card. Click empty workspace and the next frame takes the unfiltered direct path. Select Idea, then click only in its visible right-hand shadow: the workspace clears selection because shadow-only pixels are not card geometry. Select Sketch again and its filter moves with the same unchanged card bounds.

Filters compose one receiver subtree, run ordered filters in a native Canvas operation, and remain strictly visual. [] is a useful capability-free direct-path declaration; nonempty filters require the browser features documented by Filter types.

Open the interactive workbench

Read the Drawing, layout, and effects companion for ownership, adaptation, failure modes, and verification. Agent start provides the version-selection workflow.

Documentation built with @pibbl/core 0.0.2, revision 2dccb19. ALPHA — NOT FOR PRODUCTION USE.