venact icon system

Every icon size, hit box, colour, effect and prohibition in one place — rendered live at true scale. Library: lucide-react ^0.575.0. Everything on this page is scaffold (hand-drawn), not a rendered REGION.

1 · Sizes — every glyph token, at true scale

All drawn at strokeWidth 2 in COLORS.textMuted so only size varies.
ConstantValueSourceConsumed by
HEADER_ICON_SIZE11paneConstants.js:10SSOT for section-header glyphs — HeaderAction, HeaderCopyButton, collapsed detach, DatabasePlusCombo
HEADER_ICON_SIZE dup11studio tableViewConstants.js:10data-viewer header icons — duplicate, should import the shared token
GAP_MARKER_ICON_SIZE11tableViewConstants.js:12grid gap markers
STATUS_ICON_SIZE12nodeStatusConfig.js:3STATUS NODE ICON
BasePortIcon size12PortIcons.jsx:4DataInPortIcon / DataOutPortIcon
StateGlyph size12StatePortBadge.jsx:29STATE-PORT badges (strokeWidth 3)
ICON_SZ12RepoTree.jsx:14, BranchList.jsx:30landing lists
TREE_ICON_SIZE14treeChromeTokens.js:10every control glyph in a tree row
ICON_SIZE / ICON_SZ14FolderTreeNode.jsx:17, CapacitiesTreeRows.jsx:11folder + capability trees
breadcrumb separator14styleTokens.js:30topbar breadcrumb chevrons (OFFLINE_GRAY, margin 0 5px)
Dropdown chevron14controls.md:201fixed chrome affordance — exempt from the ratio helper
ToolbarIcon size16ToolbarIcon.jsx:15section-header toolbars — “VSC-style: 16px glyph in a 22×22 button”
ICON_PROPS.size48login landing/icons.jsx:4login landing tiles (strokeWidth 1.5)
module tile viewBox56×56frontend-styling.md:164module tile icons — inline SVG only, never Lucide

Derived sizing — icons that scale off the control, not a hardcoded pixel

HelperRuleSource
iconSize(icon, height)max(1, round(iconRatioFor(icon) × height))controlShell.js:48
DEFAULT_ICON_RATIO0.6controlShell.js:8
JoinIcons iconRatio1.2 → ≈29px at a 24px controlJoinIcons.jsx:85
Composite add badgebadge = round(HEADER_ICON_SIZE × 0.6) = 7 · offset = −round(× 0.2) = −2useTemplateSidePanelItems.jsx:38
Icon↔label gapCONTROL_ICON_GAP 6 (sans) · 5 (mono) · SegmentedToggle ICON_GAP 5controlTokens.js:19,71

The ratio is keyed on the icon component reference — never a name (controls.md:179). overflow: visible on icon-bearing controls: height is a floor, not a cap (controls.md:199).

2 · Hit boxes — the button shells

dashed outline = the real clickable boxHover and press them — the effects are live.
ShellBoxRadiusResting glyphSource
IconButton tilepadding 3 (auto size)6COLORS.text #111827IconButton.jsx:31
IconButton toolbarpadding 6 (auto size)6COLORS.text #111827IconButton.jsx:32
IconButton headerh 22 · padding 0 64COLORS.textMuted #6b7280IconButton.jsx:33
ToolbarIcon22 × 224COLORS.textMutedToolbarIcon.jsx:34
TREE_ICON_BOX22 × 22 · padding 0MUTEDtreeChromeTokens.js:13
HEADER_ICON_BTN_BASEpadding 64#374151styleTokens.js:36
Mapping connection dot~28px transparent hit padui-definitions.md:672
Button, icon-onlysquare at standard height (24 mono)3 monocontrols.md:222

controlBaseStyle is applied but height/minHeight/gap are explicitly nulled (IconButton.jsx:110) so the sans 28px height does not reach an IconButton — the shell is padding-sized except in header. The framed 1px border is absorbed by box-sizing: border-box, so it never grows the 22px header.

