Scene/layout/overlay model — scenes, layouts, and overlays now flow
through a single hierarchy (LayoutHost → Layout → Scene);
add_scene(name) auto-creates a same-named single-SceneView layout so
scene URLs come for free.
Polymorphic Visualizer.add — viz.add(entity) targets the main scene
and viz.add(view) mounts the view in the default layout's overlay;
viz.add_layout and viz.layout[name] expose the layout registry.
Control-owned value & history — Control.set_value/get_value and
Table.undo/redo/can_undo/can_redo/clear_history live on the control
classes (forwarded through *View).
SliderView gains on_press / on_release — sliders accept press
(drag-start) and release (drag-end) handlers in addition to on_change.
SliderView / ButtonView / CheckboxView gain variant — the view
classes expose EControlVariant ("default" / "menu").
ToolbarView and shared EStack* layout enums — a horizontal toolbar
container (a bordered StackView with an inner margin, a border toggle,
and gap/align/justify) aligns a row of controls left, right,
block-centered, or equally spaced; EStackDirection / EStackAlign /
EStackJustify replace the StackView/GroupView/MenuView string
literals (plain strings remain valid).
LabelView / MarkdownView / LogView display views — three read-only
content views render inside a layout tree: LabelView (text with a
configurable font_size), MarkdownView (rendered markdown with KaTeX
math), and LogView (a live, auto-scrolling two-column time/message log
with a history cap and JSON-lines file I/O). LabelView / MarkdownView
are settable in place via set_value; LogView appends lines
programmatically via log() / clear() / load_file() and pushes
log_update.
SeparatorView — a thin 1px divider line with configurable spacing,
usable in toolbars, menus, and stacks. orientation is the line's
orientation ("horizontal" / "vertical"); the default "auto" derives the
perpendicular orientation from the enclosing container.
Table.on_change bulk-change handler — TableView accepts an
on_change callback that fires once with the full {columns, rows} table on
undo/redo (Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y and TableView.undo() / .redo()),
complementing the per-cell on_cell_change.
Expression.bind() / Expression.evaluate() — intent-specific
evaluation entry points (also on AffineExpression) that narrow the wide
MV | Expression | list__call__ return type: bind() asserts a partial
evaluation (returns Expression), evaluate() asserts a full collapse
(returns MV), each raising ValueError when the caller's stated intent is
wrong.
Transform.from_operator() + public Transform — Transform is now
importable from pytanga.viz and can be built from a GA operator
(Translator/Rotor/GeneralRotor/Motor/Dilator), so a body's static
placement can be baked into a VizGroup at construction time.
Smooth SDF CSG — smooth_union/smooth_intersection/smooth_subtract
combine modes with a per-member smoothness blend radius on
Composed/SdfGroup/Combine (and a SdfStyle(smoothness=…) default) give
rounded, blended joins instead of hard seams.
add_* control facades removed — add_slider/add_button/add_table/…,
add_control_group, and add_menu are gone; declare controls as *View
objects and mount them with set_layout or viz.add(view).
control_position removed — the implicit orphan control panel and its
per-scene anchors are gone; position controls via GroupView(position=...).
Runtime value API removed — set_control/get_control/set_control_value/
undo_table/redo_table/update_control are gone; call set_value/undo/
redo on the control view instead.
The legacy controls_define orphan-panel path is removed — controls are
no longer emitted through a separate fixed-panel (controls_define) pipeline
with its own toggle button; they render as layout views through view_layout.
Reflected MV wedge/inner product — constant_mv ^ variable and
constant_mv | variable (constant on the left) now build the expected
Expression via the existing reflected dunders, instead of raising
AttributeError; MV.__xor__/MV.__or__ return NotImplemented for
non-MV operands.
Scene/layout/overlay ownership reworked — scenes moved into LayoutHost,
layouts are first-class Layout objects (base + overlay), and the entity
API moved into Scene (add_viz); Visualizer/VizSceneHandle become
"pick the right scene" delegates.
Banners/dialogs/editor folded into OverlayContainer — BannerHost/
DialogHost/EditorHost are merged into the per-layout overlay container.
Tree-walk dispatch — inbound control events resolve ids by walking layout
trees and dialogs (the _control_views index is deleted).
Control event handling moved onto the controls — a polymorphic
Control.handle_event(event, payload) -> Dispatch seam means each control
kind owns its own event → mutation → handler mapping; the visualizer only
resolves a control and delegates.
Explicit Visualizer facade — __getattr__ is replaced by thin
forwarders so the public API is introspectable.