···164164 let b = op.border;
165165 view.setUint32(o, b.color, true);
166166 o += 4;
167167+168168+ // ATTR_DEFAULT sentinel (bit 31 set) means "use terminal default bg"
169169+ let bg = b.bg === undefined ? 0x80000000 : b.bg & 0x00FFFFFF;
170170+ view.setUint32(o, bg, true);
171171+ o += 4;
172172+167173 view.setUint32(
168174 o,
169175 (b.left ?? 0) | ((b.right ?? 0) << 8) | ((b.top ?? 0) << 16) |
···310316 cornerRadius?: { tl?: number; tr?: number; bl?: number; br?: number };
311317 border?: {
312318 color: number;
319319+ bg?: number;
313320 left?: number;
314321 right?: number;
315322 top?: number;
···446453 if (op.layout) n += 6 * 4 + 4 + 4 + 4; // 2 axes (3 words each) + pad + gap + align
447454 if (op.bg !== undefined) n += 4;
448455 if (op.cornerRadius) n += 4;
449449- if (op.border) n += 8;
456456+ if (op.border) n += 12;
450457 if (op.clip) n += 4;
451458 // x, y, expand width/height, parent, attach/pointer, clip/z
452459 if (op.floating) n += 7 * 4;
+9-1
specs/renderer-spec.md
···644644 padding (per-side), alignment (`alignX`: `"left"` | `"center"` | `"right"`;
645645 `alignY`: `"top"` | `"center"` | `"bottom"`, defaulting to left/top when
646646 omitted), direction (top-to-bottom or left-to-right), and gap
647647-- **`border`** — per-side border widths and border color
647647+- **`border`** — per-side border widths, border color, and border background
648648+ color
648649- **`cornerRadius`** — per-corner radius values, producing rounded box-drawing
649650 characters
650651- **`clip`** — clip region configuration for scroll containers
···707708708709These property groups represent the current implementation surface. New groups
709710and fields have been added incrementally and more may follow.
711711+712712+**Border background.** When `border.bg` is provided, the renderer MUST apply
713713+that background color to all cells occupied by border glyphs (corners,
714714+horizontal edges, and vertical edges). When `border.bg` is omitted, border
715715+rendering MUST NOT override the background already present in each border cell;
716716+element backgrounds established by `open({ bg })` remain in effect, and the
717717+terminal default remains in effect where no element background applies.
710718711719**Border width and layout interaction.** In the underlying layout engine (Clay),
712720border configuration does not affect layout computation. This is Clay's intended
+7-3
src/clayterm.c
···301301}
302302303303static void render_border(struct Clayterm *ct, int x0, int y0, int x1, int y1,
304304- Clay_BorderRenderData *b) {
304304+ Clay_RenderCommand *cmd) {
305305+ Clay_BorderRenderData *b = &cmd->renderData.border;
305306 uint32_t fg = color(b->color);
306306- uint32_t bg = ATTR_DEFAULT;
307307+ /* userData is currently exclusively the packed border-bg word. */
308308+ uint32_t bg = (uint32_t)(uintptr_t)cmd->userData;
307309 int top = b->width.top > 0;
308310 int bot = b->width.bottom > 0;
309311 int left = b->width.left > 0;
···533535 if (mask & PROP_BORDER) {
534536 decl.border.color = unpack_color(rd(buf, len, &i));
535537538538+ decl.userData = (void *)(uintptr_t)rd(buf, len, &i);
539539+536540 uint32_t bw = rd(buf, len, &i);
537541 decl.border.width.left = bw & 0xff;
538542 decl.border.width.right = (bw >> 8) & 0xff;
···627631 render_text(ct, x0, y0, cmd);
628632 break;
629633 case CLAY_RENDER_COMMAND_TYPE_BORDER:
630630- render_border(ct, x0, y0, x1, y1, &cmd->renderData.border);
634634+ render_border(ct, x0, y0, x1, y1, cmd);
631635 break;
632636 case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START:
633637 ct->clipping = 1;