WCAG 2.2 AA · SC 2.5.8 Target Size (Minimum) = 24 × 24 CSS px. Every shell above is 22px or smaller, and the ones that fail sit edge-to-edge or 6px apart — too close for the spacing exception (which needs non-intersecting 24px circles). The whole header/tree/tab-bar icon family currently fails AA. The compliant floor is drawn in blue below.
red = today’s boxblue = the 24×24 AA floor

3 · Colours

Glyph state colours

Statetile / toolbarheaderSource
RestingCOLORS.text #111827COLORS.textMuted #6b7280IconButton.jsx:72
Hoverunchanged — hover is a background change only, unless hoverColor is passedIconButton.jsx:88
Active / pressedactiveColor ?? hoverColor ?? resting · bg = activeBg ?? hoverBgIconButton.jsx:87
Disabledcolour unchanged · opacity 0.4#f3f4f6 · opacity 0.45IconButton.jsx:73,76
Transient successCheck @ #16a34a for ~1500ms via useTransientFlagHeaderCopyButton.jsx:29

The header disabled treatment is a deliberate exception to the stock DISABLED_OPACITY path, kept to preserve the historical header look.

Palette

Module accents · light / dark

Runtime MODULE_COLORS (logTheme.js:30) differs for MENTOR (#059669) and adds SUPER #d97706.

4 · Effects

Hover — always a grey darkening, never a light fill

on COLORS.border #e5e7eb — the section header
on COLORS.bg #ffffff — a tile
on an opaque tint — needs iconHoverOver()

ICON_HOVER_BG = rgba(0,0,0,0.06) (colors.js:14) — translucent, so one token works on every surface. A light fill would render as a white box on the grey header. When the resting fill is an opaque colour that must survive, compose with iconHoverOver(resting)linear-gradient(HOVER,HOVER), resting.

Timing, opacity, borders, cursor, focus

EffectValueSource
IconButton backgroundtransition: background 120ms easeIconButton.jsx:27
ToolbarIcon backgroundtransition: background 0.1sToolbarIcon.jsx:38
SegmentedToggle slideSEGMENTED_TOGGLE_ANIM_MS = 200controlTokens.js:41
Refresh spinnerspin 1s linear infinitefrontend-styling.md:138
Transient success Check~1500 msfrontend-styling.md:134
Disabled opacityDISABLED_OPACITY 0.4 · header override 0.45themeTokens.js:19
Framed border1px solid COLORS.border, else transparent (header only)IconButton.jsx:74
Knockout ring--venact-header-action-bg pinned to COLORS.bg — never re-pointed at hoverIconButton.jsx:126
Cursorpointer when interactive, else default arrow — venact has no not-allowedcursors.md:86
Focusnative only — real <button type="button">, no custom ringIconButton.jsx:90
Hover mechanismonMouseEnter/Leave + useState via useHoverState — never a CSS pseudo-classcontrolShell.js:25

5 · Stroke width

WidthWhere
1JoinIcons circles · admin diagonal background · DetailGraph thresholds
1.5The documented standard for inline SVG · login landing icons · canvas group icons · edges · charts
2Port icons · SidebarTreeNode · TileShell · RunNodeIcon · ColumnsPod · markdown copy/check
2.5Combobox chevron · ContextMeter ring · mapping + alert edges
3Plus badges · StateGlyph · Hourglass/Loader2 in StatePortBadge · DataNode / AuthNode Plus

Inline SVG convention (frontend-styling.md:159): xmlns required, fill="none", strokeWidth="1.5", stroke #b0bec5, strokeLinecap/Linejoin="round". Lucide is fine inside components — never for module tile icons.

6 · Prohibitions

7 · Accessibility

Open gap. No token in the codebase encodes the WCAG 2.2 AA minimum target size. SECTION_HEADER_HEIGHT 22, TREE_ROW_HEIGHT 22, TAB_BAR_HEIGHT 22, ToolbarIcon 22×22 and CONTROL_H_COMPACT 22 are all 2px under the 24px floor — and the studio tab-bar panel toggles are bare <div onClick>s with no aria-label, no focus, and no hover treatment at all.