@volter/editor-blender 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1409 -0
- package/README.md +17 -0
- package/contributions/blender-header-menus.tsx +483 -0
- package/contributions/blender-icon-trace.mjs +403 -0
- package/contributions/blender-icons.source.mjs +2925 -0
- package/contributions/blender-node-editor.document.tsx +1402 -0
- package/contributions/blender-node-geometry.ts +1138 -0
- package/contributions/blender-node-panels.source.mjs +485 -0
- package/contributions/blender-outliner-authoring.ts +1729 -0
- package/contributions/blender-outliner-model.ts +389 -0
- package/contributions/blender-palette.source.mjs +319 -0
- package/contributions/blender-properties-model.ts +351 -0
- package/contributions/blender-properties-tab.tsx +100 -0
- package/contributions/blender-properties-view.tsx +1191 -0
- package/contributions/blender-runtime-skin.ts +619 -0
- package/contributions/blender-runtime.document.tsx +232 -0
- package/contributions/blender-timeline-geometry.ts +323 -0
- package/contributions/blender-timeline.document.tsx +1056 -0
- package/contributions/blender-uv-editor.document.tsx +483 -0
- package/contributions/blender-uv-geometry.ts +305 -0
- package/contributions/blender-version.status.tsx +93 -0
- package/contributions/blender.command.ts +102 -0
- package/contributions/blender.icons.json +1247 -0
- package/contributions/blender.icons.traced.json +1561 -0
- package/contributions/blender.keymap.ts +39 -0
- package/contributions/blender.node-panels.json +2436 -0
- package/contributions/blender.palette.json +93 -0
- package/contributions/blender.status.tsx +263 -0
- package/contributions/blender.style.ts +271 -0
- package/contributions/model.layout.ts +53 -0
- package/contributions/models.finder.ts +59 -0
- package/contributions/properties-bone-constraints.inspector.tsx +50 -0
- package/contributions/properties-bone.inspector.tsx +184 -0
- package/contributions/properties-collection.inspector.tsx +96 -0
- package/contributions/properties-constraints.inspector.tsx +69 -0
- package/contributions/properties-data.inspector.tsx +229 -0
- package/contributions/properties-material.inspector.tsx +121 -0
- package/contributions/properties-modifiers.inspector.tsx +74 -0
- package/contributions/properties-object.inspector.tsx +215 -0
- package/contributions/properties-output.inspector.tsx +210 -0
- package/contributions/properties-particles.inspector.tsx +494 -0
- package/contributions/properties-physics.inspector.tsx +614 -0
- package/contributions/properties-render.inspector.tsx +446 -0
- package/contributions/properties-scene.inspector.tsx +174 -0
- package/contributions/properties-texture.inspector.tsx +300 -0
- package/contributions/properties-view-layer.inspector.tsx +145 -0
- package/contributions/properties-world.inspector.tsx +130 -0
- package/contributions/sculpt.layout.ts +25 -0
- package/contributions/shading.layout.ts +99 -0
- package/contributions/texture.layout.ts +16 -0
- package/contributions/uv-editing.layout.ts +93 -0
- package/host/blender-runtime-host.ts +1256 -0
- package/package.json +77 -0
- package/src/layouts.tsx +48 -0
- package/src/looks.ts +14 -0
- package/src/node-view-state.ts +125 -0
- package/src/timeline-view-state.ts +154 -0
- package/src/uv-view-state.ts +125 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONE PROPERTIES TAB IS ONE `selection.inspector` CONTRIBUTION — the factory
|
|
3
|
+
* every `properties-*.inspector.tsx` in this package is built from (WORK.md
|
|
4
|
+
* §Blender in the tab is Blender, "Inspection parity", I1, item 3).
|
|
5
|
+
*
|
|
6
|
+
* WHY A TAB IS A SECTION, and not a rail of our own: under the `properties`
|
|
7
|
+
* presentation the inspector's sections ARE the vertical icon rail, 1:1
|
|
8
|
+
* (`packages/editor/src/components/InspectionProjection.tsx`,
|
|
9
|
+
* `PropertiesColumn`). So the way to make Blender's tab rail appear is to
|
|
10
|
+
* contribute Blender's tabs as sections — which is also exactly the shape I2
|
|
11
|
+
* needs, because each of these modules then grows a CURATED body over the same
|
|
12
|
+
* door while the generic view stays beneath it.
|
|
13
|
+
*
|
|
14
|
+
* WHICH TABS STAND is `buttons_context.cc`'s answer, computed in the engine
|
|
15
|
+
* (`session.py::rna_context`) and read here. Two kinds of tab:
|
|
16
|
+
*
|
|
17
|
+
* - `standing: 'any' | 'object'` — a tab `buttons_context.cc` builds a path
|
|
18
|
+
* to UNCONDITIONALLY given a scene (`buttons_context_path_scene`,
|
|
19
|
+
* `_view_layer`, `_world`) or given an object at all
|
|
20
|
+
* (`buttons_context_path_object`, of which only the OBJECT tab is standing
|
|
21
|
+
* here — Physics and Constraints share that path but are context-gated,
|
|
22
|
+
* because Blender's Properties editor follows the ACTIVE OBJECT rather
|
|
23
|
+
* than the row that was clicked, and only the door knows there is one).
|
|
24
|
+
* These match from the SELECTION alone, synchronously.
|
|
25
|
+
* - everything else — Modifiers (an object type set), Particles (a mesh),
|
|
26
|
+
* Object Data (the object has data), Bone (an active bone), Material,
|
|
27
|
+
* Collection, Texture — which only the engine can answer, so they match
|
|
28
|
+
* against the context the door last returned.
|
|
29
|
+
*
|
|
30
|
+
* THE STANDING TABS EXIST SO THE RAIL IS NEVER EMPTY: `match()` is
|
|
31
|
+
* synchronous and the first composition has read nothing, so if every tab
|
|
32
|
+
* waited on the door there would be no rail at all. The READ itself is driven
|
|
33
|
+
* from `match` (see the note there), and when its answer lands it calls
|
|
34
|
+
* `documents.contextChanged`, which re-derives the whole inspection and brings
|
|
35
|
+
* the rest of the rail in.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import type {
|
|
39
|
+
ToolContributionNode,
|
|
40
|
+
ToolInspectorContributionProps,
|
|
41
|
+
} from '@volter/editor-sdk/contributions';
|
|
42
|
+
import {
|
|
43
|
+
blenderPropertiesState,
|
|
44
|
+
resolveBlenderSubject,
|
|
45
|
+
showBlenderSubject,
|
|
46
|
+
} from './blender-properties-model';
|
|
47
|
+
import { type BlenderCuratedPanel, BlenderPropertiesSection } from './blender-properties-view';
|
|
48
|
+
|
|
49
|
+
export interface BlenderPropertiesTab {
|
|
50
|
+
/** `BCONTEXT_*` in lower case, as the door spells it. */
|
|
51
|
+
readonly id: string;
|
|
52
|
+
/** Whether this tab needs the engine's answer to exist, or stands on the
|
|
53
|
+
* selection alone — see the header. */
|
|
54
|
+
readonly standing?: 'any' | 'object';
|
|
55
|
+
/** BLENDER'S OWN PANELS for this tab, in Blender's order, transcribed from
|
|
56
|
+
* the matching `scripts/startup/bl_ui/properties_*.py`
|
|
57
|
+
* ({@link BlenderCuratedPanel}). The generic RNA view stays beneath them
|
|
58
|
+
* under "All properties"; a tab that declares none is the generic view
|
|
59
|
+
* alone, which is what I1 shipped. */
|
|
60
|
+
readonly curated?: readonly BlenderCuratedPanel[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function blenderPropertiesTabMatch(tab: BlenderPropertiesTab) {
|
|
64
|
+
return (node: ToolContributionNode | null, adapter: unknown): boolean => {
|
|
65
|
+
const subject = resolveBlenderSubject(node, adapter);
|
|
66
|
+
if (subject === null) return false;
|
|
67
|
+
// THE READ IS DRIVEN FROM `match`, NOT FROM A BODY, and that is a
|
|
68
|
+
// correction the live walk forced: under the `properties` presentation
|
|
69
|
+
// the host mounts ONLY THE ACTIVE TAB's body, so a read driven from a
|
|
70
|
+
// body never happened at all unless the person had already clicked a
|
|
71
|
+
// Blender tab — the rail showed the standing tabs and nothing else, for
|
|
72
|
+
// good (measured 2026-09-19). A matcher runs on every composition,
|
|
73
|
+
// active tab or not, so this is the one place that always sees the
|
|
74
|
+
// subject. It is idempotent by construction: `showBlenderSubject`
|
|
75
|
+
// returns immediately unless the subject moved.
|
|
76
|
+
showBlenderSubject(subject);
|
|
77
|
+
if (tab.standing === 'any') return true;
|
|
78
|
+
if (tab.standing === 'object') return subject.kind === 'object';
|
|
79
|
+
const state = blenderPropertiesState();
|
|
80
|
+
// The context must be the one read for THIS subject: a stale answer from
|
|
81
|
+
// the previously selected object would show its tabs over the new one.
|
|
82
|
+
// BOTH halves of the subject, because a COLLECTION row and the Scene
|
|
83
|
+
// Collection row both read with no object and would otherwise pass each
|
|
84
|
+
// other's context.
|
|
85
|
+
const object = subject.kind === 'object' ? subject.name : null;
|
|
86
|
+
const collection = subject.kind === 'collection' ? subject.path : null;
|
|
87
|
+
if (state.object !== object || state.collection !== collection) return false;
|
|
88
|
+
return state.context?.tabs.some((entry) => entry.id === tab.id) ?? false;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function blenderPropertiesTabSection(tab: BlenderPropertiesTab) {
|
|
93
|
+
return function BlenderPropertiesTabSection({ node, adapter }: ToolInspectorContributionProps) {
|
|
94
|
+
const subject = resolveBlenderSubject(node, adapter);
|
|
95
|
+
if (subject === null) return null;
|
|
96
|
+
return (
|
|
97
|
+
<BlenderPropertiesSection tabId={tab.id} subject={subject} curated={tab.curated ?? []} />
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
}
|