The June consumer study release. Eleven downstream apps were surveyed for footguns and papercuts; this release lands the resulting fifty-plus fixes and features (#50–#106), so most known workarounds in consumer code can now be deleted.
⚠️ Breaking (yes, in a point release — we're pre-1.0 and conserving version space)
- Key-first controlled widgets (#71):
select,toggle_group,radio_group, and friends now take theirkeyas the first argument, matchingbutton/text_input. Mechanical migration: move the key argument first. UiEventKindgained aResizedvariant (#106): exhaustive matches need a new arm.
Resizable panes
.user_resizable() (#106) makes a keyed pane edge-draggable with no divider widget and no app state — an echo of CSS resize. The runtime owns the drag (an invisible 8 px band on the pane's seam edge, axis and edge derived from the parent layout), clamps to min_width/max_width and the parent's extent, stores the result in UiState like a scroll offset, and emits Resized to the pane's key on release. user_size()/set_user_size() cover persistence. resize_handle remains for visible dividers, keyboard access, and weighted splits.
Multi-window and resident daemons
SharedText(#94): one glyph/MSDF atlas pool per device, shared acrossRunners viaRunner::with_shared_text— font system, shaping cache, and atlas pages warm once per device instead of once per window. Cross-runner page recycling is made safe by an LRU protection window sized to the attached-runner count. A GPU test proves shared-pool output is byte-identical to private pools.WindowGfx::with_surface_and_renderer(#105): inject a pre-built, pre-warmedRunneron the window-open path, skipping ~360 ms of pipeline build + glyph warmup for daemons that pool renderers.- Per-window hotkey scoping (#103): the convention (each window's
Runnergets only its own hotkey list) is now documented onApp::hotkeysandset_hotkeys.
Custom shaders: names are the contract
Registered WGSL is now introspected (#99) and uniforms route by WGSL field name — .vec4("view_bounds", b) instead of comment-enforced vec_a..vec_e packing. A key matching no declared field warns once at first draw instead of rendering garbage; non-vec4<f32> free slots fail at registration with the field name attached. New ShaderBinding::mat3/vec2 marshaling helpers. Positional aliases stay valid; existing shaders are untouched.
Widgets and layout
grid/virtual_gridwith 2D arrow navigation (#86);visible_range()exposes the realized rows of avirtual_listfor cache eviction (#87)scrollbar_gutter()reserves the thumb band CSS-style (#84);fit_contain/fit_cover/fit_contain_intrinsic(#89)- Indexed-key helpers
key::indexed+UiEvent::route_indexend hand-parsedformat!("{prefix}:{i}")keys (#83) - Tabular numerals via real OpenType
tnum(#88); arrow-key roving navigation for ARIA group widgets (#63) EventCxgains viewport/diagnostics parity withBuildCx(#85)
Color, images, GPU
- SDR transfer presets
GAMMA22/BT1886,GammaExponent::GAMMA_2_2,with_reference_luminance(#91); typedImage::from_rgba_f16_in/from_rgb8constructors (#90) - Oversized images downscale to the device texture limit on all three backends (#78); tessellated vector-mesh colors convert into the working color space (#77); vulkano/ash mirror wgpu's working-color-space negotiation (#61)
StreamingTextureowns the per-frame upload lifecycle on wgpu (#95); vulkano validates target-image usage flags with actionable errors (#93) and batches image uploads into the frame command buffer (#60); ash evicts unused image textures (#54)- Adapter/device failures surface as errors instead of panics, and the Android manifest filters on Vulkan support (#68)
Custom hosts and web
host::{input, color, gfx}expose the winit host's input mappers, color-negotiation stack, and per-window GPU bring-up for custom hosts (#79–#81), plus evdev button mapping and CSS cursor names for non-winit/non-wgpu hosts (#92)- Web:
WebHandle::destroy()for SPA embedding (#76),install_logger+Mailboxutilities (#96), soft-keyboard Enter/arrows/Delete/Home/End forwarding (#67) - Scene3D pre-pass exposed to
draw()-path hosts (#55); fresh-handle churn now warns with a documented caching contract (#98)
Text, HTML, markdown
- Process-global font registry so registered fonts reach measurement (#56); page-LRU atlas recycling + whole-px size quantization (#58); selection offsets snap to UTF-8 boundaries (#50)
- HTML: document whitespace collapses per CSS
white-space: normal(#51),sanitize_stylesactually drops inline styles (#52), every silent drop now works or lints (#70), fragmented inline-HTML styling +md_with_lints(#69) MdCachekeyed render memo for streaming/backlog markdown (#97)
Fixes and docs
Focus clears when clicking a non-focusable keyed node (#65); duplicate sibling keys warn at runtime (#64); toggle/radio gap clicks no longer act (#62); horizontal wheel/trackpad delta forwards (#66); persistent scroll side-maps are LRU-bounded (#57); intrinsic cache seeds from the dynamic-list measure pass (#59); emoji + RTL parity fixtures (#75). 100% rustdoc coverage on public core items (#73), custom-host checklist (#100), blessed app patterns guide (#102), dev-profile MSDF override snippet for consumer workspaces (#101), staleness pass (#72).