···190190 );
191191 o += 4;
192192193193- // Resolved per-side attributes (CSS-like fallback expansion done
194194- // here, not in C): fg/bg word pairs in top, right, bottom, left
195195- // order. The C renderer consumes these as explicit values.
193193+ // Must match render_border() in src/clayterm.c.
194194+ // Resolve CSS-like side fallbacks here, then write eight required
195195+ // attribute words: fg/bg pairs in top, right, bottom, left order.
196196+ // C treats the presence and order of these words as a wire-format
197197+ // invariant and only consumes the explicit values.
196198 for (let side of [b.top, b.right, b.bottom, b.left]) {
197199 view.setUint32(o, sideFg(side, b.color), true);
198200 o += 4;
+19-10
src/clayterm.c
···303303static void render_border(struct Clayterm *ct, int x0, int y0, int x1, int y1,
304304 Clay_RenderCommand *cmd) {
305305 Clay_BorderRenderData *b = &cmd->renderData.border;
306306- /* userData points at eight words in the command buffer carrying resolved
307307- * per-side attributes as fg/bg pairs in top, right, bottom, left order.
308308- * Fallback resolution (shared color/bg vs side overrides) happens on the
309309- * TypeScript side; this renderer consumes explicit values only. The
310310- * command buffer outlives the render pass within reduce(). */
306306+ /* Must match border packing in ops.ts.
307307+ * userData points at eight required words in the command buffer: resolved
308308+ * fg/bg pairs in top, right, bottom, left order. Fallback resolution
309309+ * (shared color/bg vs side overrides) happens on the TypeScript side; this
310310+ * renderer consumes explicit values only. The command buffer outlives the
311311+ * render pass within reduce(). Missing userData is a wire-format violation.
312312+ */
311313 const uint32_t *s = (const uint32_t *)cmd->userData;
312312- uint32_t deffg = color(b->color);
313313- uint32_t top_fg = s ? s[0] : deffg, top_bg = s ? s[1] : ATTR_DEFAULT;
314314- uint32_t right_fg = s ? s[2] : deffg, right_bg = s ? s[3] : ATTR_DEFAULT;
315315- uint32_t bot_fg = s ? s[4] : deffg, bot_bg = s ? s[5] : ATTR_DEFAULT;
316316- uint32_t left_fg = s ? s[6] : deffg, left_bg = s ? s[7] : ATTR_DEFAULT;
314314+ if (s == NULL) {
315315+ __builtin_trap();
316316+ }
317317+318318+ uint32_t top_fg = s[0];
319319+ uint32_t top_bg = s[1];
320320+ uint32_t right_fg = s[2];
321321+ uint32_t right_bg = s[3];
322322+ uint32_t bot_fg = s[4];
323323+ uint32_t bot_bg = s[5];
324324+ uint32_t left_fg = s[6];
325325+ uint32_t left_bg = s[7];
317326 int top = b->width.top > 0;
318327 int bot = b->width.bottom > 0;
319328 int left = b->width.left > 0;