Repository navigation
Two-pen immediate-mode layout: stack directions, hug, fill, indent, centering, origin-relative scrolling - #58
Merged
Merged
Conversation
Closed
…ter, origin-relative scrolling Implements the layout theory in docs/layout_theory.md: a layout scope is two pens (pen P, stretch pen S) plus a sign vector sigma pointing from the origin corner into the region. All direction math lives in placedPos/advancePen in the new src/silky/layout.nim; the old per-direction case blocks and parallel stacks are gone. - All four stack directions work through one rule (flip sigma). - Per-axis sizing modes: fixed, fill (remaining known space), and hug (children extent measured by the stretch pen; chrome emitted at close and rotated behind the children in the vertex buffer). - Reverse-direction hug via vertex-span translation (position is relative until close). - indent blocks (cross-axis pen nudge), center() when both sizes known. - Scrolling is origin-relative: scrollPos is the distance t from the origin corner, clamped to overflow; content translates by -sigma*t. A bottom-origin frame rests scrolled to the bottom with its thumb resting at the bottom of the track. One shared frameScrollbars proc replaces the duplicated widget/DSL scrollbar code. - tests/manual_layout.nim: interactive playground (directions, sizing modes, indent, centering, scroll frames). - tests/test_layout.nim: 14 headless tests asserting exact rects for every feature via the semantic layer. - newTestHarness now wires sk.window (interactive widgets segfaulted). All 86 existing example tests pass unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The T7 demo frame now composes fill (T3) with scrolling: fillWidth/ fillHeight instead of a fixed 340x300 box, so it uses the whole demo area. Box count cap raised to 30 (palette wraps) so horizontal directions can overflow and show their scrollbars too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scrolling is a ramification of clipping, not a sizing mode — so it's now scrollable() on any known-size node, orthogonal to fixed/fill/hug. Internally scrollable nodes route through the same clip + origin- relative-scroll machinery as frames (finishFrameScrollbars now keys off frameState instead of the node kind). Playground: "Scroll frame" radio replaced by a "Scrollable (T7)" checkbox that makes the demo area itself scrollable, composing with all three sizing modes. New test: scrollable() rectangle rests on its bottom edge in BottomToTop and translates by -sigma*t. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
treeform
force-pushed
the
silky-layout
branch
from
September 4, 2026 21:31
0cf40a7 to
87f72d6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A single-pass immediate-mode layout system built on an explicit theory: a layout scope is two pens — the pen
P(sk.at, where the next element draws) and the stretch penS(sk.stretchAt, the farthest corner reached) — plus a sign vectorσpointing from the scope's origin corner into the region. The axioms (A1–A8) and the theorems derived from them (T1–T8) live indocs/layout_theory.md;docs/layout_plan.mdmaps each one to the implementation. Everything resolves on the first frame: no layout tree, no measure pass, no caches.Features
σ— instead of per-direction case blocks. All direction math lives in the newsrc/silky/layout.nim(placedPos/advancePen/contentBox); the old parallel stacks (atStack/posStack/sizeStack/directionStack) and globalstretchAtare replaced by a scope stack in both the GPU and testing Silky variants, withsk.at/sk.stretchAtkept as accessors so existing code is unchanged.width/height/size(fixed),fillWidth/fillHeight(remaining known space, T3),hug()(children extent, T2). Hug works in one pass because the vertex buffer is patchable: the parent's chrome is emitted at scope close and rotated behind its children; reverse-direction hug translates the finished span into place (T6).indent n:blocks (T4) — cross-axis pen nudge, nests naturally.center()(T5) — legal when both parent and child sizes are known; doesn't advance the pen.FrameState.scrollPosis now the distancetfrom the origin corner, clamped to overflowmax(|S−O| − R, 0); content translates by−σ·t. A BottomToTop frame rests scrolled to the bottom with its thumb resting at the bottom of the track — chat-log behavior with no special case. One sharedframeScrollbarsproc replaces the duplicated widget/DSL scrollbar code.placedAt()before drawing, so they flow correctly in every direction.Try it
Interactive playground: radios for the four directions and for fixed/hug/fill/scroll parent modes, scrubbers for padding/spacing/box count, toggles for indent, centering, and live widgets in the flow.
Testing
nim r -d:silkyTesting tests/test_layout.nim— 14 headless tests asserting exact rects for every feature through the semantic layer, including reverse-direction hug and scroll rest/translate/clamp positions.newTestHarnessbug:sk.windowwas never assigned, so any interactive widget segfaulted under the harness.Known limitations (documented in the plan)
flex-grow) and justify/space-between are deliberately out: they require seeing all siblings before placing the first — a second pass, which the theory forbids (A8).🤖 Generated with Claude Code