@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,210 @@
1
+ /**
2
+ * BLENDER'S OUTPUT 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_output.py` at the
7
+ * engine's pin — `classes` (`:728-748`) is the panel order, `bl_label` the
8
+ * title, each `layout.prop(rd, "x")` an entry in the order the draw function
9
+ * lists it. Blender's UI layer is never run, ported or recorded.
10
+ *
11
+ * THE TAB'S DATABLOCK IS `scene.render`, and three panels reach past it: Frame
12
+ * Range is the SCENE's own `frame_start`/`frame_end`/`frame_step` (`:151`),
13
+ * Output's Color Management is `rd.image_settings` (`:371`), and Encoding is
14
+ * `rd.ffmpeg` (`:499`). The context door names each beside the render
15
+ * settings as one of this tab's paths and the rows say which they come from
16
+ * ({@link BlenderCuratedProperty}).
17
+ *
18
+ * WHAT THE TRANSCRIPTION DELIBERATELY DROPS:
19
+ * - the preset menus (`RENDER_PT_format_presets` `:15`,
20
+ * `RENDER_MT_framerate_presets` `:28`, `RENDER_PT_ffmpeg_presets` `:22`)
21
+ * and `template_image_settings`/`template_image_views` — operator and
22
+ * template widgets. Inspection parity, not editing parity.
23
+ * - `RENDER_PT_output_pixel_density` (`:396`), whose body is a preset menu
24
+ * plus two properties behind it; the two are named here.
25
+ *
26
+ * It stands when: `buttons_context_path_scene` — the same path as Render.
27
+ */
28
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
29
+ import type { BlenderCuratedPanel } from './blender-properties-view';
30
+
31
+ /** `properties_output.py`, panel by panel. Line numbers are that file's. */
32
+ const CURATED: readonly BlenderCuratedPanel[] = [
33
+ {
34
+ // RENDER_PT_format, :53 — the draw order is resolution, aspect, border,
35
+ // then the frame rate block (`draw_framerate`, :95).
36
+ title: 'Format',
37
+ properties: [
38
+ 'resolution_x',
39
+ 'resolution_y',
40
+ 'resolution_percentage',
41
+ 'pixel_aspect_x',
42
+ 'pixel_aspect_y',
43
+ 'use_border',
44
+ 'use_crop_to_border',
45
+ 'fps',
46
+ 'fps_base',
47
+ ],
48
+ },
49
+ {
50
+ // RENDER_PT_frame_range, :135 — the SCENE's, not the render settings'.
51
+ title: 'Frame Range',
52
+ properties: [
53
+ { from: 'Scene', property: 'frame_start' },
54
+ { from: 'Scene', property: 'frame_end' },
55
+ { from: 'Scene', property: 'frame_step' },
56
+ ],
57
+ sub: [
58
+ // RENDER_PT_time_stretching, :156.
59
+ { title: 'Time Stretching', closed: true, properties: ['frame_map_old', 'frame_map_new'] },
60
+ ],
61
+ },
62
+ {
63
+ // RENDER_PT_stereoscopy, :676 — `use_multiview` is the header checkbox
64
+ // (:687); the views themselves are a `template_list` over `rd.views`.
65
+ title: 'Stereoscopy',
66
+ closed: true,
67
+ properties: ['use_multiview', 'views_format', 'views'],
68
+ },
69
+ {
70
+ // RENDER_PT_output, :291.
71
+ title: 'Output',
72
+ properties: [
73
+ 'save_output',
74
+ 'filepath',
75
+ 'use_file_extension',
76
+ 'use_render_cache',
77
+ 'use_overwrite',
78
+ 'use_placeholder',
79
+ ],
80
+ sub: [
81
+ // RENDER_PT_output_color_management, :351 — `image_settings.color_management`
82
+ // then the display device beneath it.
83
+ {
84
+ title: 'Color Management',
85
+ closed: true,
86
+ from: 'Image',
87
+ properties: ['color_management'],
88
+ },
89
+ // RENDER_PT_output_pixel_density, :396.
90
+ { title: 'Pixel Density', closed: true, properties: ['ppm_factor', 'ppm_base'] },
91
+ ],
92
+ },
93
+ {
94
+ // RENDER_PT_encoding, :473 — `rd.ffmpeg`, and its poll is the image
95
+ // format being one of FFMPEG/XVID/H264/THEORA (:496).
96
+ title: 'Encoding',
97
+ closed: true,
98
+ from: 'FFmpeg',
99
+ when: [
100
+ {
101
+ from: 'Image',
102
+ property: 'file_format',
103
+ is: ['FFMPEG', 'XVID', 'H264', 'THEORA'],
104
+ },
105
+ ],
106
+ properties: ['format', 'use_autosplit'],
107
+ sub: [
108
+ // RENDER_PT_encoding_video, :503.
109
+ {
110
+ title: 'Video',
111
+ from: 'FFmpeg',
112
+ properties: [
113
+ 'codec',
114
+ { from: 'Image', property: 'color_depth' },
115
+ 'use_lossless_output',
116
+ 'ffmpeg_prores_profile',
117
+ 'constant_rate_factor',
118
+ 'custom_constant_rate_factor',
119
+ 'ffmpeg_preset',
120
+ 'gopsize',
121
+ 'use_max_b_frames',
122
+ 'max_b_frames',
123
+ 'video_bitrate',
124
+ 'minrate',
125
+ 'maxrate',
126
+ 'buffersize',
127
+ 'muxrate',
128
+ 'packetsize',
129
+ ],
130
+ },
131
+ // RENDER_PT_encoding_audio, :633.
132
+ {
133
+ title: 'Audio',
134
+ from: 'FFmpeg',
135
+ properties: [
136
+ 'audio_codec',
137
+ 'audio_channels',
138
+ 'audio_mixrate',
139
+ 'audio_volume',
140
+ 'audio_bitrate',
141
+ ],
142
+ },
143
+ ],
144
+ },
145
+ {
146
+ // RENDER_PT_stamp, :200 — `metadata_input` is drawn first (:217), then
147
+ // the flag grid.
148
+ title: 'Metadata',
149
+ closed: true,
150
+ properties: [
151
+ 'metadata_input',
152
+ 'use_stamp_date',
153
+ 'use_stamp_time',
154
+ 'use_stamp_render_time',
155
+ 'use_stamp_frame',
156
+ 'use_stamp_frame_range',
157
+ 'use_stamp_memory',
158
+ 'use_stamp_hostname',
159
+ 'use_stamp_camera',
160
+ 'use_stamp_lens',
161
+ 'use_stamp_scene',
162
+ 'use_stamp_marker',
163
+ 'use_stamp_filename',
164
+ 'use_stamp_sequencer_strip',
165
+ ],
166
+ sub: [
167
+ // RENDER_PT_stamp_note, :237 — `use_stamp_note` is its header checkbox.
168
+ { title: 'Note', closed: true, properties: ['use_stamp_note', 'stamp_note_text'] },
169
+ // RENDER_PT_stamp_burn, :261 — `use_stamp` is its header checkbox.
170
+ {
171
+ title: 'Burn Into Image',
172
+ closed: true,
173
+ properties: [
174
+ 'use_stamp',
175
+ 'stamp_font_size',
176
+ 'stamp_foreground',
177
+ 'stamp_background',
178
+ 'use_stamp_labels',
179
+ ],
180
+ },
181
+ ],
182
+ },
183
+ {
184
+ // RENDER_PT_post_processing, :178.
185
+ title: 'Post Processing',
186
+ closed: true,
187
+ properties: ['use_compositing', 'use_sequencer', 'dither_intensity'],
188
+ },
189
+ ];
190
+
191
+ const TAB = { id: 'output', standing: 'any', curated: CURATED } as const;
192
+
193
+ export const point = 'selection.inspector';
194
+ export const title = 'Output';
195
+ /** `blender.icons.json` — Blender's own mark, TRACED from
196
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
197
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
198
+ * and tinted by the group `UI_icons.hh` declares it in. */
199
+ export const icon = 'properties-output';
200
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
201
+ * these are that order, spaced so a tab can be inserted between two. */
202
+ export const order = 20;
203
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
204
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
205
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
206
+ * object group (Object … Material), then Texture. The presentation draws a
207
+ * separator wherever this changes. */
208
+ export const railGroup = 'scene';
209
+ export const match = blenderPropertiesTabMatch(TAB);
210
+ export default blenderPropertiesTabSection(TAB);
@@ -0,0 +1,494 @@
1
+ /**
2
+ * BLENDER'S PARTICLES 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_particle.py` at the
7
+ * engine's pin — `classes` (`:2248-2302`) is the panel order, `bl_label` the
8
+ * title, each `layout.prop(part, "x")` an entry. Blender's UI layer is never
9
+ * run, ported or recorded.
10
+ *
11
+ * NEARLY EVERY PANEL DRAWS `psys.settings`, NOT THE SYSTEM. `part` in these
12
+ * draw functions is `particle_get_settings(context)` (`:40-46`), which is the
13
+ * active system's ParticleSettings — a datablock of its own. The system
14
+ * itself carries only a handful (`seed`, `parent`, `child_seed`, the
15
+ * vertex-group names, `use_hair_dynamics`). The context door names both, plus
16
+ * the hair-dynamics cloth settings, as this tab's paths, and each row says
17
+ * which it comes from.
18
+ *
19
+ * THE TYPE POLLS ARE READ, and this tab is why `when` exists. Blender gates
20
+ * these panels on values rather than on structure: `settings.type == 'HAIR'`
21
+ * (Hair Dynamics `:362`, Hair Shape `:2205`), `settings.physics_type` in
22
+ * NEWTON/FLUID or == BOIDS (`:1161`, `:1195`, `:1222`, `:934`),
23
+ * `settings.render_type` (`:1449`, `:1507`, `:1536`), `settings.child_type`
24
+ * (`:1743`, `:1778`), `settings.is_fluid` (`:272`). Every one of those
25
+ * properties is on the same struct under every mode, so RNA cannot answer the
26
+ * poll and the condition is read from the ENGINE's live value instead — a copy
27
+ * of Blender's test, never of its branching.
28
+ *
29
+ * WHAT THE TRANSCRIPTION DELIBERATELY DROPS:
30
+ * - `PARTICLE_PT_context_particles` (`:156`, `bl_label = ""`) — the systems
31
+ * list plus the settings ID template. The list itself is the first panel
32
+ * here, as a collection with the active system marked; the `template_ID`
33
+ * row is an editing widget.
34
+ * - the Boids panels (`:931`-`:1045`) and the fluid-spring panels
35
+ * (`:835`-`:928`): both read sub-structs of the settings (`part.boids`,
36
+ * `part.fluid`), which stand as POINTER rows in the Physics panel and
37
+ * drill. Naming a fourth and fifth datablock on this tab to reach a mode
38
+ * almost nothing uses is the machinery the generic view exists to avoid.
39
+ * - `PARTICLE_PT_boidbrain` (`:1254`) — a rules list with per-rule operators.
40
+ * - `template_curve_mapping` (the clump and roughness curves) — a curve
41
+ * widget this view does not draw.
42
+ * - `PARTICLE_PT_custom_props` (`:2243`), IDProperties rather than RNA.
43
+ *
44
+ * It stands when: `buttons_context_path_particle` — `ob->type == OB_MESH`.
45
+ */
46
+ import { blenderPropertiesTabMatch, blenderPropertiesTabSection } from './blender-properties-tab';
47
+ import type { BlenderCuratedPanel } from './blender-properties-view';
48
+
49
+ /** `settings.type == 'HAIR'` — the poll Hair Dynamics and Hair Shape share. */
50
+ const HAIR = [{ from: 'Settings', property: 'type', is: ['HAIR'] }] as const;
51
+
52
+ /** `properties_particle.py`, panel by panel. Line numbers are that file's. */
53
+ const CURATED: readonly BlenderCuratedPanel[] = [
54
+ {
55
+ // PARTICLE_UL_particle_systems, :131, drawn by
56
+ // PARTICLE_PT_context_particles' `template_list` (:183).
57
+ title: 'Particle Systems',
58
+ from: 'Particle Systems',
59
+ collection: true,
60
+ active: 'activeParticleSystem',
61
+ properties: ['name', 'settings'],
62
+ },
63
+ {
64
+ // PARTICLE_PT_emission, :256. `psys.seed` (:293) is the SYSTEM's.
65
+ title: 'Emission',
66
+ from: 'Settings',
67
+ when: [{ from: 'Settings', property: 'is_fluid', is: [false] }],
68
+ properties: [
69
+ 'count',
70
+ { from: 'Active', property: 'seed' },
71
+ 'hair_length',
72
+ 'hair_step',
73
+ 'frame_start',
74
+ 'frame_end',
75
+ 'lifetime',
76
+ 'lifetime_random',
77
+ ],
78
+ sub: [
79
+ {
80
+ // PARTICLE_PT_emission_source, :311.
81
+ title: 'Source',
82
+ closed: true,
83
+ from: 'Settings',
84
+ properties: [
85
+ 'emit_from',
86
+ 'use_modifier_stack',
87
+ 'distribution',
88
+ 'use_emit_random',
89
+ 'invert_grid',
90
+ 'hexagonal_grid',
91
+ 'use_even_distribution',
92
+ 'userjit',
93
+ 'jitter_factor',
94
+ 'grid_resolution',
95
+ 'grid_random',
96
+ ],
97
+ },
98
+ ],
99
+ },
100
+ {
101
+ // PARTICLE_PT_hair_dynamics, :353 — `psys.use_hair_dynamics` is the header
102
+ // checkbox (:374) and the body is `psys.cloth.settings` (:390).
103
+ title: 'Hair Dynamics',
104
+ closed: true,
105
+ from: 'Hair Dynamics',
106
+ when: HAIR,
107
+ properties: [{ from: 'Active', property: 'use_hair_dynamics' }, 'quality', 'pin_stiffness'],
108
+ sub: [
109
+ {
110
+ // PARTICLE_PT_hair_dynamics_collision, :445 —
111
+ // `psys.cloth.collision_settings` (:463).
112
+ title: 'Collisions',
113
+ closed: true,
114
+ from: 'Hair Collisions',
115
+ properties: ['collision_quality', 'distance_min', 'impulse_clamp', 'collection'],
116
+ },
117
+ {
118
+ // PARTICLE_PT_hair_dynamics_structure, :481 — `bending_random` is the
119
+ // SETTINGS', the rest the cloth's.
120
+ title: 'Structure',
121
+ closed: true,
122
+ from: 'Hair Dynamics',
123
+ properties: [
124
+ 'mass',
125
+ 'bending_stiffness',
126
+ { from: 'Settings', property: 'bending_random' },
127
+ 'bending_damping',
128
+ ],
129
+ },
130
+ {
131
+ // PARTICLE_PT_hair_dynamics_volume, :516.
132
+ title: 'Volume',
133
+ closed: true,
134
+ from: 'Hair Dynamics',
135
+ properties: [
136
+ 'air_damping',
137
+ 'internal_friction',
138
+ 'voxel_cell_size',
139
+ 'density_target',
140
+ 'density_strength',
141
+ ],
142
+ },
143
+ ],
144
+ },
145
+ {
146
+ // PARTICLE_PT_cache, :552 — `point_cache_ui(self, psys.point_cache, …)`,
147
+ // so the panel is that sub-struct and its pointer row stands.
148
+ title: 'Cache',
149
+ closed: true,
150
+ from: 'Active',
151
+ when: [{ from: 'Settings', property: 'physics_type', isNot: ['NO', 'KEYED'] }],
152
+ properties: ['point_cache'],
153
+ },
154
+ {
155
+ // PARTICLE_PT_velocity, :589.
156
+ title: 'Velocity',
157
+ closed: true,
158
+ from: 'Settings',
159
+ when: [{ from: 'Settings', property: 'physics_type', isNot: ['BOIDS'] }],
160
+ properties: [
161
+ 'normal_factor',
162
+ 'tangent_factor',
163
+ 'tangent_phase',
164
+ 'object_align_factor',
165
+ 'particle_factor',
166
+ 'object_factor',
167
+ 'factor_random',
168
+ ],
169
+ },
170
+ {
171
+ // PARTICLE_PT_rotation, :642 — `use_rotations` is the header checkbox.
172
+ title: 'Rotation',
173
+ closed: true,
174
+ from: 'Settings',
175
+ when: [{ from: 'Settings', property: 'physics_type', isNot: ['BOIDS'] }],
176
+ properties: [
177
+ 'use_rotations',
178
+ 'rotation_mode',
179
+ 'rotation_factor_random',
180
+ 'phase_factor',
181
+ 'phase_factor_random',
182
+ 'use_dynamic_rotation',
183
+ ],
184
+ sub: [
185
+ {
186
+ // PARTICLE_PT_rotation_angular_velocity, :700.
187
+ title: 'Angular Velocity',
188
+ closed: true,
189
+ from: 'Settings',
190
+ properties: ['angular_velocity_mode', 'angular_velocity_factor'],
191
+ },
192
+ ],
193
+ },
194
+ {
195
+ // PARTICLE_PT_physics, :730. `boids` and `fluid` are the two mode
196
+ // sub-structs whose own panels are one drill away (see the header).
197
+ title: 'Physics',
198
+ closed: true,
199
+ from: 'Settings',
200
+ properties: [
201
+ 'physics_type',
202
+ 'mass',
203
+ 'use_multiply_size_mass',
204
+ 'keyed_loops',
205
+ { from: 'Active', property: 'use_keyed_timing' },
206
+ 'fluid',
207
+ 'boids',
208
+ ],
209
+ sub: [
210
+ {
211
+ // PARTICLE_PT_physics_forces, :1187.
212
+ title: 'Forces',
213
+ from: 'Settings',
214
+ when: [{ from: 'Settings', property: 'physics_type', is: ['NEWTON', 'FLUID'] }],
215
+ properties: ['brownian_factor', 'drag_factor', 'damping'],
216
+ },
217
+ {
218
+ // PARTICLE_PT_physics_deflection, :1156.
219
+ title: 'Deflection',
220
+ closed: true,
221
+ from: 'Settings',
222
+ when: [{ from: 'Settings', property: 'physics_type', is: ['NEWTON', 'FLUID'] }],
223
+ properties: ['use_size_deflect', 'use_die_on_collision', 'collision_collection'],
224
+ },
225
+ {
226
+ // PARTICLE_PT_physics_integration, :1217.
227
+ title: 'Integration',
228
+ closed: true,
229
+ from: 'Settings',
230
+ when: [{ from: 'Settings', property: 'physics_type', is: ['NEWTON', 'FLUID'] }],
231
+ properties: [
232
+ 'integrator',
233
+ 'timestep',
234
+ 'subframes',
235
+ 'use_adaptive_subframes',
236
+ 'courant_target',
237
+ ],
238
+ },
239
+ ],
240
+ },
241
+ {
242
+ // PARTICLE_PT_render, :1362 — `psys.parent` (:1407) is the SYSTEM's.
243
+ title: 'Render',
244
+ closed: true,
245
+ from: 'Settings',
246
+ properties: [
247
+ 'render_type',
248
+ 'particle_size',
249
+ 'size_random',
250
+ 'material_slot',
251
+ { from: 'Active', property: 'parent' },
252
+ ],
253
+ sub: [
254
+ {
255
+ // PARTICLE_PT_render_path, :1443.
256
+ title: 'Path',
257
+ from: 'Settings',
258
+ when: [{ from: 'Settings', property: 'render_type', is: ['PATH'] }],
259
+ properties: ['use_hair_bspline', 'render_step'],
260
+ sub: [
261
+ {
262
+ // PARTICLE_PT_render_path_timing, :1468.
263
+ title: 'Timing',
264
+ closed: true,
265
+ from: 'Settings',
266
+ properties: ['use_absolute_path_time', 'path_start', 'path_end', 'length_random'],
267
+ },
268
+ ],
269
+ },
270
+ {
271
+ // PARTICLE_PT_render_object, :1501.
272
+ title: 'Object',
273
+ from: 'Settings',
274
+ when: [{ from: 'Settings', property: 'render_type', is: ['OBJECT'] }],
275
+ properties: [
276
+ 'instance_object',
277
+ 'use_global_instance',
278
+ 'use_rotation_instance',
279
+ 'use_scale_instance',
280
+ ],
281
+ },
282
+ {
283
+ // PARTICLE_PT_render_collection, :1530, with its Use Count child
284
+ // (:1563) over `part.instance_weights`.
285
+ title: 'Collection',
286
+ from: 'Settings',
287
+ when: [{ from: 'Settings', property: 'render_type', is: ['COLLECTION'] }],
288
+ properties: [
289
+ 'instance_collection',
290
+ 'use_whole_collection',
291
+ 'use_collection_pick_random',
292
+ 'use_global_instance',
293
+ 'use_rotation_instance',
294
+ 'use_scale_instance',
295
+ ],
296
+ sub: [
297
+ {
298
+ title: 'Use Count',
299
+ closed: true,
300
+ from: 'Settings',
301
+ properties: ['use_collection_count', 'instance_weights'],
302
+ },
303
+ ],
304
+ },
305
+ {
306
+ // PARTICLE_PT_render_extra, :1414.
307
+ title: 'Extra',
308
+ closed: true,
309
+ from: 'Settings',
310
+ when: [{ from: 'Settings', property: 'render_type', isNot: ['NONE'] }],
311
+ properties: ['use_parent_particles', 'show_unborn', 'use_dead'],
312
+ },
313
+ ],
314
+ },
315
+ {
316
+ // PARTICLE_PT_draw, :1618.
317
+ title: 'Viewport Display',
318
+ closed: true,
319
+ from: 'Settings',
320
+ properties: [
321
+ 'display_method',
322
+ 'display_color',
323
+ 'color_maximum',
324
+ 'display_percentage',
325
+ 'display_step',
326
+ 'display_size',
327
+ ],
328
+ },
329
+ {
330
+ // PARTICLE_PT_children, :1680 — `psys.child_seed` (:1718) is the SYSTEM's.
331
+ title: 'Children',
332
+ closed: true,
333
+ from: 'Settings',
334
+ properties: [
335
+ 'child_type',
336
+ 'child_percent',
337
+ 'rendered_child_count',
338
+ 'child_length',
339
+ 'child_length_threshold',
340
+ { from: 'Active', property: 'child_seed' },
341
+ 'virtual_parents',
342
+ 'create_long_hair_children',
343
+ 'child_size',
344
+ 'child_size_random',
345
+ 'child_radius',
346
+ 'child_roundness',
347
+ ],
348
+ sub: [
349
+ {
350
+ // PARTICLE_PT_children_parting, :1737.
351
+ title: 'Parting',
352
+ closed: true,
353
+ from: 'Settings',
354
+ when: [{ from: 'Settings', property: 'child_type', is: ['INTERPOLATED'] }],
355
+ properties: ['child_parting_factor', 'child_parting_min', 'child_parting_max'],
356
+ },
357
+ {
358
+ // PARTICLE_PT_children_clumping, :1772, with Clump Noise (:1812).
359
+ title: 'Clumping',
360
+ closed: true,
361
+ from: 'Settings',
362
+ when: [{ from: 'Settings', property: 'child_type', isNot: ['NONE'] }],
363
+ properties: ['use_clump_curve', 'clump_factor', 'clump_shape', 'twist', 'use_twist_curve'],
364
+ sub: [
365
+ {
366
+ title: 'Clump Noise',
367
+ closed: true,
368
+ from: 'Settings',
369
+ properties: ['use_clump_noise', 'clump_noise_size'],
370
+ },
371
+ ],
372
+ },
373
+ {
374
+ // PARTICLE_PT_children_roughness, :1839.
375
+ title: 'Roughness',
376
+ closed: true,
377
+ from: 'Settings',
378
+ when: [{ from: 'Settings', property: 'child_type', isNot: ['NONE'] }],
379
+ properties: [
380
+ 'use_roughness_curve',
381
+ 'roughness_1',
382
+ 'roughness_1_size',
383
+ 'roughness_endpoint',
384
+ 'roughness_end_shape',
385
+ 'roughness_2',
386
+ 'roughness_2_size',
387
+ 'roughness_2_threshold',
388
+ ],
389
+ },
390
+ {
391
+ // PARTICLE_PT_children_kink, :1885.
392
+ title: 'Kink',
393
+ closed: true,
394
+ from: 'Settings',
395
+ when: [{ from: 'Settings', property: 'child_type', isNot: ['NONE'] }],
396
+ properties: [
397
+ 'kink',
398
+ 'kink_amplitude',
399
+ 'kink_amplitude_random',
400
+ 'kink_amplitude_clump',
401
+ 'kink_axis',
402
+ 'kink_axis_random',
403
+ 'kink_frequency',
404
+ 'kink_shape',
405
+ 'kink_extra_steps',
406
+ 'kink_flat',
407
+ ],
408
+ },
409
+ ],
410
+ },
411
+ {
412
+ // PARTICLE_PT_hair_shape, :2196.
413
+ title: 'Hair Shape',
414
+ closed: true,
415
+ from: 'Settings',
416
+ when: HAIR,
417
+ properties: ['shape', 'root_radius', 'tip_radius', 'radius_scale', 'use_close_tip'],
418
+ },
419
+ {
420
+ // PARTICLE_PT_field_weights, :1940 — `effector_weights_ui` over
421
+ // `part.effector_weights`, plus two of the settings' own.
422
+ title: 'Field Weights',
423
+ closed: true,
424
+ from: 'Settings',
425
+ properties: ['effector_weights', 'apply_effector_to_children', 'effect_hair'],
426
+ },
427
+ {
428
+ // PARTICLE_PT_force_fields, :1965, and its two type children (:1985,
429
+ // :2006), which draw `part.force_field_1` / `_2`.
430
+ title: 'Force Field Settings',
431
+ closed: true,
432
+ from: 'Settings',
433
+ properties: ['use_self_effect', 'effector_amount', 'force_field_1', 'force_field_2'],
434
+ },
435
+ {
436
+ // PARTICLE_PT_vertexgroups, :2067 — every row is the SYSTEM's.
437
+ title: 'Vertex Groups',
438
+ closed: true,
439
+ from: 'Active',
440
+ properties: [
441
+ 'vertex_group_density',
442
+ 'invert_vertex_group_density',
443
+ 'vertex_group_length',
444
+ 'invert_vertex_group_length',
445
+ 'vertex_group_clump',
446
+ 'invert_vertex_group_clump',
447
+ 'vertex_group_kink',
448
+ 'invert_vertex_group_kink',
449
+ 'vertex_group_roughness_1',
450
+ 'invert_vertex_group_roughness_1',
451
+ 'vertex_group_roughness_2',
452
+ 'invert_vertex_group_roughness_2',
453
+ 'vertex_group_roughness_end',
454
+ 'invert_vertex_group_roughness_end',
455
+ 'vertex_group_twist',
456
+ 'invert_vertex_group_twist',
457
+ ],
458
+ },
459
+ {
460
+ // PARTICLE_PT_textures, :2160 — `template_list` over `part.texture_slots`.
461
+ title: 'Textures',
462
+ closed: true,
463
+ from: 'Settings',
464
+ properties: ['texture_slots', 'active_texture'],
465
+ },
466
+ {
467
+ // PARTICLE_PT_animation, :2230.
468
+ title: 'Animation',
469
+ closed: true,
470
+ from: 'Settings',
471
+ properties: ['animation_data'],
472
+ },
473
+ ];
474
+
475
+ const TAB = { id: 'particle', curated: CURATED } as const;
476
+
477
+ export const point = 'selection.inspector';
478
+ export const title = 'Particles';
479
+ /** `blender.icons.json` — Blender's own mark, TRACED from
480
+ * `release/datafiles/icons_svg/` at the engine's pin (the icon this tab draws
481
+ * is named in `buttons_context_items`, `makesrna/intern/rna_space.cc:579`),
482
+ * and tinted by the group `UI_icons.hh` declares it in. */
483
+ export const icon = 'properties-particles';
484
+ /** `ED_buttons_tabs_list` (`space_buttons.cc:218-252`) is the rail's order;
485
+ * these are that order, spaced so a tab can be inserted between two. */
486
+ export const order = 90;
487
+ /** THE RAIL'S GROUPS, from `ED_buttons_tabs_list`'s own `add_spacer()` calls
488
+ * (`space_buttons/space_buttons.cc:201-255`): the tool tab, then the scene
489
+ * group (Render, Output, View Layer, Scene, World), then Collection, then the
490
+ * object group (Object … Material), then Texture. The presentation draws a
491
+ * separator wherever this changes. */
492
+ export const railGroup = 'object';
493
+ export const match = blenderPropertiesTabMatch(TAB);
494
+ export default blenderPropertiesTabSection(TAB);