@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,300 @@
1
+ /**
2
+ * BLENDER'S TEXTURE 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_texture.py` at the
7
+ * engine's pin — `classes` (`:958-986`) is the panel order and `bl_label` the
8
+ * title — AND `space_buttons/buttons_texture.cc`, which is the only thing
9
+ * that can say WHICH texture this tab is about. Blender's UI layer is never
10
+ * run, ported or recorded.
11
+ *
12
+ * THIS TAB HAS NO DATABLOCK OF ITS OWN; IT HAS A USER.
13
+ * `buttons_texture_users_from_context` (`buttons_texture.cc:244-366`) walks
14
+ * the context for every struct holding a texture pointer, in this order: the
15
+ * scene's compositing node tree ("Compositor"), the active line style's slots
16
+ * and node tree ("Line Style"), the object's modifiers ("Modifiers"), the
17
+ * ACTIVE particle system's `part.mtex[]` ("Particles"), the object's force
18
+ * field when its type is TEXTURE ("Fields"), and the active paint brush's own
19
+ * two slots ("Brush"). `buttons_texture_context_compute` (`:369`) then takes
20
+ * user `ct->index` — 0 unless a person picks another from the menu — and the
21
+ * texture it points at is `context.texture`. The door mirrors that walk in
22
+ * the C's own order and names the resolved texture as this tab's first path,
23
+ * the holder as its second, and `bpy.data.textures` as its third; the whole
24
+ * user list is on the context as `textureUsers` for anything that wants it.
25
+ *
26
+ * A LIGHT IS NOT A TEXTURE USER AT THIS PIN, and it is worth saying because
27
+ * older Blenders make it a reasonable guess: the C never looks at `ob->data`.
28
+ * Lamp textures went with 2.8's renderer rewrite. Measured, not remembered.
29
+ *
30
+ * THE TYPE PANELS ARE THE `when` MECHANISM'S OTHER HOME. `TextureTypePanel`
31
+ * (`:167`) is `tex.type == cls.tex_type and not tex.use_nodes`, once per type
32
+ * — every one of those properties lives on the same `Texture` struct under
33
+ * every type, so RNA cannot answer it and the condition is read from the
34
+ * engine's live value.
35
+ *
36
+ * WHAT THE TRANSCRIPTION DELIBERATELY DROPS:
37
+ * - `TEXTURE_PT_preview` (`:68`) and `TEXTURE_PT_context` (`:99`) — a
38
+ * `template_preview` render and the user-picker/ID templates. The picker
39
+ * is an editing widget; what it selects is the context door's answer here.
40
+ * - `TEXTURE_PT_node` (`:143`), `template_node_view` over the active texture
41
+ * node — the read-only node view is I5.
42
+ * - `template_image` (`:404`) and `template_color_ramp` (`:910`) — an image
43
+ * browser and a ramp widget; the `image` pointer and the `color_ramp`
44
+ * pointer stand and drill.
45
+ * - `TEXTURE_PT_custom_props` (`:953`), IDProperties rather than RNA.
46
+ *
47
+ * It stands when: the door's mirror of `buttons_texture_context_compute`
48
+ * finds a user, or the file holds textures at all.
49
+ */
50
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
51
+ import type { BlenderCuratedPanel } from './blender-properties-view';
52
+
53
+ /** `TextureTypePanel.poll` (`:167-173`) for one `tex_type`, as conditions. */
54
+ const ofType = (type: string) =>
55
+ [
56
+ { from: 'Texture', property: 'type', is: [type] },
57
+ { from: 'Texture', property: 'use_nodes', is: [false] },
58
+ ] as const;
59
+
60
+ /** `properties_texture.py`, panel by panel. Line numbers are that file's. */
61
+ const CURATED: readonly BlenderCuratedPanel[] = [
62
+ {
63
+ // TEXTURE_PT_context, :99 — its one property row (`tex.type`, :140);
64
+ // everything else in it is a template.
65
+ title: 'Texture',
66
+ from: 'Texture',
67
+ properties: ['type', 'use_nodes', 'node_tree'],
68
+ },
69
+ {
70
+ // TEXTURE_PT_clouds, :176.
71
+ title: 'Clouds',
72
+ from: 'Texture',
73
+ when: ofType('CLOUDS'),
74
+ properties: ['noise_basis', 'noise_type', 'cloud_type', 'noise_scale', 'noise_depth', 'nabla'],
75
+ },
76
+ {
77
+ // TEXTURE_PT_wood, :212.
78
+ title: 'Wood',
79
+ from: 'Texture',
80
+ when: ofType('WOOD'),
81
+ properties: [
82
+ 'noise_basis',
83
+ 'wood_type',
84
+ 'noise_basis_2',
85
+ 'noise_type',
86
+ 'noise_scale',
87
+ 'turbulence',
88
+ 'nabla',
89
+ ],
90
+ },
91
+ {
92
+ // TEXTURE_PT_marble, :253.
93
+ title: 'Marble',
94
+ from: 'Texture',
95
+ when: ofType('MARBLE'),
96
+ properties: [
97
+ 'noise_basis',
98
+ 'marble_type',
99
+ 'noise_basis_2',
100
+ 'noise_type',
101
+ 'noise_scale',
102
+ 'noise_depth',
103
+ 'turbulence',
104
+ 'nabla',
105
+ ],
106
+ },
107
+ {
108
+ // TEXTURE_PT_magic, :291.
109
+ title: 'Magic',
110
+ from: 'Texture',
111
+ when: ofType('MAGIC'),
112
+ properties: ['noise_depth', 'turbulence'],
113
+ },
114
+ {
115
+ // TEXTURE_PT_blend, :314.
116
+ title: 'Blend',
117
+ from: 'Texture',
118
+ when: ofType('BLEND'),
119
+ properties: ['progression', 'use_flip_axis'],
120
+ },
121
+ {
122
+ // TEXTURE_PT_stucci, :340.
123
+ title: 'Stucci',
124
+ from: 'Texture',
125
+ when: ofType('STUCCI'),
126
+ properties: ['noise_basis', 'stucci_type', 'noise_type', 'noise_scale', 'turbulence'],
127
+ },
128
+ {
129
+ // TEXTURE_PT_image, :375 — its body is `template_image`; the pointer row
130
+ // stands and its children carry the properties.
131
+ title: 'Image',
132
+ from: 'Texture',
133
+ when: ofType('IMAGE'),
134
+ properties: ['image', 'image_user'],
135
+ sub: [
136
+ {
137
+ // TEXTURE_PT_image_alpha, :430 — `use_alpha` is the header checkbox.
138
+ title: 'Alpha',
139
+ closed: true,
140
+ from: 'Texture',
141
+ properties: ['use_alpha', 'use_calculate_alpha', 'invert_alpha'],
142
+ },
143
+ {
144
+ // TEXTURE_PT_image_sampling, :407.
145
+ title: 'Sampling',
146
+ closed: true,
147
+ from: 'Texture',
148
+ properties: ['use_interpolation', 'filter_size'],
149
+ },
150
+ {
151
+ // TEXTURE_PT_image_mapping, :457, with its Crop child (:513).
152
+ title: 'Mapping',
153
+ closed: true,
154
+ from: 'Texture',
155
+ properties: [
156
+ 'use_flip_axis',
157
+ 'extension',
158
+ 'repeat_x',
159
+ 'repeat_y',
160
+ 'use_mirror_x',
161
+ 'use_mirror_y',
162
+ 'checker_distance',
163
+ 'use_checker_even',
164
+ 'use_checker_odd',
165
+ ],
166
+ sub: [
167
+ {
168
+ title: 'Crop',
169
+ closed: true,
170
+ from: 'Texture',
171
+ properties: ['crop_min_x', 'crop_min_y', 'crop_max_x', 'crop_max_y'],
172
+ },
173
+ ],
174
+ },
175
+ ],
176
+ },
177
+ {
178
+ // TEXTURE_PT_musgrave, :541.
179
+ title: 'Musgrave',
180
+ from: 'Texture',
181
+ when: ofType('MUSGRAVE'),
182
+ properties: [
183
+ 'noise_basis',
184
+ 'musgrave_type',
185
+ 'noise_scale',
186
+ 'nabla',
187
+ 'dimension_max',
188
+ 'lacunarity',
189
+ 'octaves',
190
+ 'offset',
191
+ 'noise_intensity',
192
+ 'gain',
193
+ ],
194
+ },
195
+ {
196
+ // TEXTURE_PT_voronoi, :590, with its Feature Weights child (:626).
197
+ title: 'Voronoi',
198
+ from: 'Texture',
199
+ when: ofType('VORONOI'),
200
+ properties: [
201
+ 'distance_metric',
202
+ 'minkovsky_exponent',
203
+ 'color_mode',
204
+ 'noise_intensity',
205
+ 'noise_scale',
206
+ 'nabla',
207
+ ],
208
+ sub: [
209
+ {
210
+ title: 'Feature Weights',
211
+ from: 'Texture',
212
+ properties: ['weight_1', 'weight_2', 'weight_3', 'weight_4'],
213
+ },
214
+ ],
215
+ },
216
+ {
217
+ // TEXTURE_PT_distortednoise, :652.
218
+ title: 'Distorted Noise',
219
+ from: 'Texture',
220
+ when: ofType('DISTORTED_NOISE'),
221
+ properties: ['noise_basis', 'noise_distortion', 'distortion', 'noise_scale', 'nabla'],
222
+ },
223
+ {
224
+ // TEXTURE_PT_mapping, :698 — a TextureSlotPanel: its rows are the SLOT's
225
+ // (`context.texture_slot`), which is the user the door resolved. A slot
226
+ // that is a node or a brush carries a different subset, and the rows it
227
+ // does not carry are simply not on its RNA.
228
+ title: 'Mapping',
229
+ from: 'User',
230
+ properties: [
231
+ 'texture_coords',
232
+ 'object',
233
+ 'uv_layer',
234
+ 'mapping',
235
+ 'mapping_x',
236
+ 'mapping_y',
237
+ 'mapping_z',
238
+ 'offset',
239
+ 'scale',
240
+ ],
241
+ },
242
+ {
243
+ // TEXTURE_PT_influence, :769 — also the slot's.
244
+ title: 'Influence',
245
+ closed: true,
246
+ from: 'User',
247
+ properties: ['blend_type', 'color'],
248
+ },
249
+ {
250
+ // TEXTURE_PT_colors, :855, with its Color Ramp child (:887).
251
+ title: 'Colors',
252
+ closed: true,
253
+ from: 'Texture',
254
+ properties: [
255
+ 'use_clamp',
256
+ 'factor_red',
257
+ 'factor_green',
258
+ 'factor_blue',
259
+ 'intensity',
260
+ 'contrast',
261
+ 'saturation',
262
+ ],
263
+ sub: [
264
+ {
265
+ title: 'Color Ramp',
266
+ closed: true,
267
+ from: 'Texture',
268
+ properties: ['use_color_ramp', 'color_ramp'],
269
+ },
270
+ ],
271
+ },
272
+ {
273
+ // TEXTURE_PT_animation, :915.
274
+ title: 'Animation',
275
+ closed: true,
276
+ from: 'Texture',
277
+ properties: ['animation_data'],
278
+ },
279
+ ];
280
+
281
+ const TAB = { id: 'texture', curated: CURATED } as const;
282
+
283
+ export const point = 'selection.inspector';
284
+ export const title = 'Texture';
285
+ /** `blender.icons.json` — Blender's own mark, TRACED from
286
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
287
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
288
+ * and tinted by the group `UI_icons.hh` declares it in. */
289
+ export const icon = 'properties-texture';
290
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
291
+ * these are that order, spaced so a tab can be inserted between two. */
292
+ export const order = 160;
293
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
294
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
295
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
296
+ * object group (Object … Material), then Texture. The presentation draws a
297
+ * separator wherever this changes. */
298
+ export const railGroup = 'texture';
299
+ export const match = blenderPropertiesTabMatch(TAB);
300
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,145 @@
1
+ /**
2
+ * BLENDER'S VIEW LAYER 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_view_layer.py` at the
7
+ * engine's pin — `classes` (`:345-360`) is the panel order, `bl_label` the
8
+ * title, each `layout.prop(view_layer, "x")` an entry. Blender's UI layer is
9
+ * never run, ported or recorded.
10
+ *
11
+ * THE PASSES PANEL IS TWO PANELS UNDER TWO ENGINES, and that is why this tab
12
+ * reads `COMPAT_ENGINES`. `VIEWLAYER_PT_eevee_layer_passes_data` (`:111`) and
13
+ * `VIEWLAYER_PT_workbench_layer_passes_data` (`:137`) carry the SAME
14
+ * `bl_label` ("Data") and differ only by engine — Workbench shows three
15
+ * passes where EEVEE shows seven, off the same `ViewLayer` datablock. Nothing
16
+ * about the datablock could say which; `rna_context`'s `engine` does. The
17
+ * Light panel (`:156`) is EEVEE-only for the same reason, and it also reads
18
+ * `view_layer.eevee`, which the context door names beside the layer.
19
+ *
20
+ * WHAT THE TRANSCRIPTION DELIBERATELY DROPS: `VIEWLAYER_PT_context_layer`
21
+ * (`:51`, `bl_label = ""`) — the layer search template, the host's identity
22
+ * row here; `VIEWLAYER_PT_layer_custom_props` (`:340`), IDProperties rather
23
+ * than RNA; and the AOV / light-group add-remove operators, which are
24
+ * editing rather than inspection. The two lists themselves are here as their
25
+ * collections.
26
+ *
27
+ * It stands when: `buttons_context_path_view_layer` — the window's view layer
28
+ * always resolves.
29
+ */
30
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
31
+ import type { BlenderCuratedPanel } from './blender-properties-view';
32
+
33
+ /** `properties_view_layer.py`, panel by panel. Line numbers are that file's. */
34
+ const CURATED: readonly BlenderCuratedPanel[] = [
35
+ {
36
+ // VIEWLAYER_PT_layer, :78 — `layer.use` then `rd.use_single_layer`.
37
+ title: 'View Layer',
38
+ properties: ['use', { from: 'Render', property: 'use_single_layer' }],
39
+ },
40
+ {
41
+ // VIEWLAYER_PT_layer_passes, :100 — an empty body with five children.
42
+ title: 'Passes',
43
+ properties: [],
44
+ sub: [
45
+ // VIEWLAYER_PT_eevee_layer_passes_data, :111.
46
+ {
47
+ title: 'Data',
48
+ engine: ['BLENDER_EEVEE'],
49
+ properties: [
50
+ 'use_pass_combined',
51
+ 'use_pass_z',
52
+ 'use_pass_mist',
53
+ 'use_pass_normal',
54
+ 'use_pass_position',
55
+ 'use_pass_vector',
56
+ 'use_pass_grease_pencil',
57
+ ],
58
+ },
59
+ // VIEWLAYER_PT_workbench_layer_passes_data, :137 — the same title under
60
+ // the other engine, with three of the seven.
61
+ {
62
+ title: 'Data',
63
+ engine: ['BLENDER_WORKBENCH'],
64
+ properties: ['use_pass_combined', 'use_pass_z', 'use_pass_grease_pencil'],
65
+ },
66
+ // VIEWLAYER_PT_eevee_layer_passes_light, :156 — `view_layer` and
67
+ // `view_layer_eevee = view_layer.eevee` (:169) in one list.
68
+ {
69
+ title: 'Light',
70
+ engine: ['BLENDER_EEVEE'],
71
+ properties: [
72
+ 'use_pass_diffuse_direct',
73
+ 'use_pass_diffuse_color',
74
+ 'use_pass_glossy_direct',
75
+ 'use_pass_glossy_color',
76
+ { from: 'EEVEE', property: 'use_pass_volume_direct' },
77
+ 'use_pass_emit',
78
+ 'use_pass_environment',
79
+ 'use_pass_shadow',
80
+ 'use_pass_ambient_occlusion',
81
+ { from: 'EEVEE', property: 'use_pass_transparent' },
82
+ { from: 'EEVEE', property: 'ambient_occlusion_distance' },
83
+ ],
84
+ },
85
+ // VIEWLAYER_PT_layer_passes_cryptomatte, :248, whose body is
86
+ // ViewLayerCryptomattePanelHelper.draw (:224).
87
+ {
88
+ title: 'Cryptomatte',
89
+ closed: true,
90
+ properties: [
91
+ 'use_pass_cryptomatte_object',
92
+ 'use_pass_cryptomatte_material',
93
+ 'use_pass_cryptomatte_asset',
94
+ 'pass_cryptomatte_depth',
95
+ ],
96
+ },
97
+ // VIEWLAYER_PT_layer_passes_aov, :219 (ViewLayerAOVPanelHelper, :194) —
98
+ // a `template_list` over `view_layer.aovs`.
99
+ { title: 'Shader AOV', closed: true, properties: ['aovs'] },
100
+ // VIEWLAYER_PT_layer_passes_lightgroups, :289
101
+ // (ViewLayerLightgroupsPanelHelper, :263).
102
+ { title: 'Light Groups', closed: true, properties: ['lightgroups'] },
103
+ ],
104
+ },
105
+ {
106
+ // VIEWLAYER_PT_filter, :294.
107
+ title: 'Filter',
108
+ closed: true,
109
+ properties: [
110
+ 'use_sky',
111
+ 'use_solid',
112
+ 'use_strand',
113
+ 'use_volumes',
114
+ 'use_grease_pencil',
115
+ 'use_motion_blur',
116
+ ],
117
+ },
118
+ {
119
+ // VIEWLAYER_PT_override, :320.
120
+ title: 'Override',
121
+ closed: true,
122
+ properties: ['material_override', 'world_override', 'samples'],
123
+ },
124
+ ];
125
+
126
+ const TAB = { id: 'view_layer', standing: 'any', curated: CURATED } as const;
127
+
128
+ export const point = 'selection.inspector';
129
+ export const title = 'View Layer';
130
+ /** `blender.icons.json` — Blender's own mark, TRACED from
131
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
132
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
133
+ * and tinted by the group `UI_icons.hh` declares it in. */
134
+ export const icon = 'properties-view-layer';
135
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
136
+ * these are that order, spaced so a tab can be inserted between two. */
137
+ export const order = 30;
138
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
139
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
140
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
141
+ * object group (Object … Material), then Texture. The presentation draws a
142
+ * separator wherever this changes. */
143
+ export const railGroup = 'scene';
144
+ export const match = blenderPropertiesTabMatch(TAB);
145
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,130 @@
1
+ /**
2
+ * BLENDER'S WORLD 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_world.py` at the
7
+ * engine's pin — `classes` (`:266-278`) is the panel order, `bl_label` the
8
+ * title, each `layout.prop(world, "x")` an entry. Blender's UI layer is never
9
+ * run, ported or recorded.
10
+ *
11
+ * SURFACE AND VOLUME ARE A NODE TREE, AND THIS IS NOT THE NODE VIEW.
12
+ * `EEVEE_WORLD_PT_surface` (`:109`) asks the world's node tree for its EEVEE
13
+ * output node and draws that node's `Surface` input with
14
+ * `template_node_view`; Volume (`:140`) is the same call on the `Volume`
15
+ * input. Reading those values as a flat list means walking the tree back
16
+ * through its links, which is I5's read-only node view (§Inspection parity,
17
+ * I5) — half of it here would be a second, worse implementation of the same
18
+ * walk. Exactly the reading the Material tab already made for its own Surface
19
+ * panel. What stands in these two panels is what the WORLD datablock itself
20
+ * holds: `use_nodes` and the `node_tree` pointer, which drills into the
21
+ * generic view, plus the volume flag Blender's own panel reads off the world
22
+ * (`use_eevee_finite_volume`, `:159`).
23
+ *
24
+ * THE TAB'S TONE IS THE SHADING RED. `UI_icons.hh:193` declares WORLD under
25
+ * `DEF_ICON_SHADING`, the same group as Material — corrected from a guess
26
+ * during I2's first landing, and the reason the scene group is four tabs
27
+ * rather than six.
28
+ *
29
+ * WHAT THE TRANSCRIPTION DELIBERATELY DROPS: `WORLD_PT_context_world`
30
+ * (`:24`, `bl_label = ""`) — the world ID template, the host's identity row
31
+ * here; the `world.convert_volume_to_mesh` operator (`:165`); and
32
+ * `WORLD_PT_custom_props` (`:99`), IDProperties rather than RNA.
33
+ *
34
+ * It stands when: `buttons_context_path_world` returns true from the scene
35
+ * alone, so the tab stands even when the scene holds no world — and then
36
+ * every panel here finds no datablock and none of them draw.
37
+ */
38
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
39
+ import type { BlenderCuratedPanel } from './blender-properties-view';
40
+
41
+ /** `properties_world.py`, panel by panel. Line numbers are that file's. */
42
+ const CURATED: readonly BlenderCuratedPanel[] = [
43
+ {
44
+ // EEVEE_WORLD_PT_surface, :109 — see the header for why this is the
45
+ // world's own node properties rather than the shader's inputs.
46
+ title: 'Surface',
47
+ engine: ['BLENDER_EEVEE'],
48
+ properties: ['use_nodes', 'node_tree'],
49
+ },
50
+ {
51
+ // EEVEE_WORLD_PT_volume, :140.
52
+ title: 'Volume',
53
+ closed: true,
54
+ engine: ['BLENDER_EEVEE'],
55
+ properties: ['use_eevee_finite_volume'],
56
+ },
57
+ {
58
+ // EEVEE_WORLD_PT_mist, :50 — `world.mist_settings` (:63), which the
59
+ // context door names as this tab's second datablock.
60
+ title: 'Mist Pass',
61
+ closed: true,
62
+ from: 'Mist',
63
+ engine: ['BLENDER_EEVEE'],
64
+ properties: ['start', 'depth', 'falloff'],
65
+ },
66
+ {
67
+ // EEVEE_WORLD_PT_settings, :174 — an empty body whose three children
68
+ // carry the properties (`bl_parent_id`).
69
+ title: 'Settings',
70
+ closed: true,
71
+ engine: ['BLENDER_EEVEE'],
72
+ properties: [],
73
+ sub: [
74
+ // EEVEE_WORLD_PT_lightprobe, :189.
75
+ { title: 'Light Probe', properties: ['probe_resolution'] },
76
+ {
77
+ // EEVEE_WORLD_PT_sun, :203, and its child Shadow (:218).
78
+ title: 'Sun',
79
+ properties: ['sun_threshold', 'sun_angle'],
80
+ sub: [
81
+ {
82
+ title: 'Shadow',
83
+ closed: true,
84
+ properties: [
85
+ 'use_sun_shadow',
86
+ 'use_sun_shadow_jitter',
87
+ 'sun_shadow_jitter_overblur',
88
+ 'sun_shadow_filter_radius',
89
+ 'sun_shadow_maximum_resolution',
90
+ ],
91
+ },
92
+ ],
93
+ },
94
+ ],
95
+ },
96
+ {
97
+ // WORLD_PT_viewport_display, :249 — the one colour the solid viewport
98
+ // shades the world with, which is what our own three.js presenter reads.
99
+ title: 'Viewport Display',
100
+ closed: true,
101
+ properties: ['color'],
102
+ },
103
+ {
104
+ // WORLD_PT_animation, :74.
105
+ title: 'Animation',
106
+ closed: true,
107
+ properties: ['animation_data'],
108
+ },
109
+ ];
110
+
111
+ const TAB = { id: 'world', standing: 'any', curated: CURATED } as const;
112
+
113
+ export const point = 'selection.inspector';
114
+ export const title = 'World';
115
+ /** `blender.icons.json` — Blender's own mark, TRACED from
116
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
117
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
118
+ * and tinted by the group `UI_icons.hh` declares it in. */
119
+ export const icon = 'properties-world';
120
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
121
+ * these are that order, spaced so a tab can be inserted between two. */
122
+ export const order = 50;
123
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
124
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
125
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
126
+ * object group (Object … Material), then Texture. The presentation draws a
127
+ * separator wherever this changes. */
128
+ export const railGroup = 'scene';
129
+ export const match = blenderPropertiesTabMatch(TAB);
130
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The SCULPT workspace — ZBrush-shaped sculpting over a `model` document. It
3
+ * borrows Model's arrangement until the sculpt program ships its brush rail
4
+ * (a reserved task panel ships WITH its capability program, never as empty
5
+ * chrome); it keeps its OWN persisted layout the moment a person touches it.
6
+ */
7
+
8
+ import type { WorkspaceLayoutContribution } from '@volter/editor-sdk/looks';
9
+
10
+ export const point = 'workspace.layout';
11
+ export const layout: WorkspaceLayoutContribution = {
12
+ id: 'sculpt',
13
+ title: 'Sculpt',
14
+ description:
15
+ "ZBrush-shaped sculpting. Uses Model's arrangement until the sculpt program ships its brush rail.",
16
+ requires: { documentKind: 'model' },
17
+ // `tabs` unstated — see `model.layout.ts`: the workspace layer wins over the
18
+ // style bundle, so restating the host default shadows it.
19
+ regions: {
20
+ header: 'shown',
21
+ shelf: 'shown',
22
+ inspector: 'properties',
23
+ drawer: 'hidden',
24
+ },
25
+ };