@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.
Files changed (58) hide show
  1. package/LICENSE +1409 -0
  2. package/README.md +17 -0
  3. package/contributions/blender-header-menus.tsx +483 -0
  4. package/contributions/blender-icon-trace.mjs +403 -0
  5. package/contributions/blender-icons.source.mjs +2925 -0
  6. package/contributions/blender-node-editor.document.tsx +1402 -0
  7. package/contributions/blender-node-geometry.ts +1138 -0
  8. package/contributions/blender-node-panels.source.mjs +485 -0
  9. package/contributions/blender-outliner-authoring.ts +1729 -0
  10. package/contributions/blender-outliner-model.ts +389 -0
  11. package/contributions/blender-palette.source.mjs +319 -0
  12. package/contributions/blender-properties-model.ts +351 -0
  13. package/contributions/blender-properties-tab.tsx +100 -0
  14. package/contributions/blender-properties-view.tsx +1191 -0
  15. package/contributions/blender-runtime-skin.ts +619 -0
  16. package/contributions/blender-runtime.document.tsx +232 -0
  17. package/contributions/blender-timeline-geometry.ts +323 -0
  18. package/contributions/blender-timeline.document.tsx +1056 -0
  19. package/contributions/blender-uv-editor.document.tsx +483 -0
  20. package/contributions/blender-uv-geometry.ts +305 -0
  21. package/contributions/blender-version.status.tsx +93 -0
  22. package/contributions/blender.command.ts +102 -0
  23. package/contributions/blender.icons.json +1247 -0
  24. package/contributions/blender.icons.traced.json +1561 -0
  25. package/contributions/blender.keymap.ts +39 -0
  26. package/contributions/blender.node-panels.json +2436 -0
  27. package/contributions/blender.palette.json +93 -0
  28. package/contributions/blender.status.tsx +263 -0
  29. package/contributions/blender.style.ts +271 -0
  30. package/contributions/model.layout.ts +53 -0
  31. package/contributions/models.finder.ts +59 -0
  32. package/contributions/properties-bone-constraints.inspector.tsx +50 -0
  33. package/contributions/properties-bone.inspector.tsx +184 -0
  34. package/contributions/properties-collection.inspector.tsx +96 -0
  35. package/contributions/properties-constraints.inspector.tsx +69 -0
  36. package/contributions/properties-data.inspector.tsx +229 -0
  37. package/contributions/properties-material.inspector.tsx +121 -0
  38. package/contributions/properties-modifiers.inspector.tsx +74 -0
  39. package/contributions/properties-object.inspector.tsx +215 -0
  40. package/contributions/properties-output.inspector.tsx +210 -0
  41. package/contributions/properties-particles.inspector.tsx +494 -0
  42. package/contributions/properties-physics.inspector.tsx +614 -0
  43. package/contributions/properties-render.inspector.tsx +446 -0
  44. package/contributions/properties-scene.inspector.tsx +174 -0
  45. package/contributions/properties-texture.inspector.tsx +300 -0
  46. package/contributions/properties-view-layer.inspector.tsx +145 -0
  47. package/contributions/properties-world.inspector.tsx +130 -0
  48. package/contributions/sculpt.layout.ts +25 -0
  49. package/contributions/shading.layout.ts +99 -0
  50. package/contributions/texture.layout.ts +16 -0
  51. package/contributions/uv-editing.layout.ts +93 -0
  52. package/host/blender-runtime-host.ts +1256 -0
  53. package/package.json +77 -0
  54. package/src/layouts.tsx +48 -0
  55. package/src/looks.ts +14 -0
  56. package/src/node-view-state.ts +125 -0
  57. package/src/timeline-view-state.ts +154 -0
  58. package/src/uv-view-state.ts +125 -0
