@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,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MODEL workspace — Blender-shaped modeling: a dominant document, outliner
|
|
3
|
+
* above properties (`@volter/editor-sdk/looks`, a `workspace.layout`
|
|
4
|
+
* contribution). Its arrangement carries Blender 5.2's own MODELING-workspace
|
|
5
|
+
* proportions; `../src/layouts.tsx` states the measurement and the host's
|
|
6
|
+
* fixed-pane clamp that bounds it.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { WorkspaceLayoutContribution } from '@volter/editor-sdk/looks';
|
|
10
|
+
|
|
11
|
+
export const point = 'workspace.layout';
|
|
12
|
+
export const layout: WorkspaceLayoutContribution = {
|
|
13
|
+
id: 'model',
|
|
14
|
+
title: 'Model',
|
|
15
|
+
description: 'Blender-shaped modeling: a dominant document, outliner above properties.',
|
|
16
|
+
// No `tabs` here ON PURPOSE. The host's default is already `shown`, so
|
|
17
|
+
// stating it changed nothing for a bare host — but the WORKSPACE layer wins
|
|
18
|
+
// over the style bundle (`workspace-regions.ts`), so restating the default
|
|
19
|
+
// silently shadowed `blender.style.ts`'s `tabs: 'hidden'` and the Model
|
|
20
|
+
// document still painted a 25px tab row (measured against Blender 5.2, which
|
|
21
|
+
// has none). Leave a region unstated unless this workspace genuinely needs
|
|
22
|
+
// it different from the host default.
|
|
23
|
+
regions: {
|
|
24
|
+
header: 'shown',
|
|
25
|
+
shelf: 'shown',
|
|
26
|
+
inspector: 'properties',
|
|
27
|
+
drawer: 'hidden',
|
|
28
|
+
},
|
|
29
|
+
// THE TIMELINE IS THE BOTTOM AREA (owner, 2026-09-20: "doesn't blender have
|
|
30
|
+
// a timeline at the bottom?"). It does — and the workspace this Model
|
|
31
|
+
// document stands in is Blender's LAYOUT screen for us, not its Modeling
|
|
32
|
+
// one: Layout is the four-area screen with the Timeline, and Modeling is the
|
|
33
|
+
// same screen WITHOUT it (measured below).
|
|
34
|
+
//
|
|
35
|
+
// THE PROPORTION IS BLENDER'S OWN, measured through bpy on the installed
|
|
36
|
+
// Blender 5.2.1 at factory settings in a 1920-wide window
|
|
37
|
+
// (`bpy.data.workspaces['Layout'].screens[0].areas`):
|
|
38
|
+
//
|
|
39
|
+
// PROPERTIES x1579 y23 w339 h839
|
|
40
|
+
// OUTLINER x1579 y865 w339 h189
|
|
41
|
+
// DOPESHEET_EDITOR x2 y23 w1574 h74 ui_type TIMELINE ← this area
|
|
42
|
+
// VIEW_3D x2 y100 w1574 h954
|
|
43
|
+
//
|
|
44
|
+
// and the same screen at a 1600×929 window gives the Timeline 63 of an
|
|
45
|
+
// 880-px centre column. Both are the same ratio to three places: 74/1029 =
|
|
46
|
+
// 0.0719 and 63/880 = 0.0716. The Modeling screen's own reading, for the
|
|
47
|
+
// contrast: VIEW_3D `x2 y23 w1574 h1031` and no DOPESHEET area at all.
|
|
48
|
+
//
|
|
49
|
+
// It is stated to four places because it is a measurement, not a preference;
|
|
50
|
+
// the dock uses it once, to size the group the first time this workspace
|
|
51
|
+
// stands up, and a capture of the settled grid wins afterwards.
|
|
52
|
+
areas: [{ id: 'timeline', document: 'blender-timeline.document', place: 'below', ratio: 0.0719 }],
|
|
53
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `modelsFromBlendFiles` FINDER (ARCHITECTURE-CORE §The project model,
|
|
3
|
+
* "A model is Blender data, and a prefab is not a model"): every `.blend`
|
|
4
|
+
* under the selection's `include` globs is a `model` document — a Blender
|
|
5
|
+
* file the engine in the tab opens, edits and saves. The bpy scripts that
|
|
6
|
+
* authored it are ordinary project files beside it (`src/models/<name>.py`);
|
|
7
|
+
* this document does not run them, a person or an agent does, through the
|
|
8
|
+
* session's Blender (`vgai blender-mcp`).
|
|
9
|
+
*
|
|
10
|
+
* It replaced `modelsFromMeshModules`, which listed every module exporting
|
|
11
|
+
* `build(): THREE.BufferGeometry` (owner ruling 2026-09-19, "do the delete":
|
|
12
|
+
* the TypeScript mesh kit was the modeling engine while Blender could not run
|
|
13
|
+
* in the tab; it now does, and a model is Blender data).
|
|
14
|
+
*
|
|
15
|
+
* Select it in `vgai.adapter.ts`:
|
|
16
|
+
*
|
|
17
|
+
* documents: { find: [{ finder: 'modelsFromBlendFiles', include: ['src/models/**\/*.blend'] }] }
|
|
18
|
+
*
|
|
19
|
+
* This module is a plain object the HOST registers; it mounts no UI. It reads
|
|
20
|
+
* the project only through `input.files` — the PATHS matching those globs.
|
|
21
|
+
* Deliberately not `input.sources`: a `.blend` is binary, there is nothing in
|
|
22
|
+
* it a text walk could honestly read, and the entry is the file itself.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
|
|
27
|
+
export const finder = {
|
|
28
|
+
name: 'modelsFromBlendFiles',
|
|
29
|
+
schema: z
|
|
30
|
+
.object({
|
|
31
|
+
finder: z.literal('modelsFromBlendFiles'),
|
|
32
|
+
include: z
|
|
33
|
+
.array(z.string().min(1))
|
|
34
|
+
.min(1)
|
|
35
|
+
.describe('Project-relative globs of the Blender files to list (`src/models/**/*.blend`)'),
|
|
36
|
+
})
|
|
37
|
+
.strict(),
|
|
38
|
+
run(
|
|
39
|
+
_selection: { finder: 'modelsFromBlendFiles'; include: readonly string[] },
|
|
40
|
+
input: { files?: readonly string[] },
|
|
41
|
+
) {
|
|
42
|
+
const entries = [];
|
|
43
|
+
const notes: string[] = [];
|
|
44
|
+
for (const path of input.files ?? []) {
|
|
45
|
+
if (!path.endsWith('.blend')) continue;
|
|
46
|
+
const name = (path.split('/').pop() ?? path).replace(/\.blend$/, '');
|
|
47
|
+
entries.push({
|
|
48
|
+
id: `model:${path}`,
|
|
49
|
+
label: name,
|
|
50
|
+
kind: 'model',
|
|
51
|
+
region: null,
|
|
52
|
+
authorable: true,
|
|
53
|
+
reach: { kind: 'root-mount' as const },
|
|
54
|
+
source: { path },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return { entries, notes };
|
|
58
|
+
},
|
|
59
|
+
} as const;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLENDER'S BONE CONSTRAINTS TAB, as a Properties section (WORK.md §Blender in
|
|
3
|
+
* the tab is Blender, "Inspection parity", I2): the active POSE BONE's
|
|
4
|
+
* constraint stack, with the generic view beneath under "All properties".
|
|
5
|
+
*
|
|
6
|
+
* It is the Object Constraints tab over a different datablock, and Blender
|
|
7
|
+
* says so itself: `properties_constraint.py` registers
|
|
8
|
+
* `BONE_PT_constraints` beside `OBJECT_PT_constraints` with the same
|
|
9
|
+
* `template_constraints()` body, differing only in reading
|
|
10
|
+
* `context.pose_bone.constraints`. So it shares the header list that module
|
|
11
|
+
* exports rather than restating it — a second copy is a second thing to keep
|
|
12
|
+
* in step.
|
|
13
|
+
*
|
|
14
|
+
* It stands when: `buttons_context_path_pose_bone` — a pose channel for the
|
|
15
|
+
* active bone, and never in Edit mode.
|
|
16
|
+
*/
|
|
17
|
+
import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
|
|
18
|
+
import type { BlenderCuratedPanel } from './blender-properties-view';
|
|
19
|
+
import { CONSTRAINT_HEADER } from './properties-constraints.inspector';
|
|
20
|
+
|
|
21
|
+
const CURATED: readonly BlenderCuratedPanel[] = [
|
|
22
|
+
{
|
|
23
|
+
title: 'Bone Constraints',
|
|
24
|
+
from: 'Constraints',
|
|
25
|
+
collection: true,
|
|
26
|
+
properties: CONSTRAINT_HEADER,
|
|
27
|
+
andDeclared: true,
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const TAB = { id: 'bone_constraint', curated: CURATED } as const;
|
|
32
|
+
|
|
33
|
+
export const point = 'selection.inspector';
|
|
34
|
+
export const title = 'Bone Constraints';
|
|
35
|
+
/** `blender.icons.json` — Blender's own mark, TRACED from
|
|
36
|
+
* `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
|
|
37
|
+
* is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
|
|
38
|
+
* and tinted by the group `UI_icons.hh` declares it in. */
|
|
39
|
+
export const icon = 'properties-bone-constraints';
|
|
40
|
+
/** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
|
|
41
|
+
* these are that order, spaced so a tab can be inserted between two. */
|
|
42
|
+
export const order = 140;
|
|
43
|
+
/** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
|
|
44
|
+
* (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
|
|
45
|
+
* group (Render, Output, View Layer, Scene, World), then Collection, then the
|
|
46
|
+
* object group (Object … Material), then Texture. The presentation draws a
|
|
47
|
+
* separator wherever this changes. */
|
|
48
|
+
export const railGroup = 'object';
|
|
49
|
+
export const match = blenderPropertiesTabMatch(TAB);
|
|
50
|
+
export default blenderPropertiesTabSection(TAB);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLENDER'S BONE TAB, as a Properties section (WORK.md §Blender in the tab is
|
|
3
|
+
* Blender, "Inspection parity", I2). Blender's own panels over the RNA door,
|
|
4
|
+
* with the generic view beneath under "All properties".
|
|
5
|
+
*
|
|
6
|
+
* THE SPECIFICATION IS `scripts/startup/bl_ui/properties_data_bone.py` at the
|
|
7
|
+
* engine's pin: its `classes` tuple is the panel order, `bl_label` the title,
|
|
8
|
+
* each `layout.prop(bone, "x")` an entry. Blender's UI layer is never run,
|
|
9
|
+
* ported or recorded.
|
|
10
|
+
*
|
|
11
|
+
* TWO DATABLOCKS, AND THAT IS THE WHOLE STRUCTURE OF THIS TAB. Blender's panels
|
|
12
|
+
* read `bone` (the armature's `Bone`, or the `EditBone` in Edit mode) for the
|
|
13
|
+
* rest pose — head, tail, roll, envelope, collections, display — and `pchan`
|
|
14
|
+
* (the `PoseBone`) for the POSE: its location/rotation/scale and its inverse
|
|
15
|
+
* kinematics. `buttons_context_path_bone` and `_pose_bone` build both, and the
|
|
16
|
+
* door hands this tab both as "Bone" and "Pose Bone", so each panel names the
|
|
17
|
+
* one Blender's draw function reads. That is why Transform below is split in
|
|
18
|
+
* two the way `BONE_PT_transform` (:39) is: its first half is `pchan`, its
|
|
19
|
+
* second `bone`.
|
|
20
|
+
*
|
|
21
|
+
* It stands when: `buttons_context_path_bone` — an armature with an ACTIVE bone
|
|
22
|
+
* (the edit bone in Edit mode).
|
|
23
|
+
*/
|
|
24
|
+
import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
|
|
25
|
+
import type { BlenderCuratedPanel } from './blender-properties-view';
|
|
26
|
+
|
|
27
|
+
/** `properties_data_bone.py`, panel by panel. Line numbers are that file's. */
|
|
28
|
+
const CURATED: readonly BlenderCuratedPanel[] = [
|
|
29
|
+
{
|
|
30
|
+
// BONE_PT_transform, :39, pose half (:63-99) — drawn in Pose mode.
|
|
31
|
+
title: 'Transform (Pose)',
|
|
32
|
+
from: 'Pose Bone',
|
|
33
|
+
properties: [
|
|
34
|
+
'location',
|
|
35
|
+
'lock_location',
|
|
36
|
+
'rotation_quaternion',
|
|
37
|
+
'rotation_axis_angle',
|
|
38
|
+
'rotation_euler',
|
|
39
|
+
'lock_rotation_w',
|
|
40
|
+
'lock_rotation',
|
|
41
|
+
'rotation_mode',
|
|
42
|
+
'scale',
|
|
43
|
+
'lock_scale',
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
// BONE_PT_transform, :39, rest half (:104-110) — the bone's own geometry.
|
|
48
|
+
// NO MATRICES. The first cut named `matrix` and `matrix_local` beside them
|
|
49
|
+
// and the live read showed why Blender does not: a 3x3 and a 4x4 draw as
|
|
50
|
+
// twenty-five numbered rows, which buries the five values the panel is
|
|
51
|
+
// about. They are still in "All properties" beneath, where a matrix is
|
|
52
|
+
// something you go looking for. (`roll` is an EditBone property, so it
|
|
53
|
+
// draws in Edit mode and not in Object mode — the datablock's answer, not
|
|
54
|
+
// a condition of ours.)
|
|
55
|
+
title: 'Transform',
|
|
56
|
+
from: 'Bone',
|
|
57
|
+
properties: ['head', 'tail', 'roll', 'length', 'lock'],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
// BONE_PT_curved, :114 — "Bendy Bones".
|
|
61
|
+
title: 'Bendy Bones',
|
|
62
|
+
closed: true,
|
|
63
|
+
from: 'Bone',
|
|
64
|
+
properties: [
|
|
65
|
+
'bbone_segments',
|
|
66
|
+
'bbone_x',
|
|
67
|
+
'bbone_z',
|
|
68
|
+
'bbone_mapping_mode',
|
|
69
|
+
'use_endroll_as_inroll',
|
|
70
|
+
'use_scale_easing',
|
|
71
|
+
'bbone_handle_type_start',
|
|
72
|
+
'bbone_handle_use_scale_start',
|
|
73
|
+
'bbone_handle_use_ease_start',
|
|
74
|
+
'bbone_handle_type_end',
|
|
75
|
+
'bbone_handle_use_scale_end',
|
|
76
|
+
'bbone_handle_use_ease_end',
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// BONE_PT_relations, :213.
|
|
81
|
+
title: 'Relations',
|
|
82
|
+
from: 'Bone',
|
|
83
|
+
properties: [
|
|
84
|
+
'parent',
|
|
85
|
+
'children',
|
|
86
|
+
'use_relative_parent',
|
|
87
|
+
'use_connect',
|
|
88
|
+
'use_local_location',
|
|
89
|
+
'use_inherit_rotation',
|
|
90
|
+
'inherit_scale',
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
// BONE_PT_collections, :252 — the collections this bone is in.
|
|
95
|
+
title: 'Bone Collections',
|
|
96
|
+
closed: true,
|
|
97
|
+
from: 'Bone',
|
|
98
|
+
properties: ['collections'],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
// BONE_PT_inverse_kinematics, :430 — every one of these is on the POSE
|
|
102
|
+
// channel, not the bone.
|
|
103
|
+
title: 'Inverse Kinematics',
|
|
104
|
+
closed: true,
|
|
105
|
+
from: 'Pose Bone',
|
|
106
|
+
properties: [
|
|
107
|
+
'ik_stretch',
|
|
108
|
+
'lock_ik_x',
|
|
109
|
+
'lock_ik_y',
|
|
110
|
+
'lock_ik_z',
|
|
111
|
+
'ik_stiffness_x',
|
|
112
|
+
'ik_stiffness_y',
|
|
113
|
+
'ik_stiffness_z',
|
|
114
|
+
'use_ik_limit_x',
|
|
115
|
+
'ik_min_x',
|
|
116
|
+
'ik_max_x',
|
|
117
|
+
'use_ik_limit_y',
|
|
118
|
+
'ik_min_y',
|
|
119
|
+
'ik_max_y',
|
|
120
|
+
'use_ik_limit_z',
|
|
121
|
+
'ik_min_z',
|
|
122
|
+
'ik_max_z',
|
|
123
|
+
'use_ik_rotation_control',
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
// BONE_PT_deform, :535 — `use_deform` is the panel's own header checkbox.
|
|
128
|
+
title: 'Deform',
|
|
129
|
+
closed: true,
|
|
130
|
+
from: 'Bone',
|
|
131
|
+
properties: [
|
|
132
|
+
'use_deform',
|
|
133
|
+
'envelope_distance',
|
|
134
|
+
'envelope_weight',
|
|
135
|
+
'use_envelope_multiply',
|
|
136
|
+
'head_radius',
|
|
137
|
+
'tail_radius',
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
// BONE_PT_display, :304, and BONE_PT_display_custom_shape (:388), whose
|
|
142
|
+
// properties are all on the pose channel.
|
|
143
|
+
title: 'Viewport Display',
|
|
144
|
+
closed: true,
|
|
145
|
+
from: 'Bone',
|
|
146
|
+
properties: ['hide', 'hide_select', 'display_type', 'color', 'show_wire'],
|
|
147
|
+
sub: [
|
|
148
|
+
{
|
|
149
|
+
title: 'Custom Shape',
|
|
150
|
+
closed: true,
|
|
151
|
+
from: 'Pose Bone',
|
|
152
|
+
properties: [
|
|
153
|
+
'custom_shape',
|
|
154
|
+
'custom_shape_translation',
|
|
155
|
+
'custom_shape_rotation_euler',
|
|
156
|
+
'custom_shape_scale_xyz',
|
|
157
|
+
'use_custom_shape_bone_size',
|
|
158
|
+
'custom_shape_transform',
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
const TAB = { id: 'bone', curated: CURATED } as const;
|
|
166
|
+
|
|
167
|
+
export const point = 'selection.inspector';
|
|
168
|
+
export const title = 'Bone';
|
|
169
|
+
/** `blender.icons.json` — Blender's own mark, TRACED from
|
|
170
|
+
* `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
|
|
171
|
+
* is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
|
|
172
|
+
* and tinted by the group `UI_icons.hh` declares it in. */
|
|
173
|
+
export const icon = 'properties-bone';
|
|
174
|
+
/** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
|
|
175
|
+
* these are that order, spaced so a tab can be inserted between two. */
|
|
176
|
+
export const order = 130;
|
|
177
|
+
/** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
|
|
178
|
+
* (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
|
|
179
|
+
* group (Render, Output, View Layer, Scene, World), then Collection, then the
|
|
180
|
+
* object group (Object … Material), then Texture. The presentation draws a
|
|
181
|
+
* separator wherever this changes. */
|
|
182
|
+
export const railGroup = 'object';
|
|
183
|
+
export const match = blenderPropertiesTabMatch(TAB);
|
|
184
|
+
export default blenderPropertiesTabSection(TAB);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLENDER'S COLLECTION TAB, as a Properties section (WORK.md §Blender in the
|
|
3
|
+
* tab is Blender, "Inspection parity", I2). Blender's own panels over the RNA
|
|
4
|
+
* door, with the generic view beneath under "All properties".
|
|
5
|
+
*
|
|
6
|
+
* THE SPECIFICATION IS `scripts/startup/bl_ui/properties_collection.py` at the
|
|
7
|
+
* engine's pin — `classes` (`:146-155`) is the panel order and `bl_label` the
|
|
8
|
+
* title. Blender's UI layer is never run, ported or recorded.
|
|
9
|
+
*
|
|
10
|
+
* THE FIRST PANEL IS CALLED "VISIBILITY" AT THIS PIN, not "Restrictions":
|
|
11
|
+
* `COLLECTION_PT_collection_flags.bl_label` is `"Visibility"` (`:32`). Its
|
|
12
|
+
* child View Layer (`:47`) does not read the collection at all — it reads
|
|
13
|
+
* `view_layer.active_layer_collection` (`:56`), a different datablock, which
|
|
14
|
+
* the context door now names beside the collection as this tab's second path.
|
|
15
|
+
*
|
|
16
|
+
* TWO CHECKBOXES BLENDER DRAWS INVERTED. `hide_select` is labelled
|
|
17
|
+
* "Selectable" with `invert_checkbox=True` (`:41`) and `exclude` is labelled
|
|
18
|
+
* "Include" the same way (`:60`). What stands here is the RNA's own value
|
|
19
|
+
* under the RNA's own name, because inverting a value in the presentation is
|
|
20
|
+
* exactly the fabrication the anti-shim rule forbids — the same reading the
|
|
21
|
+
* Object tab's Visibility panel already made.
|
|
22
|
+
*
|
|
23
|
+
* WHAT THE TRANSCRIPTION DELIBERATELY DROPS: `COLLECTION_PT_importer`
|
|
24
|
+
* (`:65`), whose poll is a PREFERENCE (`prefs.experimental.use_collection_
|
|
25
|
+
* importer`) and whose body is `template_collection_importer()` — an operator
|
|
26
|
+
* template. Exporters (`:80`) is the same widget over `collection.exporters`,
|
|
27
|
+
* and the collection itself is real RNA (`rna_collection.cc:954`), so its row
|
|
28
|
+
* stands. `COLLECTION_PT_collection_custom_props` (`:143`) is IDProperties
|
|
29
|
+
* rather than RNA.
|
|
30
|
+
*
|
|
31
|
+
* It stands when: `buttons_context_path_collection` — the view layer's ACTIVE
|
|
32
|
+
* collection, and never the scene's master collection, which only the engine
|
|
33
|
+
* knows.
|
|
34
|
+
*/
|
|
35
|
+
import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
|
|
36
|
+
import type { BlenderCuratedPanel } from './blender-properties-view';
|
|
37
|
+
|
|
38
|
+
/** `properties_collection.py`, panel by panel. Line numbers are that file's. */
|
|
39
|
+
const CURATED: readonly BlenderCuratedPanel[] = [
|
|
40
|
+
{
|
|
41
|
+
// COLLECTION_PT_collection_flags, :31.
|
|
42
|
+
title: 'Visibility',
|
|
43
|
+
properties: ['hide_select', 'hide_render'],
|
|
44
|
+
sub: [
|
|
45
|
+
{
|
|
46
|
+
// COLLECTION_PT_viewlayer_flags, :47 — the LayerCollection's.
|
|
47
|
+
title: 'View Layer',
|
|
48
|
+
from: 'View Layer Collection',
|
|
49
|
+
properties: ['exclude', 'holdout', 'indirect_only'],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
// COLLECTION_PT_instancing, :99.
|
|
55
|
+
title: 'Instancing',
|
|
56
|
+
properties: ['instance_offset'],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
// COLLECTION_PT_lineart_collection, :113 — the mask is drawn as eight
|
|
60
|
+
// indexed toggles (:130); the array row carries all eight.
|
|
61
|
+
title: 'Line Art',
|
|
62
|
+
properties: [
|
|
63
|
+
'lineart_usage',
|
|
64
|
+
'lineart_use_intersection_mask',
|
|
65
|
+
'lineart_intersection_mask',
|
|
66
|
+
'use_lineart_intersection_priority',
|
|
67
|
+
'lineart_intersection_priority',
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
// COLLECTION_PT_exporters, :80.
|
|
72
|
+
title: 'Exporters',
|
|
73
|
+
properties: ['exporters'],
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const TAB = { id: 'collection', curated: CURATED } as const;
|
|
78
|
+
|
|
79
|
+
export const point = 'selection.inspector';
|
|
80
|
+
export const title = 'Collection';
|
|
81
|
+
/** `blender.icons.json` — Blender's own mark, TRACED from
|
|
82
|
+
* `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
|
|
83
|
+
* is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
|
|
84
|
+
* and tinted by the group `UI_icons.hh` declares it in. */
|
|
85
|
+
export const icon = 'properties-collection';
|
|
86
|
+
/** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
|
|
87
|
+
* these are that order, spaced so a tab can be inserted between two. */
|
|
88
|
+
export const order = 60;
|
|
89
|
+
/** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
|
|
90
|
+
* (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
|
|
91
|
+
* group (Render, Output, View Layer, Scene, World), then Collection, then the
|
|
92
|
+
* object group (Object … Material), then Texture. The presentation draws a
|
|
93
|
+
* separator wherever this changes. */
|
|
94
|
+
export const railGroup = 'collection';
|
|
95
|
+
export const match = blenderPropertiesTabMatch(TAB);
|
|
96
|
+
export default blenderPropertiesTabSection(TAB);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLENDER'S OBJECT CONSTRAINTS TAB, as a Properties section (WORK.md §Blender
|
|
3
|
+
* in the tab is Blender, "Inspection parity", I2): the STACK, each constraint
|
|
4
|
+
* its own panel with its own settings, the generic view beneath under "All
|
|
5
|
+
* properties".
|
|
6
|
+
*
|
|
7
|
+
* THE SPECIFICATION IS `scripts/startup/bl_ui/properties_constraint.py`, and
|
|
8
|
+
* it has the same shape `properties_data_modifier.py` does: `draw` is
|
|
9
|
+
* `layout.template_constraints()` and the per-type panels are built in C from
|
|
10
|
+
* each constraint's RNA. So the stack is derived the same way — the shared
|
|
11
|
+
* `Constraint` header properties named, then everything THIS constraint's own
|
|
12
|
+
* struct declares (`andDeclared`, which reads `BlenderRnaRow.group`). A Copy
|
|
13
|
+
* Location constraint gets `CopyLocationConstraint`'s target, subtarget, use_x
|
|
14
|
+
* / use_y / use_z, invert flags and offset, in RNA's order.
|
|
15
|
+
*
|
|
16
|
+
* The ACTIVE constraint (`buttons_context_path_constraint`, reported as
|
|
17
|
+
* `activeConstraint`) is marked.
|
|
18
|
+
*
|
|
19
|
+
* It stands when: `buttons_context_path_object` — Constraints shares Object's
|
|
20
|
+
* path, so the engine grants it whenever it grants Object.
|
|
21
|
+
*/
|
|
22
|
+
import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
|
|
23
|
+
import type { BlenderCuratedPanel } from './blender-properties-view';
|
|
24
|
+
|
|
25
|
+
/** The shared header every constraint panel carries — `Constraint`'s own
|
|
26
|
+
* properties, in the order `template_constraints` heads a panel with them. */
|
|
27
|
+
export const CONSTRAINT_HEADER: readonly string[] = [
|
|
28
|
+
'name',
|
|
29
|
+
'type',
|
|
30
|
+
'enabled',
|
|
31
|
+
'mute',
|
|
32
|
+
'influence',
|
|
33
|
+
'error_location',
|
|
34
|
+
'error_rotation',
|
|
35
|
+
'is_valid',
|
|
36
|
+
'is_override_data',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const CURATED: readonly BlenderCuratedPanel[] = [
|
|
40
|
+
{
|
|
41
|
+
title: 'Constraints',
|
|
42
|
+
from: 'Constraints',
|
|
43
|
+
collection: true,
|
|
44
|
+
active: 'activeConstraint',
|
|
45
|
+
properties: CONSTRAINT_HEADER,
|
|
46
|
+
andDeclared: true,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const TAB = { id: 'constraint', curated: CURATED } as const;
|
|
51
|
+
|
|
52
|
+
export const point = 'selection.inspector';
|
|
53
|
+
export const title = 'Object Constraints';
|
|
54
|
+
/** `blender.icons.json` — Blender's own mark, TRACED from
|
|
55
|
+
* `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
|
|
56
|
+
* is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
|
|
57
|
+
* and tinted by the group `UI_icons.hh` declares it in. */
|
|
58
|
+
export const icon = 'properties-constraints';
|
|
59
|
+
/** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
|
|
60
|
+
* these are that order, spaced so a tab can be inserted between two. */
|
|
61
|
+
export const order = 110;
|
|
62
|
+
/** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
|
|
63
|
+
* (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
|
|
64
|
+
* group (Render, Output, View Layer, Scene, World), then Collection, then the
|
|
65
|
+
* object group (Object … Material), then Texture. The presentation draws a
|
|
66
|
+
* separator wherever this changes. */
|
|
67
|
+
export const railGroup = 'object';
|
|
68
|
+
export const match = blenderPropertiesTabMatch(TAB);
|
|
69
|
+
export default blenderPropertiesTabSection(TAB);
|