-
Notifications
You must be signed in to change notification settings - Fork 289
v2: refactor: new Canvas, Compositor, and Layer API #591
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2-exp
Are you sure you want to change the base?
Conversation
andreynering
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
I have some concerns with the layer functionality, not necessarily specific to this PR (as it was present with the previous version in v2-exp as well). There are a couple of things on layers that I feel like are too easy to accidentally misconfigure, primarily around recursive child layers.
|
Good points you raise here. I've made some changes, with the help of Crush, to work around these concerns. Let me know if you see any other issues 🙂 |
I mentioned this in Discord as well, but an alternative, and I think a bit cleaner approach could be used. See my version of addressing those concerns here. Some addl. notes on my proposed tweaks:
I'm still working on a layout wrapper PoC to create more complex layouts, so I will keep poking things to see where any gaps might be/may make some follow up PRs. |
This change redefines what a Canvas and Layer are within the lipgloss package. The Canvas is now a simple screen buffer that can compose layers and drawable types. The layer implementation is now responsible for holding metadata about its position and z-index, as well as managing child layers. This separation of concerns simplifies the Canvas and makes it more flexible for composing various drawable types. The id is now mandatory when creating a Layer, ensuring each layer can be uniquely identified.
Layer x, y, z coordinates are now relative to parent instead of absolute. Positions are calculated dynamically during draw/hit/bounds operations without mutating children. This provides cleaner hierarchy semantics and prevents unintended state changes when repositioning layers. - Add absolutePosition() to calculate absolute coords on-demand - Add drawWithOffset() for recursive drawing with parent context - Add hitWithOffset() for recursive hit testing with proper z-sorting - Add boundsWithOffset() for recursive bounds calculation - Simplify X(), Y(), Z() setters to only update own coordinates - Simplify AddLayers() to not mutate children - Make GetLayer() fully recursive to search entire tree 💘 Generated with Crush Assisted-by: Claude Sonnet 4.5 via Crush <[email protected]>
All layers are now drawn in global z-index order regardless of hierarchy depth. Previously, parents always drew before children, making z-ordering only meaningful among siblings. Now a deeply nested child with z=100 will correctly draw on top of a top-level layer with z=50. - Add flatLayer type to hold calculated absolute positions - Add flattenLayers() to recursively collect all layers with absolute coords - Refactor Draw() to flatten hierarchy, sort by absolute z, then draw - Remove drawWithOffset() in favor of flatten-sort-draw approach 💘 Generated with Crush Assisted-by: Claude Sonnet 4.5 via Crush <[email protected]>
5387b9d to
015bed7
Compare
lrstanley
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor tweaks that may be worth looking at:
- remove absolute Z functionality, as I don't think this will work how people expect it would.
- This was causing the following to be rendered behind other lower z layers: https://cdn.liam.sh/share/2025/11/layers.txt (last layer in this go-spew output should be on top)
- see also: https://cdn.liam.sh/share/2025/11/explorer_GQ10NjdU0j.mp4
- maybe there is still a usecase for absolute z that I can't think of, so maybe it should be configurable on the compositor?
- E.g.
(c *Compositor) UseAbsoluteZ(bool). Alternatively, on*Layer, we could also do(l *Layer) CompoundingZ(int), which sets both azfield, in addition to ancompoundingZfield, and if that is present, it's always added onto children?
- E.g.
- Allow
lipgloss.Canvasto be reused, for users who would like higher perf.
Patch for the above: https://cdn.liam.sh/share/2025/11/misc-v2-canvas-1.patch
$ curl -sL https://cdn.liam.sh/share/2025/11/misc-v2-canvas-1.patch | git apply
This change redefines what a Canvas and Layer are within the lipgloss
package. The Canvas is now a simple screen buffer that can compose
layers and drawable types.
A layer now doesn't do any computation and only represents a tree node. Using a compositor flattens a list of layers, and is able to draw them or render them into a string.