@@ -0,0 +1,229 @@
1
+ /**
2
+ * BLENDER'S OBJECT DATA 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 of the whole datablock beneath under "All
5
+ * properties".
6
+ *
7
+ * THE SPECIFICATION IS `scripts/startup/bl_ui/properties_data_mesh.py`, read
8
+ * at the engine's pin: its `classes` tuple is the panel ORDER, each class's
9
+ * `bl_label` the title, each `layout.prop(me, "x")` an entry in the order the
10
+ * draw function lists it, `bl_options = {'DEFAULT_CLOSED'}` a `closed`, and a
11
+ * `template_list` a `collection` panel. Blender's UI layer is never run,
12
+ * ported or recorded.
13
+ *
14
+ * ONE TAB, MANY DATA TYPES, ONE LIST. `buttons_context_path_data` builds this
15
+ * tab for whatever the object's data IS, so the same section draws a Mesh, an
16
+ * Armature, a Camera or a Light — and the panels for all of them live in one
17
+ * list here, because a panel draws only where its properties exist. A Camera's
18
+ * data carries no `remesh_mode`, so the Remesh panel finds nothing and renders
19
+ * nothing; an Armature's carries no `uv_layers` and every mesh panel stands
20
+ * down for it. That is the same answer `MeshButtonsPanel.poll` /
21
+ * `ArmatureButtonsPanel.poll` give, from the datablock rather than from a copy
22
+ * of their conditions — which is why there is no per-type branch in this file
23
+ * and no second module per data type.
24
+ *
25
+ * NO "NORMALS" PANEL: the brief expected one and 5.2 does not have it. The
26
+ * mesh's `DATA_PT_normals` was folded away before this pin — `has_custom_normals`
27
+ * survives as the Geometry Data panel's operator condition (`:456`), and the
28
+ * shading-per-face data now lives on the Attributes list. Stated rather than
29
+ * invented.
30
+ *
31
+ * It stands when: `buttons_context_path_data` — the object HAS data (an Empty
32
+ * usually has none).
33
+ */
34
+ import type { ToolContributionNode } from '@volter/editor-sdk/contributions';
35
+ import { blenderPropertiesState, resolveBlenderSubject } from './blender-properties-model';
36
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
37
+ import type { BlenderCuratedPanel } from './blender-properties-view';
38
+
39
+ /** `properties_data_mesh.py`, panel by panel. Line numbers are that file's. */
40
+ const CURATED: readonly BlenderCuratedPanel[] = [
41
+ {
42
+ // DATA_PT_vertex_groups, :198 — `template_list` over `ob.vertex_groups`,
43
+ // then the active group's name and lock (`MESH_UL_vgroups.draw_item`,
44
+ // :127). The door hands this tab the object's collection as its own path
45
+ // because a vertex group lives on the OBJECT, not on the mesh.
46
+ title: 'Vertex Groups',
47
+ from: 'Vertex Groups',
48
+ collection: true,
49
+ active: 'activeVertexGroup',
50
+ properties: ['name', 'index', 'lock_weight'],
51
+ },
52
+ {
53
+ // DATA_PT_shape_keys, :300 — `template_list` over `key.key_blocks`, with
54
+ // each key's value and slider range (:282-294). The door names the Key
55
+ // datablock; its `key_blocks` is the list.
56
+ title: 'Shape Keys',
57
+ from: 'Shape Keys',
58
+ properties: ['key_blocks', 'use_relative', 'eval_time', 'reference_key'],
59
+ },
60
+ {
61
+ // DATA_PT_uv_texture, :377 — `template_list` over `mesh.uv_layers`
62
+ // (`MESH_UL_uvmaps.draw_item`, :135: the name and `active_render`).
63
+ title: 'UV Maps',
64
+ properties: ['uv_layers'],
65
+ },
66
+ {
67
+ // DATA_PT_vertex_colors, :683 — `mesh.color_attributes`.
68
+ title: 'Color Attributes',
69
+ properties: ['color_attributes'],
70
+ },
71
+ {
72
+ // DATA_PT_mesh_attributes, :545 — `mesh.attributes`.
73
+ title: 'Attributes',
74
+ properties: ['attributes'],
75
+ },
76
+ {
77
+ // DATA_PT_texture_space, :173.
78
+ title: 'Texture Space',
79
+ closed: true,
80
+ properties: ['texture_mesh', 'use_auto_texspace', 'texspace_location', 'texspace_size'],
81
+ },
82
+ {
83
+ // DATA_PT_remesh, :403.
84
+ title: 'Remesh',
85
+ closed: true,
86
+ properties: [
87
+ 'remesh_mode',
88
+ 'remesh_voxel_size',
89
+ 'remesh_voxel_adaptivity',
90
+ 'use_remesh_fix_poles',
91
+ 'use_remesh_preserve_volume',
92
+ 'use_remesh_preserve_attributes',
93
+ ],
94
+ },
95
+ {
96
+ // DATA_PT_customdata, :435, titled "Geometry Data". Its body is FIVE
97
+ // OPERATORS and one condition (`has_custom_normals`, :456) — no
98
+ // properties at all. Inspection parity is not editing parity
99
+ // (ARCHITECTURE-CORE §Blender north star), so what stands here is the
100
+ // condition the operators branch on, which is the only thing in the panel
101
+ // a reader can learn something from.
102
+ title: 'Geometry Data',
103
+ closed: true,
104
+ properties: ['has_custom_normals', 'total_vert_sel', 'total_edge_sel', 'total_face_sel'],
105
+ },
106
+ {
107
+ // DATA_PT_mesh_animation, :461 — and DATA_PT_armature_animation, the same
108
+ // panel on an armature.
109
+ title: 'Animation',
110
+ closed: true,
111
+ properties: ['animation_data'],
112
+ },
113
+
114
+ // ---- `properties_data_armature.py`, for an ARMATURE's data. Same tab,
115
+ // same path, and each of these finds nothing on a mesh.
116
+ {
117
+ // DATA_PT_pose, :44 — Rest Position / Pose Position.
118
+ title: 'Pose',
119
+ properties: ['pose_position'],
120
+ },
121
+ {
122
+ // DATA_PT_bone_collections, :101 — `template_list` over
123
+ // `arm.collections_all`. The door also hands this tab the armature's BONES
124
+ // as a path of its own, which the next panel lists.
125
+ title: 'Bone Collections',
126
+ closed: true,
127
+ properties: ['collections_all', 'collections'],
128
+ },
129
+ {
130
+ // The armature's bones, which `buttons_context_path_data` puts on this
131
+ // tab's path list (`session.py::rna_context`) because Blender's Object
132
+ // Data tab is where an armature's skeleton is read. Blender itself draws
133
+ // them in the Outliner and the viewport rather than as a Properties list;
134
+ // this is the one panel here that is OURS, and it is named so.
135
+ title: 'Bones',
136
+ from: 'Bones',
137
+ collection: true,
138
+ active: 'activeBone',
139
+ properties: ['name', 'parent', 'use_connect', 'use_deform', 'head', 'tail', 'length'],
140
+ },
141
+ {
142
+ // DATA_PT_display, :55 (armature).
143
+ title: 'Viewport Display',
144
+ closed: true,
145
+ properties: [
146
+ 'display_type',
147
+ 'show_names',
148
+ 'show_bone_custom_shapes',
149
+ 'show_bone_colors',
150
+ 'show_axes',
151
+ 'axes_position',
152
+ 'relation_line_position',
153
+ ],
154
+ },
155
+ {
156
+ // DATA_PT_iksolver_itasc, :192.
157
+ title: 'Inverse Kinematics',
158
+ closed: true,
159
+ properties: ['pose'],
160
+ },
161
+ ];
162
+
163
+ const TAB = { id: 'data', curated: CURATED } as const;
164
+
165
+ export const point = 'selection.inspector';
166
+ export const title = 'Object Data';
167
+
168
+ /**
169
+ * THE DATA TAB'S GLYPH IS PER OBJECT TYPE, and it is the one tab in the rail
170
+ * that is. `buttons_context_items` gives it `ICON_NONE`
171
+ * (`makesrna/intern/rna_space.cc:595`) because `buttons_context_compute`
172
+ * fills it in at read time: `sbuts->dataicon = RNA_struct_ui_icon(ptr->type)`
173
+ * over the data on the context path, with Light special-cased to
174
+ * `ICON_OUTLINER_DATA_LIGHT` (`space_buttons/buttons_context.cc:795-810`).
175
+ * So a mesh's tab is the MESH_DATA triangle, an armature's the ARMATURE_DATA
176
+ * figure, a camera's the camera body.
177
+ *
178
+ * Each key below is the RNA STRUCT's own `bl_rna.identifier` — which is what
179
+ * `rna_context` reports as `active.dataType` — and each value is the glyph
180
+ * traced from the icon that struct's `RNA_def_struct_ui_icon` call names.
181
+ */
182
+ const DATA_GLYPHS: Readonly<Record<string, string>> = {
183
+ Mesh: 'properties-data-mesh', // rna_mesh.cc:2916 ICON_MESH_DATA
184
+ Armature: 'properties-data-armature', // rna_armature.cc:2191 ICON_ARMATURE_DATA
185
+ Curve: 'properties-data-curve', // rna_curve.cc:1685 ICON_CURVE_DATA
186
+ SurfaceCurve: 'properties-data-surface', // ICON_SURFACE_DATA
187
+ MetaBall: 'properties-data-meta', // rna_meta.cc:331 ICON_META_DATA
188
+ TextCurve: 'properties-data-font', // ICON_FONT_DATA
189
+ Lattice: 'properties-data-lattice', // rna_lattice.cc:337 ICON_LATTICE_DATA
190
+ Camera: 'properties-data-camera', // rna_camera.cc:741 ICON_CAMERA_DATA
191
+ Light: 'properties-data-light', // special-cased above ICON_OUTLINER_DATA_LIGHT
192
+ Speaker: 'properties-data-speaker', // rna_speaker.cc:40 ICON_SPEAKER
193
+ PointCloud: 'properties-data-pointcloud', // rna_pointcloud.cc:174 ICON_POINTCLOUD_DATA
194
+ Volume: 'properties-data-volume', // rna_volume.cc:278 ICON_VOLUME_DATA
195
+ };
196
+
197
+ /**
198
+ * The host reads either a NAME or a function of the subject
199
+ * (`tool-loader.ts`'s `LoadedToolContributionBase.icon`). The type comes from
200
+ * the context the door last answered for this subject — the same read every
201
+ * tab's `match()` drives — so no extra engine call happens to paint a glyph,
202
+ * and before the first answer lands the tab draws the mesh mark, which is what
203
+ * Blender shows for the starter cube.
204
+ */
205
+ export const icon = (node: ToolContributionNode | null, adapter: unknown): string => {
206
+ const subject = resolveBlenderSubject(node, adapter);
207
+ if (subject === null || subject.kind !== 'object') return 'properties-data';
208
+ const state = blenderPropertiesState();
209
+ if (state.object !== subject.name) return 'properties-data';
210
+ const type = state.context?.active?.dataType;
211
+ // An object with no data at all draws Blender's EMPTY_DATA — though the tab
212
+ // itself does not stand for one (`buttons_context_path_data` fails), so this
213
+ // arm is what a type this table has no row for falls back to rather than a
214
+ // state the rail normally shows.
215
+ if (type === null || type === undefined) return 'properties-data-empty';
216
+ return DATA_GLYPHS[type] ?? 'properties-data';
217
+ };
218
+
219
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
220
+ * these are that order, spaced so a tab can be inserted between two. */
221
+ export const order = 120;
222
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
223
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
224
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
225
+ * object group (Object … Material), then Texture. The presentation draws a
226
+ * separator wherever this changes. */
227
+ export const railGroup = 'object';
228
+ export const match = blenderPropertiesTabMatch(TAB);
229
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,121 @@
1
+ /**
2
+ * BLENDER'S MATERIAL TAB, as a Properties section (WORK.md §Blender in the tab
3
+ * 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_material.py` at the
7
+ * engine's pin — its `classes` tuple is the panel order, `bl_label` the
8
+ * title, each `layout.prop(mat, "x")` an entry. Blender's UI layer is never
9
+ * run, ported or recorded.
10
+ *
11
+ * THE SLOTS LIST IS FIRST, and it is `MATERIAL_UL_matslots` over
12
+ * `ob.material_slots` (`:76`, `EEVEE_MATERIAL_PT_context_material`, whose
13
+ * `bl_label` is empty because in Blender it is the tab's header block rather
14
+ * than a panel). The context door hands it to this tab as its own path, with
15
+ * the ACTIVE slot named separately (`buttons_context_path_material`:
16
+ * `BKE_object_material_get(ob, ob->actcol)`), so the list marks it.
17
+ *
18
+ * SURFACE IS A NODE TREE, AND THIS IS NOT THE NODE VIEW. Blender's Surface
19
+ * panel (`:164`) calls `panel_node_draw`, which walks the material output
20
+ * node's `Surface` input back to the shader that feeds it and draws THAT
21
+ * node's inputs by name. Showing those values as a flat list needs the node
22
+ * tree walked, which is I5's read-only node view (§Inspection parity, I5) —
23
+ * and a half version of it here would be a second, worse implementation of
24
+ * the same walk. What stands in this panel instead is what the MATERIAL
25
+ * itself holds: `use_nodes` and the `node_tree` pointer, which drills into
26
+ * the generic view, plus the settings Blender's own EEVEE panels read off the
27
+ * material datablock directly.
28
+ *
29
+ * It stands when: `buttons_context_path_material` — the object's data holds a
30
+ * `materials` collection (the tab stands even when the active slot is empty).
31
+ */
32
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
33
+ import type { BlenderCuratedPanel } from './blender-properties-view';
34
+
35
+ /** `properties_material.py`, panel by panel. Line numbers are that file's. */
36
+ const CURATED: readonly BlenderCuratedPanel[] = [
37
+ {
38
+ // EEVEE_MATERIAL_PT_context_material, :76 — the slot list. `link` is the
39
+ // slot's own Object/Data toggle, `material` the pointer it holds.
40
+ title: 'Material Slots',
41
+ from: 'Material Slots',
42
+ collection: true,
43
+ active: 'activeMaterial',
44
+ properties: ['name', 'material', 'link', 'slot_index'],
45
+ },
46
+ {
47
+ // EEVEE_MATERIAL_PT_surface, :164 — see the header for why this is the
48
+ // material's own two node properties rather than the shader's inputs.
49
+ title: 'Surface',
50
+ from: 'Material',
51
+ properties: ['use_nodes', 'node_tree', 'surface_render_method', 'use_backface_culling'],
52
+ },
53
+ {
54
+ // EEVEE_MATERIAL_PT_volume (:178) and _displacement (:201) / _thickness
55
+ // (:223), all three of them node-tree panels like Surface; what the
56
+ // material holds for them is its own.
57
+ title: 'Volume',
58
+ closed: true,
59
+ from: 'Material',
60
+ properties: ['volume_intersection_method', 'displacement_method', 'max_vertex_displacement'],
61
+ },
62
+ {
63
+ // EEVEE_MATERIAL_PT_settings (:297) and its two children (:322, :338).
64
+ title: 'Settings',
65
+ closed: true,
66
+ from: 'Material',
67
+ properties: [
68
+ 'pass_index',
69
+ 'use_backface_culling_shadow',
70
+ 'use_backface_culling_lightprobe_volume',
71
+ 'use_transparent_shadow',
72
+ 'use_transparency_overlap',
73
+ 'use_raytrace_refraction',
74
+ 'thickness_mode',
75
+ 'use_thickness_from_shadow',
76
+ ],
77
+ },
78
+ {
79
+ // MATERIAL_PT_lineart, :377 — reads `mat.lineart`, a sub-struct, so its
80
+ // pointer row stands and the values are one drill down.
81
+ title: 'Line Art',
82
+ closed: true,
83
+ from: 'Material',
84
+ properties: ['lineart'],
85
+ },
86
+ {
87
+ // MATERIAL_PT_viewport, :354 — the three values the solid viewport
88
+ // shades with, which is what our own three.js presenter reads.
89
+ title: 'Viewport Display',
90
+ from: 'Material',
91
+ properties: ['diffuse_color', 'metallic', 'roughness'],
92
+ },
93
+ {
94
+ // MATERIAL_PT_animation, :390-ish (after Line Art in the `classes` tuple).
95
+ title: 'Animation',
96
+ closed: true,
97
+ from: 'Material',
98
+ properties: ['animation_data'],
99
+ },
100
+ ];
101
+
102
+ const TAB = { id: 'material', curated: CURATED } as const;
103
+
104
+ export const point = 'selection.inspector';
105
+ export const title = 'Material';
106
+ /** `blender.icons.json` — Blender's own mark, TRACED from
107
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
108
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
109
+ * and tinted by the group `UI_icons.hh` declares it in. */
110
+ export const icon = 'properties-material';
111
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
112
+ * these are that order, spaced so a tab can be inserted between two. */
113
+ export const order = 160;
114
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
115
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
116
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
117
+ * object group (Object … Material), then Texture. The presentation draws a
118
+ * separator wherever this changes. */
119
+ export const railGroup = 'object';
120
+ export const match = blenderPropertiesTabMatch(TAB);
121
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,74 @@
1
+ /**
2
+ * BLENDER'S MODIFIERS TAB, as a Properties section (WORK.md §Blender in the
3
+ * tab is Blender, "Inspection parity", I2): the STACK, each modifier its own
4
+ * panel with its own settings, with the generic view beneath under "All
5
+ * properties".
6
+ *
7
+ * THE SPECIFICATION IS `scripts/startup/bl_ui/properties_data_modifier.py` at
8
+ * the engine's pin, and reading it is what decided the shape here. That file
9
+ * is barely a panel list at all: `DATA_PT_modifiers.draw` is `Add Modifier`
10
+ * plus `layout.template_modifiers()`, and the per-modifier panels are built in
11
+ * C from each type's own RNA (`MOD_*.cc`'s `panel_draw`). There is no Python
12
+ * table of sixty modifier types to transcribe — and transcribing one would be
13
+ * a COPY of Blender's layout, which the ruling forbids, and would go stale the
14
+ * first time a modifier gained a property.
15
+ *
16
+ * So the stack is derived instead: each member of `ob.modifiers` is a panel
17
+ * headed by the four toggles every modifier has (`ModifierData`'s own
18
+ * `show_viewport` / `show_render` / `show_in_editmode` / `show_on_cage`,
19
+ * which is the header row `template_modifiers` draws), followed by every
20
+ * property THIS MODIFIER'S OWN struct declares — `andDeclared`, which reads
21
+ * `BlenderRnaRow.group`, RNA's own answer to "which struct declares this".
22
+ * For a Subdivision modifier that is exactly `SubsurfModifier`'s levels,
23
+ * render_levels, quality, uv_smooth and the rest, in RNA's order.
24
+ *
25
+ * The ACTIVE modifier (`buttons_context_path_modifier`, which the door reports
26
+ * as `activeModifier`) is marked, the way Blender outlines the active panel.
27
+ *
28
+ * It stands when: the object's type is in `buttons_context.cc`'s modifier set.
29
+ */
30
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
31
+ import type { BlenderCuratedPanel } from './blender-properties-view';
32
+
33
+ const CURATED: readonly BlenderCuratedPanel[] = [
34
+ {
35
+ title: 'Modifiers',
36
+ from: 'Modifiers',
37
+ collection: true,
38
+ active: 'activeModifier',
39
+ // `ModifierData`'s own, in the order `template_modifiers` heads a panel
40
+ // with them; everything after these is the type's own (see the header).
41
+ properties: [
42
+ 'name',
43
+ 'type',
44
+ 'show_viewport',
45
+ 'show_render',
46
+ 'show_in_editmode',
47
+ 'show_on_cage',
48
+ 'use_pin_to_last',
49
+ 'is_active',
50
+ ],
51
+ andDeclared: true,
52
+ },
53
+ ];
54
+
55
+ const TAB = { id: 'modifier', curated: CURATED } as const;
56
+
57
+ export const point = 'selection.inspector';
58
+ export const title = 'Modifiers';
59
+ /** `blender.icons.json` — Blender's own mark, TRACED from
60
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
61
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
62
+ * and tinted by the group `UI_icons.hh` declares it in. */
63
+ export const icon = 'properties-modifiers';
64
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
65
+ * these are that order, spaced so a tab can be inserted between two. */
66
+ export const order = 80;
67
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
68
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
69
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
70
+ * object group (Object … Material), then Texture. The presentation draws a
71
+ * separator wherever this changes. */
72
+ export const railGroup = 'object';
73
+ export const match = blenderPropertiesTabMatch(TAB);
74
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,215 @@
1
+ /**
2
+ * BLENDER'S OBJECT TAB, as a Properties section (WORK.md §Blender in the tab
3
+ * is Blender, "Inspection parity", I2). The body is Blender's own panels, in
4
+ * Blender's own order, over the RNA door; the generic view of every property
5
+ * the object has stays beneath them under "All properties".
6
+ *
7
+ * THE SPECIFICATION IS `scripts/startup/bl_ui/properties_object.py`, read at
8
+ * the engine's pin. Its `classes` tuple at the foot of the file is the panel
9
+ * ORDER, each class's `bl_label` the title, each `layout.prop(ob, "x")` an
10
+ * entry below in the order the draw function lists it, and `bl_options =
11
+ * {'DEFAULT_CLOSED'}` a `closed: true`. Blender's UI layer is never run,
12
+ * ported or recorded — the Python is read as a statement of WHICH properties
13
+ * this tab shows, and our widgets draw them from the door's rows.
14
+ *
15
+ * WHAT THE TRANSCRIPTION DELIBERATELY DROPS:
16
+ * - the `poll`/`if` branches. `show_all_edges` is mesh-only in Python; here
17
+ * it is simply not on a Camera's RNA, so it does not draw. Same outcome,
18
+ * from the datablock rather than from a copy of Blender's conditions.
19
+ * - `OBJECT_PT_context_object` (`bl_label = ""`) — the breadcrumb row, which
20
+ * is the host's identity row here.
21
+ * - the four panels whose datablock is NOT the object: Motion Paths reads
22
+ * `ob.animation_visualization` and `ob.motion_path`, Light/Shadow Linking
23
+ * their collections. The context door names the object, so those are
24
+ * reached by drilling their POINTER row in the generic view beneath — a
25
+ * curated panel addresses one of the TAB's own datablocks, and inventing a
26
+ * second addressing scheme to reach a sub-struct is the kind of machinery
27
+ * the generic view exists to make unnecessary.
28
+ *
29
+ * It stands when: `buttons_context_path_object` — there is an active object.
30
+ */
31
+
32
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
33
+ import type { BlenderCuratedPanel } from './blender-properties-view';
34
+
35
+ /** `properties_object.py`, panel by panel. Line numbers are that file's. */
36
+ const CURATED: readonly BlenderCuratedPanel[] = [
37
+ {
38
+ // OBJECT_PT_transform, :36. Blender draws the rotation channel that
39
+ // `rotation_mode` selects; all three are listed, and the two the object is
40
+ // not in are still real RNA, so all three draw. That is MORE than Blender
41
+ // shows and it is the honest reading: the door reports what the object
42
+ // holds, and a quaternion object's euler is not a fiction.
43
+ title: 'Transform',
44
+ properties: [
45
+ 'location',
46
+ 'lock_location',
47
+ 'rotation_quaternion',
48
+ 'rotation_axis_angle',
49
+ 'rotation_euler',
50
+ 'lock_rotation_w',
51
+ 'lock_rotation',
52
+ 'rotation_mode',
53
+ 'scale',
54
+ 'lock_scale',
55
+ ],
56
+ },
57
+ {
58
+ // OBJECT_PT_delta_transform, :86.
59
+ title: 'Delta Transform',
60
+ closed: true,
61
+ properties: [
62
+ 'delta_location',
63
+ 'delta_rotation_quaternion',
64
+ 'delta_rotation_euler',
65
+ 'delta_scale',
66
+ ],
67
+ },
68
+ {
69
+ // OBJECT_PT_relations, :132.
70
+ title: 'Relations',
71
+ closed: true,
72
+ properties: [
73
+ 'parent',
74
+ 'parent_type',
75
+ 'parent_bone',
76
+ 'parent_bone_head_tail_factor',
77
+ 'parent_vertices',
78
+ 'use_parent_final_indices',
79
+ 'use_camera_lock_parent',
80
+ 'track_axis',
81
+ 'up_axis',
82
+ 'pass_index',
83
+ ],
84
+ },
85
+ {
86
+ // OBJECT_PT_collections, :185 — a UIList of the collections this object is
87
+ // in. `users_collection` is the RNA behind it.
88
+ title: 'Collections',
89
+ closed: true,
90
+ properties: ['users_collection'],
91
+ },
92
+ {
93
+ // OBJECT_PT_instancing, :284, with OBJECT_PT_instancing_size (:317) as its
94
+ // `bl_parent_id` child.
95
+ title: 'Instancing',
96
+ closed: true,
97
+ properties: [
98
+ 'instance_type',
99
+ 'use_instance_vertices_rotation',
100
+ 'instance_collection',
101
+ 'show_instancer_for_viewport',
102
+ 'show_instancer_for_render',
103
+ ],
104
+ sub: [
105
+ {
106
+ title: 'Scale by Face Size',
107
+ closed: true,
108
+ properties: ['use_instance_faces_scale', 'instance_faces_scale'],
109
+ },
110
+ ],
111
+ },
112
+ {
113
+ // OBJECT_PT_display, :218.
114
+ title: 'Viewport Display',
115
+ closed: true,
116
+ properties: [
117
+ 'show_name',
118
+ 'show_axis',
119
+ 'show_wire',
120
+ 'show_all_edges',
121
+ 'show_texture_space',
122
+ 'show_in_front',
123
+ 'display_type',
124
+ 'color',
125
+ 'show_bounds',
126
+ 'display_bounds_type',
127
+ 'display',
128
+ ],
129
+ },
130
+ {
131
+ // OBJECT_PT_shadow_terminator, :602.
132
+ title: 'Shadow Terminator',
133
+ closed: true,
134
+ properties: [
135
+ 'shadow_terminator_normal_offset',
136
+ 'shadow_terminator_geometry_offset',
137
+ 'shadow_terminator_shading_offset',
138
+ ],
139
+ },
140
+ {
141
+ // OBJECT_PT_visibility, :412. Blender draws four of these INVERTED
142
+ // (`invert_checkbox=True`, so "Selectable" is `not hide_select`); the
143
+ // checkbox here is the RNA's own value and its label is the RNA's own
144
+ // name, because inverting a value in the presentation is exactly the
145
+ // fabrication the anti-shim rule forbids.
146
+ title: 'Visibility',
147
+ closed: true,
148
+ properties: [
149
+ 'hide_select',
150
+ 'hide_surface_pick',
151
+ 'hide_viewport',
152
+ 'hide_render',
153
+ 'visible_camera',
154
+ 'visible_shadow',
155
+ 'visible_raycast',
156
+ 'visible_diffuse',
157
+ 'visible_glossy',
158
+ 'visible_transmission',
159
+ 'visible_volume_scatter',
160
+ 'hide_probe_volume',
161
+ 'hide_probe_sphere',
162
+ 'hide_probe_plane',
163
+ 'use_grease_pencil_lights',
164
+ 'is_holdout',
165
+ ],
166
+ },
167
+ {
168
+ // OBJECT_PT_lineart, :340 — the panel reads `ob.lineart`, a sub-struct, so
169
+ // what stands here is its POINTER row; the values are one drill down.
170
+ title: 'Line Art',
171
+ closed: true,
172
+ properties: ['lineart'],
173
+ },
174
+ {
175
+ // OBJECT_PT_animation (:631) and OBJECT_PT_custom_props (:635).
176
+ title: 'Animation',
177
+ closed: true,
178
+ properties: ['animation_data'],
179
+ },
180
+ ];
181
+
182
+ const TAB = { id: 'object', standing: 'object', curated: CURATED } as const;
183
+
184
+ export const point = 'selection.inspector';
185
+ export const title = 'Object';
186
+ /** `blender.icons.json` — Blender's own mark, TRACED from
187
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
188
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
189
+ * and tinted by the group `UI_icons.hh` declares it in. */
190
+ export const icon = 'properties-object';
191
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
192
+ * these are that order, spaced so a tab can be inserted between two. */
193
+ export const order = 70;
194
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
195
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
196
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
197
+ * object group (Object … Material), then Texture. The presentation draws a
198
+ * separator wherever this changes. */
199
+ export const railGroup = 'object';
200
+ /** THE TAB THE RAIL OPENS ON. Blender's Properties editor stores its context
201
+ * per screen in the startup file, and at factory settings the Layout
202
+ * workspace's is OBJECT:
203
+ *
204
+ * bpy.data.screens['Layout'].areas[PROPERTIES].spaces[0].context -> 'OBJECT'
205
+ *
206
+ * (measured against Blender 5.2.0 LTS at `--factory-startup`, walk 5 parity
207
+ * row 3; the other screens read OBJECT, MODIFIER, WORLD, DATA, TOOL, OUTPUT
208
+ * and RENDER, so a per-workspace default is the next fidelity step and this
209
+ * one declaration is the Layout/Model answer). Without it the rail opened on
210
+ * Render — the first tab in `ED_buttons_tabs_list`'s order — and a person
211
+ * selecting the cube got Sampling and Light Paths where Blender shows
212
+ * Transform. */
213
+ export const railDefault = true;
214
+ export const match = blenderPropertiesTabMatch(TAB);
215
+ export default blenderPropertiesTabSection(TAB);