blendertk v0.5.39
-
2026-07-29 — Scene-data sidecar (mirrors mayatk's rename, plus the exporter-side write Blender never had).
HierarchySidecar→SceneDataSidecar(scene_data_sidecar.py, registered asbtk.SceneDataSidecar; old module = import shim): the manifest is now format v2 — hierarchy diff baseline +data_exportchannel snapshot in one.{stem}.scene_data.json, withread_data()and themigrate_legacy()promotion of v1-named sidecars (mayatk's changelog has the full design rationale). New here: the SceneExporter actually writes the sidecar post-export. mayatk maintained its manifest via the hierarchy check's task-manager hook, but blendertk's exporter had no sidecar wiring at all — the check is still a disabled placeholder (TODO(blender-parity), tooltip updated to say precisely that). The write lives on the engine (_write_scene_data_sidecar, same reason as_create_glb: blendertk'sTaskManagercarries noexport_path), is gated on the carrier having actually shipped (present in the export set — a hidden carrier excluded from a selected-mode export records nothing) or an existing manifest to maintain, and is best-effort — the record can never break the export it records. The engine's native_VERSION_SUFFIX_REre-implementation (its comment claimed the sidecar class "lives in the unported hierarchy_sync subsystem" — stale since the sidecar port) is deleted in favor ofSceneDataSidecar.VERSION_SUFFIX_RE.test_scene_data_sidecar.py(wastest_hierarchy_sidecar.py) 43/43 headless, incl. v2-format / v1-compat / name-migration checks. -
2026-07-29 — Scene Exporter's missing-file check no longer fails an export over textures that never ship (mirrors mayatk).
check_valid_pathswalked everyFILEimage datablock in the .blend — its docstring even called the whole-file scope deliberate, "matching Maya's version". The Maya version turned out to be the bug (see mayatk's entry: an HDR environment map and orphaned duplicate-material file nodes flooded a real export log), so both sides move to the export scope. Image scope is now_get_export_images()— the datablocks feeding the materials assigned toself.objects— which drops the World/Environment-Texture HDR and the zero-user images a duplicate-material cleanup leaves behind. Linked libraries stay whole-file: they are the analogue of Maya's scene references, not of a texture. The scoping is applied by filteringMatUtils.get_image_records()against the export set rather than re-deriving "is a FILE image whose abspath exists" locally — that predicate belongs toget_image_records, and a second copy of it in the check would be free to drift.test_scene_exporter.py+2 (an unassigned broken image is ignored; a missing texture on an export material still fails). -
2026-07-29 — The "blendertk panels get a hide button" rule is now a default the UI Browser can override (mirrors mayatk).
BlenderUiHandler.apply_styleshardcodedstyle["header_buttons"] = ("menu","collapse","hide")for anything taggedblendertk— a fixed tuple no user preference could outrank, and one of the three reasons the UI Browser's window-persistence setting had no effect (uitk's changelog has the diagnosis). Replaced by uitk's newdefault_persistence(ui)hook: blendertk-tagged UIs declarePERSISTENCE_STICKY, everything else falls through to the basePERSISTENCE_TRANSIENT— identical defaults, now at the bottom of a precedence chain the browser's global setting and per-window "Open as" override sit above. The gesture-scoped panels that ask for a pin button inheader_initare unaffected (the handler leaves a self-configured header alone unless there's an explicit choice, and then swaps onlypin/hide).test_blender_ui_handler.py+3 (default is sticky, an override outranks it,apply_stylesis no longer overridden). Also fixed a stale assertion in that suite (pre-existing, unrelated): it pinnedUnityBridgeSlots.MODE_LABELSto the single{copy: "Copy to Project"}entry from before the panel-native "Manage Unity Scripts" mode shipped — the mayatk twin carries the same two modes, so parity holds and the test, not the code, was wrong; it now asserts both modes plus the still-retired Unity Studio / existing-project ones. Suite back to 226/226. -
2026-07-29 — 25 panels declared fixed-vertical (mirrors mayatk): no more stretching into dead space above the footer. Same sweep and same classification as the mayatk entry — a panel is locked only when its trailing spacer is the sole vertical absorber. Those panels' spacers are now
sizeType=Fixedwith each group box declaringvsizetype="Fixed", making Qt's ownQLayout.maximumSize()finite rather than leaning on uitk's container see-through; seven untuned Qt Designer 20x40 spacers are tuned to the 10px norm (aFixedspacer's hint is its exact, unresizable height). Panels with real growable content stay resizable. Parity with mayatk is preserved panel-for-panel; verified through the real loader (finite native cap, ~10px footer gap, exact collapse/expand round-trips). -
2026-07-29 — Shell Xform gains
Gather to Tile, and its snap now respects the tile border padding (parity with mayatk).UvUtils.gather_to_udimmirrors the Maya twin: stray islands return to the target UDIM by whole-tile offsets that keep their sub-tile position, clamped inside the shared border margin, with the target decided by majority vote when no UDIM is given. Islands are resolved in two passes (vote, then apply) because the object-mode bmesh is freed when the edit callback returns, so island references must not escape it. The vote pass runs only when no UDIM is given, and the vote itself isptk.MathUtils.majority_tile. The move pad's grid snap lands islands one margin inside each grid line instead of on it._island_boundsfactored out of_island_bbox_centerbacks both. A partial selection moves the whole island — free here via_target_islands, and now asserted, because the Maya twin had to be fixed to match.