Window Titlebar Dynamics
This document describes the current titlebar mechanics in @wonderlandlabs-pixi-ux/window.
Renderer Frame Of Reference
titlebarContentRenderer(...) keeps the same public contract for both regular and counter-scaled titlebars:
titlebarContentRenderer: ({
titlebarStore,
titlebarValue,
windowStore,
windowValue,
contentContainer,
localRect,
localScale,
}) => {
// upsert Pixi content here
}
The important context is:
contentContaineris always the public parent container passed to the renderer.contentContainerbelongs to the titlebar, not the window body.contentContaineruses titlebar-local coordinates with origin(0, 0)at the titlebar's top-left corner.localRectandlocalScaleare not rewritten byCounterScalingTitlebar.localRectdescribes the titlebar render bounds incontentContainer's local coordinate space.localScaleis the effective scale ofcontentContaineritself.- If a titlebar needs zoom-independent content, the renderer should explicitly choose the counter-scaled child layer.
So the renderer context is always: "you are drawing into the titlebar layer." It is never a window-body renderer, and CounterScalingTitlebar does not silently substitute a different frame of reference.
Titlebar Height And Anchor
TitlebarStore.height is the geometry source of truth for titlebar layout.
- Regular titlebars return the configured titlebar height.
CounterScalingTitlebaroverridesheightto return the computed current visual height.- Titlebar rect, pivot, background, and hit area all derive from
height.
The titlebar is anchored upward from the window origin.
- The body/window rect remains the canonical content rect.
- The titlebar container is pivoted upward by its computed height.
- Window body renderers do not need to offset themselves by titlebar height.
Counter-Scaled Titlebars
CounterScalingTitlebar adds a first child inside contentContainer labeled counter-scale.
contentContainerremains the root renderer target.contentContainer.getChildByLabel('counter-scale')is the zoom-independent child layer.- That child is inverse-scaled during layout.
- When you render into
counter-scale, you are intentionally moving from the default titlebar-local layer into a zoom-independent inner titlebar layer.
Recommended renderer pattern:
titlebarContentRenderer: ({ contentContainer }) => {
const counterScale = contentContainer.getChildByLabel('counter-scale') as Container | null;
const target = counterScale ?? contentContainer;
// upsert titlebar controls into target
}
The stock titlebar renderer follows the same rule: when counter-scale exists, stock title text/icons/buttons render there.
Hover Dynamics
For titlebar.mode === 'onHover', the titlebar uses one shared hover session across both the window body and the titlebar itself.
Current behavior:
pointeroveron the body shows the titlebar immediately.pointeroveron the titlebar also keeps it visible.pointeroutfrom either region starts a delayed unhover.- A new
pointeroverfrom either region cancels that pending unhover.
This means the titlebar stays available while the pointer moves from body to titlebar, instead of flickering off between the two regions.
State And Refresh Pattern
Keep titlebar updates state-first:
- Mutate titlebar/window state.
- Call
dirty()on the relevant store. - Upsert Pixi objects from
titlebarContentRenderer(...)during resolve.
Avoid treating titlebar callbacks as imperative one-off mutation hooks outside the refresh cycle.