Changes since version 1.17.0 (2.0.0-rc1)¶
New Features¶
-
Client → server log channel — the browser now reports warnings/errors to the backend over the existing
(id, event)envelope viasendLog(level, message, { source, data })(targeting the reservedclient_logcontrol with thelogevent). A backend-onlyClientLogcontrol normalizes each message and, by default, logs it undertanga.viz.client;viz.on_client_log(handler)replaces the sink. The frontend's_log(...)init/WS trace lines can additionally be forwarded atinfolevel by opting in withsetLogForwarding(true)/?log=1. -
SdfComposecombine descriptor —SdfCompose(element, mode, smoothness=…)names aComposed/SdfGroupmember's combine mode and optional blend radius, replacing the opaque(element, mode[, smoothness])tuple (which still works). -
Unified transform arguments —
set_transform()andapply_transform()(onVizSceneObject/VizObjectRef) accept the same inputs: aTransform, anMV, or a GA operator (Rotor/GeneralRotor/Motor/Translator/Dilator). -
Configurable versor factorization —
blade_factorize_versor(eps=1e-6, max_iterations=64)exposes the degeneracy threshold and the iteration cap. -
Native, dependency-free editable table —
TableViewno longer loads the Tabulator CDN; it is now a plain-DOM table styled only by--tanga-*tokens, so it themes like every other control. -
Optional column titles and row numbers —
TableViewacceptsshow_column_titlesandshow_row_numbersto toggle the header row and a leading 1-based row-number column. -
Active cell + cursor-key movement — a single highlighted cell, moved with the arrow keys, anchors cell editing and keyboard navigation.
-
Column deletion — a new
column_deleteevent,TableColumnDeletepayload,Table.delete_columnmutation, andon_column_deletehandler, covered by backend undo/redo. -
Header-click sorting — click a column header to sort ascending/descending (a third click clears the sort); display-only, gated by
sortable. -
Programmatic table control —
TableView.get_cell/set_cell/get_value/clear_historyround out the backend control API (set_cellpushes the grid to the browser). -
Table viewport, zoom + resize — the
TableViewgrid has a natural default size (scrolling internally instead of growing its container), a standard row height, title-bar+/−controls to zoom column width and row height, and a bottom-right corner grip to resize the whole table. -
Backend-driven table rows/columns —
TableView.add_row/add_column/delete_row/delete_columnmutate the model and push the grid, so apps add their ownButtonViews to the layout (the widget ships no add/delete buttons). -
Table column types, editors & persistence — columns can be typed (
number/string/bool/ an enum of allowed values), deduced from the data or set explicitly viaTableView(column_types=[...]). Numbers right-align and reject non-numeric input, booleans render an always-on checkbox, and enums edit through a dropdown.save(path)/load(path)round-trip data + types + relative column widths + row height + sort order as a versioned JSON file (id+version);to_csv(path)/from_csv(path)exchange plain data; andjson_path=...auto-saves on every change. -
Selection-relative table add/delete — the table now reports its active cell to the backend (
TableCellSelectpayload,on_cell_selecthandler, andTable.active_cell/TableView.active_cell), andTableViewgainsinsert_row(index)/insert_column(index)alongsidedelete_row/delete_column, so apps can insert above/below or left/right of the selected cell and delete the selected row/column — falling back to the table edges when no cell is selected. -
Editable table columns —
TableViewheaders can be renamed by double-clicking (editable_titles, default on), anumbercolumn carries a Pythonstr.formatdisplay template (set_column_format, persisted in the saved JSON), and a right-click header menu proposes a different column type, applied or rejected by a backendconvert_column(string always; bool↔number 1/0; enum only below 20 distinct values) with anon_column_type_changehandler for custom handling (e.g. a warning banner). The sort arrow is also larger and directly clickable. -
Auto-height toolbars —
ToolbarViewnow sizes its height to its tallest control (plus themargin/borderchrome) instead of a fixed control floor, so taller controls such as dropdowns no longer overflow the row, and a toolbar of only icon/button controls collapses to fit them with a small margin. -
Per-scene, switchable space dimension —
viz.scene(name, space_dim=…)/viz.add_scene(name, space_dim=…)set the space dimension when a scene is created, andviz.set_space_dim(2 | 3, scene_name=…)(orhandle.space_dim =) switches it live — the browser re-applies camera mode and controls without a reload. A newcamera/switch_2d_3d.pyexample toggles one plot between a flat 2D view and a tilted 3D view with a checkbox. -
2D camera
stretchmodes — the 2D camera's singleuniformboolean is replaced by astretchparameter ("fit"letterbox,"fill"stretch both axes,"fill_x"x-fills/y-keeps-aspect,"fill_y"y-fills/x-keeps-aspect), exposed onView2DConfig,CameraConfig2d,fit_view2d, andCoordinateSystem, and mirrored in the live viewer and HTML export.
Breaking Changes¶
uniformremoved from the 2D camera —View2DConfig,CameraConfig2d, andfit_view2dno longer acceptuniform; usestretch="fit"(the olduniform=True) orstretch="fill"(the olduniform=False).
Bug Fixes¶
-
parent_idcontrol groups not shown on the single-scene page — aGroupView(parent_id=…)in aSceneView(overlay=[...])is now attached via CSS2D once its parent entity is registered (deferred attach), instead of being dropped when the layout is built before the scene entities arrive. -
Versor factorization hangs on near-degenerate motors —
FactorizeVersorno longer loops forever when a max-grade blade is numerical noise (a pruned high-grade component); it discards that grade and returns the stable factors found so far. -
Last column/row cell editing — replacing Tabulator's event layer with a plain-DOM grid fixes the double-click edit failing on the last column/row inside auto-sized overlay panels.
-
Column zoom no longer inflates the page — zooming column width keeps the grid's viewport fixed and scrolls horizontally, instead of stretching the table wider than the window.
-
Broken/overlapping toolbar icons — the
material:icon family now loads Google Material Symbols Outlined (replacing the classic Material Icons font), so ligatures such asadd_row_below,add_column_right, andsplitscreen_bottomrender as glyphs instead of raw text that mispositioned the toolbar layout and hover backgrounds. The four split-screen enum values were also corrected fromsplit_screen_*to the realsplitscreen_*ligature names. -
Table resize grip overlapping the scrollbar — the bottom-right resize handle now has an opaque themed background so it cleanly covers the scrollbar corner (and the adjacent ends of the horizontal/vertical scrollbars) instead of the scrollbar track showing through the handle.
-
2D plots clipped in split panes —
fit_view2d(...)now defaults to aborder_pxof 60 (matchingCoordinateSystem), so a per-pane camera embedded viaSceneView(..., camera=fit_view2d(...))leaves a label margin instead of clipping the axis labels and axes at the pane edge. -
multi_plot.pyrendered empty panes — the example referenced scenes (left/middle/right) that it never created; it is rewritten as three named 2D plots (sine, log power law, parabola) in a horizontalSplitView. -
2D→3D switch stayed orthographic —
switchToCameranow recreates a default perspective camera when the space dimension changes to 3D and the current camera is orthographic, so a runtimeset_space_dim(3)(with no explicit camera) actually switches to a 3D view.