SKILL.md
---
name: blender-cli
description: "Implement Blender CLI tasks from a bundled feature catalog and offline Python API evidence. Discover capabilities before querying APIs; reject Blender facts or recipes supplied only by model memory."
---
# Blender CLI from supplied evidence
All Blender-specific capability choices, API identifiers, enum values, parameter meanings and workflow claims must come from this skill's data. **Pretrained Blender knowledge is not admissible evidence.** Use normal language comprehension, logic and Python composition to connect supported facts; do not fill a Blender knowledge gap with remembered behavior. User requirements supply desired outputs and artistic choices, not proof that an API exists or behaves a certain way.
## First context: the available capability families
Read the complete [capability overview](references/catalog/overview.md) **before querying the API database or drafting Blender code**. This layer is plain Markdown and transparently compressed JSON, available without SQLite. It lists the authored routes, all source API page cards, statuses and how to select them.
| User's area of work | Catalog domain |
|---|---|
| Scenes, objects, collections and transforms | `scene` |
| Mesh, BMesh and modifiers | `geometry` |
| Geometry Nodes, fields and instances | `geometry-nodes` |
| Curves, 3D text, hair, point clouds and volumes | `curves-volumes` |
| Sculpting, brushes and painting | `sculpt-paint` |
| UV maps, images and texture baking | `uv` |
| Materials, shaders, textures and worlds | `shading` |
| Lights, cameras and shadows | `lights-shadows` |
| Rendering, passes, color and image output | `render` |
| Compositing, masks and image processing | `compositor` |
| Video editing, titles and audio | `video-audio` |
| Grease Pencil, 2D strokes and Freestyle | `grease-pencil-freestyle` |
| Motion tracking and movie clips | `tracking` |
| Keyframes, drivers, rigs and constraints | `animation-rigging` |
| Simulation, physics and caches | `simulation` |
| Files, import/export, libraries and assets | `files-assets` |
| Python integration, math, GPU and UI | `integration-gpu` |
| API guides, enums and source indices | `api-guides` |
These are navigation categories, not guarantees of background-mode execution. Exact feature claims live in source-linked cards. `documented_route_runtime_unverified` means the source describes a route; `api_discovery_only` means a source page exists and must be read before claiming a behavior. `identifier_only` means the introductory source text does not describe enough behavior. Do not turn those latter statuses into implementation promises.
## Evidence workflow
1. **Discover before querying.** Read the overview, then the relevant domain file linked there. `python3 scripts/features.py match "the user request"` searches supplied Vietnamese/English aliases without opening SQLite. Read each candidate with `features.py show ID`; compare its `choose_when`, evidence excerpts and gaps. The presence of the same keyword is not enough to select it. Clarify output if several documented routes remain plausible.
2. **Handle unknowns explicitly.** If no authored route fits, use `features.py pages DOMAIN` and `features.py symbols TEXT` to discover source-provided names/descriptions outside the database. Select an `api:...` page card only as a discovery step. If no source supports the requested behavior, return `insufficient_skill_evidence` and name the missing fact. Do not invent an English Blender term, API, parameter or recipe from memory. External search is not a silent fallback: new material must be incorporated with provenance into the skill before it becomes task evidence.
3. **Make the selection reviewable.** Create a plan with `features.py plan --request "..." --feature ID --output /absolute/path/plan.json`. Repeat `--feature` for combined work. Its initial API queries come directly from the selected cards, not guessed identifiers.
4. **Read the API evidence.** Use `docs.py read REF --plan /absolute/path/plan.json` with a card's `next_queries`. The plan records the actual source hash and displayed line ranges. Continue pagination until the relevant selected passage is complete. Follow links actually exposed by read evidence, or select another documented feature/card when more context is needed. `docs.py search`/`symbol` may refine terminology already found in this supplied context; never treat a search hit or a matching identifier as behavioral proof.
5. **Implement only supported operations.** Record each Blender operation's source and what that source establishes in the plan's `bindings`; keep missing facts in `unresolved`. A property with only a type/default proves that limited contract, not an undocumented renderer effect. Node socket labels, dynamic enums and operator context must be inspected when the source leaves them open. Do not reuse a familiar recipe without grounding its Blender-specific statements. See [evidence workflow](references/evidence-workflow.md) for the exact plan format.
6. **Verify the selected runtime.** Follow [CLI workflow](references/cli-workflow.md). The bundled probe can collect observed RNA/version data; it cannot provide missing conceptual workflow semantics. Runtime observations are task evidence only when recorded, and any newly used Blender fact must still be explained from those observations and/or supplied source. If it remains undocumented, stop that dependent operation. Keep a missing executable or unresolved runtime fact explicit.
7. **Bind, execute and verify.** `evidence.py inspect` lists operations to review; `evidence.py seal` validates recorded reads/bindings and binds the script hash. `run_blender.py --plan ...` rejects missing/stale plans, unresolved facts, unrecorded citations and uncovered operation lines. Only the bundled probe is exempt. Read the actual result, reopen important saved data and inspect visual outputs before claiming success. These checks enforce traceability; they cannot prove arbitrary code semantics or that a model's internal knowledge was never activated.
## Commands
Paths below are relative to **this installed skill**, not the user's project. Host helpers use Python 3.10+ and the standard library; API lookups also require SQLite FTS5. Use absolute script paths when working elsewhere.
```sh
python3 scripts/features.py overview
python3 scripts/features.py match "text strip shadow"
python3 scripts/features.py show FEATURE_ID
python3 scripts/features.py pages lights-shadows
python3 scripts/features.py plan --request "..." --feature FEATURE_ID --output /tmp/blender-plan.json
python3 scripts/docs.py read SOURCE_REF --plan /tmp/blender-plan.json
python3 scripts/evidence.py inspect --script /absolute/path/task.py
python3 scripts/evidence.py seal --plan /tmp/blender-plan.json --script /absolute/path/task.py
python3 scripts/run_blender.py --script /absolute/path/task.py --plan /tmp/blender-plan.json --timeout 900 -- --output /absolute/path/result.blend
```
Use real IDs/refs returned by the catalog. The runner does not install Blender, save automatically, or make undocumented operations valid. Do not bypass this evidence workflow with raw CLI, remembered snippets, old forward-test examples or a fabricated binding. A citation must support its associated statement; a valid hash alone is insufficient.
## Data scope and maintenance
The supplied snapshot identifies API 5.2 and inventory project `Blender 5.2.1 LTS Python API`. It is not proof of the installed version. The [catalog coverage](references/catalog/coverage.json) distinguishes authored feature routes, all source page cards and unresolved description gaps. `references/api/api.sqlite3` is the packaged source of truth for API text, anchors, links, symbols, search and coverage metadata; see the [corpus guide](references/corpus.md).
The indexed reference is deliberately packaged for offline evidence reads. Read only the selected evidence in a task. The catalog is built from SQLite, not from embeddings or model memory. Raw HTML/assets, Blender Manual, upstream repository and extension pages are not packaged. Rebuild/update instructions live in the corpus guide; updating semantic source content invalidates prior evidence plans and requires reviewing the affected feature claims.
LICENSE
MIT License
Copyright (c) 2026 Blender CLI Skill contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
agents/openai.yaml
interface:
display_name: "Blender CLI"
short_description: "Choose Blender features from bundled evidence before CLI"
references/catalog/domains/compositor.md
# Compositing, masks and image processing
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Compositor image blur — `compositor-image-blur`
CompositorNodeBlur blurs images with multiple blur modes.
Choose when: Blur an image in the compositor.
Search aliases: làm mờ ảnh, blur ảnh, image blur, compositor blur
Evidence: `bpy.types.CompositorNodeBlur.html#bpy.types.CompositorNodeBlur` — Blur images with multiple modes.
Read next: `bpy.types.CompositorNodeBlur.html`, `bpy.types.Scene.html#bpy.types.Scene.compositing_node_group`, `bpy.types.NodeLinks.html`
Limits: The class description does not enumerate sockets or detailed modes. Do not use remembered older blur properties; read supplied metadata and inspect runtime sockets.
## Glare, flares and glow in an image — `compositor-glare-glow`
CompositorNodeGlare adds lens flares, fog and glow around bright image regions.
Choose when: Create effects around bright image regions, often requested as glow or bloom.
Search aliases: quầng sáng, glow, glare, lens flare, bloom, phát sáng quanh vùng sáng
Evidence: `bpy.types.CompositorNodeGlare.html#bpy.types.CompositorNodeGlare` — Add lens flares, fog and glow around bright image regions.
Read next: `bpy.types.CompositorNodeGlare.html`, `bpy.types.Scene.html#bpy.types.Scene.compositing_node_group`, `bpy.types.Node.html#bpy.types.Node.inputs`
Limits: The bloom alias maps intent; it does not establish a BLOOM enum or Eevee bloom property. Obtain modes, thresholds and sockets from skill data/runtime.
## Chroma keying and despill — `compositor-chroma-key-despill`
CompositorNodeKeying removes a backdrop through chroma keying and corrects backdrop color spill.
Choose when: Remove a backdrop by color and optionally correct its color cast.
Search aliases: tách phông xanh, xóa phông màu, chroma key, green screen, despill, khử ám màu
Evidence: `bpy.types.CompositorNodeKeying.html#bpy.types.CompositorNodeKeying` — Remove a backdrop through chroma keying and correct its color cast with despill.
Read next: `bpy.types.CompositorNodeKeying.html`, `bpy.types.CompositorNodeImage.html`, `bpy.types.CompositorNodeAlphaOver.html`
Limits: The source does not promise arbitrary background removal or automatic key-color detection. Inspect image data and supported sockets/values; do not infer semantic segmentation.
## Foreground over background compositing — `compositor-foreground-over-background`
CompositorNodeAlphaOver overlays a foreground image on a background.
Choose when: Combine identified foreground and background images.
Search aliases: ghép ảnh, ghép nền, alpha over, overlay foreground, composite foreground background
Evidence: `bpy.types.CompositorNodeAlphaOver.html#bpy.types.CompositorNodeAlphaOver` — Overlay a foreground image on a background image.
Read next: `bpy.types.CompositorNodeAlphaOver.html`, `bpy.types.CompositorNodeImage.html`, `bpy.types.NodeLinks.html`
Limits: The description does not establish socket index order, straight/premultiplied handling or background removal. Read socket and alpha-source contracts before linking.
## Compositor image file output — `compositor-file-output`
CompositorNodeOutputFile writes image files; this snapshot exposes directory, file_name, file_output_items and format.
Choose when: Save compositor output with specified paths and formats.
Search aliases: xuất ảnh compositor, file output, ghi ảnh, output passes, write image file
Evidence: `bpy.types.CompositorNodeOutputFile.html#bpy.types.CompositorNodeOutputFile` — Write image files with this version's directory, file_name, file_output_items and format properties.
Read next: `bpy.types.CompositorNodeOutputFile.html`, `bpy.types.NodeCompositorFileOutputItems.html`, `bpy.types.ImageFormatSettings.html`
Limits: Do not use remembered base_path/file_slots properties when this snapshot documents directory/file_output_items. Path-template documentation is external and unbundled; do not invent missing template syntax.
## Ray-traced render denoising — `compositor-render-denoise`
CompositorNodeDenoise is described as denoising Cycles and other ray-traced renders.
Choose when: Denoise a ray-traced render in the compositor.
Search aliases: khử nhiễu, denoise, render noise, ảnh render nhiễu
Evidence: `bpy.types.CompositorNodeDenoise.html#bpy.types.CompositorNodeDenoise` — Denoise Cycles and other ray-traced renders.
Read next: `bpy.types.CompositorNodeDenoise.html`, `bpy.types.CompositorNodeRLayers.html`, `bpy.types.Node.html#bpy.types.Node.inputs`
Limits: The class does not fully document required sockets, auxiliary passes or denoiser libraries. Read available data and verify the runtime instead of supplying remembered Cycles configuration.
## 2D depth of field from depth or mask — `compositor-depth-of-field`
CompositorNodeDefocus applies 2D depth of field using a Z-depth map or mask, with documented bokeh, f_stop, blur_max and use_zbuffer.
Choose when: Apply depth of field during image processing using depth or mask data.
Search aliases: xóa phông theo độ sâu, defocus, depth of field, bokeh, Z depth blur
Evidence: `bpy.types.CompositorNodeDefocus.html#bpy.types.CompositorNodeDefocus` — Apply 2D depth of field using a Z-depth map or mask, with bokeh and f_stop.
Read next: `bpy.types.CompositorNodeDefocus.html`, `bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_z`, `bpy.types.CompositorNodeRLayers.html`
Limits: This is not camera optics configuration or proof that depth/mask data exists. Read the distinction between Z-buffer and image inputs and inspect the data.
## Cryptomatte object and material masks — `cryptomatte-object-material-masks`
CompositorNodeCryptomatteV2 creates object/material mattes from Cryptomatte render passes; ViewLayer.use_pass_cryptomatte_object outputs a pass for object isolation.
Choose when: Create object/material mattes from a render or image containing Cryptomatte passes.
Search aliases: mask vật thể, mask vật liệu, cryptomatte, object matte, material matte, tách vật thể compositing
Evidence: `bpy.types.CompositorNodeCryptomatteV2.html#bpy.types.CompositorNodeCryptomatteV2` — Create individual object/material mattes from Cryptomatte passes with RENDER or IMAGE sources.; `bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_object` — Render an object pass for isolation during compositing.
Read next: `bpy.types.CompositorNodeCryptomatteV2.html`, `bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_object`, `bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_material`
Limits: This is not object recognition in arbitrary images. Confirm passes and IDs, read source/layer_name and verify engine support.
## Discover all source pages in this domain
`python3 scripts/features.py pages compositor` lists 112 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/coverage.json
{
"schema_version": 4,
"authored_routes": 112,
"domains": 18,
"api_page_cards": 2192,
"source_html_pages": 2192,
"inventory_entries": 26775,
"mapped_pages": 2192,
"unmapped_pages": [],
"cards_without_description": [
"api:bpy.types.AOV",
"api:bpy.types.ASSETBROWSER_UL_metadata_tags",
"api:bpy.types.ActionLayer",
"api:bpy.types.ActionStrip",
"api:bpy.types.AddStrip",
"api:bpy.types.BoidRule",
"api:bpy.types.BoidRuleAverageSpeed",
"api:bpy.types.BoidRuleAvoid",
"api:bpy.types.BoidRuleAvoidCollision",
"api:bpy.types.BoidRuleFight",
"api:bpy.types.BoidRuleFollowLeader",
"api:bpy.types.BoidRuleGoal",
"api:bpy.types.BrushCurvesSculptSettings",
"api:bpy.types.CLIP_UL_tracking_objects",
"api:bpy.types.CURVES_UL_attributes",
"api:bpy.types.CacheFile",
"api:bpy.types.CollectionExport",
"api:bpy.types.CompositorNodeGamma",
"api:bpy.types.CompositorNodeGroup",
"api:bpy.types.CompositorStrip",
"api:bpy.types.CrossStrip",
"api:bpy.types.CryptomatteEntry",
"api:bpy.types.CurvePaintSettings",
"api:bpy.types.CurvesSculpt",
"api:bpy.types.DATA_UL_bone_collections",
"api:bpy.types.DecimateModifier",
"api:bpy.types.DisplaceModifier",
"api:bpy.types.DynamicPaintBrushSettings",
"api:bpy.types.EQCurveMappingData",
"api:bpy.types.EchoModifier",
"api:bpy.types.EvaluateClosureNodeViewerPathElem",
"api:bpy.types.FILEBROWSER_UL_dir",
"api:bpy.types.FloatVectorValueReadOnly",
"api:bpy.types.ForeachGeometryElementGenerationItem",
"api:bpy.types.ForeachGeometryElementInputItem",
"api:bpy.types.ForeachGeometryElementMainItem",
"api:bpy.types.ForeachGeometryElementZoneViewerPathElem",
"api:bpy.types.GPENCIL_UL_annotation_layer",
"api:bpy.types.GPENCIL_UL_matslots",
"api:bpy.types.GREASE_PENCIL_UL_attributes",
"api:bpy.types.GREASE_PENCIL_UL_masks",
"api:bpy.types.GeometryNodeApplySimulatedData",
"api:bpy.types.GeometryNodeClosureToListItem",
"api:bpy.types.GeometryNodeFieldToGridItem",
"api:bpy.types.GeometryNodeFieldToListItem",
"api:bpy.types.GeometryNodeForeachGeometryElementInput",
"api:bpy.types.GeometryNodeForeachGeometryElementOutput",
"api:bpy.types.GeometryNodeGroup",
"api:bpy.types.GeometryNodeRepeatInput",
"api:bpy.types.GeometryNodeRepeatOutput",
"api:bpy.types.GpPaint",
"api:bpy.types.GpSculptPaint",
"api:bpy.types.GpVertexPaint",
"api:bpy.types.GpWeightPaint",
"api:bpy.types.GreasePencilColorModifier",
"api:bpy.types.GreasePencilMirrorModifier",
"api:bpy.types.GreasePencilOffsetModifier",
"api:bpy.types.GreasePencilOpacityModifier",
"api:bpy.types.GreasePencilTimeModifier",
"api:bpy.types.GreasePencilTintModifier",
"api:bpy.types.GroupNodeViewerPathElem",
"api:bpy.types.IDPropertyWrapPtr",
"api:bpy.types.IDViewerPathElem",
"api:bpy.types.IMAGE_AST_brush_paint",
"api:bpy.types.IMAGE_FH_drop_handler",
"api:bpy.types.IMAGE_UL_render_slots",
"api:bpy.types.IMAGE_UL_udim_tiles",
"api:bpy.types.IO_FH_gltf2",
"api:bpy.types.IO_FH_svg_as_curves",
"api:bpy.types.ImagePackedFile",
"api:bpy.types.ImageTexture",
"api:bpy.types.IndexSwitchItem",
"api:bpy.types.KeyConfigPreferences",
"api:bpy.types.KinematicConstraint",
"api:bpy.types.LayerCollection",
"api:bpy.types.LayoutPanelState",
"api:bpy.types.Lightgroup",
"api:bpy.types.MASK_UL_layers",
"api:bpy.types.MATERIAL_UL_matslots",
"api:bpy.types.MESH_UL_attributes",
"api:bpy.types.MESH_UL_color_attributes",
"api:bpy.types.MESH_UL_color_attributes_selector",
"api:bpy.types.MESH_UL_uvmaps",
"api:bpy.types.MESH_UL_vgroups",
"api:bpy.types.MaterialGPencilStyle",
"api:bpy.types.MaterialLineArt",
"api:bpy.types.MeshCacheModifier",
"api:bpy.types.MeshSequenceCacheModifier",
"api:bpy.types.MeshStatVis",
"api:bpy.types.MeshToVolumeModifier",
"api:bpy.types.MeshUVLoopLayer",
"api:bpy.types.MirrorModifier",
"api:bpy.types.ModifierViewerPathElem",
"api:bpy.types.MultiplyStrip",
"api:bpy.types.NODE_AST_compositor",
"api:bpy.types.NODE_FH_image_node",
"api:bpy.types.NodeClosureInput",
"api:bpy.types.NodeClosureInputItem",
"api:bpy.types.NodeClosureInputItems",
"api:bpy.types.NodeClosureOutput",
"api:bpy.types.NodeClosureOutputItem",
"api:bpy.types.NodeClosureOutputItems",
"api:bpy.types.NodeCombineBundleItem",
"api:bpy.types.NodeCompositorFileOutputItem",
"api:bpy.types.NodeEnumItem",
"api:bpy.types.NodeEvaluateClosureInputItem",
"api:bpy.types.NodeEvaluateClosureInputItems",
"api:bpy.types.NodeEvaluateClosureOutputItem",
"api:bpy.types.NodeEvaluateClosureOutputItems",
"api:bpy.types.NodeFunctionFormatStringItem",
"api:bpy.types.NodeGeometryBakeItem",
"api:bpy.types.NodeGeometryCaptureAttributeItem",
"api:bpy.types.NodeGeometryViewerItem",
"api:bpy.types.NodeGroup",
"api:bpy.types.NodeRaycastSampleAttributeItem",
"api:bpy.types.NodeSeparateBundleItem",
"api:bpy.types.NodesModifier",
"api:bpy.types.NodesModifierBake",
"api:bpy.types.NodesModifierDataBlock",
"api:bpy.types.NodesModifierPanel",
"api:bpy.types.NodesModifierProperties",
"api:bpy.types.NodesModifierPropertiesEmpty",
"api:bpy.types.ObjectLightLinking",
"api:bpy.types.OperatorFileListElement",
"api:bpy.types.OperatorOptions",
"api:bpy.types.OperatorStrokeElement",
"api:bpy.types.PARTICLE_UL_particle_systems",
"api:bpy.types.PHYSICS_UL_dynapaint_surfaces",
"api:bpy.types.POINTCLOUD_UL_attributes",
"api:bpy.types.POSE_UL_selection_set",
"api:bpy.types.PaintCurve",
"api:bpy.types.Palette",
"api:bpy.types.PaletteColor",
"api:bpy.types.Preferences",
"api:bpy.types.PreferencesAssetLibraries",
"api:bpy.types.PreferencesExperimental",
"api:bpy.types.RENDER_UL_renderviews",
"api:bpy.types.ReadOnlyInteger",
"api:bpy.types.RenderLayer",
"api:bpy.types.RenderPass",
"api:bpy.types.RenderView",
"api:bpy.types.RepeatItem",
"api:bpy.types.RepeatZoneViewerPathElem",
"api:bpy.types.Report",
"api:bpy.types.SCENE_UL_gltf2_filter_action",
"api:bpy.types.SCENE_UL_keying_set_paths",
"api:bpy.types.SEQUENCER_FH_image_strip",
"api:bpy.types.SEQUENCER_FH_movie_strip",
"api:bpy.types.SEQUENCER_FH_sound_strip",
"api:bpy.types.SceneGpencil",
"api:bpy.types.ScrewModifier",
"api:bpy.types.ScriptDirectory",
"api:bpy.types.ScriptDirectoryCollection",
"api:bpy.types.Sculpt",
"api:bpy.types.SelectedUvElement",
"api:bpy.types.SequenceTimelineChannel",
"api:bpy.types.SequencerCacheOverlay",
"api:bpy.types.SequencerCompositorModifierData",
"api:bpy.types.SequencerCompositorModifierProperties",
"api:bpy.types.SequencerCompositorModifierPropertiesEmpty",
"api:bpy.types.SequencerPreviewOverlay",
"api:bpy.types.SequencerTimelineOverlay",
"api:bpy.types.SequencerToolSettings",
"api:bpy.types.ShaderFxColorize",
"api:bpy.types.ShaderFxFlip",
"api:bpy.types.ShaderFxGlow",
"api:bpy.types.ShaderFxPixel",
"api:bpy.types.ShaderFxRim",
"api:bpy.types.ShaderFxShadow",
"api:bpy.types.ShaderFxSwirl",
"api:bpy.types.ShaderNodeGroup",
"api:bpy.types.ShaderNodeSqueeze",
"api:bpy.types.SimulationStateItem",
"api:bpy.types.SimulationZoneViewerPathElem",
"api:bpy.types.SkinModifier",
"api:bpy.types.SoundEqualizerModifier",
"api:bpy.types.SpaceDopeSheetOverlay",
"api:bpy.types.SpreadsheetRowFilter",
"api:bpy.types.SpreadsheetTableIDGeometry",
"api:bpy.types.StudioLight",
"api:bpy.types.SubtractStrip",
"api:bpy.types.SurfaceDeformModifier",
"api:bpy.types.TEXTURE_UL_texpaintslots",
"api:bpy.types.TEXTURE_UL_texslots",
"api:bpy.types.TextboxState",
"api:bpy.types.TextureNodeAt",
"api:bpy.types.TextureNodeBricks",
"api:bpy.types.TextureNodeChecker",
"api:bpy.types.TextureNodeCombineColor",
"api:bpy.types.TextureNodeCompose",
"api:bpy.types.TextureNodeCoordinates",
"api:bpy.types.TextureNodeCurveRGB",
"api:bpy.types.TextureNodeCurveTime",
"api:bpy.types.TextureNodeDecompose",
"api:bpy.types.TextureNodeDistance",
"api:bpy.types.TextureNodeGroup",
"api:bpy.types.TextureNodeHueSaturation",
"api:bpy.types.TextureNodeImage",
"api:bpy.types.TextureNodeInvert",
"api:bpy.types.TextureNodeMath",
"api:bpy.types.TextureNodeMixRGB",
"api:bpy.types.TextureNodeOutput",
"api:bpy.types.TextureNodeRGBToBW",
"api:bpy.types.TextureNodeRotate",
"api:bpy.types.TextureNodeScale",
"api:bpy.types.TextureNodeSeparateColor",
"api:bpy.types.TextureNodeTexBlend",
"api:bpy.types.TextureNodeTexClouds",
"api:bpy.types.TextureNodeTexDistNoise",
"api:bpy.types.TextureNodeTexMagic",
"api:bpy.types.TextureNodeTexMarble",
"api:bpy.types.TextureNodeTexMusgrave",
"api:bpy.types.TextureNodeTexNoise",
"api:bpy.types.TextureNodeTexStucci",
"api:bpy.types.TextureNodeTexVoronoi",
"api:bpy.types.TextureNodeTexWood",
"api:bpy.types.TextureNodeTexture",
"api:bpy.types.TextureNodeTranslate",
"api:bpy.types.TextureNodeValToNor",
"api:bpy.types.TextureNodeValToRGB",
"api:bpy.types.TextureNodeViewer",
"api:bpy.types.ThemeRegionsChannels",
"api:bpy.types.ThemeRegionsScrubbing",
"api:bpy.types.ThemeRegionsSidebars",
"api:bpy.types.ThemeSpaceGeneric",
"api:bpy.types.ThemeSpaceGradient",
"api:bpy.types.ToolSettings",
"api:bpy.types.TransformOrientation",
"api:bpy.types.TransformOrientationSlot",
"api:bpy.types.TriangulateModifier",
"api:bpy.types.UIPieMenu",
"api:bpy.types.UIPopover",
"api:bpy.types.UIPopupMenu",
"api:bpy.types.USERPREF_UL_extension_repos",
"api:bpy.types.UnitSettings",
"api:bpy.types.UvSculpt",
"api:bpy.types.VIEW3D_AST_brush_gpencil_paint",
"api:bpy.types.VIEW3D_AST_brush_gpencil_sculpt",
"api:bpy.types.VIEW3D_AST_brush_gpencil_vertex",
"api:bpy.types.VIEW3D_AST_brush_gpencil_weight",
"api:bpy.types.VIEW3D_AST_brush_sculpt",
"api:bpy.types.VIEW3D_AST_brush_sculpt_curves",
"api:bpy.types.VIEW3D_AST_brush_texture_paint",
"api:bpy.types.VIEW3D_AST_brush_vertex_paint",
"api:bpy.types.VIEW3D_AST_brush_weight_paint",
"api:bpy.types.VIEW3D_AST_pose_library",
"api:bpy.types.VIEW3D_FH_camera_background_image",
"api:bpy.types.VIEW3D_FH_empty_image",
"api:bpy.types.VIEW3D_FH_vdb_volume",
"api:bpy.types.VIEWLAYER_UL_aov",
"api:bpy.types.VIEWLAYER_UL_linesets",
"api:bpy.types.VOLUME_UL_grids",
"api:bpy.types.View3DCursor",
"api:bpy.types.ViewLayer",
"api:bpy.types.ViewerNodeViewerPathElem",
"api:bpy.types.VolumeDisplaceModifier",
"api:bpy.types.VolumeToMeshModifier",
"api:bpy.types.WORKSPACE_UL_addons_items",
"api:bpy.types.WarpModifier",
"api:bpy.types.WeightedNormalModifier",
"api:bpy.types.WeldModifier",
"api:bpy.types.Window",
"api:bpy.types.WorkSpaceTool",
"api:bpy.types.XrActionMap",
"api:bpy.types.XrActionMapItem",
"api:bpy.types.XrComponentPath",
"api:bpy.types.XrSessionSettings",
"api:bpy.types.XrUserPath",
"api:bpy.types",
"api:bpy.types.wmOwnerID",
"api:bpy.types.wmOwnerIDs",
"api:bpy_types_enum_items/index",
"api:genindex-A",
"api:genindex-B",
"api:genindex-C",
"api:genindex-D",
"api:genindex-E",
"api:genindex-F",
"api:genindex-G",
"api:genindex-H",
"api:genindex-I",
"api:genindex-J",
"api:genindex-K",
"api:genindex-L",
"api:genindex-M",
"api:genindex-N",
"api:genindex-O",
"api:genindex-P",
"api:genindex-Q",
"api:genindex-R",
"api:genindex-S",
"api:genindex-T",
"api:genindex-U",
"api:genindex-V",
"api:genindex-W",
"api:genindex-X",
"api:genindex-Y",
"api:genindex-Z",
"api:genindex-_"
],
"evidence_references": 229,
"coverage_meaning": "All source pages/symbols are discoverable before SQLite. Authored routes are not every possible Blender workflow. Missing semantics remain explicit gaps.",
"semantic_corpus_sha256": "2daab299f0787620df6c173282d4a6dd90114410c33af291fb6ea0c771bb6cb4",
"catalog_sha256": "53e68a65c0b4cd4d4dddacdf396ed83cd84a752da3340ca522fd8cacfc34fb09"
}
references/catalog/domains/curves-volumes.md
# Curves, 3D text, hair, point clouds and volumes
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Curves splines bevel and extrusion — `curves-splines-and-thickness`
Curve stores curves, splines and NURBS; create POLY, BEZIER or NURBS splines and set bevel radius and extrusion along local Z.
Choose when: Describe geometry as splines and use Curve bevel/extrusion properties.
Search aliases: đường cong Bézier, đường NURBS, tạo dây theo đường, curve spline, bezier path, curve bevel, curve extrusion
Evidence: `bpy.types.Curve.html` — A Curve data-block stores curves, splines and NURBS.; `bpy.types.CurveSplines.html#bpy.types.CurveSplines.new` — Add a POLY, BEZIER or NURBS spline.; `bpy.types.Curve.html#bpy.types.Curve.bevel_depth` — Bevel radius excludes extrusion.; `bpy.types.Curve.html#bpy.types.Curve.extrude` — Add depth along local Z, along the curve and perpendicular to normals.
Read next: `bpy.types.Curve.html`, `bpy.types.CurveSplines.html#bpy.types.CurveSplines.new`, `bpy.types.Spline.html`, `bpy.types.BezierSplinePoint.html`
Limits: bevel_depth excludes extrusion; the source defines extrude along local Z, along the curve and perpendicular to its normals.
## Text curve geometry — `curves-text-geometry`
TextCurve stores text in a curve data-block, with body holding the text; StringToCurves generates a paragraph with a font and stores each character as a curve instance.
Choose when: Create text geometry or curve instances in Geometry Nodes.
Search aliases: chữ 3D, hình học chữ, text object, text curve, string to curves, font geometry
Evidence: `bpy.types.TextCurve.html` — A curve data-block stores text.; `bpy.types.TextCurve.html#bpy.types.TextCurve.body` — body holds the text object's content.; `bpy.types.GeometryNodeStringToCurves.html` — Generate a paragraph with a font, storing each character as a curve instance.
Read next: `bpy.types.TextCurve.html`, `bpy.types.Curve.html`, `bpy.types.GeometryNodeStringToCurves.html`
Limits: These sources describe text geometry; they do not establish sequencer titles or screen font drawing.
## Hair curves data — `curves-hair-data`
Curves is a hair-curves data-block with geometry attributes; add_curves accepts a point count for each curve.
Choose when: Create hair-curves data with specified point counts per curve.
Search aliases: dữ liệu tóc, hair curves, thêm sợi tóc, curves strands, hair geometry attributes
Evidence: `bpy.types.Curves.html` — A hair-curves data-block exposes geometry attributes.; `bpy.types.Curves.html#bpy.types.Curves.add_curves` — sizes specifies the number of points in each curve.
Read next: `bpy.types.Curves.html`, `bpy.types.Curves.html#bpy.types.Curves.add_curves`, `bpy.types.Attribute.html`, `bpy.ops.sculpt_curves.html`
Limits: add_curves only describes curve sizes; it does not establish a complete grooming or hairstyle workflow.
## Volume grids mesh to volume and volume to mesh — `volume-grids-and-conversion`
Volume stores 3D grids; MeshToVolume creates fog volume from a mesh surface and VolumeToMesh creates a surface mesh from volume. VolumeGrids.load reads grid lists and metadata from a file.
Choose when: Use volume grids or a documented mesh/volume conversion.
Search aliases: tạo volume từ mesh, chuyển volume thành mesh, đọc volume file, fog volume, volume grids, mesh to volume, volume to mesh
Evidence: `bpy.types.Volume.html` — A Volume data-block stores 3D volume grids.; `bpy.types.VolumeGrids.html#bpy.types.VolumeGrids.load` — Load grid lists and metadata from a file and return a success boolean.; `bpy.types.GeometryNodeMeshToVolume.html` — Create fog volume following an input mesh surface.; `bpy.types.GeometryNodeVolumeToMesh.html` — Create a mesh on a volume surface.
Read next: `bpy.types.Volume.html`, `bpy.types.VolumeGrids.html`, `bpy.types.GeometryNodeMeshToVolume.html`, `bpy.types.GeometryNodeVolumeToMesh.html`
Limits: VolumeGrids.load only promises grid lists and metadata; success does not prove all voxels are loaded or the volume renders correctly.
## Point cloud positions and radii — `point-cloud-fields`
PointCloud is a point-cloud data-block; GeometryNodePoints generates points with positions and radii defined by fields.
Choose when: Create points with position/radius data rather than mesh faces.
Search aliases: đám mây điểm, tập điểm 3D, point cloud, points radii, generate points from fields
Evidence: `bpy.types.PointCloud.html` — A point-cloud data-block exposes geometry attributes.; `bpy.types.GeometryNodePoints.html` — Generate a point cloud with positions and radii defined by fields.; `bpy.types.PointCloud.html#bpy.types.PointCloud.points` — points is a read-only collection in this snapshot.
Read next: `bpy.types.PointCloud.html`, `bpy.types.GeometryNodePoints.html`, `bpy.types.Attribute.html`
Limits: PointCloud.points is documented as a read-only collection; do not infer an add_points method on the data-block.
## Metaball blobby surfaces — `metaball-blobby-surfaces`
MetaBall defines blobby surfaces and contains MetaElement items.
Choose when: Use the documented blobby surface type and continue selecting its elements through the API.
Search aliases: metaball, bề mặt blob, khối mềm dạng blob, blobby surfaces, metaball elements
Evidence: `bpy.types.MetaBall.html` — A metaball data-block defines blobby surfaces.; `bpy.types.MetaBall.html#bpy.types.MetaBall.elements` — A collection contains metaball elements.
Read next: `bpy.types.MetaBall.html`, `bpy.types.MetaBallElements.html`, `bpy.types.MetaElement.html`
Limits: A blobby surface description does not establish fluid or soft-body simulation.
## Discover all source pages in this domain
`python3 scripts/features.py pages curves-volumes` lists 59 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/api-guides.md
# API guides, enums and source indices
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Discover all source pages in this domain
`python3 scripts/features.py pages api-guides` lists 258 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/capability-map.md
# Capability map entry point
The former broad task map has been replaced by the source-linked [pre-query overview](catalog/overview.md). Read that overview and the relevant domain/feature cards before any API database query or Blender-specific implementation.
The [evidence workflow](evidence-workflow.md) defines the requirement to reject pretrained Blender knowledge as evidence, preserve source gaps, record the passages actually read, and bind task code to those passages before execution.
This file is retained as a compatibility link for earlier references; it contains no independent feature advice.
references/catalog/domains/files-assets.md
# Files, import/export, libraries and assets
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Open and save blend files — `blend-file-open-save`
wm.open_mainfile opens a Blender file; wm.save_as_mainfile saves the current file to a specified location.
Choose when: Load a .blend project or save a script's output as .blend.
Search aliases: mở blend, lưu blend, save scene, open blend file, dự án Blender
Evidence: `bpy.ops.wm.html#bpy.ops.wm.open_mainfile` — Open a Blender file with load_ui and use_scripts options.; `bpy.ops.wm.html#bpy.ops.wm.save_as_mainfile` — Save the current file with copy, compress and relative_remap options.
Read next: `bpy.ops.wm.html#bpy.ops.wm.open_mainfile`, `bpy.ops.wm.html#bpy.ops.wm.save_as_mainfile`, `bpy.path.html`
Limits: Opening a file replaces current data; identify the requested input and output files. Do not enable use_scripts or overwrite unrelated files automatically; read load/save options and inspect the created file.
## Blend library linking and appending — `blend-library-datablocks`
BlendDataLibraries.load exposes available data-block names and links/appends selected names when its context ends; write saves selected data-blocks and indirect references.
Choose when: Reuse part of another .blend file or package data-blocks as a library.
Search aliases: append, link library, thư viện blend, lấy object từ file khác, data-block library
Evidence: `bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.load` — The context manager returns input/output; output names are linked or appended on exit and input is read-only.; `bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.write` — Write data-blocks to a blend file, expanding indirectly referenced data-blocks.
Read next: `bpy.types.BlendDataLibraries.html`, `bpy.types.CollectionObjects.html`, `bpy.path.html#bpy.path.abspath`
Limits: Treat context-manager input as read-only and place selected names in its output as documented. Choose link/append and paths according to the request; loading a data-block does not prove collection membership.
## Asset marking and metadata — `asset-metadata-marking`
ID.asset_mark enables data-block reuse through the Asset Browser; AssetMetaData stores description, author, tags and a catalog identifier.
Choose when: Mark a reusable data-block and prepare asset metadata.
Search aliases: asset, asset browser, tạo thư viện asset, asset metadata, gắn tag, catalog asset
Evidence: `bpy.types.ID.html#bpy.types.ID.asset_mark` — Enable reuse through the Asset Browser with previews, descriptions and tags.; `bpy.types.AssetMetaData.html#bpy.types.AssetMetaData` — Metadata includes author, description and catalog_id; catalog_id must be an RFC4122 UUID.
Read next: `bpy.types.ID.html#bpy.types.ID.asset_mark`, `bpy.types.AssetMetaData.html`, `bpy.types.BlendDataLibraries.html`
Limits: Marking an asset does not establish library configuration or publication. catalog_id must meet the source's UUID requirement; a catalog name is not its ID.
## OBJ and STL file exchange — `obj-stl-exchange`
wm.obj_import loads Wavefront OBJ scenes; wm operators import/export OBJ and STL with scale, axis and object-selection parameters.
Choose when: Exchange files in OBJ or STL format.
Search aliases: OBJ, STL, nhập mesh, xuất obj, xuất stl, Wavefront
Evidence: `bpy.ops.wm.html#bpy.ops.wm.obj_import` — Load a Wavefront OBJ scene with scale and forward/up axes.; `bpy.ops.wm.html#bpy.ops.wm.obj_export` — OBJ export declares export_selected_objects, apply_modifiers, scale and axes.; `bpy.ops.wm.html#bpy.ops.wm.stl_import` — Import STL as an object.; `bpy.ops.wm.html#bpy.ops.wm.stl_export` — Save the scene as an STL file.
Read next: `bpy.ops.wm.html#bpy.ops.wm.obj_import`, `bpy.ops.wm.html#bpy.ops.wm.obj_export`, `bpy.ops.wm.html#bpy.ops.wm.stl_import`, `bpy.ops.wm.html#bpy.ops.wm.stl_export`
Limits: Successful STL export does not prove printability or watertightness. Read scale, axes and modifier options and verify runtime operators; do not use remembered older operator names.
## glTF 2.0 file exchange — `gltf-file-exchange`
import_scene.gltf loads glTF 2.0; export_scene.gltf exports scenes with documented geometry, material, animation, skin and morph options.
Choose when: Exchange glTF/GLB or inspect glTF 2.0 transfer options.
Search aliases: glTF, GLB, gltf 2.0, xuất glb, nhập gltf
Evidence: `bpy.ops.import_scene.html#bpy.ops.import_scene.gltf` — Import glTF 2.0 with glb/gltf filters.; `bpy.ops.export_scene.html#bpy.ops.export_scene.gltf` — Export a scene to glTF 2.0 with export_animations, export_skins and export_morph parameters.
Read next: `bpy.ops.import_scene.html#bpy.ops.import_scene.gltf`, `bpy.ops.export_scene.html#bpy.ops.export_scene.gltf`
Limits: Export options do not guarantee faithful transfer of every shader, constraint or animation. Verify operator registration, read the actual export_format enum and validate the file in a suitable consumer.
## FBX file exchange — `fbx-file-exchange`
import_scene.fbx loads FBX; export_scene.fbx writes FBX with object, axis, armature and animation-baking options.
Choose when: Exchange files in FBX format.
Search aliases: FBX, xuất fbx, nhập fbx, fbx animation, fbx armature
Evidence: `bpy.ops.import_scene.html#bpy.ops.import_scene.fbx` — Import FBX with animation and bone-orientation options.; `bpy.ops.export_scene.html#bpy.ops.export_scene.fbx` — Write FBX with bake_anim and armature options; global_scale warns about importer support for scaled armatures.
Read next: `bpy.ops.import_scene.html#bpy.ops.import_scene.fbx`, `bpy.ops.export_scene.html#bpy.ops.export_scene.fbx`
Limits: The documentation warns that some importers do not support scaled armatures; verify the target consumer. Default bake/axis/bone options do not guarantee correctness; read parameters and validate by re-import or target consumer.
## USD scene exchange — `usd-scene-exchange`
wm.usd_import imports a USD stage into the scene; wm.usd_export writes a USD archive with geometry, light, camera, material, animation and unit options.
Choose when: Exchange USD scenes or inspect source-documented USDZ export options.
Search aliases: USD, USDZ, USD stage, xuất usd, nhập usd
Evidence: `bpy.ops.wm.html#bpy.ops.wm.usd_import` — Import a USD stage with camera, light, geometry, skeleton and material options.; `bpy.ops.wm.html#bpy.ops.wm.usd_export` — Export a USD archive; the signature includes export_animation, convert_scene_units and usdz_downscale_size.
Read next: `bpy.ops.wm.html#bpy.ops.wm.usd_import`, `bpy.ops.wm.html#bpy.ops.wm.usd_export`, `bpy.app.html#bpy.app.build_options`
Limits: USDZ parameters do not establish compatibility with every target consumer; read the options and test. Verify USD build support and exported/imported scene content, including units and material conversion.
## Alembic archive exchange — `alembic-archive-exchange`
wm.alembic_import loads Alembic archives; wm.alembic_export writes scenes with frame ranges, transform/geometry samples and data options.
Choose when: Exchange Alembic files or inspect frame-range scene export to this archive format.
Search aliases: Alembic, ABC, xuất abc, nhập abc, alembic archive
Evidence: `bpy.ops.wm.html#bpy.ops.wm.alembic_import` — Load an Alembic archive with set_frame_range and as_background_job.; `bpy.ops.wm.html#bpy.ops.wm.alembic_export` — Export an Alembic archive with start/end, xsamples, gsamples and UV, normal, hair and particle options.
Read next: `bpy.ops.wm.html#bpy.ops.wm.alembic_import`, `bpy.ops.wm.html#bpy.ops.wm.alembic_export`, `bpy.app.html#bpy.app.build_options`
Limits: The API does not prove preservation of every Blender data type; verify the required fields. as_background_job does not guarantee operation in every CLI context; probe operators/build and inspect output files.
## External paths and packed resources — `external-assets-paths-pack`
blend_paths lists external .blend references; abspath resolves // paths; pack_all/unpack_all pack or extract .blend resources.
Choose when: Audit resource paths or move between packed and external resources.
Search aliases: pack assets, đóng gói texture, file phụ thuộc, relative path, unpack, thiếu texture
Evidence: `bpy.utils.html#bpy.utils.blend_paths` — List external paths referenced by the loaded .blend.; `bpy.path.html#bpy.path.abspath` — Resolve // paths relative to the blend file or library.; `bpy.ops.file.html#bpy.ops.file.pack_all` — Pack used external files into the .blend.; `bpy.ops.file.html#bpy.ops.file.unpack_all` — Unpack resources using the selected method.
Read next: `bpy.utils.html#bpy.utils.blend_paths`, `bpy.path.html`, `bpy.ops.file.html#bpy.ops.file.pack_all`, `bpy.ops.file.html#bpy.ops.file.unpack_all`
Limits: A path list does not prove file existence or content correctness; inspect required resources. Unpack modes write external files; use only requested destinations and behavior.
## Discover all source pages in this domain
`python3 scripts/features.py pages files-assets` lists 71 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/animation-rigging.md
# Keyframes, drivers, rigs and constraints
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Property keyframes — `property-keyframes`
Insert a property value at a frame; keyframe_insert creates F-Curves and animation data when needed.
Choose when: Represent a property changing at specified times.
Search aliases: keyframe, đặt khóa chuyển động, animate thuộc tính, chuyển động theo frame, thay đổi theo mốc thời gian, đổi vị trí theo các mốc thời gian, property animation
Evidence: `bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert` — Insert a property keyframe, creating F-Curves and animation data as needed; accept data_path and frame.
Read next: `bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert`, `bpy.types.Scene.html#bpy.types.Scene.frame_set`
Limits: The valid, animatable data_path for the actual object is not yet known; read the property and probe before insertion. Keyframes alone do not prove that motion or rendered images meet the request.
## Property drivers — `property-drivers`
A Driver controls a property; DriverVariable supplies inputs from RNA properties, transforms, distances between bones/objects or angles between bones.
Choose when: Make a value depend on another input or expression instead of setting individual keyframes.
Search aliases: driver, liên kết tham số, thuộc tính phụ thuộc thuộc tính khác, scripted expression, property relationship
Evidence: `bpy.types.bpy_struct.html#bpy.types.bpy_struct.driver_add` — driver_add adds a driver to the property specified by path.; `bpy.types.DriverVariable.html#bpy.types.DriverVariable` — Driver variables use RNA properties, transforms, angular differences, distances or context properties.; `bpy.types.Driver.html#bpy.types.Driver.expression` — expression stores a Scripted Expression.
Read next: `bpy.types.bpy_struct.html#bpy.types.bpy_struct.driver_add`, `bpy.types.DriverVariable.html`, `bpy.types.DriverTarget.html`
Limits: The data_path, variable sources and expression execution in the current runtime are not yet verified. Valid expression syntax does not prove the absence of dependency cycles.
## F-Curve interpolation and evaluation — `animation-curve-interpolation`
Keyframe.interpolation controls interpolation to the next keyframe; FCurve.evaluate returns the value at a frame.
Choose when: Adjust transitions between keyframes or inspect numerical animation values at specific frames.
Search aliases: nội suy, easing, đường cong chuyển động, F-Curve, interpolation, giá trị tại frame
Evidence: `bpy.types.Keyframe.html#bpy.types.Keyframe.interpolation` — Set the interpolation method for the F-Curve segment from this keyframe to the next.; `bpy.types.FCurve.html#bpy.types.FCurve.evaluate` — evaluate(frame) returns the F-Curve value at the requested frame.
Read next: `bpy.types.Keyframe.html`, `bpy_types_enum_items/beztriple_interpolation_mode_items.html`, `bpy.types.FCurve.html`
Limits: Do not select interpolation enums from memory; read the linked enum list and verify the runtime. An individual F-Curve value does not prove the final result after constraints, drivers or blending.
## Actions and NLA composition — `actions-nla-composition`
An Action contains F-Curves; NlaStrip references an Action and controls repetition and blending with other strips.
Choose when: Reuse, repeat or combine existing animation segments.
Search aliases: Action, NLA, clip animation, trộn chuyển động, lặp chuyển động, repeat action, blend actions
Evidence: `bpy.types.Action.html#bpy.types.Action` — An Action is a collection of animation F-Curves.; `bpy.types.NlaStrip.html#bpy.types.NlaStrip` — NlaStrip references an existing Action and has action_slot.; `bpy.types.NlaStrip.html#bpy.types.NlaStrip.repeat` — repeat sets the number of repetitions of the Action range.; `bpy.types.NlaStrip.html#bpy.types.NlaStrip.blend_type` — REPLACE, COMBINE, ADD, SUBTRACT and MULTIPLY combine strip results.
Read next: `bpy.types.Action.html#bpy.types.Action.slots`, `bpy.types.Action.html#bpy.types.Action.layers`, `bpy.types.NlaStrips.html`, `bpy.types.NlaStrip.html`
Limits: The 5.2 source includes Action slots and layers; do not use a remembered older Action layout. Compatibility of the Action slot with the target and the blending result remain unverified.
## Armature bone hierarchy — `armature-bone-hierarchy`
Armature contains a bone hierarchy, commonly used for character rigging; ArmatureEditBones.new creates an edit bone.
Choose when: Create or edit a rig's bone structure.
Search aliases: hệ xương, rig nhân vật, armature, bone hierarchy, tạo bone, skeleton
Evidence: `bpy.types.Armature.html#bpy.types.Armature` — An Armature data-block contains a bone hierarchy, commonly used for character rigging.; `bpy.types.EditBone.html#bpy.types.EditBone` — EditBone is a bone in an Armature data-block's Edit Mode.; `bpy.types.ArmatureEditBones.html#bpy.types.ArmatureEditBones.new` — new(name) adds a bone and returns EditBone.
Read next: `bpy.types.Armature.html`, `bpy.types.ArmatureEditBones.html`, `info_gotchas_armatures_and_bones.html`
Limits: EditBone belongs to Edit Mode; verify mode/context before creating or editing. A bone structure does not prove mesh deformation bindings or correct weights.
## Pose bone control — `bone-pose-control`
PoseBone holds bone pose data; matrix_basis accesses location, scale and rotation relative to the parent and the bone's rest state.
Choose when: Set or animate pose data on an existing armature.
Search aliases: pose, tư thế nhân vật, xoay bone, pose bone, bone transform
Evidence: `bpy.types.PoseBone.html#bpy.types.PoseBone` — PoseBone is a channel defining bone pose data within a Pose.; `bpy.types.PoseBone.html#bpy.types.PoseBone.matrix_basis` — matrix_basis accesses transforms relative to the parent and the bone's own rest state.
Read next: `bpy.types.Pose.html`, `bpy.types.PoseBone.html`, `bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert`
Limits: Do not equate pose coordinates with world space or EditBone data; read each property's coordinate-space contract. API documentation does not supply scene bone names or joint limits; inspect the actual scene.
## Copy transforms constraint — `copy-transform-constraint`
CopyTransformsConstraint copies a target's full transform and provides modes for combining it with the existing transform.
Choose when: An object or bone needs the transform of a specified target.
Search aliases: copy transforms, sao chép transform, đi theo đối tượng, constraint transform, ràng buộc chuyển động
Evidence: `bpy.types.CopyTransformsConstraint.html#bpy.types.CopyTransformsConstraint` — Copy all transforms; describe mix_mode order and shear caveats.; `bpy.types.ObjectConstraints.html#bpy.types.ObjectConstraints.new` — ObjectConstraints.new adds a constraint by type.
Read next: `bpy.types.CopyTransformsConstraint.html`, `bpy.types.Constraint.html`, `bpy.types.ObjectConstraints.html`
Limits: Do not select mix_mode, target space or owner space from memory; read this constraint's contract. The documentation warns that some matrix combinations produce shear with rotation and non-uniform scale.
## Inverse kinematics constraint — `inverse-kinematics-chain`
KinematicConstraint provides inverse kinematics; chain_count sets the affected bone count and iterations limits solver iterations.
Choose when: Control an IK relationship within a bone chain.
Search aliases: IK, inverse kinematics, động học ngược, chuỗi xương, IK constraint
Evidence: `bpy.types.KinematicConstraint.html#bpy.types.KinematicConstraint` — Describe inverse kinematics; chain_count=0 uses all bones and iterations limits solving.
Read next: `bpy.types.KinematicConstraint.html`, `bpy.types.PoseBoneConstraints.html`, `bpy.types.Constraint.html`
Limits: The API establishes IK parameters, not a complete rig for a particular character. Read target, pole, chain and constraint spaces; solver convergence and the desired pose remain unproven.
## Follow path motion — `motion-follow-path`
FollowPathConstraint locks motion to a target Curve, with frame-relative offset or curve-length offset_factor and curve-following orientation.
Choose when: Move an object or camera along a specified Curve.
Search aliases: chạy theo đường, bay theo curve, camera theo đường, follow path, path animation
Evidence: `bpy.types.FollowPathConstraint.html#bpy.types.FollowPathConstraint` — Lock motion to a Curve target; offset_factor follows length and use_curve_follow follows curve heading/banking.
Read next: `bpy.types.FollowPathConstraint.html`, `bpy.types.ObjectConstraints.html`, `bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert`
Limits: This route does not supply a Curve, keyframes or axis configuration; establish these from scene data and relevant sources. The name Follow Path does not establish constant speed; measure positions by frame when required.
## Shape key creation and values — `shape-key-values`
Object.shape_key_add creates a shape key, optionally from the current shape mix; ShapeKey.value gives its value at the current frame.
Choose when: Create or animate shape keys for an identified object.
Search aliases: shape key, blend shape, trộn hình dạng, animate shape key, morph
Evidence: `bpy.types.Object.html#bpy.types.Object.shape_key_add` — Add a shape key; from_mix creates the shape from the current mix.; `bpy.types.ShapeKey.html#bpy.types.ShapeKey.value` — value is the shape-key value at the current frame.; `bpy.types.ShapeKey.html#bpy.types.ShapeKey` — ShapeKey.points provides optimized access but excludes legacy Curve shape keys.
Read next: `bpy.types.ShapeKey.html`, `bpy.types.Key.html`, `bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert`
Limits: Object support, compatible topology and the existence of the target shape are not yet established. ShapeKey.points does not support legacy Curve shape keys; choose accessors for the actual data type.
## Bake animation to an Action — `animation-bake-action`
nla.bake records selected objects' location/scale/rotation animation into an Action; visual_keying uses final transforms including constraints.
Choose when: Record evaluated motion into an Action over a specified frame range.
Search aliases: bake animation, bake constraint, chốt chuyển động thành keyframe, visual keying, bake action
Evidence: `bpy.ops.nla.html#bpy.ops.nla.bake` — Bake transform animation into an Action; visual_keying uses final transforms; document constraint/parent removal and writing to an existing Action.
Read next: `bpy.ops.nla.html#bpy.ops.nla.bake`, `bpy.ops.html`, `bpy.types.Action.html`
Limits: This bakes animation, not necessarily simulation caches. clear_constraints, clear_parents and use_current_action modify existing data; use them only within the requested scope. Check selection, mode, poll and the resulting Action after baking.
## Discover all source pages in this domain
`python3 scripts/features.py pages animation-rigging` lists 119 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
THIRD_PARTY_NOTICES.md
# Third-party notices and source provenance
## License scope
The adjacent [MIT License](LICENSE) covers original project code and original documentation. It does **not** replace the licenses or copyright of third-party content. In particular, source excerpts embedded in otherwise original catalog files retain their upstream rights.
| Material | Location | Treatment |
| --- | --- | --- |
| Extracted Blender API text and inventory | `references/api/api.sqlite3` | Derived from the authoring snapshot; not relicensed as original project text |
| Source excerpts and inventory-derived cards | `references/catalog/catalog.json.gz`, `symbols.json.gz` | Upstream content remains subject to its own terms |
| Original helper code and editorial text | `scripts/`, `SKILL.md`, authored workflow descriptions | Project MIT terms, excluding incorporated third-party content |
## Blender documentation
The authoring HTML attributed copyright to **Blender Authors**. Its `documentation_options.js` identified version `5.2`; root `objects.inv` named `Blender 5.2.1 LTS Python API`. The authoring input was a local snapshot named `blender_python_reference_5_2`, not a freshly downloaded release verified by this project. Raw HTML, web assets and build caches are not packaged in the skill.
Coverage and provenance metadata are stored in `references/api/api.sqlite3` and can be inspected with `scripts/docs.py stats`. An exact upstream source commit/build hash is not established by the current record.
The upstream [Blender license page](https://www.blender.org/about/license/) describes GPL licensing and component-specific terms. The official repository's [API documentation configuration](https://github.com/blender/blender/blob/main/doc/python_api/conf.py) carries a `GPL-2.0-or-later` identifier. These are upstream provenance references, not a complete license determination for every file in this particular supplied HTML snapshot. Do not assign the Blender Manual's license to API documentation merely because both are hosted by Blender.
The authoring snapshot contained a cached `Blender 5.3 Manual` inventory, not the complete Manual. It is not merged into API search. Linked external pages and their licenses are not automatically included in this corpus.
## Redistribution review
The current provenance record does not establish complete redistribution terms for the derived API text. Before publicly redistributing the SQLite corpus or catalog excerpts:
1. Identify the exact source snapshot and applicable terms for API text.
2. Add the required license texts, attribution and source information for those components.
3. Confirm that distribution of the derived forms meets those terms; do not describe the whole corpus as MIT-licensed.
4. Record any deliberate source changes in provenance and rebuild derived data when needed.
Adding a project MIT License does not complete these upstream checks. This notice deliberately preserves the remaining provenance gap rather than claiming blanket redistribution clearance.
## Attribution and affiliation
Blender and its documentation are created by Blender's contributors. This repository is an independent community project and is not endorsed by or affiliated with the Blender Foundation.
references/catalog/domains/geometry-nodes.md
# Geometry Nodes, fields and instances
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Geometry Nodes graph and modifier — `geometry-nodes-graph`
GeometryNodeTree holds linked geometry nodes; NodesModifier.node_group references the graph driving the modifier.
Choose when: Create a geometry graph or a modifier driven by a node group; select specific node routes for processing operations.
Search aliases: dựng Geometry Nodes, hình học procedural, node graph hình học, geometry node group, nodes modifier, procedural geometry graph
Evidence: `bpy.types.GeometryNodeTree.html` — A node tree contains linked nodes for geometry.; `bpy.types.NodesModifier.html#bpy.types.NodesModifier.node_group` — A node group controls the modifier.; `bpy.types.Nodes.html#bpy.types.Nodes.new` — Create a node using bl_idname; the source warns against node.type.; `bpy.types.NodeTreeInterface.html#bpy.types.NodeTreeInterface.new_socket` — Create an interface socket; socket_type is listed as DEFAULT.
Read next: `bpy.types.GeometryNodeTree.html`, `bpy.types.NodesModifier.html#bpy.types.NodesModifier.node_group`, `bpy.types.Nodes.html#bpy.types.Nodes.new`, `bpy.types.NodeLinks.html#bpy.types.NodeLinks.new`, `bpy.types.NodeTreeInterface.html#bpy.types.NodeTreeInterface.new_socket`
Limits: Nodes.new requires node.bl_idname, not node.type. NodeTreeInterface.new_socket lists only DEFAULT for socket_type; this page does not establish all runtime socket types.
## Surface point distribution and instancing — `geometry-nodes-surface-scatter`
DistributePointsOnFaces generates points on mesh surfaces; InstanceOnPoints creates geometry references at points without duplicating underlying data.
Choose when: Distribute geometry instances over a surface; trees or rocks describe user-supplied content, not assets generated by these nodes.
Search aliases: rải cây, rải đá, phân bố vật thể trên mặt, scatter objects, surface scattering, distribute points on faces, instance on points
Evidence: `bpy.types.GeometryNodeDistributePointsOnFaces.html` — Generate points scattered on a mesh surface with RANDOM or POISSON distribution.; `bpy.types.GeometryNodeInstanceOnPoints.html` — Generate geometry references at each point without duplicating underlying data.
Read next: `bpy.types.GeometryNodeDistributePointsOnFaces.html`, `bpy.types.GeometryNodeInstanceOnPoints.html`, `bpy.types.GeometryNodeTree.html`
Limits: These nodes do not supply tree or rock models; they describe point distribution and geometry references.
## Realize instances — `geometry-nodes-realize`
RealizeInstances converts instances into real geometry data.
Choose when: The input contains instances and a later step requires geometry data instead of instance references.
Search aliases: chuyển instance thành hình học thật, hiện thực instance, realize instances, instances to geometry, real geometry data
Evidence: `bpy.types.GeometryNodeRealizeInstances.html` — Convert instances to real geometry data; describe realize_to_point_domain as legacy compatibility.
Read next: `bpy.types.GeometryNodeRealizeInstances.html`, `bpy.types.GeometryNodeInstanceOnPoints.html`
Limits: The source says geometry data; it does not claim every input type becomes a mesh. realize_to_point_domain is documented as compatibility behavior for version 5.0 and earlier.
## Named attribute field storage and retrieval — `geometry-nodes-attribute-fields`
StoreNamedAttribute stores a field result on geometry under a name; InputNamedAttribute reads the specified attribute.
Choose when: Exchange geometry data through named attributes in a node graph, with source-supported types and domains.
Search aliases: ghi named attribute, đọc thuộc tính node, lưu field, store named attribute, named attribute, field to attribute
Evidence: `bpy.types.GeometryNodeStoreNamedAttribute.html` — Store a field result under a name with data_type and domain.; `bpy.types.GeometryNodeInputNamedAttribute.html` — Retrieve a specified attribute with data_type.
Read next: `bpy.types.GeometryNodeStoreNamedAttribute.html`, `bpy.types.GeometryNodeInputNamedAttribute.html`, `bpy.types.Attribute.html`
## Geometry raycast hit information — `geometry-nodes-raycast`
GeometryNodeRaycast casts rays from context geometry toward target geometry and retrieves hit information.
Choose when: Compute ray/geometry hit information in a Geometry Nodes graph.
Search aliases: raycast trong node, bắn tia vào mesh, lấy điểm chạm bề mặt, geometry raycast, hit point data, ray target geometry
Evidence: `bpy.types.GeometryNodeRaycast.html` — Cast rays from context geometry to target geometry and retrieve hit-point information.
Read next: `bpy.types.GeometryNodeRaycast.html`, `bpy.types.GeometryNodeTree.html`
Limits: This describes a geometry query, not renderer shadow configuration.
## Simulation zone input output pairing — `geometry-nodes-simulation-zone`
SimulationInput/Output pass data into and out of a simulation zone; pair_with_output pairs the nodes and reports success.
Choose when: A simulation zone is required and the task needs the node pairing and state-data APIs.
Search aliases: simulation zone, vùng mô phỏng Geometry Nodes, ghép simulation input output, node simulation state
Evidence: `bpy.types.GeometryNodeSimulationInput.html` — Describe simulation zone input and paired_output.; `bpy.types.GeometryNodeSimulationOutput.html` — Describe simulation zone output and state_items.; `bpy.types.GeometryNodeSimulationInput.html#bpy.types.GeometryNodeSimulationInput.pair_with_output` — Pair a zone input with an output and return a success boolean.
Read next: `bpy.types.GeometryNodeSimulationInput.html`, `bpy.types.GeometryNodeSimulationOutput.html`, `bpy.types.NodesModifier.html`
Limits: These pages describe node pairing and state items; they do not provide simulation equations or a complete evaluation/baking workflow for a particular effect.
## Discover all source pages in this domain
`python3 scripts/features.py pages geometry-nodes` lists 510 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/lights-shadows.md
# Lights, cameras and shadows
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Scene object shadow-ray controls — `scene-shadow-ray-controls`
Object.visible_shadow controls visibility to shadow rays. AreaLight.shadow_soft_size describes light size for ray-traced shadow sampling; Light.use_shadow has only type/default information in the source.
Choose when: Explore scene-object, light or shadow-ray controls; continue reading object, light and engine evidence.
Search aliases: đổ bóng, bóng vật thể, bóng xuống sàn, bóng mềm, cast shadow, soft shadow, shadow rays
Evidence: `bpy.types.Object.html#bpy.types.Object.visible_shadow` — Control object visibility to shadow rays.; `bpy.types.AreaLight.html#bpy.types.AreaLight.shadow_soft_size` — Set light size for ray-traced shadow sampling without a complete engine-specific softness contract.; `bpy.types.AreaLight.html#bpy.types.AreaLight.size` — Set area-light size, or X dimension for rectangular lights.
Read next: `bpy.types.Object.html#bpy.types.Object.visible_shadow`, `bpy.types.Light.html`, `bpy.types.AreaLight.html`, `bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine`
Limits: Light.use_shadow does not document a complete shadow algorithm. Do not assume increasing AreaLight.shadow_soft_size guarantees softer shadows in every engine; AreaLight.size describes source area separately. This corpus does not supply a complete soft-shadow recipe; implement supported parts and report remaining evidence gaps.
## Shadow catcher for real footage — `shadow-catcher-real-footage`
Object.is_shadow_catcher renders only shadows and reflections on an object for compositing into real footage. Flagged objects are considered present in the footage; unflagged objects are synthetic additions.
Choose when: Composite synthetic objects into footage where an existing surface should receive rendered shadows/reflections.
Search aliases: đổ bóng, bắt bóng, ghép model vào footage, ghép vào ảnh thật, shadow catcher, real footage, compositing shadows
Evidence: `bpy.types.Object.html#bpy.types.Object.is_shadow_catcher` — Render shadows and reflections for real-footage compositing; describe the roles of flagged and unflagged objects.
Read next: `bpy.types.Object.html#bpy.types.Object.is_shadow_catcher`, `bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent`, `bpy.types.CompositorNodeAlphaOver.html`, `bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine`
Limits: The anchor does not establish supported engines or a camera, lighting and compositing recipe. A flag alone does not complete the composite; read further and verify runtime/render output.
## Light linking and blocker collections — `light-linking-and-blockers`
ObjectLightLinking.receiver_collection defines an emitter's light-linking relationships; blocker_collection defines objects blocking that emitter's light.
Choose when: Control emitter relationships with receiver collections or light-blocker collections.
Search aliases: light linking, shadow linking, chặn ánh sáng, vật nhận sáng, blocker collection, receiver collection
Evidence: `bpy.types.ObjectLightLinking.html#bpy.types.ObjectLightLinking.receiver_collection` — A collection defines emitter light-linking relationships.; `bpy.types.ObjectLightLinking.html#bpy.types.ObjectLightLinking.blocker_collection` — A collection defines objects blocking light from the emitter.
Read next: `bpy.types.ObjectLightLinking.html`, `bpy.types.CollectionLightLinking.html`, `bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine`
Limits: The source does not establish support in every engine. Read collection contracts and editing APIs and check the actual engine before promising an effect.
## Point, sun, spot and area light sources — `choose-light-source-shape`
The source describes POINT as omnidirectional, SUN as fixed-direction parallel rays, SPOT as a directional cone and AREA as a directional area source. BlendDataLights.new creates a light data-block.
Choose when: Choose a light-source shape before reading PointLight, SunLight, SpotLight or AreaLight properties.
Search aliases: tạo đèn, nguồn sáng, đèn điểm, đèn rọi, đèn diện tích, point light, sun light, spot light, area light
Evidence: `bpy_types_enum_items/light_type_items.html` — Describe POINT, SUN, SPOT and AREA source shapes.; `bpy.types.BlendDataLights.html#bpy.types.BlendDataLights.new` — Create a light data-block using the type enum.
Read next: `bpy_types_enum_items/light_type_items.html`, `bpy.types.BlendDataLights.html#bpy.types.BlendDataLights.new`, `bpy.types.AreaLight.html`, `bpy.types.SpotLight.html`, `bpy.types.PointLight.html`, `bpy.types.SunLight.html`
Limits: Source shape does not provide appropriate power, position, exposure or shadow settings. Derive these from the request, supplied evidence and output checks.
## Discover all source pages in this domain
`python3 scripts/features.py pages lights-shadows` lists 27 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/grease-pencil-freestyle.md
# Grease Pencil, 2D strokes and Freestyle
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Grease Pencil shadow effect — `grease-pencil-shadow-effect`
ShaderFx affects Grease Pencil objects. ShaderFxShadow provides shadow offset, color, scale, rotation and pixel blur; ObjectShaderFx.new adds an effect.
Choose when: Apply the documented shadow effect to an existing Grease Pencil object.
Search aliases: đổ bóng, bóng Grease Pencil, bóng nét vẽ, Grease Pencil shadow, ShaderFxShadow, bóng 2D
Evidence: `bpy.types.ShaderFx.html#bpy.types.ShaderFx` — Effects apply to Grease Pencil objects.; `bpy.types.ShaderFxShadow.html#bpy.types.ShaderFxShadow` — Describe a shadow effect with offset, shadow_color, scale, rotation and pixel blur.; `bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new` — Add a shader effect by name and type.
Read next: `bpy.types.ShaderFx.html`, `bpy.types.ShaderFxShadow.html`, `bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new`, `bpy_types_enum_items/object_shaderfx_type_items.html`
Limits: A request for a 2D shadow does not extend this route to arbitrary images or meshes. Verify object type, effect enum and render behavior; the source is not a complete recipe.
## Grease Pencil glow effect — `grease-pencil-glow-effect`
ShaderFxGlow is a Grease Pencil effect with glow_color, mode, opacity, size and a color-selection threshold; use_glow_under has a Regular blend-mode limitation.
Choose when: Apply glow to a Grease Pencil object rather than a compositor image or emission shader.
Search aliases: glow Grease Pencil, quầng sáng nét vẽ, Grease Pencil glow, ShaderFxGlow
Evidence: `bpy.types.ShaderFx.html#bpy.types.ShaderFx` — ShaderFx affects Grease Pencil objects.; `bpy.types.ShaderFxGlow.html#bpy.types.ShaderFxGlow` — Describe glow parameters and the use_glow_under limitation with Regular blend mode.
Read next: `bpy.types.ShaderFxGlow.html`, `bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new`, `bpy_types_enum_items/object_shaderfx_type_items.html`
Limits: The glow name does not determine mode or size. Read blending rules and verify the runtime; the source does not support use_glow_under with Regular blend mode.
## Freestyle contours, silhouettes and edges — `freestyle-edge-lines`
FreestyleLineSet associates lines with styles and selects contours, silhouettes, creases and other edges; FreestyleSettings offers scripting/parameter-editor modes and a separate render pass.
Choose when: Select and render documented edge/contour types through FreestyleLineSet.
Search aliases: đường viền vật thể, silhouette, Freestyle, render nét, contour lines, crease edges
Evidence: `bpy.types.FreestyleLineSet.html#bpy.types.FreestyleLineSet` — Select contours, silhouettes, creases and material boundaries and reference a linestyle.; `bpy.types.FreestyleSettings.html#bpy.types.FreestyleSettings` — Configure Freestyle per ViewLayer with SCRIPT/EDITOR modes and as_render_pass.
Read next: `bpy.types.FreestyleLineSet.html`, `bpy.types.FreestyleSettings.html`, `bpy.types.FreestyleLineStyle.html`, `freestyle.html`
Limits: This is not every Grease Pencil workflow or a guarantee of any cartoon style. Read edge selection, style and engine contracts; the snapshot is not a complete artistic recipe.
## Discover all source pages in this domain
`python3 scripts/features.py pages grease-pencil-freestyle` lists 130 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/geometry.md
# Mesh, BMesh and modifiers
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Mesh from explicit vertices edges and faces — `mesh-from-explicit-data`
Mesh.from_pydata accepts vertex coordinates and edge/face indices; an empty edge list causes edges to be inferred from polygons.
Choose when: The output can be specified as coordinates and geometry connections.
Search aliases: tạo mesh bằng tọa độ, dựng đa giác, mesh từ mảng, vertices edges faces, from_pydata, procedural mesh arrays
Evidence: `bpy.types.Mesh.html#bpy.types.Mesh.from_pydata` — Create a mesh from vertices, edges and faces; infer missing edges from polygons; warn about invalid data.; `bpy.types.Mesh.html#bpy.types.Mesh.validate` — validate returns True if invalid data was corrected or removed.
Read next: `bpy.types.Mesh.html#bpy.types.Mesh.from_pydata`, `bpy.types.Mesh.html#bpy.types.Mesh.validate`, `info_gotchas_meshes.html`
Limits: from_pydata does not prevent invalid mesh data; the source calls for validation when input validity is not guaranteed.
## Connected topology editing with BMesh — `mesh-connected-topology-editing`
BMesh exposes geometry connectivity and mesh editing operations such as split, separate, collapse and dissolve.
Choose when: Edit connectivity flexibly rather than only construct mesh storage arrays.
Search aliases: sửa topology, chỉnh liên kết đỉnh cạnh mặt, tách cạnh, dissolve, collapse, connected mesh editing, BMesh
Evidence: `bmesh.html` — The introduction describes connectivity and split/separate/collapse/dissolve editing; Disk/Radial data is not exposed.; `bmesh.html#bmesh.from_edit_mesh` — Retrieve the BMesh of a mesh in Edit Mode.; `info_gotchas_meshes.html` — Edit Mode has separate data and obj.data may be out of sync.
Read next: `bmesh.html`, `bmesh.types.html`, `bmesh.ops.html`, `info_gotchas_meshes.html`
Limits: bmesh.from_edit_mesh requires a mesh already in Edit Mode; obj.data may not be synchronized with Edit Mode. The BMesh page states that Disk/Radial data is not exposed to Python.
## Extrude a face region — `mesh-extrude-region`
BMesh extrude_face_region creates extruded geometry from input edges/faces and returns geometry; it does not transform positions itself.
Choose when: Create extruded geometry from a selected BMesh region.
Search aliases: đùn mặt, extrude mặt, kéo dài vùng mesh, extrude faces, face region extrusion
Evidence: `bmesh.ops.html#bmesh.ops.extrude_face_region` — Extrude faces without transformation; accept edges/faces and return geom.
Read next: `bmesh.ops.html#bmesh.ops.extrude_face_region`, `bmesh.ops.html#bmesh.ops.translate`, `bmesh.html`
Limits: The source explicitly states that extrude_face_region does not transform; displacement requires a separately documented transformation operation.
## Bisect mesh with a plane — `mesh-plane-cut`
BMesh bisect_plane cuts a mesh using a plane point and normal, with options to remove either side.
Choose when: Specify a cutting plane and the side to keep or remove.
Search aliases: cắt đôi mesh, cắt theo mặt phẳng, plane cut, bisect mesh, trim geometry
Evidence: `bmesh.ops.html#bmesh.ops.bisect_plane` — Cut a mesh with a plane; document plane_co, plane_no and clear_outer/clear_inner.
Read next: `bmesh.ops.html#bmesh.ops.bisect_plane`, `bmesh.html`
Limits: The bisect_plane description does not promise to cap the cut automatically.
## Weld nearby vertices and triangulate faces — `mesh-weld-and-triangulate`
remove_doubles merges groups of vertices within a distance threshold; triangulate splits quads and n-gons into triangles.
Choose when: Merge nearby vertices or convert faces into triangles using the documented topology operations.
Search aliases: gộp đỉnh trùng, hàn đỉnh, tam giác hóa, remove doubles, merge by distance, triangulate faces
Evidence: `bmesh.ops.html#bmesh.ops.remove_doubles` — Find and merge vertex groups closer than dist.; `bmesh.ops.html#bmesh.ops.triangulate` — Split quads and n-gons into triangles.; `bpy.types.Mesh.html#bpy.types.Mesh.calc_loop_triangles` — Compute loop triangle tessellation.
Read next: `bmesh.ops.html#bmesh.ops.remove_doubles`, `bmesh.ops.html#bmesh.ops.triangulate`, `bmesh.html`
Limits: Mesh.calc_loop_triangles computes tessellation; this is not the same as changing topology with bmesh.ops.triangulate.
## Geometry attributes by name type and domain — `mesh-geometry-attributes`
An Attribute stores data attached to geometry elements, with a name, data type and domain such as points, curves or faces.
Choose when: Store typed data on a geometry domain for later reading or processing.
Search aliases: thuộc tính hình học, dữ liệu trên đỉnh, thuộc tính trên mặt, geometry attribute, named data, point face domain
Evidence: `bpy.types.Attribute.html` — Explain geometry attributes, unique names, types and domains.; `bpy.types.AttributeGroupMesh.html#bpy.types.AttributeGroupMesh.new` — Add an attribute with name, type and domain.
Read next: `bpy.types.Attribute.html`, `bpy.types.AttributeGroupMesh.html#bpy.types.AttributeGroupMesh.new`, `bpy_types_enum_items/attribute_domain_items.html`, `bpy_types_enum_items/attribute_type_items.html`
Limits: Name, type and domain are separate properties; do not infer a domain solely from vertex count.
## Boolean intersection union and difference — `modifier-boolean`
The Boolean modifier supports intersection, union and difference of meshes; a collection can supply operand meshes.
Choose when: Represent mesh intersection, union or subtraction as a modifier.
Search aliases: khoét lỗ bằng vật thể, trừ khối, giao khối, hợp khối, boolean modifier, mesh union, mesh difference, mesh intersection
Evidence: `bpy.types.BooleanModifier.html#bpy.types.BooleanModifier.operation` — INTERSECT keeps common geometry; UNION combines additively; DIFFERENCE subtracts.; `bpy.types.BooleanModifier.html` — collection supplies mesh objects for the Boolean operation.
Read next: `bpy.types.BooleanModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`, `bpy_types_enum_items/object_modifier_type_items.html`
## Bevel edges and vertices — `geometry-bevel`
BevelModifier rounds edges/vertices; bmesh.ops.bevel operates on geometry with offset, segments and profile.
Choose when: Round edges/vertices; select the modifier route to retain a modifier, or BMesh when editing topology directly.
Search aliases: bo cạnh, bo góc, vát cạnh, làm tròn cạnh, bevel, round edges, chamfer
Evidence: `bpy.types.BevelModifier.html` — The modifier rounds edges and vertices.; `bmesh.ops.html#bmesh.ops.bevel` — Bevel edges/vertices with offset, segments and profile; profile 0.5 is described as round.
Read next: `bpy.types.BevelModifier.html`, `bmesh.ops.html#bmesh.ops.bevel`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
## Array duplication modifier — `modifier-array`
ArrayModifier duplicates geometry with a copy count, constant offset and a curve for fitting array length.
Choose when: Create an array controlled by modifier count and spacing.
Search aliases: tạo dãy vật thể, lặp hình học, nhân theo khoảng cách, array modifier, repeated geometry, duplicate array
Evidence: `bpy.types.ArrayModifier.html` — Describe array duplication, count, constant_offset_displace and a curve for fitting length.
Read next: `bpy.types.ArrayModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
## Mirror modifier — `modifier-mirror`
MirrorModifier exposes mirroring axes, a reference object and a merge distance for mirrored vertices.
Choose when: Mirror geometry across axes or relative to a reference object using a modifier.
Search aliases: đối xứng mesh, phản chiếu hình học, mirror mesh, symmetrical model, mirror modifier
Evidence: `bpy.types.MirrorModifier.html` — Describe mirroring, mirror_object and the vertex merge threshold.; `bpy.types.MirrorModifier.html#bpy.types.MirrorModifier.use_axis` — An array of three flags enables mirroring by axis.
Read next: `bpy.types.MirrorModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
## Solidify shell thickness — `modifier-solidify`
SolidifyModifier creates a solid skin; thickness controls its shell thickness.
Choose when: Create a shell with thickness from input geometry.
Search aliases: tạo độ dày, làm vỏ dày, solidify, shell thickness, thicken surface
Evidence: `bpy.types.SolidifyModifier.html` — Create a solid skin and compensate for sharp angles.; `bpy.types.SolidifyModifier.html#bpy.types.SolidifyModifier.thickness` — thickness sets shell thickness.
Read next: `bpy.types.SolidifyModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
## Subdivision surface — `modifier-subdivision`
SubsurfModifier provides Catmull-Clark for smooth curved surfaces and Simple for subdividing faces without changing shape.
Choose when: Increase surface subdivisions and explicitly choose whether to curve the surface.
Search aliases: chia nhỏ bề mặt, làm mịn bằng subdivision, subdivision surface, Catmull-Clark, simple subdivision
Evidence: `bpy.types.SubsurfModifier.html#bpy.types.SubsurfModifier.subdivision_type` — CATMULL_CLARK creates a smooth curved surface; SIMPLE subdivides without changing shape.
Read next: `bpy.types.SubsurfModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
## Remesh regular topology — `modifier-remesh`
RemeshModifier generates a new surface with regular topology following the input mesh; adaptivity reduces detail where less is needed and creates triangles.
Choose when: Replace surface topology with a new mesh following the input shape.
Search aliases: remesh, tạo lại lưới, topology đều, voxel remesh modifier, rebuild mesh surface
Evidence: `bpy.types.RemeshModifier.html` — Generate regular surface topology from an input mesh; adaptivity creates triangles when simplifying.
Read next: `bpy.types.RemeshModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
Limits: The source says adaptivity can create triangles; it does not promise all-quad output.
## Decimate geometry — `modifier-decimate`
DecimateModifier offers edge collapse, un-subdivision and planar dissolve; ratio controls the target triangle ratio for collapse.
Choose when: Reduce geometry with a documented decimation method.
Search aliases: giảm polygon, giảm số mặt, mesh nhẹ hơn, decimate, polygon reduction, low poly reduction
Evidence: `bpy.types.DecimateModifier.html` — Describe COLLAPSE, UNSUBDIV and DISSOLVE.; `bpy.types.DecimateModifier.html#bpy.types.DecimateModifier.ratio` — Target triangle ratio applies only to collapse.
Read next: `bpy.types.DecimateModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
Limits: The source limits ratio to collapse; do not use it as a common control for every decimate_type.
## Shrinkwrap to a target — `modifier-shrinkwrap`
ShrinkwrapModifier wraps an object onto a target, with an auxiliary target and cull_face controls for projection based on face orientation.
Choose when: Make geometry follow a target mesh through shrink wrapping.
Search aliases: áp lưới lên bề mặt, bám mesh mục tiêu, shrinkwrap, wrap mesh to target, project vertices onto mesh
Evidence: `bpy.types.ShrinkwrapModifier.html` — Describe wrapping to a target, auxiliary_target and cull_face.
Read next: `bpy.types.ShrinkwrapModifier.html`, `bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new`
Limits: The shrinkwrap description does not establish a complete automatic retopology workflow.
## Discover all source pages in this domain
`python3 scripts/features.py pages geometry` lists 118 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/render.md
# Rendering, passes, color and image output
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Still and animation rendering — `render-still-or-animation`
bpy.ops.render.render parameters describe animation rendering over a scene frame range; write_still saves to the output path when animation is off; frame_start/frame_end bound animation rendering.
Choose when: Render a still or frame range; read RenderSettings for requested paths, dimensions and formats.
Search aliases: render ảnh, render animation, xuất frame, render still, render animation range, write still
Evidence: `bpy.ops.render.html#bpy.ops.render.render` — Describe animation, write_still, frame_start, frame_end and scene.; `bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine` — Expose engine with the snapshot's BLENDER_EEVEE enum.
Read next: `bpy.ops.render.html#bpy.ops.render.render`, `bpy.types.RenderSettings.html`, `bpy.types.ImageFormatSettings.html`
Limits: The operator introduction says Undocumented, but parameters have descriptions. The engine enum lists only BLENDER_EEVEE in this snapshot; it is not a complete runtime inventory and does not justify remembered Cycles settings.
## Shadow render pass — `shadow-render-pass`
ViewLayer.use_pass_shadow is described as delivering a shadow pass.
Choose when: Obtain a separate shadow layer for later rendering/compositing.
Search aliases: đổ bóng, lớp bóng, xuất bóng riêng, shadow pass, shadow render pass
Evidence: `bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_shadow` — Deliver a shadow pass.
Read next: `bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_shadow`, `bpy.types.RenderPass.html`, `bpy.types.CompositorNodeRLayers.html`, `bpy.types.CompositorNodeOutputFile.html`
Limits: The source does not define pixel values, compositing formulas or engine availability. Enabling the flag does not prove correct pass data; read pass access APIs and inspect a real render.
## Transparent world background — `transparent-world-background`
RenderSettings.film_transparent makes the world background transparent for compositing over another background.
Choose when: Composite the rendered world background over another image.
Search aliases: nền trong suốt, render alpha, transparent background, transparent film, tách nền render
Evidence: `bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent` — Make the world background transparent for compositing over another background.
Read next: `bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent`, `bpy.types.ImageFormatSettings.html`, `bpy.types.CompositorNodeAlphaOver.html`
Limits: The property does not establish alpha-capable file output, remove scene background geometry or supply a compositing recipe. Read output-format and scene-data contracts.
## Bake selected-object image textures — `bake-selected-object-textures`
bpy.ops.object.bake bakes selected-object image textures; use_selected_to_active bakes selected objects' shading onto the active object; type describes passes and engine limitations.
Choose when: Bake textures with identified source objects, active object and required pass type.
Search aliases: bake texture, bake normal, bake vật liệu, bake image textures, selected to active
Evidence: `bpy.ops.object.html#bpy.ops.object.bake` — Bake image textures with selected-to-active behavior, pass engine limitations and target/save_mode parameters.
Read next: `bpy.ops.object.html#bpy.ops.object.bake`, `bpy_types_enum_items/bake_pass_type_items.html`, `bpy_types_enum_items/bake_target_items.html`, `bpy.types.BakeSettings.html`
Limits: Read pass/target enums and confirm selection, active object and engine support. Do not supply remembered high-poly/low-poly recipes or pass choices.
## Display color management — `display-color-management`
ColorManagedViewSettings controls image display; exposure scales by 2^exposure before the display transform and gamma applies afterward, with white-balance and view_transform properties.
Choose when: Adjust display color transformation, exposure or white balance rather than surface shader properties.
Search aliases: quản lý màu, exposure, gamma, white balance, cân bằng trắng, view transform, color management
Evidence: `bpy.types.ColorManagedViewSettings.html#bpy.types.ColorManagedViewSettings` — Describe display color management, exposure/gamma order, white balance and view transforms.
Read next: `bpy.types.ColorManagedViewSettings.html`, `bpy.types.Scene.html#bpy.types.Scene.view_settings`
Limits: The snapshot's view_transform enum lists only NONE; do not choose AgX, Filmic or looks from memory. Inspect runtime color configurations; exposure changes are not light-power changes.
## Discover all source pages in this domain
`python3 scripts/features.py pages render` lists 31 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/scene.md
# Scenes, objects, collections and transforms
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Create objects and link collections — `scene-object-assembly`
Create an object in the database using a data-block, or None for an empty; linking it to a collection is a separate API operation.
Choose when: Assemble objects or empties and specify the collection that contains them.
Search aliases: dựng cảnh, thêm vật thể, tạo object, tổ chức collection, scene assembly, create object, link collection, empty object
Evidence: `bpy.types.BlendDataObjects.html#bpy.types.BlendDataObjects.new` — Create a database object; object_data can be None for an empty.; `bpy.types.CollectionObjects.html#bpy.types.CollectionObjects.link` — Add an object to a collection.
Read next: `bpy.types.BlendDataObjects.html#bpy.types.BlendDataObjects.new`, `bpy.types.CollectionObjects.html#bpy.types.CollectionObjects.link`, `bpy.types.Scene.html`
Limits: BlendDataObjects.new only creates the database object; use CollectionObjects.link to add it to a collection.
## Object transforms and parenting — `scene-transforms-parenting`
Object exposes a world-space transformation matrix and a reference to its parent object.
Choose when: Set spatial transforms or establish object parenting.
Search aliases: di chuyển vật thể, xoay vật thể, đặt vị trí, cha con, phân cấp object, world transform, parent object, matrix_world
Evidence: `bpy.types.Object.html#bpy.types.Object.matrix_world` — matrix_world is the world-space transformation matrix.; `bpy.types.Object.html#bpy.types.Object.parent` — parent references the parent object.
Read next: `bpy.types.Object.html#bpy.types.Object.matrix_world`, `bpy.types.Object.html#bpy.types.Object.parent`, `bpy.types.Object.html#bpy.types.Object.matrix_parent_inverse`, `mathutils.html`
Limits: The parent description identifies the parent object; it does not establish how to preserve the world transform when changing parents.
## Collection and child object instancing — `scene-collection-instancing`
An Object can instance an existing collection or instance child objects on vertices or faces.
Choose when: Use Object instancing with an existing collection or parent-child object relationship.
Search aliases: lặp collection, instance bộ vật thể, nhân vật thể trên đỉnh, collection instance, vertex instancing, face instancing
Evidence: `bpy.types.Object.html#bpy.types.Object.instance_collection` — instance_collection uses an existing collection.; `bpy.types.Object.html#bpy.types.Object.instance_type` — VERTS and FACES instance child objects on vertices or faces; COLLECTION enables collection instancing.
Read next: `bpy.types.Object.html#bpy.types.Object.instance_type`, `bpy.types.Object.html#bpy.types.Object.instance_collection`, `bpy.types.Depsgraph.html#bpy.types.Depsgraph.object_instances`
## Evaluated geometry and instances — `scene-evaluated-geometry`
The dependency graph exposes evaluated animation, constraints and modifiers; to_mesh creates a temporary mesh owned by the object.
Choose when: Measure, inspect or retrieve evaluated geometry rather than only the original data.
Search aliases: mesh sau modifier, đo kết quả biến dạng, hình học đã đánh giá, đọc instances, evaluated geometry, evaluated mesh, dependency graph, geometry after modifiers
Evidence: `bpy.types.Depsgraph.html` — The Evaluated ID example describes animation, constraints and modifiers in evaluated state.; `bpy.types.ID.html#bpy.types.ID.evaluated_get` — Return the ID from the last evaluation without guaranteeing graph re-evaluation.; `bpy.types.Object.html#bpy.types.Object.to_mesh` — Create a temporary mesh owned by the object and release it with to_mesh_clear.
Read next: `bpy.types.Depsgraph.html`, `bpy.types.Context.html#bpy.types.Context.evaluated_depsgraph_get`, `bpy.types.Object.html#bpy.types.Object.to_mesh`, `bpy.types.Depsgraph.html#bpy.types.Depsgraph.object_instances`
Limits: ID.evaluated_get returns the last evaluation result; it does not guarantee that the graph has been evaluated. Object.to_mesh creates temporary data that requires to_mesh_clear; do not link it directly to an object in the main database.
## Discover all source pages in this domain
`python3 scripts/features.py pages scene` lists 35 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/shading.md
# Materials, shaders, textures and worlds
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Principled surface material — `surface-principled-material`
ShaderNodeBsdfPrincipled is described as a physically based surface shader based on OpenPBR; Material.node_tree holds the material's node tree.
Choose when: Use a physically based surface shader; read subsurface or scattering methods when those properties are required.
Search aliases: vật liệu bề mặt, shader vật lý, surface material, principled, OpenPBR
Evidence: `bpy.types.ShaderNodeBsdfPrincipled.html#bpy.types.ShaderNodeBsdfPrincipled` — Describe an OpenPBR-based physically based surface shader.; `bpy.types.Material.html#bpy.types.Material.node_tree` — Expose the node tree of a node-based material.
Read next: `bpy.types.ShaderNodeBsdfPrincipled.html`, `bpy.types.Material.html`, `bpy.types.Nodes.html`, `bpy.types.NodeLinks.html`
Limits: The class page does not list all inputs or a complete material recipe. Read node/socket data and probe the runtime; do not supply remembered socket names, values or links.
## Image texture sampling — `image-texture-sampling`
ShaderNodeTexImage samples an image file as a texture, with documented extension, interpolation and FLAT, BOX, SPHERE and TUBE projection modes.
Choose when: Use an image file in a shader network and select projection from its documented contract.
Search aliases: texture ảnh, dán ảnh lên vật thể, image texture, texture projection, image mapping
Evidence: `bpy.types.ShaderNodeTexImage.html#bpy.types.ShaderNodeTexImage` — Sample an image as a texture; projection describes ways to project a 2D image.
Read next: `bpy.types.ShaderNodeTexImage.html`, `bpy.types.BlendDataImages.html`, `bpy.types.NodeLinks.html`
Limits: Projection documentation does not establish UV availability, a loaded image or shader connections. Inspect inputs before choosing links.
## Procedural fractal Perlin noise — `procedural-noise-texture`
ShaderNodeTexNoise generates fractal Perlin noise in one to four dimensions; noise types describe sharp peaks, peaks/valleys and terrain-like signals.
Choose when: Supply noise to a shader network. Terrain wording describes the signal, not a terrain geometry recipe.
Search aliases: texture nhiễu, nhiễu thủ tục, vân ngẫu nhiên, noise texture, Perlin, fractal noise
Evidence: `bpy.types.ShaderNodeTexNoise.html#bpy.types.ShaderNodeTexNoise` — Generate fractal Perlin noise; noise_dimensions and noise_type describe dimensionality and noise forms.
Read next: `bpy.types.ShaderNodeTexNoise.html`, `bpy.types.Node.html#bpy.types.Node.inputs`
Limits: A noise name does not establish a complete node network or terrain mesh. Read noise_type, dimensions and actual sockets before connecting.
## Bump mapping from height texture — `bump-from-height`
ShaderNodeBump perturbs normals from a height texture to simulate surface detail; invert points bumps into the surface.
Choose when: Use a height texture to simulate surface detail through normals.
Search aliases: bump, bump mapping, height texture, giả gồ ghề, giả chi tiết bề mặt
Evidence: `bpy.types.ShaderNodeBump.html#bpy.types.ShaderNodeBump` — Generate a perturbed normal from a height texture to simulate detailed surfaces.
Read next: `bpy.types.ShaderNodeBump.html`, `bpy.types.ShaderNodeTexImage.html`, `bpy.types.NodeLinks.html`
Limits: The description establishes normal changes, not geometry or silhouette changes. Confirm relevant sockets from skill data/runtime.
## RGB normal map surface detail — `normal-map-surface-detail`
ShaderNodeNormalMap perturbs normals from an RGB normal image; the API describes OpenGL/DirectX conventions, normal spaces and tangent-space UV maps.
Choose when: The input is an RGB normal map; choose convention and space from the actual image data.
Search aliases: normal map, bản đồ pháp tuyến, RGB normal, DirectX normal, OpenGL normal
Evidence: `bpy.types.ShaderNodeNormalMap.html#bpy.types.ShaderNodeNormalMap` — Generate perturbed normals from an RGB normal map; describe convention, space and uv_map.
Read next: `bpy.types.ShaderNodeNormalMap.html`, `bpy.types.ShaderNodeTexImage.html`
Limits: Do not guess image convention or normal space. This route describes normals that simulate detail, not mesh changes.
## Principled volume shading — `principled-volume-shading`
ShaderNodeVolumePrincipled combines volume-shading components in one node.
Choose when: Discover a source-supported volume shader configuration.
Search aliases: shading thể tích, vật liệu thể tích, volume shading, principled volume
Evidence: `bpy.types.ShaderNodeVolumePrincipled.html#bpy.types.ShaderNodeVolumePrincipled` — Combine all volume-shading components in one node.
Read next: `bpy.types.ShaderNodeVolumePrincipled.html`, `bpy.types.Node.html#bpy.types.Node.inputs`, `bpy.types.ShaderNodeOutputMaterial.html`
Limits: The description does not supply smoke/fire simulation or a fog recipe. Do not assign those workflows without related evidence; inspect sockets and engine support.
## Lambertian emission shader — `emission-shader`
ShaderNodeEmission is described as a Lambertian emission shader.
Choose when: Add an emission component to a shader; consider compositor glare when the request specifically concerns halos around bright image regions.
Search aliases: shader phát xạ, vật liệu phát sáng, emission shader, Lambertian emission
Evidence: `bpy.types.ShaderNodeEmission.html#bpy.types.ShaderNodeEmission` — Describe a Lambertian emission shader.; `bpy.types.CompositorNodeGlare.html#bpy.types.CompositorNodeGlare` — Glare separately adds flares, fog and glow around bright image regions.
Read next: `bpy.types.ShaderNodeEmission.html`, `bpy.types.ShaderNodeOutputMaterial.html`, `bpy.types.CompositorNodeGlare.html`
Limits: This description does not establish automatic halos or illumination of other objects in every engine. Do not fill unsupported details from memory.
## Discover all source pages in this domain
`python3 scripts/features.py pages shading` lists 174 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/integration-gpu.md
# Python integration, math, GPU and UI
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Runtime, build and context inspection — `runtime-build-context-inspection`
bpy.app exposes version, background state and build options; context depends on the accessed area and operators need suitable context.
Choose when: Inspect API, engine and operator availability in the running Blender before CLI implementation.
Search aliases: phiên bản Blender, background, headless, build options, operator poll, kiểm tra runtime
Evidence: `bpy.app.html#bpy.app.version` — version returns a major/minor/micro tuple.; `bpy.app.html#bpy.app.background` — background is True when started without a UI using -b.; `bpy.app.html#bpy.app.build_options` — The snapshot exposes build options including fluid, usd, alembic and cycles.; `bpy.ops.html` — Wrong context may raise RuntimeError; poll helps check it and CANCELLED may not raise.; `bpy.context.html` — Available context members depend on the accessed area.
Read next: `bpy.app.html`, `bpy.ops.html`, `bpy.types.Context.html`
Limits: Documented build_options describe the documentation build; inspect the actual runtime. No exception does not establish success: operators can return CANCELLED without raising.
## Application event handlers — `application-event-handlers`
bpy.app.handlers provides callback lists; persistent retains callbacks when another file is loaded.
Choose when: Run logic on frame events or Blender load/render lifecycle events.
Search aliases: handler, frame change, load post, callback Blender, sự kiện nạp file, sự kiện đổi frame
Evidence: `bpy.app.handlers.html` — Provide callback lists including frame_change_pre/load_post, with warnings about changing data during rendering.; `bpy.app.handlers.html#bpy.app.handlers.persistent` — A decorator retains callbacks across file loads.
Read next: `bpy.app.handlers.html`, `info_gotchas_threading.html`
Limits: Handlers are removed on file load by default; persistent is a separate choice. The source warns that simultaneous handler data changes and render/viewport access can crash; read the warning and choose appropriate synchronization.
## Application timers — `application-timer-callbacks`
bpy.app.timers.register calls a function after a delay; return a float to schedule the next call or None to unregister.
Choose when: Schedule callbacks within a Blender process that remains running.
Search aliases: timer, chạy sau vài giây, callback định kỳ, application timer, lặp callback
Evidence: `bpy.app.timers.html#bpy.app.timers.register` — Register a no-argument function with first_interval in seconds; None unregisters and a float sets the next delay.; `info_gotchas_threading.html` — Python integration is not thread-safe; the source limits threading and discusses multiprocessing for Blender-independent code.
Read next: `bpy.app.timers.html`, `info_gotchas_threading.html`
Limits: Timers do not run after the CLI process exits and are not an external scheduler. Do not substitute remembered Python threads that access Blender data; read the separate threading limitations.
## RNA property message bus — `rna-property-notifications`
bpy.msgbus receives RNA property-change notifications; subscribe_rna registers callbacks for a property or struct/property pair.
Choose when: Respond to property changes made through the Python data API or UI fields.
Search aliases: message bus, msgbus, theo dõi property, RNA notification, property change callback
Evidence: `bpy.msgbus.html` — Receive RNA/Python/UI field changes, excluding animation and viewport movement; callbacks are deferred until after operators.; `bpy.msgbus.html#bpy.msgbus.subscribe_rna` — Subscribe to notifications; file loads clear subscriptions and PERSISTENT preserves ID remapping.
Read next: `bpy.msgbus.html`, `bpy.app.handlers.html`
Limits: Animation and object movement in the 3D Viewport do not trigger msgbus according to the source; select another route for those events. Loading another blend clears subscriptions; msgbus PERSISTENT preserves ID remapping, not file-load subscriptions.
## Custom operators, properties and UI — `custom-operators-properties-ui`
bpy.utils.register_class registers Blender subclasses; bpy.props defines their properties; Panel contains UI elements.
Choose when: Create reusable operators/properties or controls inside Blender.
Search aliases: custom operator, custom property, addon panel, bảng điều khiển, mở rộng Blender, đăng ký class
Evidence: `bpy.utils.html#bpy.utils.register_class` — Register supported subclasses including Operator, Panel, PropertyGroup and Node.; `bpy.props.html` — Define properties for registered classes; avoid direct use and observe callback threading warnings.; `bpy.types.Panel.html#bpy.types.Panel` — Panel contains UI elements; the snapshot leaves context/region/space combinations as a TODO under bl_context.
Read next: `bpy.utils.html#bpy.utils.register_class`, `bpy.props.html`, `bpy.types.Operator.html`, `bpy.types.Panel.html`, `bpy.ops.html`
Limits: A Panel is UI; class creation does not establish display or interaction in background -b. Assign bpy.props results to registered classes rather than using them directly; property callbacks may run in threaded contexts.
## GPU drawing and offscreen buffers — `gpu-drawing-offscreen`
gpu exposes GPU wrappers, geometry batches and GPUOffScreen; the 5.2 source includes gpu.init for background initialization.
Choose when: Draw through the GPU API, process offscreen buffers or render a 3D View into a texture.
Search aliases: GPU offscreen, vẽ GPU, offscreen buffer, shader drawing, GPU batch, viewport texture
Evidence: `gpu.html` — Expose GPU wrappers and geometry batches with vertex/index buffers.; `gpu.html#gpu.init` — Initialize the GPU for background use; failure raises SystemError.; `gpu.types.html#gpu.types.GPUOffScreen` — Access offscreen buffers; draw_view3d needs a scene, view layer, SpaceView3D and Region.; `gpu.shader.html` — Initialize shader uniforms to avoid retaining earlier values.; `gpu.types.html#gpu.types.GPUOffScreen.free` — Freeing offscreen resources makes associated framebuffer, texture and render objects inaccessible.
Read next: `gpu.html`, `gpu.shader.html`, `gpu.types.html#gpu.types.GPUOffScreen`, `gpu_extras.batch.html`
Limits: GPU use is not necessarily UI-only: gpu.init documents background use but may raise SystemError. GPUOffScreen.draw_view3d still requires SpaceView3D and Region; do not assume they exist in -b. Initialize shader uniforms explicitly; freeing offscreen resources makes framebuffer, texture and render objects inaccessible.
## GPU compute shaders — `gpu-compute-dispatch`
GPUShaderCreateInfo accepts GLSL compute source; create_from_info creates a shader; gpu.compute.dispatch runs workgroup dimensions and capabilities reports support.
Choose when: Use compute shaders directly through Blender's GPU API.
Search aliases: compute shader, GPU compute, GLSL compute, dispatch GPU, tính toán GPU
Evidence: `gpu.types.html#gpu.types.GPUShaderCreateInfo.compute_source` — Accept GLSL compute shader source; include examples and an external cross-compilation documentation link.; `gpu.shader.html#gpu.shader.create_from_info` — Create GPUShader from GPUShaderCreateInfo.; `gpu.compute.html#gpu.compute.dispatch` — Dispatch compute work using a shader and x/y/z group counts.; `gpu.capabilities.html#gpu.capabilities.compute_shader_support_get` — Return whether compute shaders are supported.
Read next: `gpu.html#gpu.init`, `gpu.capabilities.html`, `gpu.types.html#gpu.types.GPUShaderCreateInfo`, `gpu.compute.html`
Limits: The name GPU does not establish compute availability; check compute_shader_support_get and initialize the runtime. GLSL cross-compilation documentation is linked outside the corpus; do not fill that missing content from memory. A dispatch API does not prove shader correctness, input/output data, synchronization or numerical results.
## Discover all source pages in this domain
`python3 scripts/features.py pages integration-gpu` lists 404 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/sculpt-paint.md
# Sculpting, brushes and painting
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Sculpt mesh deformation filters — `sculpt-mesh-filters`
sculpt.mesh_filter modifies the current mesh with filters including smooth, inflate, sphere, random, volume-preserving surface smooth, sharpen and enhance details.
Choose when: Apply a sculpt filter whose documented effect matches the intended change.
Search aliases: làm trơn sculpt, phồng mesh, tăng chi tiết bề mặt, sculpt mesh filter, inflate mesh, surface smooth, sharpen cavities
Evidence: `bpy.ops.sculpt.html#bpy.ops.sculpt.mesh_filter` — Apply a filter to the current mesh; list and describe filter types.; `info_gotchas_operators.html` — Operators use context and can fail poll.
Read next: `bpy.ops.sculpt.html#bpy.ops.sculpt.mesh_filter`, `info_gotchas_operators.html`
Limits: The API does not confirm operation in every background context; the operator guide requires context/poll checks.
## Sculpt mask filters and face sets — `sculpt-masks-face-sets`
mask_filter smooths, sharpens, grows, shrinks or changes mask contrast; face_sets_create creates face sets from a mask, visible region, whole mesh or Edit Mode selection.
Choose when: Adjust a mask or group faces from an existing selection source.
Search aliases: mở rộng mask sculpt, thu nhỏ mask, làm mềm mask, tạo face set, mask filter, grow shrink mask, face sets
Evidence: `bpy.ops.sculpt.html#bpy.ops.sculpt.mask_filter` — Filter the current mask with listed filter_type values.; `bpy.ops.sculpt.html#bpy.ops.sculpt.face_sets_create` — Create face sets from masked, visible, all or selected faces.; `info_gotchas_operators.html` — Operators use context.
Read next: `bpy.ops.sculpt.html#bpy.ops.sculpt.mask_filter`, `bpy.ops.sculpt.html#bpy.ops.sculpt.face_sets_create`, `info_gotchas_operators.html`
Limits: Masks and face sets are different outputs; select the operation matching the requested output. Both APIs are operators and require a valid context.
## Sculpt brush strokes — `sculpt-brush-strokes`
sculpt.brush_stroke applies a geometry stroke using OperatorStrokeElement data, normal/invert mode, brush toggle and pen flip.
Choose when: The task requires brush strokes and can supply stroke data with an appropriate context.
Search aliases: nét cọ sculpt, điêu khắc bằng brush, sculpt stroke, brush sculpt, sculpt brush stroke
Evidence: `bpy.ops.sculpt.html#bpy.ops.sculpt.brush_stroke` — Apply a sculpt stroke using OperatorStrokeElement; override_location can be recomputed from mouse_event.; `info_gotchas_operators.html` — Operators obtain their working data from context.
Read next: `bpy.ops.sculpt.html#bpy.ops.sculpt.brush_stroke`, `bpy.types.OperatorStrokeElement.html`, `bpy.types.Brush.html`, `info_gotchas_operators.html`
Limits: The page describes stroke and mouse_event but does not provide an editor-context setup for background CLI use.
## Assign vertex group weights — `paint-vertex-weights`
VertexGroup.add assigns weights to vertex indices with replace/add/subtract modes; paint.weight_set fills the active group with the current paint weight.
Choose when: Use VertexGroup.add for explicit indexed weights; inspect weight_set to fill the active group using the current paint weight.
Search aliases: gán weight, trọng số đỉnh, vertex group weights, weight paint fill, assign vertex weights
Evidence: `bpy.types.VertexGroup.html#bpy.types.VertexGroup.add` — Add vertices by index with weight 0..1 and REPLACE/ADD/SUBTRACT.; `bpy.ops.paint.html#bpy.ops.paint.weight_set` — Fill the active vertex group with the current paint weight.
Read next: `bpy.types.VertexGroup.html#bpy.types.VertexGroup.add`, `bpy.types.VertexGroups.html`, `bpy.ops.paint.html#bpy.ops.paint.weight_set`, `info_gotchas_operators.html`
Limits: VertexGroup.add does not infer appropriate weights; weight_set uses the active group and current paint weight.
## Fill active vertex color layer — `paint-vertex-color-fill`
paint.vertex_color_set fills the active vertex color layer using the current paint color; use_alpha selects opaque or existing alpha.
Choose when: Fill the active color layer with the paint color and choose alpha handling.
Search aliases: tô màu vertex, fill màu vertex, vertex color fill, paint vertex color, active color layer
Evidence: `bpy.ops.paint.html#bpy.ops.paint.vertex_color_set` — Fill the active vertex color layer; use_alpha selects opaque alpha or preserves existing alpha.; `info_gotchas_operators.html` — The operator works through context.
Read next: `bpy.ops.paint.html#bpy.ops.paint.vertex_color_set`, `bpy.types.Attribute.html`, `info_gotchas_operators.html`
Limits: The source only describes the active layer and current paint color; it does not establish layer creation or render material setup.
## Paint strokes into an image — `paint-image-strokes`
paint.image_paint paints a stroke into an image using OperatorStrokeElement data, normal/invert mode, brush toggle and pen flip.
Choose when: Apply an image paint stroke with specified stroke data and context.
Search aliases: vẽ texture bằng cọ, nét cọ lên ảnh, image paint stroke, texture painting, paint image
Evidence: `bpy.ops.paint.html#bpy.ops.paint.image_paint` — Paint a stroke into an image with stroke, mode, brush_toggle and pen_flip.; `info_gotchas_operators.html` — Operators use context and can fail poll.
Read next: `bpy.ops.paint.html#bpy.ops.paint.image_paint`, `bpy.types.OperatorStrokeElement.html`, `bpy.types.ImagePaint.html`, `info_gotchas_operators.html`
Limits: The operator page does not provide a complete background CLI paint context; it does not establish that stroke data alone is sufficient.
## Discover all source pages in this domain
`python3 scripts/features.py pages sculpt-paint` lists 36 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/simulation.md
# Simulation, physics and caches
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Rigid body simulation — `rigid-body-simulation`
RigidBodyObject stores participant settings; RigidBodyWorld contains the simulation environment, participating collection, substeps and solver iterations.
Choose when: Simulate objects with the Rigid Body system, collision settings and a shared environment.
Search aliases: rigid body, vật thể rắn, vật rơi va chạm, rigid collision, mô phỏng va chạm
Evidence: `bpy.types.RigidBodyObject.html#bpy.types.RigidBodyObject` — Store rigid-body participant settings including collision shape and damping.; `bpy.types.RigidBodyWorld.html#bpy.types.RigidBodyWorld` — Define a self-contained environment; collection selects participants, while solver_iterations and substeps_per_frame trade accuracy for speed.; `bpy.ops.rigidbody.html#bpy.ops.rigidbody.object_add` — Add the active object as a Rigid Body.
Read next: `bpy.types.RigidBodyObject.html`, `bpy.types.RigidBodyWorld.html`, `bpy.types.PointCache.html`, `bpy.ops.ptcache.html`
Limits: Creating settings does not mean simulation has run or caches have been baked. Check the participating collection, collision shapes, frame range, runtime and evaluated results.
## Rigid body constraints — `rigid-body-joints`
RigidBodyConstraint affects objects in Rigid Body Simulation, with an impulse breaking threshold and angular limits.
Choose when: Create physical constraints between rigid-body simulation participants.
Search aliases: rigid body constraint, khớp vật lý, giới hạn góc vật lý, ràng buộc có thể đứt, physics joints
Evidence: `bpy.types.RigidBodyConstraint.html#bpy.types.RigidBodyConstraint` — Constrain rigid-body objects; breaking_threshold is the breaking impulse and angular limits are available.
Read next: `bpy.types.RigidBodyConstraint.html`, `bpy.ops.rigidbody.html`, `bpy.types.RigidBodyWorld.html`
Limits: These are distinct from pose/object transform constraints. The route name does not verify joint types, endpoints or a working simulation; read type and probe.
## Cloth simulation and collision — `cloth-simulation`
ClothSettings defines cloth simulation parameters including bending stiffness; ClothCollisionSettings manages self-collision and collisions with other objects.
Choose when: Use Cloth simulation and adjust its collision response.
Search aliases: cloth, vải, rèm, mô phỏng vải, cloth collision, self collision
Evidence: `bpy.types.ClothSettings.html#bpy.types.ClothSettings` — Define cloth bending models, stiffness and damping.; `bpy.types.ClothCollisionSettings.html#bpy.types.ClothCollisionSettings` — Configure self-collision and object collision; collision_quality trades time for quality.
Read next: `bpy.types.ClothModifier.html`, `bpy.types.ClothSettings.html`, `bpy.types.ClothCollisionSettings.html`, `bpy.types.PointCache.html`
Limits: A curtain keyword identifies a Cloth candidate; the source does not supply a curtain recipe or real-world material parameters. Verify modifiers, geometry, caches and output frames; settings alone are not simulation proof.
## Soft body simulation — `soft-body-simulation`
SoftBodySettings exposes soft-body simulation settings including bending stiffness, collision damping and aerodynamic interaction.
Choose when: Simulate an object with the Soft Body system.
Search aliases: soft body, vật thể mềm, mô phỏng đàn hồi, soft body collision
Evidence: `bpy.types.SoftBodySettings.html#bpy.types.SoftBodySettings` — Define object soft-body settings including bending stiffness, collision damping and aerodynamic interaction.
Read next: `bpy.types.SoftBodyModifier.html`, `bpy.types.SoftBodySettings.html`, `bpy.types.PointCache.html`
Limits: The settings API does not provide suitable physical parameters for every material or topology. Verify modifiers, colliders, frame evaluation and caches before claiming a working effect.
## Liquid fluid simulation — `fluid-liquid-simulation`
FluidDomainSettings provides a LIQUID domain; FluidFlowSettings provides LIQUID flow with inflow, outflow or geometry behavior.
Choose when: Explore liquid simulation using a Fluid domain and flow.
Search aliases: chất lỏng, nước, liquid, fluid simulation, inflow, outflow
Evidence: `bpy.types.FluidDomainSettings.html#bpy.types.FluidDomainSettings.domain_type` — LIQUID creates a liquid domain; GAS creates a gas domain.; `bpy.types.FluidFlowSettings.html#bpy.types.FluidFlowSettings` — flow_type=LIQUID adds liquid; flow_behavior includes INFLOW, OUTFLOW and GEOMETRY; flow_source lists only NONE.; `bpy.ops.fluid.html#bpy.ops.fluid.bake_all` — bake_all bakes the entire Fluid Simulation.
Read next: `bpy.types.FluidModifier.html`, `bpy.types.FluidDomainSettings.html`, `bpy.types.FluidFlowSettings.html`, `bpy.types.FluidEffectorSettings.html`, `bpy.ops.fluid.html`
Limits: flow_source lists only NONE in this snapshot; do not invent additional enums from memory. Domain/flow configuration does not create a simulation or baked water surface; inspect baking, caches and actual results. A water keyword does not establish a need for simulation; compare supported geometry/material routes for still-image requirements.
## Smoke and fire simulation — `fluid-smoke-fire-simulation`
Fluid provides a GAS domain and SMOKE, FIRE or BOTH flow; domain parameters control density/heat buoyancy and combustion rate.
Choose when: Simulate smoke or fire over time using Fluid.
Search aliases: khói, lửa, smoke, fire, gas simulation, fire and smoke
Evidence: `bpy.types.FluidDomainSettings.html#bpy.types.FluidDomainSettings.domain_type` — GAS creates a gas domain.; `bpy.types.FluidFlowSettings.html#bpy.types.FluidFlowSettings.flow_type` — SMOKE adds smoke, FIRE adds fire and BOTH adds both.; `bpy.types.FluidDomainSettings.html#bpy.types.FluidDomainSettings` — alpha and beta control buoyancy from smoke density/heat; burning_rate controls combustion rate.
Read next: `bpy.types.FluidModifier.html`, `bpy.types.FluidDomainSettings.html`, `bpy.types.FluidFlowSettings.html`, `bpy.ops.fluid.html`
Limits: Simulation parameters alone do not establish shading or flame appearance. Current build support, completed baking and valid caches are unverified; probe and inspect outputs.
## Physics force fields — `physics-force-fields`
FieldSettings.type distinguishes WIND along local Z, TURBULENCE noise, VORTEX rotation and DRAG that reduces movement.
Choose when: Select a candidate force for a compatible simulation system.
Search aliases: gió, trường lực, wind, force field, turbulence, vortex, lực cản
Evidence: `bpy.types.FieldSettings.html#bpy.types.FieldSettings.type` — Describe WIND, TURBULENCE, VORTEX, DRAG and other force-field enum values.
Read next: `bpy.types.FieldSettings.html`, `bpy.types.EffectorWeights.html`
Limits: Do not assume every object responds to FieldSettings; read the target simulation and effector weights. WIND is described along local Z; inspect transforms and results instead of assuming a world axis.
## Dynamic Paint canvas and brush — `dynamic-paint-canvas`
DynamicPaintSurface is a canvas surface layer with a brush collection, influence and wet-paint color spreading speed.
Choose when: Explore Dynamic Paint brush/canvas interaction.
Search aliases: dynamic paint, vệt sơn, canvas, brush simulation, wet paint, sơn động
Evidence: `bpy.types.DynamicPaintSurface.html#bpy.types.DynamicPaintSurface` — A canvas surface selects brushes with brush_collection and controls wet-paint mixing with color_spread_speed.; `bpy.types.DynamicPaintSurface.html#bpy.types.DynamicPaintSurface.surface_type` — The snapshot's surface_type enum contains only PAINT.
Read next: `bpy.types.DynamicPaintModifier.html`, `bpy.types.DynamicPaintCanvasSettings.html`, `bpy.types.DynamicPaintBrushSettings.html`, `bpy.types.DynamicPaintSurface.html`, `bpy.ops.dpaint.html`
Limits: surface_type lists only PAINT in this snapshot; do not supply other modes from memory. These parameters do not provide a complete paint-trail or baking recipe; read modifier/settings contracts and verify the runtime.
## Particle system settings — `particle-system-settings`
ParticleSettings can be shared across particle systems; the snapshot's type enum includes EMITTER and HAIR.
Choose when: Control a Particle System identified in the supplied source or scene.
Search aliases: particle, hệ hạt, particle emitter, particle hair, phát hạt
Evidence: `bpy.types.ParticleSettings.html#bpy.types.ParticleSettings` — Settings can be reused by multiple particle systems.; `bpy.types.ParticleSettings.html#bpy.types.ParticleSettings.type` — type includes EMITTER and HAIR; the anchor does not explain their workflows.
Read next: `bpy.types.ParticleSettings.html`, `bpy.types.ParticleSystem.html`, `bpy.types.PointCache.html`
Limits: Do not equate particle HAIR with all hair systems or Geometry Nodes; read the correct data type. EMITTER/HAIR establish enum values, not motion, rendering or cache recipes for a particular effect.
## Physics cache baking and inspection — `physics-cache-baking`
PointCache exposes physics cache paths, frame ranges and is_baked/is_baking; ptcache.bake is a physics baking operator.
Choose when: Execute or verify caches for a simulation using PointCache.
Search aliases: bake physics, cache mô phỏng, bake cache, point cache, kiểm tra cache
Evidence: `bpy.types.PointCache.html#bpy.types.PointCache` — PointCache is the active physics cache, with filepath, frame_start/end, is_baked/is_baking and skipped-frame status.; `bpy.ops.ptcache.html#bpy.ops.ptcache.bake` — The operator is described as Bake physics.; `bpy.ops.fluid.html#bpy.ops.fluid.bake_all` — Fluid has a separate operator for baking the entire simulation.
Read next: `bpy.types.PointCache.html`, `bpy.ops.ptcache.html`, `bpy.ops.html`
Limits: ptcache.bake is not universal; Fluid has separate baking operators. Distinguish FINISHED, is_baked and actual cache/frame data; no single signal proves the complete result.
## Discover all source pages in this domain
`python3 scripts/features.py pages simulation` lists 58 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/domains/tracking.md
# Motion tracking and movie clips
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Movie clip marker tracking — `movie-clip-marker-tracking`
MovieTracking holds match-moving data; bpy.ops.clip.track_markers tracks selected markers backward or across a sequence rather than one image.
Choose when: Track markers in footage; inspect clip/tracking data before invoking the operator.
Search aliases: tracking marker, theo dõi điểm, motion tracking, track markers, theo dõi footage
Evidence: `bpy.types.MovieTracking.html#bpy.types.MovieTracking` — Expose match-moving data for tracking.; `bpy.ops.clip.html#bpy.ops.clip.track_markers` — Track selected markers backward or across a sequence.
Read next: `bpy.types.MovieClip.html`, `bpy.types.MovieTracking.html`, `bpy.types.MovieTrackingTracks.html`, `bpy.ops.clip.html#bpy.ops.clip.track_markers`
Limits: Marker tracking is not arbitrary object recognition. It requires suitable context and selection; do not promise background CLI operation without a successful poll in that context.
## Marker-based 2D footage stabilization — `movie-clip-two-dimensional-stabilization`
MovieTrackingStabilization stabilizes footage in 2D using markers, with location/rotation/scale influence, an anchor frame and automatic scaling to cover gaps.
Choose when: Stabilize 2D footage using existing tracking data.
Search aliases: ổn định video, chống rung, 2D stabilization, stabilize footage, marker stabilization
Evidence: `bpy.types.MovieTrackingStabilization.html#bpy.types.MovieTrackingStabilization` — Describe marker-based 2D stabilization with anchor frame, location/rotation/scale and autoscale.
Read next: `bpy.types.MovieTrackingStabilization.html`, `bpy.types.MovieTracking.html`, `bpy.types.CompositorNodeStabilize.html`
Limits: This does not establish correction of all shake or rolling shutter. Suitable tracks and output checks are required; the route does not automatically create tracking input.
## Camera motion solving from tracks — `camera-motion-solve-from-tracks`
bpy.ops.clip.solve_camera solves camera motion from tracks. MovieTrackingReconstruction stores solved cameras, average_error and is_valid.
Choose when: Solve camera motion from existing tracks and inspect reconstruction validity/error.
Search aliases: camera tracking, solve camera, match moving, giải camera, khôi phục chuyển động camera
Evidence: `bpy.ops.clip.html#bpy.ops.clip.solve_camera` — Solve camera motion from tracks.; `bpy.types.MovieTrackingReconstruction.html#bpy.types.MovieTrackingReconstruction` — Expose reconstruction cameras, average_error and is_valid.
Read next: `bpy.ops.clip.html#bpy.ops.clip.solve_camera`, `bpy.types.MovieTrackingReconstruction.html`, `bpy.types.MovieTrackingSettings.html`, `bpy.types.MovieTrackingCamera.html`
Limits: The source does not guarantee a solve for all footage or supply complete calibration/background-context requirements. Report success only when the actual operator and reconstruction support it.
## Discover all source pages in this domain
`python3 scripts/features.py pages tracking` lists 30 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/routes-geometry.json
{
"schema_version": 1,
"routes": [
{
"id": "scene-object-assembly",
"domain": "scene",
"label_vi": "Tạo object và đưa vào collection",
"label_en": "Create objects and link collections",
"intent_aliases": [
"dựng cảnh",
"thêm vật thể",
"tạo object",
"tổ chức collection",
"scene assembly",
"create object",
"link collection",
"empty object"
],
"summary": "Create an object in the database using a data-block, or None for an empty; linking it to a collection is a separate API operation.",
"choose_when": "Assemble objects or empties and specify the collection that contains them.",
"do_not_assume": [
"BlendDataObjects.new only creates the database object; use CollectionObjects.link to add it to a collection."
],
"evidence": [
{
"ref": "bpy.types.BlendDataObjects.html#bpy.types.BlendDataObjects.new",
"supports": "Create a database object; object_data can be None for an empty."
},
{
"ref": "bpy.types.CollectionObjects.html#bpy.types.CollectionObjects.link",
"supports": "Add an object to a collection."
}
],
"api_refs": [
"bpy.types.BlendDataObjects.html#bpy.types.BlendDataObjects.new",
"bpy.types.CollectionObjects.html#bpy.types.CollectionObjects.link"
],
"next_queries": [
"bpy.types.BlendDataObjects.html#bpy.types.BlendDataObjects.new",
"bpy.types.CollectionObjects.html#bpy.types.CollectionObjects.link",
"bpy.types.Scene.html"
]
},
{
"id": "scene-transforms-parenting",
"domain": "scene",
"label_vi": "Biến đổi không gian và quan hệ cha con",
"label_en": "Object transforms and parenting",
"intent_aliases": [
"di chuyển vật thể",
"xoay vật thể",
"đặt vị trí",
"cha con",
"phân cấp object",
"world transform",
"parent object",
"matrix_world"
],
"summary": "Object exposes a world-space transformation matrix and a reference to its parent object.",
"choose_when": "Set spatial transforms or establish object parenting.",
"do_not_assume": [
"The parent description identifies the parent object; it does not establish how to preserve the world transform when changing parents."
],
"evidence": [
{
"ref": "bpy.types.Object.html#bpy.types.Object.matrix_world",
"supports": "matrix_world is the world-space transformation matrix."
},
{
"ref": "bpy.types.Object.html#bpy.types.Object.parent",
"supports": "parent references the parent object."
}
],
"api_refs": [
"bpy.types.Object.html#bpy.types.Object.matrix_world",
"bpy.types.Object.html#bpy.types.Object.parent"
],
"next_queries": [
"bpy.types.Object.html#bpy.types.Object.matrix_world",
"bpy.types.Object.html#bpy.types.Object.parent",
"bpy.types.Object.html#bpy.types.Object.matrix_parent_inverse",
"mathutils.html"
]
},
{
"id": "scene-collection-instancing",
"domain": "scene",
"label_vi": "Instance collection hoặc object con",
"label_en": "Collection and child object instancing",
"intent_aliases": [
"lặp collection",
"instance bộ vật thể",
"nhân vật thể trên đỉnh",
"collection instance",
"vertex instancing",
"face instancing"
],
"summary": "An Object can instance an existing collection or instance child objects on vertices or faces.",
"choose_when": "Use Object instancing with an existing collection or parent-child object relationship.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.Object.html#bpy.types.Object.instance_collection",
"supports": "instance_collection uses an existing collection."
},
{
"ref": "bpy.types.Object.html#bpy.types.Object.instance_type",
"supports": "VERTS and FACES instance child objects on vertices or faces; COLLECTION enables collection instancing."
}
],
"api_refs": [
"bpy.types.Object.html#bpy.types.Object.instance_collection",
"bpy.types.Object.html#bpy.types.Object.instance_type"
],
"next_queries": [
"bpy.types.Object.html#bpy.types.Object.instance_type",
"bpy.types.Object.html#bpy.types.Object.instance_collection",
"bpy.types.Depsgraph.html#bpy.types.Depsgraph.object_instances"
]
},
{
"id": "scene-evaluated-geometry",
"domain": "scene",
"label_vi": "Đọc hình học đã tính animation, constraint và modifier",
"label_en": "Evaluated geometry and instances",
"intent_aliases": [
"mesh sau modifier",
"đo kết quả biến dạng",
"hình học đã đánh giá",
"đọc instances",
"evaluated geometry",
"evaluated mesh",
"dependency graph",
"geometry after modifiers"
],
"summary": "The dependency graph exposes evaluated animation, constraints and modifiers; to_mesh creates a temporary mesh owned by the object.",
"choose_when": "Measure, inspect or retrieve evaluated geometry rather than only the original data.",
"do_not_assume": [
"ID.evaluated_get returns the last evaluation result; it does not guarantee that the graph has been evaluated.",
"Object.to_mesh creates temporary data that requires to_mesh_clear; do not link it directly to an object in the main database."
],
"evidence": [
{
"ref": "bpy.types.Depsgraph.html",
"supports": "The Evaluated ID example describes animation, constraints and modifiers in evaluated state."
},
{
"ref": "bpy.types.ID.html#bpy.types.ID.evaluated_get",
"supports": "Return the ID from the last evaluation without guaranteeing graph re-evaluation."
},
{
"ref": "bpy.types.Object.html#bpy.types.Object.to_mesh",
"supports": "Create a temporary mesh owned by the object and release it with to_mesh_clear."
}
],
"api_refs": [
"bpy.types.Context.html#bpy.types.Context.evaluated_depsgraph_get",
"bpy.types.ID.html#bpy.types.ID.evaluated_get",
"bpy.types.Object.html#bpy.types.Object.to_mesh"
],
"next_queries": [
"bpy.types.Depsgraph.html",
"bpy.types.Context.html#bpy.types.Context.evaluated_depsgraph_get",
"bpy.types.Object.html#bpy.types.Object.to_mesh",
"bpy.types.Depsgraph.html#bpy.types.Depsgraph.object_instances"
]
},
{
"id": "mesh-from-explicit-data",
"domain": "geometry",
"label_vi": "Tạo mesh từ danh sách đỉnh, cạnh và mặt",
"label_en": "Mesh from explicit vertices edges and faces",
"intent_aliases": [
"tạo mesh bằng tọa độ",
"dựng đa giác",
"mesh từ mảng",
"vertices edges faces",
"from_pydata",
"procedural mesh arrays"
],
"summary": "Mesh.from_pydata accepts vertex coordinates and edge/face indices; an empty edge list causes edges to be inferred from polygons.",
"choose_when": "The output can be specified as coordinates and geometry connections.",
"do_not_assume": [
"from_pydata does not prevent invalid mesh data; the source calls for validation when input validity is not guaranteed."
],
"evidence": [
{
"ref": "bpy.types.Mesh.html#bpy.types.Mesh.from_pydata",
"supports": "Create a mesh from vertices, edges and faces; infer missing edges from polygons; warn about invalid data."
},
{
"ref": "bpy.types.Mesh.html#bpy.types.Mesh.validate",
"supports": "validate returns True if invalid data was corrected or removed."
}
],
"api_refs": [
"bpy.types.Mesh.html#bpy.types.Mesh.from_pydata",
"bpy.types.Mesh.html#bpy.types.Mesh.validate"
],
"next_queries": [
"bpy.types.Mesh.html#bpy.types.Mesh.from_pydata",
"bpy.types.Mesh.html#bpy.types.Mesh.validate",
"info_gotchas_meshes.html"
]
},
{
"id": "mesh-connected-topology-editing",
"domain": "geometry",
"label_vi": "Sửa topology qua BMesh",
"label_en": "Connected topology editing with BMesh",
"intent_aliases": [
"sửa topology",
"chỉnh liên kết đỉnh cạnh mặt",
"tách cạnh",
"dissolve",
"collapse",
"connected mesh editing",
"BMesh"
],
"summary": "BMesh exposes geometry connectivity and mesh editing operations such as split, separate, collapse and dissolve.",
"choose_when": "Edit connectivity flexibly rather than only construct mesh storage arrays.",
"do_not_assume": [
"bmesh.from_edit_mesh requires a mesh already in Edit Mode; obj.data may not be synchronized with Edit Mode.",
"The BMesh page states that Disk/Radial data is not exposed to Python."
],
"evidence": [
{
"ref": "bmesh.html",
"supports": "The introduction describes connectivity and split/separate/collapse/dissolve editing; Disk/Radial data is not exposed."
},
{
"ref": "bmesh.html#bmesh.from_edit_mesh",
"supports": "Retrieve the BMesh of a mesh in Edit Mode."
},
{
"ref": "info_gotchas_meshes.html",
"supports": "Edit Mode has separate data and obj.data may be out of sync."
}
],
"api_refs": [
"bmesh.html",
"bmesh.types.html",
"bmesh.ops.html"
],
"next_queries": [
"bmesh.html",
"bmesh.types.html",
"bmesh.ops.html",
"info_gotchas_meshes.html"
]
},
{
"id": "mesh-extrude-region",
"domain": "geometry",
"label_vi": "Extrude một vùng mặt",
"label_en": "Extrude a face region",
"intent_aliases": [
"đùn mặt",
"extrude mặt",
"kéo dài vùng mesh",
"extrude faces",
"face region extrusion"
],
"summary": "BMesh extrude_face_region creates extruded geometry from input edges/faces and returns geometry; it does not transform positions itself.",
"choose_when": "Create extruded geometry from a selected BMesh region.",
"do_not_assume": [
"The source explicitly states that extrude_face_region does not transform; displacement requires a separately documented transformation operation."
],
"evidence": [
{
"ref": "bmesh.ops.html#bmesh.ops.extrude_face_region",
"supports": "Extrude faces without transformation; accept edges/faces and return geom."
}
],
"api_refs": [
"bmesh.ops.html#bmesh.ops.extrude_face_region"
],
"next_queries": [
"bmesh.ops.html#bmesh.ops.extrude_face_region",
"bmesh.ops.html#bmesh.ops.translate",
"bmesh.html"
]
},
{
"id": "mesh-plane-cut",
"domain": "geometry",
"label_vi": "Cắt mesh bằng mặt phẳng",
"label_en": "Bisect mesh with a plane",
"intent_aliases": [
"cắt đôi mesh",
"cắt theo mặt phẳng",
"plane cut",
"bisect mesh",
"trim geometry"
],
"summary": "BMesh bisect_plane cuts a mesh using a plane point and normal, with options to remove either side.",
"choose_when": "Specify a cutting plane and the side to keep or remove.",
"do_not_assume": [
"The bisect_plane description does not promise to cap the cut automatically."
],
"evidence": [
{
"ref": "bmesh.ops.html#bmesh.ops.bisect_plane",
"supports": "Cut a mesh with a plane; document plane_co, plane_no and clear_outer/clear_inner."
}
],
"api_refs": [
"bmesh.ops.html#bmesh.ops.bisect_plane"
],
"next_queries": [
"bmesh.ops.html#bmesh.ops.bisect_plane",
"bmesh.html"
]
},
{
"id": "mesh-weld-and-triangulate",
"domain": "geometry",
"label_vi": "Gộp đỉnh gần nhau và tam giác hóa",
"label_en": "Weld nearby vertices and triangulate faces",
"intent_aliases": [
"gộp đỉnh trùng",
"hàn đỉnh",
"tam giác hóa",
"remove doubles",
"merge by distance",
"triangulate faces"
],
"summary": "remove_doubles merges groups of vertices within a distance threshold; triangulate splits quads and n-gons into triangles.",
"choose_when": "Merge nearby vertices or convert faces into triangles using the documented topology operations.",
"do_not_assume": [
"Mesh.calc_loop_triangles computes tessellation; this is not the same as changing topology with bmesh.ops.triangulate."
],
"evidence": [
{
"ref": "bmesh.ops.html#bmesh.ops.remove_doubles",
"supports": "Find and merge vertex groups closer than dist."
},
{
"ref": "bmesh.ops.html#bmesh.ops.triangulate",
"supports": "Split quads and n-gons into triangles."
},
{
"ref": "bpy.types.Mesh.html#bpy.types.Mesh.calc_loop_triangles",
"supports": "Compute loop triangle tessellation."
}
],
"api_refs": [
"bmesh.ops.html#bmesh.ops.remove_doubles",
"bmesh.ops.html#bmesh.ops.triangulate"
],
"next_queries": [
"bmesh.ops.html#bmesh.ops.remove_doubles",
"bmesh.ops.html#bmesh.ops.triangulate",
"bmesh.html"
]
},
{
"id": "mesh-geometry-attributes",
"domain": "geometry",
"label_vi": "Lưu thuộc tính trên phần tử hình học",
"label_en": "Geometry attributes by name type and domain",
"intent_aliases": [
"thuộc tính hình học",
"dữ liệu trên đỉnh",
"thuộc tính trên mặt",
"geometry attribute",
"named data",
"point face domain"
],
"summary": "An Attribute stores data attached to geometry elements, with a name, data type and domain such as points, curves or faces.",
"choose_when": "Store typed data on a geometry domain for later reading or processing.",
"do_not_assume": [
"Name, type and domain are separate properties; do not infer a domain solely from vertex count."
],
"evidence": [
{
"ref": "bpy.types.Attribute.html",
"supports": "Explain geometry attributes, unique names, types and domains."
},
{
"ref": "bpy.types.AttributeGroupMesh.html#bpy.types.AttributeGroupMesh.new",
"supports": "Add an attribute with name, type and domain."
}
],
"api_refs": [
"bpy.types.Attribute.html",
"bpy.types.AttributeGroupMesh.html#bpy.types.AttributeGroupMesh.new"
],
"next_queries": [
"bpy.types.Attribute.html",
"bpy.types.AttributeGroupMesh.html#bpy.types.AttributeGroupMesh.new",
"bpy_types_enum_items/attribute_domain_items.html",
"bpy_types_enum_items/attribute_type_items.html"
]
},
{
"id": "modifier-boolean",
"domain": "geometry",
"label_vi": "Giao, hợp và trừ mesh bằng Boolean modifier",
"label_en": "Boolean intersection union and difference",
"intent_aliases": [
"khoét lỗ bằng vật thể",
"trừ khối",
"giao khối",
"hợp khối",
"boolean modifier",
"mesh union",
"mesh difference",
"mesh intersection"
],
"summary": "The Boolean modifier supports intersection, union and difference of meshes; a collection can supply operand meshes.",
"choose_when": "Represent mesh intersection, union or subtraction as a modifier.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.BooleanModifier.html#bpy.types.BooleanModifier.operation",
"supports": "INTERSECT keeps common geometry; UNION combines additively; DIFFERENCE subtracts."
},
{
"ref": "bpy.types.BooleanModifier.html",
"supports": "collection supplies mesh objects for the Boolean operation."
}
],
"api_refs": [
"bpy.types.BooleanModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.BooleanModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new",
"bpy_types_enum_items/object_modifier_type_items.html"
]
},
{
"id": "geometry-bevel",
"domain": "geometry",
"label_vi": "Bo tròn cạnh hoặc đỉnh",
"label_en": "Bevel edges and vertices",
"intent_aliases": [
"bo cạnh",
"bo góc",
"vát cạnh",
"làm tròn cạnh",
"bevel",
"round edges",
"chamfer"
],
"summary": "BevelModifier rounds edges/vertices; bmesh.ops.bevel operates on geometry with offset, segments and profile.",
"choose_when": "Round edges/vertices; select the modifier route to retain a modifier, or BMesh when editing topology directly.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.BevelModifier.html",
"supports": "The modifier rounds edges and vertices."
},
{
"ref": "bmesh.ops.html#bmesh.ops.bevel",
"supports": "Bevel edges/vertices with offset, segments and profile; profile 0.5 is described as round."
}
],
"api_refs": [
"bpy.types.BevelModifier.html",
"bmesh.ops.html#bmesh.ops.bevel"
],
"next_queries": [
"bpy.types.BevelModifier.html",
"bmesh.ops.html#bmesh.ops.bevel",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-array",
"domain": "geometry",
"label_vi": "Nhân hình học thành dãy",
"label_en": "Array duplication modifier",
"intent_aliases": [
"tạo dãy vật thể",
"lặp hình học",
"nhân theo khoảng cách",
"array modifier",
"repeated geometry",
"duplicate array"
],
"summary": "ArrayModifier duplicates geometry with a copy count, constant offset and a curve for fitting array length.",
"choose_when": "Create an array controlled by modifier count and spacing.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.ArrayModifier.html",
"supports": "Describe array duplication, count, constant_offset_displace and a curve for fitting length."
}
],
"api_refs": [
"bpy.types.ArrayModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.ArrayModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-mirror",
"domain": "geometry",
"label_vi": "Đối xứng hình học",
"label_en": "Mirror modifier",
"intent_aliases": [
"đối xứng mesh",
"phản chiếu hình học",
"mirror mesh",
"symmetrical model",
"mirror modifier"
],
"summary": "MirrorModifier exposes mirroring axes, a reference object and a merge distance for mirrored vertices.",
"choose_when": "Mirror geometry across axes or relative to a reference object using a modifier.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.MirrorModifier.html",
"supports": "Describe mirroring, mirror_object and the vertex merge threshold."
},
{
"ref": "bpy.types.MirrorModifier.html#bpy.types.MirrorModifier.use_axis",
"supports": "An array of three flags enables mirroring by axis."
}
],
"api_refs": [
"bpy.types.MirrorModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.MirrorModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-solidify",
"domain": "geometry",
"label_vi": "Tạo vỏ có độ dày",
"label_en": "Solidify shell thickness",
"intent_aliases": [
"tạo độ dày",
"làm vỏ dày",
"solidify",
"shell thickness",
"thicken surface"
],
"summary": "SolidifyModifier creates a solid skin; thickness controls its shell thickness.",
"choose_when": "Create a shell with thickness from input geometry.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.SolidifyModifier.html",
"supports": "Create a solid skin and compensate for sharp angles."
},
{
"ref": "bpy.types.SolidifyModifier.html#bpy.types.SolidifyModifier.thickness",
"supports": "thickness sets shell thickness."
}
],
"api_refs": [
"bpy.types.SolidifyModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.SolidifyModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-subdivision",
"domain": "geometry",
"label_vi": "Chia nhỏ bề mặt, có hoặc không làm cong",
"label_en": "Subdivision surface",
"intent_aliases": [
"chia nhỏ bề mặt",
"làm mịn bằng subdivision",
"subdivision surface",
"Catmull-Clark",
"simple subdivision"
],
"summary": "SubsurfModifier provides Catmull-Clark for smooth curved surfaces and Simple for subdividing faces without changing shape.",
"choose_when": "Increase surface subdivisions and explicitly choose whether to curve the surface.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.SubsurfModifier.html#bpy.types.SubsurfModifier.subdivision_type",
"supports": "CATMULL_CLARK creates a smooth curved surface; SIMPLE subdivides without changing shape."
}
],
"api_refs": [
"bpy.types.SubsurfModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.SubsurfModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-remesh",
"domain": "geometry",
"label_vi": "Tái tạo bề mặt với topology đều",
"label_en": "Remesh regular topology",
"intent_aliases": [
"remesh",
"tạo lại lưới",
"topology đều",
"voxel remesh modifier",
"rebuild mesh surface"
],
"summary": "RemeshModifier generates a new surface with regular topology following the input mesh; adaptivity reduces detail where less is needed and creates triangles.",
"choose_when": "Replace surface topology with a new mesh following the input shape.",
"do_not_assume": [
"The source says adaptivity can create triangles; it does not promise all-quad output."
],
"evidence": [
{
"ref": "bpy.types.RemeshModifier.html",
"supports": "Generate regular surface topology from an input mesh; adaptivity creates triangles when simplifying."
}
],
"api_refs": [
"bpy.types.RemeshModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.RemeshModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-decimate",
"domain": "geometry",
"label_vi": "Giảm số mặt hình học",
"label_en": "Decimate geometry",
"intent_aliases": [
"giảm polygon",
"giảm số mặt",
"mesh nhẹ hơn",
"decimate",
"polygon reduction",
"low poly reduction"
],
"summary": "DecimateModifier offers edge collapse, un-subdivision and planar dissolve; ratio controls the target triangle ratio for collapse.",
"choose_when": "Reduce geometry with a documented decimation method.",
"do_not_assume": [
"The source limits ratio to collapse; do not use it as a common control for every decimate_type."
],
"evidence": [
{
"ref": "bpy.types.DecimateModifier.html",
"supports": "Describe COLLAPSE, UNSUBDIV and DISSOLVE."
},
{
"ref": "bpy.types.DecimateModifier.html#bpy.types.DecimateModifier.ratio",
"supports": "Target triangle ratio applies only to collapse."
}
],
"api_refs": [
"bpy.types.DecimateModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.DecimateModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "modifier-shrinkwrap",
"domain": "geometry",
"label_vi": "Áp hình học vào object mục tiêu",
"label_en": "Shrinkwrap to a target",
"intent_aliases": [
"áp lưới lên bề mặt",
"bám mesh mục tiêu",
"shrinkwrap",
"wrap mesh to target",
"project vertices onto mesh"
],
"summary": "ShrinkwrapModifier wraps an object onto a target, with an auxiliary target and cull_face controls for projection based on face orientation.",
"choose_when": "Make geometry follow a target mesh through shrink wrapping.",
"do_not_assume": [
"The shrinkwrap description does not establish a complete automatic retopology workflow."
],
"evidence": [
{
"ref": "bpy.types.ShrinkwrapModifier.html",
"supports": "Describe wrapping to a target, auxiliary_target and cull_face."
}
],
"api_refs": [
"bpy.types.ShrinkwrapModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
],
"next_queries": [
"bpy.types.ShrinkwrapModifier.html",
"bpy.types.ObjectModifiers.html#bpy.types.ObjectModifiers.new"
]
},
{
"id": "geometry-nodes-graph",
"domain": "geometry-nodes",
"label_vi": "Dựng graph Geometry Nodes",
"label_en": "Geometry Nodes graph and modifier",
"intent_aliases": [
"dựng Geometry Nodes",
"hình học procedural",
"node graph hình học",
"geometry node group",
"nodes modifier",
"procedural geometry graph"
],
"summary": "GeometryNodeTree holds linked geometry nodes; NodesModifier.node_group references the graph driving the modifier.",
"choose_when": "Create a geometry graph or a modifier driven by a node group; select specific node routes for processing operations.",
"do_not_assume": [
"Nodes.new requires node.bl_idname, not node.type.",
"NodeTreeInterface.new_socket lists only DEFAULT for socket_type; this page does not establish all runtime socket types."
],
"evidence": [
{
"ref": "bpy.types.GeometryNodeTree.html",
"supports": "A node tree contains linked nodes for geometry."
},
{
"ref": "bpy.types.NodesModifier.html#bpy.types.NodesModifier.node_group",
"supports": "A node group controls the modifier."
},
{
"ref": "bpy.types.Nodes.html#bpy.types.Nodes.new",
"supports": "Create a node using bl_idname; the source warns against node.type."
},
{
"ref": "bpy.types.NodeTreeInterface.html#bpy.types.NodeTreeInterface.new_socket",
"supports": "Create an interface socket; socket_type is listed as DEFAULT."
}
],
"api_refs": [
"bpy.types.GeometryNodeTree.html",
"bpy.types.NodesModifier.html",
"bpy.types.Nodes.html#bpy.types.Nodes.new",
"bpy.types.NodeLinks.html#bpy.types.NodeLinks.new"
],
"next_queries": [
"bpy.types.GeometryNodeTree.html",
"bpy.types.NodesModifier.html#bpy.types.NodesModifier.node_group",
"bpy.types.Nodes.html#bpy.types.Nodes.new",
"bpy.types.NodeLinks.html#bpy.types.NodeLinks.new",
"bpy.types.NodeTreeInterface.html#bpy.types.NodeTreeInterface.new_socket"
]
},
{
"id": "geometry-nodes-surface-scatter",
"domain": "geometry-nodes",
"label_vi": "Rải điểm trên bề mặt và instance hình học",
"label_en": "Surface point distribution and instancing",
"intent_aliases": [
"rải cây",
"rải đá",
"phân bố vật thể trên mặt",
"scatter objects",
"surface scattering",
"distribute points on faces",
"instance on points"
],
"summary": "DistributePointsOnFaces generates points on mesh surfaces; InstanceOnPoints creates geometry references at points without duplicating underlying data.",
"choose_when": "Distribute geometry instances over a surface; trees or rocks describe user-supplied content, not assets generated by these nodes.",
"do_not_assume": [
"These nodes do not supply tree or rock models; they describe point distribution and geometry references."
],
"evidence": [
{
"ref": "bpy.types.GeometryNodeDistributePointsOnFaces.html",
"supports": "Generate points scattered on a mesh surface with RANDOM or POISSON distribution."
},
{
"ref": "bpy.types.GeometryNodeInstanceOnPoints.html",
"supports": "Generate geometry references at each point without duplicating underlying data."
}
],
"api_refs": [
"bpy.types.GeometryNodeDistributePointsOnFaces.html",
"bpy.types.GeometryNodeInstanceOnPoints.html"
],
"next_queries": [
"bpy.types.GeometryNodeDistributePointsOnFaces.html",
"bpy.types.GeometryNodeInstanceOnPoints.html",
"bpy.types.GeometryNodeTree.html"
]
},
{
"id": "geometry-nodes-realize",
"domain": "geometry-nodes",
"label_vi": "Chuyển instance thành dữ liệu hình học",
"label_en": "Realize instances",
"intent_aliases": [
"chuyển instance thành hình học thật",
"hiện thực instance",
"realize instances",
"instances to geometry",
"real geometry data"
],
"summary": "RealizeInstances converts instances into real geometry data.",
"choose_when": "The input contains instances and a later step requires geometry data instead of instance references.",
"do_not_assume": [
"The source says geometry data; it does not claim every input type becomes a mesh.",
"realize_to_point_domain is documented as compatibility behavior for version 5.0 and earlier."
],
"evidence": [
{
"ref": "bpy.types.GeometryNodeRealizeInstances.html",
"supports": "Convert instances to real geometry data; describe realize_to_point_domain as legacy compatibility."
}
],
"api_refs": [
"bpy.types.GeometryNodeRealizeInstances.html"
],
"next_queries": [
"bpy.types.GeometryNodeRealizeInstances.html",
"bpy.types.GeometryNodeInstanceOnPoints.html"
]
},
{
"id": "geometry-nodes-attribute-fields",
"domain": "geometry-nodes",
"label_vi": "Đọc/ghi thuộc tính có tên trong graph",
"label_en": "Named attribute field storage and retrieval",
"intent_aliases": [
"ghi named attribute",
"đọc thuộc tính node",
"lưu field",
"store named attribute",
"named attribute",
"field to attribute"
],
"summary": "StoreNamedAttribute stores a field result on geometry under a name; InputNamedAttribute reads the specified attribute.",
"choose_when": "Exchange geometry data through named attributes in a node graph, with source-supported types and domains.",
"do_not_assume": [],
"evidence": [
{
"ref": "bpy.types.GeometryNodeStoreNamedAttribute.html",
"supports": "Store a field result under a name with data_type and domain."
},
{
"ref": "bpy.types.GeometryNodeInputNamedAttribute.html",
"supports": "Retrieve a specified attribute with data_type."
}
],
"api_refs": [
"bpy.types.GeometryNodeStoreNamedAttribute.html",
"bpy.types.GeometryNodeInputNamedAttribute.html"
],
"next_queries": [
"bpy.types.GeometryNodeStoreNamedAttribute.html",
"bpy.types.GeometryNodeInputNamedAttribute.html",
"bpy.types.Attribute.html"
]
},
{
"id": "geometry-nodes-raycast",
"domain": "geometry-nodes",
"label_vi": "Bắn tia lấy thông tin điểm chạm hình học",
"label_en": "Geometry raycast hit information",
"intent_aliases": [
"raycast trong node",
"bắn tia vào mesh",
"lấy điểm chạm bề mặt",
"geometry raycast",
"hit point data",
"ray target geometry"
],
"summary": "GeometryNodeRaycast casts rays from context geometry toward target geometry and retrieves hit information.",
"choose_when": "Compute ray/geometry hit information in a Geometry Nodes graph.",
"do_not_assume": [
"This describes a geometry query, not renderer shadow configuration."
],
"evidence": [
{
"ref": "bpy.types.GeometryNodeRaycast.html",
"supports": "Cast rays from context geometry to target geometry and retrieve hit-point information."
}
],
"api_refs": [
"bpy.types.GeometryNodeRaycast.html"
],
"next_queries": [
"bpy.types.GeometryNodeRaycast.html",
"bpy.types.GeometryNodeTree.html"
]
},
{
"id": "geometry-nodes-simulation-zone",
"domain": "geometry-nodes",
"label_vi": "Dữ liệu và cặp node simulation zone",
"label_en": "Simulation zone input output pairing",
"intent_aliases": [
"simulation zone",
"vùng mô phỏng Geometry Nodes",
"ghép simulation input output",
"node simulation state"
],
"summary": "SimulationInput/Output pass data into and out of a simulation zone; pair_with_output pairs the nodes and reports success.",
"choose_when": "A simulation zone is required and the task needs the node pairing and state-data APIs.",
"do_not_assume": [
"These pages describe node pairing and state items; they do not provide simulation equations or a complete evaluation/baking workflow for a particular effect."
],
"evidence": [
{
"ref": "bpy.types.GeometryNodeSimulationInput.html",
"supports": "Describe simulation zone input and paired_output."
},
{
"ref": "bpy.types.GeometryNodeSimulationOutput.html",
"supports": "Describe simulation zone output and state_items."
},
{
"ref": "bpy.types.GeometryNodeSimulationInput.html#bpy.types.GeometryNodeSimulationInput.pair_with_output",
"supports": "Pair a zone input with an output and return a success boolean."
}
],
"api_refs": [
"bpy.types.GeometryNodeSimulationInput.html",
"bpy.types.GeometryNodeSimulationOutput.html"
],
"next_queries": [
"bpy.types.GeometryNodeSimulationInput.html",
"bpy.types.GeometryNodeSimulationOutput.html",
"bpy.types.NodesModifier.html"
]
},
{
"id": "curves-splines-and-thickness",
"domain": "curves-volumes",
"label_vi": "Đường cong, spline và hình học có tiết diện",
"label_en": "Curves splines bevel and extrusion",
"intent_aliases": [
"đường cong Bézier",
"đường NURBS",
"tạo dây theo đường",
"curve spline",
"bezier path",
"curve bevel",
"curve extrusion"
],
"summary": "Curve stores curves, splines and NURBS; create POLY, BEZIER or NURBS splines and set bevel radius and extrusion along local Z.",
"choose_when": "Describe geometry as splines and use Curve bevel/extrusion properties.",
"do_not_assume": [
"bevel_depth excludes extrusion; the source defines extrude along local Z, along the curve and perpendicular to its normals."
],
"evidence": [
{
"ref": "bpy.types.Curve.html",
"supports": "A Curve data-block stores curves, splines and NURBS."
},
{
"ref": "bpy.types.CurveSplines.html#bpy.types.CurveSplines.new",
"supports": "Add a POLY, BEZIER or NURBS spline."
},
{
"ref": "bpy.types.Curve.html#bpy.types.Curve.bevel_depth",
"supports": "Bevel radius excludes extrusion."
},
{
"ref": "bpy.types.Curve.html#bpy.types.Curve.extrude",
"supports": "Add depth along local Z, along the curve and perpendicular to normals."
}
],
"api_refs": [
"bpy.types.Curve.html",
"bpy.types.CurveSplines.html#bpy.types.CurveSplines.new",
"bpy.types.Spline.html"
],
"next_queries": [
"bpy.types.Curve.html",
"bpy.types.CurveSplines.html#bpy.types.CurveSplines.new",
"bpy.types.Spline.html",
"bpy.types.BezierSplinePoint.html"
]
},
{
"id": "curves-text-geometry",
"domain": "curves-volumes",
"label_vi": "Chữ dưới dạng hình học curve",
"label_en": "Text curve geometry",
"intent_aliases": [
"chữ 3D",
"hình học chữ",
"text object",
"text curve",
"string to curves",
"font geometry"
],
"summary": "TextCurve stores text in a curve data-block, with body holding the text; StringToCurves generates a paragraph with a font and stores each character as a curve instance.",
"choose_when": "Create text geometry or curve instances in Geometry Nodes.",
"do_not_assume": [
"These sources describe text geometry; they do not establish sequencer titles or screen font drawing."
],
"evidence": [
{
"ref": "bpy.types.TextCurve.html",
"supports": "A curve data-block stores text."
},
{
"ref": "bpy.types.TextCurve.html#bpy.types.TextCurve.body",
"supports": "body holds the text object's content."
},
{
"ref": "bpy.types.GeometryNodeStringToCurves.html",
"supports": "Generate a paragraph with a font, storing each character as a curve instance."
}
],
"api_refs": [
"bpy.types.TextCurve.html",
"bpy.types.GeometryNodeStringToCurves.html"
],
"next_queries": [
"bpy.types.TextCurve.html",
"bpy.types.Curve.html",
"bpy.types.GeometryNodeStringToCurves.html"
]
},
{
"id": "curves-hair-data",
"domain": "curves-volumes",
"label_vi": "Dữ liệu hair curves",
"label_en": "Hair curves data",
"intent_aliases": [
"dữ liệu tóc",
"hair curves",
"thêm sợi tóc",
"curves strands",
"hair geometry attributes"
],
"summary": "Curves is a hair-curves data-block with geometry attributes; add_curves accepts a point count for each curve.",
"choose_when": "Create hair-curves data with specified point counts per curve.",
"do_not_assume": [
"add_curves only describes curve sizes; it does not establish a complete grooming or hairstyle workflow."
],
"evidence": [
{
"ref": "bpy.types.Curves.html",
"supports": "A hair-curves data-block exposes geometry attributes."
},
{
"ref": "bpy.types.Curves.html#bpy.types.Curves.add_curves",
"supports": "sizes specifies the number of points in each curve."
}
],
"api_refs": [
"bpy.types.Curves.html",
"bpy.types.Curves.html#bpy.types.Curves.add_curves"
],
"next_queries": [
"bpy.types.Curves.html",
"bpy.types.Curves.html#bpy.types.Curves.add_curves",
"bpy.types.Attribute.html",
"bpy.ops.sculpt_curves.html"
]
},
{
"id": "volume-grids-and-conversion",
"domain": "curves-volumes",
"label_vi": "Volume grids và chuyển đổi mesh/volume",
"label_en": "Volume grids mesh to volume and volume to mesh",
"intent_aliases": [
"tạo volume từ mesh",
"chuyển volume thành mesh",
"đọc volume file",
"fog volume",
"volume grids",
"mesh to volume",
"volume to mesh"
],
"summary": "Volume stores 3D grids; MeshToVolume creates fog volume from a mesh surface and VolumeToMesh creates a surface mesh from volume. VolumeGrids.load reads grid lists and metadata from a file.",
"choose_when": "Use volume grids or a documented mesh/volume conversion.",
"do_not_assume": [
"VolumeGrids.load only promises grid lists and metadata; success does not prove all voxels are loaded or the volume renders correctly."
],
"evidence": [
{
"ref": "bpy.types.Volume.html",
"supports": "A Volume data-block stores 3D volume grids."
},
{
"ref": "bpy.types.VolumeGrids.html#bpy.types.VolumeGrids.load",
"supports": "Load grid lists and metadata from a file and return a success boolean."
},
{
"ref": "bpy.types.GeometryNodeMeshToVolume.html",
"supports": "Create fog volume following an input mesh surface."
},
{
"ref": "bpy.types.GeometryNodeVolumeToMesh.html",
"supports": "Create a mesh on a volume surface."
}
],
"api_refs": [
"bpy.types.Volume.html",
"bpy.types.VolumeGrids.html",
"bpy.types.GeometryNodeMeshToVolume.html",
"bpy.types.GeometryNodeVolumeToMesh.html"
],
"next_queries": [
"bpy.types.Volume.html",
"bpy.types.VolumeGrids.html",
"bpy.types.GeometryNodeMeshToVolume.html",
"bpy.types.GeometryNodeVolumeToMesh.html"
]
},
{
"id": "point-cloud-fields",
"domain": "curves-volumes",
"label_vi": "Point cloud có vị trí và bán kính",
"label_en": "Point cloud positions and radii",
"intent_aliases": [
"đám mây điểm",
"tập điểm 3D",
"point cloud",
"points radii",
"generate points from fields"
],
"summary": "PointCloud is a point-cloud data-block; GeometryNodePoints generates points with positions and radii defined by fields.",
"choose_when": "Create points with position/radius data rather than mesh faces.",
"do_not_assume": [
"PointCloud.points is documented as a read-only collection; do not infer an add_points method on the data-block."
],
"evidence": [
{
"ref": "bpy.types.PointCloud.html",
"supports": "A point-cloud data-block exposes geometry attributes."
},
{
"ref": "bpy.types.GeometryNodePoints.html",
"supports": "Generate a point cloud with positions and radii defined by fields."
},
{
"ref": "bpy.types.PointCloud.html#bpy.types.PointCloud.points",
"supports": "points is a read-only collection in this snapshot."
}
],
"api_refs": [
"bpy.types.PointCloud.html",
"bpy.types.GeometryNodePoints.html"
],
"next_queries": [
"bpy.types.PointCloud.html",
"bpy.types.GeometryNodePoints.html",
"bpy.types.Attribute.html"
]
},
{
"id": "metaball-blobby-surfaces",
"domain": "curves-volumes",
"label_vi": "Bề mặt dạng khối mềm bằng Metaball",
"label_en": "Metaball blobby surfaces",
"intent_aliases": [
"metaball",
"bề mặt blob",
"khối mềm dạng blob",
"blobby surfaces",
"metaball elements"
],
"summary": "MetaBall defines blobby surfaces and contains MetaElement items.",
"choose_when": "Use the documented blobby surface type and continue selecting its elements through the API.",
"do_not_assume": [
"A blobby surface description does not establish fluid or soft-body simulation."
],
"evidence": [
{
"ref": "bpy.types.MetaBall.html",
"supports": "A metaball data-block defines blobby surfaces."
},
{
"ref": "bpy.types.MetaBall.html#bpy.types.MetaBall.elements",
"supports": "A collection contains metaball elements."
}
],
"api_refs": [
"bpy.types.MetaBall.html",
"bpy.types.MetaBallElements.html",
"bpy.types.MetaElement.html"
],
"next_queries": [
"bpy.types.MetaBall.html",
"bpy.types.MetaBallElements.html",
"bpy.types.MetaElement.html"
]
},
{
"id": "uv-explicit-coordinates",
"domain": "uv",
"label_vi": "Tạo UV layer và đọc/ghi tọa độ góc mặt",
"label_en": "UV layers and face corner coordinates",
"intent_aliases": [
"tạo UV map",
"tọa độ UV",
"gán UV thủ công",
"UV layer",
"face corner UV",
"explicit UV coordinates"
],
"summary": "UVLoopLayers.new adds a UV map; MeshUVLoopLayer.uv holds face-corner UV coordinates associated with mesh loops.",
"choose_when": "Assign known UV coordinates by face corner, or create/inspect a UV layer directly.",
"do_not_assume": [
"UVs belong to face corners; do not assume one UV per vertex without supporting evidence.",
"A read-only uv collection does not mean every contained Float2AttributeValue is immutable; read the value type."
],
"evidence": [
{
"ref": "bpy.types.UVLoopLayers.html#bpy.types.UVLoopLayers.new",
"supports": "Add a UV map layer to a Mesh."
},
{
"ref": "bpy.types.MeshUVLoopLayer.html#bpy.types.MeshUVLoopLayer.uv",
"supports": "Face-corner UV coordinates form a Float2AttributeValue collection."
},
{
"ref": "bpy.types.Mesh.html",
"supports": "Polygons reference loops; corner data such as UVs is attached to loops."
}
],
"api_refs": [
"bpy.types.UVLoopLayers.html#bpy.types.UVLoopLayers.new",
"bpy.types.MeshUVLoopLayer.html#bpy.types.MeshUVLoopLayer.uv",
"bpy.types.Float2AttributeValue.html"
],
"next_queries": [
"bpy.types.UVLoopLayers.html#bpy.types.UVLoopLayers.new",
"bpy.types.MeshUVLoopLayer.html#bpy.types.MeshUVLoopLayer.uv",
"bpy.types.Float2AttributeValue.html",
"bpy.types.Mesh.html"
]
},
{
"id": "uv-unwrap-projection",
"domain": "uv",
"label_vi": "Unwrap mesh hoặc chiếu UV các mặt đã chọn",
"label_en": "UV unwrap and smart projection",
"intent_aliases": [
"trải UV",
"mở UV",
"unwrap mesh",
"smart UV project",
"projection unwrap",
"giảm méo UV"
],
"summary": "uv.unwrap unwraps the mesh being edited; smart_project projection-unwraps selected faces with angle_limit and island spacing.",
"choose_when": "Have Blender compute UVs from a mesh or selected faces instead of supplying coordinates.",
"do_not_assume": [
"unwrap refers to an object being edited and smart_project to selected faces; these operators depend on context and can fail poll."
],
"evidence": [
{
"ref": "bpy.ops.uv.html#bpy.ops.uv.unwrap",
"supports": "Unwrap the mesh object being edited with the listed methods."
},
{
"ref": "bpy.ops.uv.html#bpy.ops.uv.smart_project",
"supports": "Projection-unwrap selected mesh faces; angle_limit controls projection grouping/distortion."
},
{
"ref": "info_gotchas_operators.html",
"supports": "Operators use context and can fail poll."
}
],
"api_refs": [
"bpy.ops.uv.html#bpy.ops.uv.unwrap",
"bpy.ops.uv.html#bpy.ops.uv.smart_project"
],
"next_queries": [
"bpy.ops.uv.html#bpy.ops.uv.unwrap",
"bpy.ops.uv.html#bpy.ops.uv.smart_project",
"info_gotchas_operators.html"
]
},
{
"id": "uv-pack-islands",
"domain": "uv",
"label_vi": "Xếp UV islands trong UV/UDIM space",
"label_en": "Pack UV islands into UV or UDIM space",
"intent_aliases": [
"xếp UV",
"đóng gói UV islands",
"pack UV",
"UV packing",
"UDIM islands",
"tối ưu diện tích UV"
],
"summary": "pack_islands transforms UV islands to fill UV/UDIM space, with rotation, scale, margin and packing-target options.",
"choose_when": "Existing UV islands need arrangement in UV or UDIM space.",
"do_not_assume": [
"pack_islands transforms islands; it does not prove that the mesh has been unwrapped.",
"This operator depends on context as described in the operator guide."
],
"evidence": [
{
"ref": "bpy.ops.uv.html#bpy.ops.uv.pack_islands",
"supports": "Transform islands to fill UV/UDIM space; describe rotate, scale, margin and udim_source."
},
{
"ref": "info_gotchas_operators.html",
"supports": "Operators obtain their targets from context."
}
],
"api_refs": [
"bpy.ops.uv.html#bpy.ops.uv.pack_islands"
],
"next_queries": [
"bpy.ops.uv.html#bpy.ops.uv.pack_islands",
"info_gotchas_operators.html"
]
},
{
"id": "sculpt-mesh-filters",
"domain": "sculpt-paint",
"label_vi": "Lọc biến dạng mesh khi sculpt",
"label_en": "Sculpt mesh deformation filters",
"intent_aliases": [
"làm trơn sculpt",
"phồng mesh",
"tăng chi tiết bề mặt",
"sculpt mesh filter",
"inflate mesh",
"surface smooth",
"sharpen cavities"
],
"summary": "sculpt.mesh_filter modifies the current mesh with filters including smooth, inflate, sphere, random, volume-preserving surface smooth, sharpen and enhance details.",
"choose_when": "Apply a sculpt filter whose documented effect matches the intended change.",
"do_not_assume": [
"The API does not confirm operation in every background context; the operator guide requires context/poll checks."
],
"evidence": [
{
"ref": "bpy.ops.sculpt.html#bpy.ops.sculpt.mesh_filter",
"supports": "Apply a filter to the current mesh; list and describe filter types."
},
{
"ref": "info_gotchas_operators.html",
"supports": "Operators use context and can fail poll."
}
],
"api_refs": [
"bpy.ops.sculpt.html#bpy.ops.sculpt.mesh_filter"
],
"next_queries": [
"bpy.ops.sculpt.html#bpy.ops.sculpt.mesh_filter",
"info_gotchas_operators.html"
]
},
{
"id": "sculpt-masks-face-sets",
"domain": "sculpt-paint",
"label_vi": "Lọc mask và tạo face set trong sculpt",
"label_en": "Sculpt mask filters and face sets",
"intent_aliases": [
"mở rộng mask sculpt",
"thu nhỏ mask",
"làm mềm mask",
"tạo face set",
"mask filter",
"grow shrink mask",
"face sets"
],
"summary": "mask_filter smooths, sharpens, grows, shrinks or changes mask contrast; face_sets_create creates face sets from a mask, visible region, whole mesh or Edit Mode selection.",
"choose_when": "Adjust a mask or group faces from an existing selection source.",
"do_not_assume": [
"Masks and face sets are different outputs; select the operation matching the requested output.",
"Both APIs are operators and require a valid context."
],
"evidence": [
{
"ref": "bpy.ops.sculpt.html#bpy.ops.sculpt.mask_filter",
"supports": "Filter the current mask with listed filter_type values."
},
{
"ref": "bpy.ops.sculpt.html#bpy.ops.sculpt.face_sets_create",
"supports": "Create face sets from masked, visible, all or selected faces."
},
{
"ref": "info_gotchas_operators.html",
"supports": "Operators use context."
}
],
"api_refs": [
"bpy.ops.sculpt.html#bpy.ops.sculpt.mask_filter",
"bpy.ops.sculpt.html#bpy.ops.sculpt.face_sets_create"
],
"next_queries": [
"bpy.ops.sculpt.html#bpy.ops.sculpt.mask_filter",
"bpy.ops.sculpt.html#bpy.ops.sculpt.face_sets_create",
"info_gotchas_operators.html"
]
},
{
"id": "sculpt-brush-strokes",
"domain": "sculpt-paint",
"label_vi": "Áp nét cọ sculpt lên geometry",
"label_en": "Sculpt brush strokes",
"intent_aliases": [
"nét cọ sculpt",
"điêu khắc bằng brush",
"sculpt stroke",
"brush sculpt",
"sculpt brush stroke"
],
"summary": "sculpt.brush_stroke applies a geometry stroke using OperatorStrokeElement data, normal/invert mode, brush toggle and pen flip.",
"choose_when": "The task requires brush strokes and can supply stroke data with an appropriate context.",
"do_not_assume": [
"The page describes stroke and mouse_event but does not provide an editor-context setup for background CLI use."
],
"evidence": [
{
"ref": "bpy.ops.sculpt.html#bpy.ops.sculpt.brush_stroke",
"supports": "Apply a sculpt stroke using OperatorStrokeElement; override_location can be recomputed from mouse_event."
},
{
"ref": "info_gotchas_operators.html",
"supports": "Operators obtain their working data from context."
}
],
"api_refs": [
"bpy.ops.sculpt.html#bpy.ops.sculpt.brush_stroke",
"bpy.types.OperatorStrokeElement.html"
],
"next_queries": [
"bpy.ops.sculpt.html#bpy.ops.sculpt.brush_stroke",
"bpy.types.OperatorStrokeElement.html",
"bpy.types.Brush.html",
"info_gotchas_operators.html"
]
},
{
"id": "paint-vertex-weights",
"domain": "sculpt-paint",
"label_vi": "Gán trọng số vertex group",
"label_en": "Assign vertex group weights",
"intent_aliases": [
"gán weight",
"trọng số đỉnh",
"vertex group weights",
"weight paint fill",
"assign vertex weights"
],
"summary": "VertexGroup.add assigns weights to vertex indices with replace/add/subtract modes; paint.weight_set fills the active group with the current paint weight.",
"choose_when": "Use VertexGroup.add for explicit indexed weights; inspect weight_set to fill the active group using the current paint weight.",
"do_not_assume": [
"VertexGroup.add does not infer appropriate weights; weight_set uses the active group and current paint weight."
],
"evidence": [
{
"ref": "bpy.types.VertexGroup.html#bpy.types.VertexGroup.add",
"supports": "Add vertices by index with weight 0..1 and REPLACE/ADD/SUBTRACT."
},
{
"ref": "bpy.ops.paint.html#bpy.ops.paint.weight_set",
"supports": "Fill the active vertex group with the current paint weight."
}
],
"api_refs": [
"bpy.types.VertexGroup.html#bpy.types.VertexGroup.add",
"bpy.ops.paint.html#bpy.ops.paint.weight_set"
],
"next_queries": [
"bpy.types.VertexGroup.html#bpy.types.VertexGroup.add",
"bpy.types.VertexGroups.html",
"bpy.ops.paint.html#bpy.ops.paint.weight_set",
"info_gotchas_operators.html"
]
},
{
"id": "paint-vertex-color-fill",
"domain": "sculpt-paint",
"label_vi": "Tô màu toàn lớp vertex color hiện hành",
"label_en": "Fill active vertex color layer",
"intent_aliases": [
"tô màu vertex",
"fill màu vertex",
"vertex color fill",
"paint vertex color",
"active color layer"
],
"summary": "paint.vertex_color_set fills the active vertex color layer using the current paint color; use_alpha selects opaque or existing alpha.",
"choose_when": "Fill the active color layer with the paint color and choose alpha handling.",
"do_not_assume": [
"The source only describes the active layer and current paint color; it does not establish layer creation or render material setup."
],
"evidence": [
{
"ref": "bpy.ops.paint.html#bpy.ops.paint.vertex_color_set",
"supports": "Fill the active vertex color layer; use_alpha selects opaque alpha or preserves existing alpha."
},
{
"ref": "info_gotchas_operators.html",
"supports": "The operator works through context."
}
],
"api_refs": [
"bpy.ops.paint.html#bpy.ops.paint.vertex_color_set"
],
"next_queries": [
"bpy.ops.paint.html#bpy.ops.paint.vertex_color_set",
"bpy.types.Attribute.html",
"info_gotchas_operators.html"
]
},
{
"id": "paint-image-strokes",
"domain": "sculpt-paint",
"label_vi": "Vẽ nét cọ vào ảnh",
"label_en": "Paint strokes into an image",
"intent_aliases": [
"vẽ texture bằng cọ",
"nét cọ lên ảnh",
"image paint stroke",
"texture painting",
"paint image"
],
"summary": "paint.image_paint paints a stroke into an image using OperatorStrokeElement data, normal/invert mode, brush toggle and pen flip.",
"choose_when": "Apply an image paint stroke with specified stroke data and context.",
"do_not_assume": [
"The operator page does not provide a complete background CLI paint context; it does not establish that stroke data alone is sufficient."
],
"evidence": [
{
"ref": "bpy.ops.paint.html#bpy.ops.paint.image_paint",
"supports": "Paint a stroke into an image with stroke, mode, brush_toggle and pen_flip."
},
{
"ref": "info_gotchas_operators.html",
"supports": "Operators use context and can fail poll."
}
],
"api_refs": [
"bpy.ops.paint.html#bpy.ops.paint.image_paint",
"bpy.types.OperatorStrokeElement.html"
],
"next_queries": [
"bpy.ops.paint.html#bpy.ops.paint.image_paint",
"bpy.types.OperatorStrokeElement.html",
"bpy.types.ImagePaint.html",
"info_gotchas_operators.html"
]
}
]
}
references/catalog/overview.md
# Capability catalog before API lookup
Read this entire page before opening SQLite. This catalog supplies Blender context to the agent; do not add capabilities, APIs, enums or workflows from pretrained Blender knowledge.
The catalog contains 112 source-backed routes, 2192 source-page cards and 26775 inventory entries. An API card is a discovery entry point, not proof of a documented workflow or working CLI implementation.
| Domain | Search aliases (English / Vietnamese) | Authored routes | Source cards |
|---|---|---|---|
| [Scenes, objects, collections and transforms](domains/scene.md) | cảnh, đối tượng, vị trí, xoay, scene, object, collection, transform | 4 | 35 |
| [Mesh, BMesh and modifiers](domains/geometry.md) | lưới, hình học, bo cạnh, cắt khối, mesh, bmesh, modifier, topology | 15 | 118 |
| [Geometry Nodes, fields and instances](domains/geometry-nodes.md) | nút hình học, phân bố, nhân bản, geometry nodes, instance, field | 6 | 510 |
| [Curves, 3D text, hair, point clouds and volumes](domains/curves-volumes.md) | đường cong, chữ 3d, tóc, thể tích, curve, text geometry, hair, volume, grid | 6 | 59 |
| [Sculpting, brushes and painting](domains/sculpt-paint.md) | điêu khắc, tô màu, trọng số, sculpt, paint, brush, weight | 6 | 36 |
| [UV maps, images and texture baking](domains/uv.md) | trải uv, tọa độ uv, nướng texture, uv, unwrap, image, bake | 3 | 18 |
| [Materials, shaders, textures and worlds](domains/shading.md) | vật liệu, bề mặt, shader, material, texture, world | 7 | 174 |
| [Lights, cameras and shadows](domains/lights-shadows.md) | ánh sáng, đèn, đổ bóng, bóng, camera, light, shadow, reflection | 4 | 27 |
| [Rendering, passes, color and image output](domains/render.md) | kết xuất, render, pass, màu, png, output, color management | 5 | 31 |
| [Compositing, masks and image processing](domains/compositor.md) | hậu kỳ, ghép ảnh, khử nhiễu, compositing, mask, denoise, keying | 8 | 112 |
| [Video editing, titles and audio](domains/video-audio.md) | dựng phim, chữ video, âm thanh, video, sequencer, text strip, audio | 5 | 66 |
| [Grease Pencil, 2D strokes and Freestyle](domains/grease-pencil-freestyle.md) | vẽ 2d, nét vẽ, grease pencil, freestyle, line art, stroke | 3 | 130 |
| [Motion tracking and movie clips](domains/tracking.md) | bám chuyển động, giải camera, tracking, movie clip, camera solve | 3 | 30 |
| [Keyframes, drivers, rigs and constraints](domains/animation-rigging.md) | chuyển động, khung hình chính, xương, rig, animation, keyframe, driver, constraint | 11 | 119 |
| [Simulation, physics and caches](domains/simulation.md) | mô phỏng, vải, chất lỏng, khói, vật lý, simulation, physics, fluid, cloth, rigid body, particle | 10 | 58 |
| [Files, import/export, libraries and assets](domains/files-assets.md) | tệp, nhập, xuất, tài nguyên, file, import, export, library, asset | 9 | 71 |
| [Python integration, math, GPU and UI](domains/integration-gpu.md) | tích hợp, tiện ích, giao diện, toán, python, math, gpu, ui, registration | 7 | 404 |
| [API guides, enums and source indices](domains/api-guides.md) | tài liệu, hướng dẫn, enum, index, api reference, gotchas | 0 | 258 |
## Selecting a route
1. Match the request to the domains above using the supplied language and context. Do not guess API identifiers.
2. Read the domain file and compare purpose, selection criteria and gaps. `features.py match` searches English/Vietnamese aliases using JSON only, without opening the database.
3. Read selected routes with `features.py show ID` for source excerpts, limits and seed queries. Select multiple routes for combined tasks.
4. If no route fits, inspect domain page cards (`features.py pages DOMAIN`) and select only behavior supported by source descriptions. Missing descriptions do not permit inferring behavior from names.
5. If evidence is still insufficient, report `insufficient_skill_evidence`, identify the missing fact and request source material or clarification of the output. Do not substitute model memory.
## Status values
- `documented_route_runtime_unverified`: a source-backed description and query route; inspect the actual API/runtime before execution.
- `api_discovery_only`: a source page/API exists, but this card is not an authored task route; read the source before proceeding.
- `identifier_only`: introductory text does not sufficiently describe behavior. Preserve the gap; a class name is not evidence.
Routes and cards derive from the bundled API corpus. Blender Manual and web content have not been added to this layer. The catalog does not establish background-mode support for every feature.
references/catalog/domains/video-audio.md
# Video editing, titles and audio
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## Sequencer text titles — `sequencer-text-titles`
TextStrip generates text with content, font, size, position, alignment, outline and box properties. StripsTopLevel.new_effect includes TEXT for adding a text strip.
Choose when: Add text over specified intervals in a video sequence.
Search aliases: chữ trong video, tiêu đề video, text strip, video title, phụ đề bằng text
Evidence: `bpy.types.TextStrip.html#bpy.types.TextStrip` — A sequence strip generates text and exposes text-display properties.; `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect` — The TEXT effect adds a simple text strip.
Read next: `bpy.types.TextStrip.html`, `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect`, `bpy.types.Scene.html#bpy.types.Scene.sequence_editor_create`
Limits: The source does not establish speech recognition or automatic subtitle timing. The default font falls back to a UI font; inspect the supplied font and required glyph rendering.
## Text strip drop shadow — `sequencer-text-drop-shadow`
TextStrip.use_shadow displays a shadow behind text; the class also exposes shadow_angle, shadow_blur, shadow_color and shadow_offset with types/ranges.
Choose when: Apply a shadow to Video Sequencer text, distinct from 3D shadow rays or footage shadow catchers.
Search aliases: đổ bóng, bóng chữ, đổ bóng chữ, text shadow, text drop shadow, bóng chữ video
Evidence: `bpy.types.TextStrip.html#bpy.types.TextStrip.use_shadow` — Display a shadow behind text.; `bpy.types.TextStrip.html#bpy.types.TextStrip` — TextStrip generates text and exposes shadow parameters with types/ranges.
Read next: `bpy.types.TextStrip.html`, `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect`
Limits: shadow_blur/offset have type/range information without complete pixel-unit semantics. Do not transfer CSS numbers or 3D light controls by assumption.
## Load and trim sequencer video — `sequencer-load-trim-video`
MovieStrip loads video; StripsTopLevel.new_movie adds a clip by file, channel and frame_start. content_trim_start/end skip source frames and turn corresponding time into holds.
Choose when: Load a clip into the timeline or adjust source content at its ends according to the documented trimming semantics.
Search aliases: dựng video, nạp video, cắt đầu cuối clip, movie strip, trim video, load video
Evidence: `bpy.types.MovieStrip.html#bpy.types.MovieStrip` — A sequence strip loads video; document content trimming and deprecation.; `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_movie` — Add a movie strip with filepath, channel and frame_start.
Read next: `bpy.types.MovieStrip.html`, `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_movie`, `bpy.types.Strip.html`
Limits: The source marks animation_offset_start/end deprecated since 5.10 in favor of content_trim_start/end. Do not assume source trimming shortens the timeline; read frame ranges and inspect results.
## Timed audio strips and playback volume — `sequencer-timed-sound`
SoundStrip plays audio over an interval; volume controls level, pan applies to mono sources and sound_offset is measured in seconds. StripsTopLevel.new_sound adds a sound strip.
Choose when: Place audio on the timeline and adjust timing, volume or pan as documented.
Search aliases: thêm âm thanh, nhạc nền, sound strip, audio timeline, volume âm thanh, pan âm thanh
Evidence: `bpy.types.SoundStrip.html#bpy.types.SoundStrip` — Describe timed audio, volume, mono pan and sound_offset in seconds.; `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_sound` — Add a sound strip from a file at a timeline position.
Read next: `bpy.types.SoundStrip.html`, `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_sound`, `bpy.ops.sound.html`
Limits: A sound strip does not establish codec or mixdown support. Pan is limited to mono sources; inspect media and audio output separately.
## Sequencer transitions and effects — `sequencer-transitions-effects`
StripsTopLevel.new_effect describes CROSS fading, WIPE transitions, GLOW on bright regions, SPEED playback time-warping, GAUSSIAN_BLUR detail softening and blending effects.
Choose when: Create timeline strip effects or transitions, selecting types from new_effect descriptions.
Search aliases: chuyển cảnh, crossfade, wipe, video glow, timewarp, đổi tốc độ video, blend strips
Evidence: `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect` — Describe CROSS, WIPE, GLOW, SPEED, GAUSSIAN_BLUR and blending effects.
Read next: `bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect`, `bpy.types.EffectStrip.html`, `bpy.types.SpeedControlStrip.html`, `bpy.types.WipeStrip.html`
Limits: Read each effect's inputs and settings; do not assume every effect takes two strips or uses older properties. SPEED does not establish optical-flow interpolation.
## Discover all source pages in this domain
`python3 scripts/features.py pages video-audio` lists 66 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/catalog/routes-render-media.json
{
"schema_version": 1,
"routes": [
{
"id": "surface-principled-material",
"domain": "shading",
"label_vi": "Vật liệu bề mặt theo mô hình OpenPBR",
"label_en": "Principled surface material",
"intent_aliases": [
"vật liệu bề mặt",
"shader vật lý",
"surface material",
"principled",
"OpenPBR"
],
"summary": "ShaderNodeBsdfPrincipled is described as a physically based surface shader based on OpenPBR; Material.node_tree holds the material's node tree.",
"choose_when": "Use a physically based surface shader; read subsurface or scattering methods when those properties are required.",
"do_not_assume": [
"The class page does not list all inputs or a complete material recipe. Read node/socket data and probe the runtime; do not supply remembered socket names, values or links."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeBsdfPrincipled.html#bpy.types.ShaderNodeBsdfPrincipled",
"supports": "Describe an OpenPBR-based physically based surface shader."
},
{
"ref": "bpy.types.Material.html#bpy.types.Material.node_tree",
"supports": "Expose the node tree of a node-based material."
}
],
"api_refs": [
"bpy.types.ShaderNodeBsdfPrincipled.html",
"bpy.types.Material.html#bpy.types.Material.node_tree"
],
"next_queries": [
"bpy.types.ShaderNodeBsdfPrincipled.html",
"bpy.types.Material.html",
"bpy.types.Nodes.html",
"bpy.types.NodeLinks.html"
]
},
{
"id": "image-texture-sampling",
"domain": "shading",
"label_vi": "Dùng tệp ảnh làm texture",
"label_en": "Image texture sampling",
"intent_aliases": [
"texture ảnh",
"dán ảnh lên vật thể",
"image texture",
"texture projection",
"image mapping"
],
"summary": "ShaderNodeTexImage samples an image file as a texture, with documented extension, interpolation and FLAT, BOX, SPHERE and TUBE projection modes.",
"choose_when": "Use an image file in a shader network and select projection from its documented contract.",
"do_not_assume": [
"Projection documentation does not establish UV availability, a loaded image or shader connections. Inspect inputs before choosing links."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeTexImage.html#bpy.types.ShaderNodeTexImage",
"supports": "Sample an image as a texture; projection describes ways to project a 2D image."
}
],
"api_refs": [
"bpy.types.ShaderNodeTexImage.html"
],
"next_queries": [
"bpy.types.ShaderNodeTexImage.html",
"bpy.types.BlendDataImages.html",
"bpy.types.NodeLinks.html"
]
},
{
"id": "procedural-noise-texture",
"domain": "shading",
"label_vi": "Texture nhiễu Perlin dạng fractal",
"label_en": "Procedural fractal Perlin noise",
"intent_aliases": [
"texture nhiễu",
"nhiễu thủ tục",
"vân ngẫu nhiên",
"noise texture",
"Perlin",
"fractal noise"
],
"summary": "ShaderNodeTexNoise generates fractal Perlin noise in one to four dimensions; noise types describe sharp peaks, peaks/valleys and terrain-like signals.",
"choose_when": "Supply noise to a shader network. Terrain wording describes the signal, not a terrain geometry recipe.",
"do_not_assume": [
"A noise name does not establish a complete node network or terrain mesh. Read noise_type, dimensions and actual sockets before connecting."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeTexNoise.html#bpy.types.ShaderNodeTexNoise",
"supports": "Generate fractal Perlin noise; noise_dimensions and noise_type describe dimensionality and noise forms."
}
],
"api_refs": [
"bpy.types.ShaderNodeTexNoise.html"
],
"next_queries": [
"bpy.types.ShaderNodeTexNoise.html",
"bpy.types.Node.html#bpy.types.Node.inputs"
]
},
{
"id": "bump-from-height",
"domain": "shading",
"label_vi": "Giả chi tiết bề mặt bằng height texture",
"label_en": "Bump mapping from height texture",
"intent_aliases": [
"bump",
"bump mapping",
"height texture",
"giả gồ ghề",
"giả chi tiết bề mặt"
],
"summary": "ShaderNodeBump perturbs normals from a height texture to simulate surface detail; invert points bumps into the surface.",
"choose_when": "Use a height texture to simulate surface detail through normals.",
"do_not_assume": [
"The description establishes normal changes, not geometry or silhouette changes. Confirm relevant sockets from skill data/runtime."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeBump.html#bpy.types.ShaderNodeBump",
"supports": "Generate a perturbed normal from a height texture to simulate detailed surfaces."
}
],
"api_refs": [
"bpy.types.ShaderNodeBump.html"
],
"next_queries": [
"bpy.types.ShaderNodeBump.html",
"bpy.types.ShaderNodeTexImage.html",
"bpy.types.NodeLinks.html"
]
},
{
"id": "normal-map-surface-detail",
"domain": "shading",
"label_vi": "Giả chi tiết bằng ảnh normal RGB",
"label_en": "RGB normal map surface detail",
"intent_aliases": [
"normal map",
"bản đồ pháp tuyến",
"RGB normal",
"DirectX normal",
"OpenGL normal"
],
"summary": "ShaderNodeNormalMap perturbs normals from an RGB normal image; the API describes OpenGL/DirectX conventions, normal spaces and tangent-space UV maps.",
"choose_when": "The input is an RGB normal map; choose convention and space from the actual image data.",
"do_not_assume": [
"Do not guess image convention or normal space. This route describes normals that simulate detail, not mesh changes."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeNormalMap.html#bpy.types.ShaderNodeNormalMap",
"supports": "Generate perturbed normals from an RGB normal map; describe convention, space and uv_map."
}
],
"api_refs": [
"bpy.types.ShaderNodeNormalMap.html"
],
"next_queries": [
"bpy.types.ShaderNodeNormalMap.html",
"bpy.types.ShaderNodeTexImage.html"
]
},
{
"id": "principled-volume-shading",
"domain": "shading",
"label_vi": "Gộp các thành phần shading thể tích",
"label_en": "Principled volume shading",
"intent_aliases": [
"shading thể tích",
"vật liệu thể tích",
"volume shading",
"principled volume"
],
"summary": "ShaderNodeVolumePrincipled combines volume-shading components in one node.",
"choose_when": "Discover a source-supported volume shader configuration.",
"do_not_assume": [
"The description does not supply smoke/fire simulation or a fog recipe. Do not assign those workflows without related evidence; inspect sockets and engine support."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeVolumePrincipled.html#bpy.types.ShaderNodeVolumePrincipled",
"supports": "Combine all volume-shading components in one node."
}
],
"api_refs": [
"bpy.types.ShaderNodeVolumePrincipled.html"
],
"next_queries": [
"bpy.types.ShaderNodeVolumePrincipled.html",
"bpy.types.Node.html#bpy.types.Node.inputs",
"bpy.types.ShaderNodeOutputMaterial.html"
]
},
{
"id": "emission-shader",
"domain": "shading",
"label_vi": "Shader phát xạ Lambertian",
"label_en": "Lambertian emission shader",
"intent_aliases": [
"shader phát xạ",
"vật liệu phát sáng",
"emission shader",
"Lambertian emission"
],
"summary": "ShaderNodeEmission is described as a Lambertian emission shader.",
"choose_when": "Add an emission component to a shader; consider compositor glare when the request specifically concerns halos around bright image regions.",
"do_not_assume": [
"This description does not establish automatic halos or illumination of other objects in every engine. Do not fill unsupported details from memory."
],
"evidence": [
{
"ref": "bpy.types.ShaderNodeEmission.html#bpy.types.ShaderNodeEmission",
"supports": "Describe a Lambertian emission shader."
},
{
"ref": "bpy.types.CompositorNodeGlare.html#bpy.types.CompositorNodeGlare",
"supports": "Glare separately adds flares, fog and glow around bright image regions."
}
],
"api_refs": [
"bpy.types.ShaderNodeEmission.html"
],
"next_queries": [
"bpy.types.ShaderNodeEmission.html",
"bpy.types.ShaderNodeOutputMaterial.html",
"bpy.types.CompositorNodeGlare.html"
]
},
{
"id": "scene-shadow-ray-controls",
"domain": "lights-shadows",
"label_vi": "Bóng vật thể trong cảnh và shadow rays",
"label_en": "Scene object shadow-ray controls",
"intent_aliases": [
"đổ bóng",
"bóng vật thể",
"bóng xuống sàn",
"bóng mềm",
"cast shadow",
"soft shadow",
"shadow rays"
],
"summary": "Object.visible_shadow controls visibility to shadow rays. AreaLight.shadow_soft_size describes light size for ray-traced shadow sampling; Light.use_shadow has only type/default information in the source.",
"choose_when": "Explore scene-object, light or shadow-ray controls; continue reading object, light and engine evidence.",
"do_not_assume": [
"Light.use_shadow does not document a complete shadow algorithm. Do not assume increasing AreaLight.shadow_soft_size guarantees softer shadows in every engine; AreaLight.size describes source area separately. This corpus does not supply a complete soft-shadow recipe; implement supported parts and report remaining evidence gaps."
],
"evidence": [
{
"ref": "bpy.types.Object.html#bpy.types.Object.visible_shadow",
"supports": "Control object visibility to shadow rays."
},
{
"ref": "bpy.types.AreaLight.html#bpy.types.AreaLight.shadow_soft_size",
"supports": "Set light size for ray-traced shadow sampling without a complete engine-specific softness contract."
},
{
"ref": "bpy.types.AreaLight.html#bpy.types.AreaLight.size",
"supports": "Set area-light size, or X dimension for rectangular lights."
}
],
"api_refs": [
"bpy.types.Object.html#bpy.types.Object.visible_shadow",
"bpy.types.Light.html#bpy.types.Light.use_shadow",
"bpy.types.AreaLight.html#bpy.types.AreaLight.shadow_soft_size",
"bpy.types.AreaLight.html#bpy.types.AreaLight.size"
],
"next_queries": [
"bpy.types.Object.html#bpy.types.Object.visible_shadow",
"bpy.types.Light.html",
"bpy.types.AreaLight.html",
"bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine"
]
},
{
"id": "shadow-catcher-real-footage",
"domain": "lights-shadows",
"label_vi": "Bắt bóng và phản xạ để ghép vào footage thật",
"label_en": "Shadow catcher for real footage",
"intent_aliases": [
"đổ bóng",
"bắt bóng",
"ghép model vào footage",
"ghép vào ảnh thật",
"shadow catcher",
"real footage",
"compositing shadows"
],
"summary": "Object.is_shadow_catcher renders only shadows and reflections on an object for compositing into real footage. Flagged objects are considered present in the footage; unflagged objects are synthetic additions.",
"choose_when": "Composite synthetic objects into footage where an existing surface should receive rendered shadows/reflections.",
"do_not_assume": [
"The anchor does not establish supported engines or a camera, lighting and compositing recipe. A flag alone does not complete the composite; read further and verify runtime/render output."
],
"evidence": [
{
"ref": "bpy.types.Object.html#bpy.types.Object.is_shadow_catcher",
"supports": "Render shadows and reflections for real-footage compositing; describe the roles of flagged and unflagged objects."
}
],
"api_refs": [
"bpy.types.Object.html#bpy.types.Object.is_shadow_catcher"
],
"next_queries": [
"bpy.types.Object.html#bpy.types.Object.is_shadow_catcher",
"bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent",
"bpy.types.CompositorNodeAlphaOver.html",
"bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine"
]
},
{
"id": "light-linking-and-blockers",
"domain": "lights-shadows",
"label_vi": "Quan hệ nhận sáng và chặn sáng theo collection",
"label_en": "Light linking and blocker collections",
"intent_aliases": [
"light linking",
"shadow linking",
"chặn ánh sáng",
"vật nhận sáng",
"blocker collection",
"receiver collection"
],
"summary": "ObjectLightLinking.receiver_collection defines an emitter's light-linking relationships; blocker_collection defines objects blocking that emitter's light.",
"choose_when": "Control emitter relationships with receiver collections or light-blocker collections.",
"do_not_assume": [
"The source does not establish support in every engine. Read collection contracts and editing APIs and check the actual engine before promising an effect."
],
"evidence": [
{
"ref": "bpy.types.ObjectLightLinking.html#bpy.types.ObjectLightLinking.receiver_collection",
"supports": "A collection defines emitter light-linking relationships."
},
{
"ref": "bpy.types.ObjectLightLinking.html#bpy.types.ObjectLightLinking.blocker_collection",
"supports": "A collection defines objects blocking light from the emitter."
}
],
"api_refs": [
"bpy.types.Object.html#bpy.types.Object.light_linking",
"bpy.types.ObjectLightLinking.html"
],
"next_queries": [
"bpy.types.ObjectLightLinking.html",
"bpy.types.CollectionLightLinking.html",
"bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine"
]
},
{
"id": "choose-light-source-shape",
"domain": "lights-shadows",
"label_vi": "Chọn nguồn sáng điểm, tia song song, nón hoặc diện tích",
"label_en": "Point, sun, spot and area light sources",
"intent_aliases": [
"tạo đèn",
"nguồn sáng",
"đèn điểm",
"đèn rọi",
"đèn diện tích",
"point light",
"sun light",
"spot light",
"area light"
],
"summary": "The source describes POINT as omnidirectional, SUN as fixed-direction parallel rays, SPOT as a directional cone and AREA as a directional area source. BlendDataLights.new creates a light data-block.",
"choose_when": "Choose a light-source shape before reading PointLight, SunLight, SpotLight or AreaLight properties.",
"do_not_assume": [
"Source shape does not provide appropriate power, position, exposure or shadow settings. Derive these from the request, supplied evidence and output checks."
],
"evidence": [
{
"ref": "bpy_types_enum_items/light_type_items.html",
"supports": "Describe POINT, SUN, SPOT and AREA source shapes."
},
{
"ref": "bpy.types.BlendDataLights.html#bpy.types.BlendDataLights.new",
"supports": "Create a light data-block using the type enum."
}
],
"api_refs": [
"bpy.types.BlendDataLights.html#bpy.types.BlendDataLights.new",
"bpy_types_enum_items/light_type_items.html"
],
"next_queries": [
"bpy_types_enum_items/light_type_items.html",
"bpy.types.BlendDataLights.html#bpy.types.BlendDataLights.new",
"bpy.types.AreaLight.html",
"bpy.types.SpotLight.html",
"bpy.types.PointLight.html",
"bpy.types.SunLight.html"
]
},
{
"id": "render-still-or-animation",
"domain": "render",
"label_vi": "Render ảnh hoặc dải frame",
"label_en": "Still and animation rendering",
"intent_aliases": [
"render ảnh",
"render animation",
"xuất frame",
"render still",
"render animation range",
"write still"
],
"summary": "bpy.ops.render.render parameters describe animation rendering over a scene frame range; write_still saves to the output path when animation is off; frame_start/frame_end bound animation rendering.",
"choose_when": "Render a still or frame range; read RenderSettings for requested paths, dimensions and formats.",
"do_not_assume": [
"The operator introduction says Undocumented, but parameters have descriptions. The engine enum lists only BLENDER_EEVEE in this snapshot; it is not a complete runtime inventory and does not justify remembered Cycles settings."
],
"evidence": [
{
"ref": "bpy.ops.render.html#bpy.ops.render.render",
"supports": "Describe animation, write_still, frame_start, frame_end and scene."
},
{
"ref": "bpy.types.RenderSettings.html#bpy.types.RenderSettings.engine",
"supports": "Expose engine with the snapshot's BLENDER_EEVEE enum."
}
],
"api_refs": [
"bpy.ops.render.html#bpy.ops.render.render",
"bpy.types.RenderSettings.html"
],
"next_queries": [
"bpy.ops.render.html#bpy.ops.render.render",
"bpy.types.RenderSettings.html",
"bpy.types.ImageFormatSettings.html"
]
},
{
"id": "shadow-render-pass",
"domain": "render",
"label_vi": "Xuất shadow pass",
"label_en": "Shadow render pass",
"intent_aliases": [
"đổ bóng",
"lớp bóng",
"xuất bóng riêng",
"shadow pass",
"shadow render pass"
],
"summary": "ViewLayer.use_pass_shadow is described as delivering a shadow pass.",
"choose_when": "Obtain a separate shadow layer for later rendering/compositing.",
"do_not_assume": [
"The source does not define pixel values, compositing formulas or engine availability. Enabling the flag does not prove correct pass data; read pass access APIs and inspect a real render."
],
"evidence": [
{
"ref": "bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_shadow",
"supports": "Deliver a shadow pass."
}
],
"api_refs": [
"bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_shadow"
],
"next_queries": [
"bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_shadow",
"bpy.types.RenderPass.html",
"bpy.types.CompositorNodeRLayers.html",
"bpy.types.CompositorNodeOutputFile.html"
]
},
{
"id": "transparent-world-background",
"domain": "render",
"label_vi": "Render nền world trong suốt",
"label_en": "Transparent world background",
"intent_aliases": [
"nền trong suốt",
"render alpha",
"transparent background",
"transparent film",
"tách nền render"
],
"summary": "RenderSettings.film_transparent makes the world background transparent for compositing over another background.",
"choose_when": "Composite the rendered world background over another image.",
"do_not_assume": [
"The property does not establish alpha-capable file output, remove scene background geometry or supply a compositing recipe. Read output-format and scene-data contracts."
],
"evidence": [
{
"ref": "bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent",
"supports": "Make the world background transparent for compositing over another background."
}
],
"api_refs": [
"bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent"
],
"next_queries": [
"bpy.types.RenderSettings.html#bpy.types.RenderSettings.film_transparent",
"bpy.types.ImageFormatSettings.html",
"bpy.types.CompositorNodeAlphaOver.html"
]
},
{
"id": "bake-selected-object-textures",
"domain": "render",
"label_vi": "Bake image texture của vật thể được chọn",
"label_en": "Bake selected-object image textures",
"intent_aliases": [
"bake texture",
"bake normal",
"bake vật liệu",
"bake image textures",
"selected to active"
],
"summary": "bpy.ops.object.bake bakes selected-object image textures; use_selected_to_active bakes selected objects' shading onto the active object; type describes passes and engine limitations.",
"choose_when": "Bake textures with identified source objects, active object and required pass type.",
"do_not_assume": [
"Read pass/target enums and confirm selection, active object and engine support. Do not supply remembered high-poly/low-poly recipes or pass choices."
],
"evidence": [
{
"ref": "bpy.ops.object.html#bpy.ops.object.bake",
"supports": "Bake image textures with selected-to-active behavior, pass engine limitations and target/save_mode parameters."
}
],
"api_refs": [
"bpy.ops.object.html#bpy.ops.object.bake"
],
"next_queries": [
"bpy.ops.object.html#bpy.ops.object.bake",
"bpy_types_enum_items/bake_pass_type_items.html",
"bpy_types_enum_items/bake_target_items.html",
"bpy.types.BakeSettings.html"
]
},
{
"id": "display-color-management",
"domain": "render",
"label_vi": "Exposure, gamma và chuyển đổi màu hiển thị",
"label_en": "Display color management",
"intent_aliases": [
"quản lý màu",
"exposure",
"gamma",
"white balance",
"cân bằng trắng",
"view transform",
"color management"
],
"summary": "ColorManagedViewSettings controls image display; exposure scales by 2^exposure before the display transform and gamma applies afterward, with white-balance and view_transform properties.",
"choose_when": "Adjust display color transformation, exposure or white balance rather than surface shader properties.",
"do_not_assume": [
"The snapshot's view_transform enum lists only NONE; do not choose AgX, Filmic or looks from memory. Inspect runtime color configurations; exposure changes are not light-power changes."
],
"evidence": [
{
"ref": "bpy.types.ColorManagedViewSettings.html#bpy.types.ColorManagedViewSettings",
"supports": "Describe display color management, exposure/gamma order, white balance and view transforms."
}
],
"api_refs": [
"bpy.types.ColorManagedViewSettings.html"
],
"next_queries": [
"bpy.types.ColorManagedViewSettings.html",
"bpy.types.Scene.html#bpy.types.Scene.view_settings"
]
},
{
"id": "compositor-image-blur",
"domain": "compositor",
"label_vi": "Làm mờ ảnh bằng compositor",
"label_en": "Compositor image blur",
"intent_aliases": [
"làm mờ ảnh",
"blur ảnh",
"image blur",
"compositor blur"
],
"summary": "CompositorNodeBlur blurs images with multiple blur modes.",
"choose_when": "Blur an image in the compositor.",
"do_not_assume": [
"The class description does not enumerate sockets or detailed modes. Do not use remembered older blur properties; read supplied metadata and inspect runtime sockets."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeBlur.html#bpy.types.CompositorNodeBlur",
"supports": "Blur images with multiple modes."
}
],
"api_refs": [
"bpy.types.CompositorNodeBlur.html",
"bpy.types.Scene.html#bpy.types.Scene.compositing_node_group"
],
"next_queries": [
"bpy.types.CompositorNodeBlur.html",
"bpy.types.Scene.html#bpy.types.Scene.compositing_node_group",
"bpy.types.NodeLinks.html"
]
},
{
"id": "compositor-glare-glow",
"domain": "compositor",
"label_vi": "Quầng sáng, flare và fog quanh vùng sáng của ảnh",
"label_en": "Glare, flares and glow in an image",
"intent_aliases": [
"quầng sáng",
"glow",
"glare",
"lens flare",
"bloom",
"phát sáng quanh vùng sáng"
],
"summary": "CompositorNodeGlare adds lens flares, fog and glow around bright image regions.",
"choose_when": "Create effects around bright image regions, often requested as glow or bloom.",
"do_not_assume": [
"The bloom alias maps intent; it does not establish a BLOOM enum or Eevee bloom property. Obtain modes, thresholds and sockets from skill data/runtime."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeGlare.html#bpy.types.CompositorNodeGlare",
"supports": "Add lens flares, fog and glow around bright image regions."
}
],
"api_refs": [
"bpy.types.CompositorNodeGlare.html"
],
"next_queries": [
"bpy.types.CompositorNodeGlare.html",
"bpy.types.Scene.html#bpy.types.Scene.compositing_node_group",
"bpy.types.Node.html#bpy.types.Node.inputs"
]
},
{
"id": "compositor-chroma-key-despill",
"domain": "compositor",
"label_vi": "Tách phông theo màu và khử ám màu phông",
"label_en": "Chroma keying and despill",
"intent_aliases": [
"tách phông xanh",
"xóa phông màu",
"chroma key",
"green screen",
"despill",
"khử ám màu"
],
"summary": "CompositorNodeKeying removes a backdrop through chroma keying and corrects backdrop color spill.",
"choose_when": "Remove a backdrop by color and optionally correct its color cast.",
"do_not_assume": [
"The source does not promise arbitrary background removal or automatic key-color detection. Inspect image data and supported sockets/values; do not infer semantic segmentation."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeKeying.html#bpy.types.CompositorNodeKeying",
"supports": "Remove a backdrop through chroma keying and correct its color cast with despill."
}
],
"api_refs": [
"bpy.types.CompositorNodeKeying.html"
],
"next_queries": [
"bpy.types.CompositorNodeKeying.html",
"bpy.types.CompositorNodeImage.html",
"bpy.types.CompositorNodeAlphaOver.html"
]
},
{
"id": "compositor-foreground-over-background",
"domain": "compositor",
"label_vi": "Ghép ảnh foreground lên background",
"label_en": "Foreground over background compositing",
"intent_aliases": [
"ghép ảnh",
"ghép nền",
"alpha over",
"overlay foreground",
"composite foreground background"
],
"summary": "CompositorNodeAlphaOver overlays a foreground image on a background.",
"choose_when": "Combine identified foreground and background images.",
"do_not_assume": [
"The description does not establish socket index order, straight/premultiplied handling or background removal. Read socket and alpha-source contracts before linking."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeAlphaOver.html#bpy.types.CompositorNodeAlphaOver",
"supports": "Overlay a foreground image on a background image."
}
],
"api_refs": [
"bpy.types.CompositorNodeAlphaOver.html"
],
"next_queries": [
"bpy.types.CompositorNodeAlphaOver.html",
"bpy.types.CompositorNodeImage.html",
"bpy.types.NodeLinks.html"
]
},
{
"id": "compositor-file-output",
"domain": "compositor",
"label_vi": "Ghi ảnh từ compositor ra tệp",
"label_en": "Compositor image file output",
"intent_aliases": [
"xuất ảnh compositor",
"file output",
"ghi ảnh",
"output passes",
"write image file"
],
"summary": "CompositorNodeOutputFile writes image files; this snapshot exposes directory, file_name, file_output_items and format.",
"choose_when": "Save compositor output with specified paths and formats.",
"do_not_assume": [
"Do not use remembered base_path/file_slots properties when this snapshot documents directory/file_output_items. Path-template documentation is external and unbundled; do not invent missing template syntax."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeOutputFile.html#bpy.types.CompositorNodeOutputFile",
"supports": "Write image files with this version's directory, file_name, file_output_items and format properties."
}
],
"api_refs": [
"bpy.types.CompositorNodeOutputFile.html"
],
"next_queries": [
"bpy.types.CompositorNodeOutputFile.html",
"bpy.types.NodeCompositorFileOutputItems.html",
"bpy.types.ImageFormatSettings.html"
]
},
{
"id": "compositor-render-denoise",
"domain": "compositor",
"label_vi": "Khử nhiễu ảnh render ray tracing",
"label_en": "Ray-traced render denoising",
"intent_aliases": [
"khử nhiễu",
"denoise",
"render noise",
"ảnh render nhiễu"
],
"summary": "CompositorNodeDenoise is described as denoising Cycles and other ray-traced renders.",
"choose_when": "Denoise a ray-traced render in the compositor.",
"do_not_assume": [
"The class does not fully document required sockets, auxiliary passes or denoiser libraries. Read available data and verify the runtime instead of supplying remembered Cycles configuration."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeDenoise.html#bpy.types.CompositorNodeDenoise",
"supports": "Denoise Cycles and other ray-traced renders."
}
],
"api_refs": [
"bpy.types.CompositorNodeDenoise.html"
],
"next_queries": [
"bpy.types.CompositorNodeDenoise.html",
"bpy.types.CompositorNodeRLayers.html",
"bpy.types.Node.html#bpy.types.Node.inputs"
]
},
{
"id": "compositor-depth-of-field",
"domain": "compositor",
"label_vi": "Độ sâu trường ảnh 2D từ Z depth hoặc mask",
"label_en": "2D depth of field from depth or mask",
"intent_aliases": [
"xóa phông theo độ sâu",
"defocus",
"depth of field",
"bokeh",
"Z depth blur"
],
"summary": "CompositorNodeDefocus applies 2D depth of field using a Z-depth map or mask, with documented bokeh, f_stop, blur_max and use_zbuffer.",
"choose_when": "Apply depth of field during image processing using depth or mask data.",
"do_not_assume": [
"This is not camera optics configuration or proof that depth/mask data exists. Read the distinction between Z-buffer and image inputs and inspect the data."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeDefocus.html#bpy.types.CompositorNodeDefocus",
"supports": "Apply 2D depth of field using a Z-depth map or mask, with bokeh and f_stop."
}
],
"api_refs": [
"bpy.types.CompositorNodeDefocus.html"
],
"next_queries": [
"bpy.types.CompositorNodeDefocus.html",
"bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_z",
"bpy.types.CompositorNodeRLayers.html"
]
},
{
"id": "cryptomatte-object-material-masks",
"domain": "compositor",
"label_vi": "Tạo matte riêng cho object hoặc material",
"label_en": "Cryptomatte object and material masks",
"intent_aliases": [
"mask vật thể",
"mask vật liệu",
"cryptomatte",
"object matte",
"material matte",
"tách vật thể compositing"
],
"summary": "CompositorNodeCryptomatteV2 creates object/material mattes from Cryptomatte render passes; ViewLayer.use_pass_cryptomatte_object outputs a pass for object isolation.",
"choose_when": "Create object/material mattes from a render or image containing Cryptomatte passes.",
"do_not_assume": [
"This is not object recognition in arbitrary images. Confirm passes and IDs, read source/layer_name and verify engine support."
],
"evidence": [
{
"ref": "bpy.types.CompositorNodeCryptomatteV2.html#bpy.types.CompositorNodeCryptomatteV2",
"supports": "Create individual object/material mattes from Cryptomatte passes with RENDER or IMAGE sources."
},
{
"ref": "bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_object",
"supports": "Render an object pass for isolation during compositing."
}
],
"api_refs": [
"bpy.types.CompositorNodeCryptomatteV2.html",
"bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_object"
],
"next_queries": [
"bpy.types.CompositorNodeCryptomatteV2.html",
"bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_object",
"bpy.types.ViewLayer.html#bpy.types.ViewLayer.use_pass_cryptomatte_material"
]
},
{
"id": "sequencer-text-titles",
"domain": "video-audio",
"label_vi": "Thêm chữ vào video bằng text strip",
"label_en": "Sequencer text titles",
"intent_aliases": [
"chữ trong video",
"tiêu đề video",
"text strip",
"video title",
"phụ đề bằng text"
],
"summary": "TextStrip generates text with content, font, size, position, alignment, outline and box properties. StripsTopLevel.new_effect includes TEXT for adding a text strip.",
"choose_when": "Add text over specified intervals in a video sequence.",
"do_not_assume": [
"The source does not establish speech recognition or automatic subtitle timing. The default font falls back to a UI font; inspect the supplied font and required glyph rendering."
],
"evidence": [
{
"ref": "bpy.types.TextStrip.html#bpy.types.TextStrip",
"supports": "A sequence strip generates text and exposes text-display properties."
},
{
"ref": "bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect",
"supports": "The TEXT effect adds a simple text strip."
}
],
"api_refs": [
"bpy.types.TextStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect"
],
"next_queries": [
"bpy.types.TextStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect",
"bpy.types.Scene.html#bpy.types.Scene.sequence_editor_create"
]
},
{
"id": "sequencer-text-drop-shadow",
"domain": "video-audio",
"label_vi": "Bóng phía sau chữ trong video",
"label_en": "Text strip drop shadow",
"intent_aliases": [
"đổ bóng",
"bóng chữ",
"đổ bóng chữ",
"text shadow",
"text drop shadow",
"bóng chữ video"
],
"summary": "TextStrip.use_shadow displays a shadow behind text; the class also exposes shadow_angle, shadow_blur, shadow_color and shadow_offset with types/ranges.",
"choose_when": "Apply a shadow to Video Sequencer text, distinct from 3D shadow rays or footage shadow catchers.",
"do_not_assume": [
"shadow_blur/offset have type/range information without complete pixel-unit semantics. Do not transfer CSS numbers or 3D light controls by assumption."
],
"evidence": [
{
"ref": "bpy.types.TextStrip.html#bpy.types.TextStrip.use_shadow",
"supports": "Display a shadow behind text."
},
{
"ref": "bpy.types.TextStrip.html#bpy.types.TextStrip",
"supports": "TextStrip generates text and exposes shadow parameters with types/ranges."
}
],
"api_refs": [
"bpy.types.TextStrip.html#bpy.types.TextStrip.use_shadow",
"bpy.types.TextStrip.html#bpy.types.TextStrip.shadow_blur",
"bpy.types.TextStrip.html#bpy.types.TextStrip.shadow_offset",
"bpy.types.TextStrip.html#bpy.types.TextStrip.shadow_color"
],
"next_queries": [
"bpy.types.TextStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect"
]
},
{
"id": "sequencer-load-trim-video",
"domain": "video-audio",
"label_vi": "Nạp video và trim nội dung strip",
"label_en": "Load and trim sequencer video",
"intent_aliases": [
"dựng video",
"nạp video",
"cắt đầu cuối clip",
"movie strip",
"trim video",
"load video"
],
"summary": "MovieStrip loads video; StripsTopLevel.new_movie adds a clip by file, channel and frame_start. content_trim_start/end skip source frames and turn corresponding time into holds.",
"choose_when": "Load a clip into the timeline or adjust source content at its ends according to the documented trimming semantics.",
"do_not_assume": [
"The source marks animation_offset_start/end deprecated since 5.10 in favor of content_trim_start/end. Do not assume source trimming shortens the timeline; read frame ranges and inspect results."
],
"evidence": [
{
"ref": "bpy.types.MovieStrip.html#bpy.types.MovieStrip",
"supports": "A sequence strip loads video; document content trimming and deprecation."
},
{
"ref": "bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_movie",
"supports": "Add a movie strip with filepath, channel and frame_start."
}
],
"api_refs": [
"bpy.types.MovieStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_movie"
],
"next_queries": [
"bpy.types.MovieStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_movie",
"bpy.types.Strip.html"
]
},
{
"id": "sequencer-timed-sound",
"domain": "video-audio",
"label_vi": "Âm thanh theo timeline và volume",
"label_en": "Timed audio strips and playback volume",
"intent_aliases": [
"thêm âm thanh",
"nhạc nền",
"sound strip",
"audio timeline",
"volume âm thanh",
"pan âm thanh"
],
"summary": "SoundStrip plays audio over an interval; volume controls level, pan applies to mono sources and sound_offset is measured in seconds. StripsTopLevel.new_sound adds a sound strip.",
"choose_when": "Place audio on the timeline and adjust timing, volume or pan as documented.",
"do_not_assume": [
"A sound strip does not establish codec or mixdown support. Pan is limited to mono sources; inspect media and audio output separately."
],
"evidence": [
{
"ref": "bpy.types.SoundStrip.html#bpy.types.SoundStrip",
"supports": "Describe timed audio, volume, mono pan and sound_offset in seconds."
},
{
"ref": "bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_sound",
"supports": "Add a sound strip from a file at a timeline position."
}
],
"api_refs": [
"bpy.types.SoundStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_sound"
],
"next_queries": [
"bpy.types.SoundStrip.html",
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_sound",
"bpy.ops.sound.html"
]
},
{
"id": "sequencer-transitions-effects",
"domain": "video-audio",
"label_vi": "Chuyển cảnh, blend, blur và đổi tốc độ strip",
"label_en": "Sequencer transitions and effects",
"intent_aliases": [
"chuyển cảnh",
"crossfade",
"wipe",
"video glow",
"timewarp",
"đổi tốc độ video",
"blend strips"
],
"summary": "StripsTopLevel.new_effect describes CROSS fading, WIPE transitions, GLOW on bright regions, SPEED playback time-warping, GAUSSIAN_BLUR detail softening and blending effects.",
"choose_when": "Create timeline strip effects or transitions, selecting types from new_effect descriptions.",
"do_not_assume": [
"Read each effect's inputs and settings; do not assume every effect takes two strips or uses older properties. SPEED does not establish optical-flow interpolation."
],
"evidence": [
{
"ref": "bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect",
"supports": "Describe CROSS, WIPE, GLOW, SPEED, GAUSSIAN_BLUR and blending effects."
}
],
"api_refs": [
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect"
],
"next_queries": [
"bpy.types.StripsTopLevel.html#bpy.types.StripsTopLevel.new_effect",
"bpy.types.EffectStrip.html",
"bpy.types.SpeedControlStrip.html",
"bpy.types.WipeStrip.html"
]
},
{
"id": "grease-pencil-shadow-effect",
"domain": "grease-pencil-freestyle",
"label_vi": "Hiệu ứng bóng cho Grease Pencil",
"label_en": "Grease Pencil shadow effect",
"intent_aliases": [
"đổ bóng",
"bóng Grease Pencil",
"bóng nét vẽ",
"Grease Pencil shadow",
"ShaderFxShadow",
"bóng 2D"
],
"summary": "ShaderFx affects Grease Pencil objects. ShaderFxShadow provides shadow offset, color, scale, rotation and pixel blur; ObjectShaderFx.new adds an effect.",
"choose_when": "Apply the documented shadow effect to an existing Grease Pencil object.",
"do_not_assume": [
"A request for a 2D shadow does not extend this route to arbitrary images or meshes. Verify object type, effect enum and render behavior; the source is not a complete recipe."
],
"evidence": [
{
"ref": "bpy.types.ShaderFx.html#bpy.types.ShaderFx",
"supports": "Effects apply to Grease Pencil objects."
},
{
"ref": "bpy.types.ShaderFxShadow.html#bpy.types.ShaderFxShadow",
"supports": "Describe a shadow effect with offset, shadow_color, scale, rotation and pixel blur."
},
{
"ref": "bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new",
"supports": "Add a shader effect by name and type."
}
],
"api_refs": [
"bpy.types.ShaderFxShadow.html",
"bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new"
],
"next_queries": [
"bpy.types.ShaderFx.html",
"bpy.types.ShaderFxShadow.html",
"bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new",
"bpy_types_enum_items/object_shaderfx_type_items.html"
]
},
{
"id": "grease-pencil-glow-effect",
"domain": "grease-pencil-freestyle",
"label_vi": "Hiệu ứng glow của Grease Pencil",
"label_en": "Grease Pencil glow effect",
"intent_aliases": [
"glow Grease Pencil",
"quầng sáng nét vẽ",
"Grease Pencil glow",
"ShaderFxGlow"
],
"summary": "ShaderFxGlow is a Grease Pencil effect with glow_color, mode, opacity, size and a color-selection threshold; use_glow_under has a Regular blend-mode limitation.",
"choose_when": "Apply glow to a Grease Pencil object rather than a compositor image or emission shader.",
"do_not_assume": [
"The glow name does not determine mode or size. Read blending rules and verify the runtime; the source does not support use_glow_under with Regular blend mode."
],
"evidence": [
{
"ref": "bpy.types.ShaderFx.html#bpy.types.ShaderFx",
"supports": "ShaderFx affects Grease Pencil objects."
},
{
"ref": "bpy.types.ShaderFxGlow.html#bpy.types.ShaderFxGlow",
"supports": "Describe glow parameters and the use_glow_under limitation with Regular blend mode."
}
],
"api_refs": [
"bpy.types.ShaderFxGlow.html"
],
"next_queries": [
"bpy.types.ShaderFxGlow.html",
"bpy.types.ObjectShaderFx.html#bpy.types.ObjectShaderFx.new",
"bpy_types_enum_items/object_shaderfx_type_items.html"
]
},
{
"id": "freestyle-edge-lines",
"domain": "grease-pencil-freestyle",
"label_vi": "Đường viền, silhouette và cạnh Freestyle",
"label_en": "Freestyle contours, silhouettes and edges",
"intent_aliases": [
"đường viền vật thể",
"silhouette",
"Freestyle",
"render nét",
"contour lines",
"crease edges"
],
"summary": "FreestyleLineSet associates lines with styles and selects contours, silhouettes, creases and other edges; FreestyleSettings offers scripting/parameter-editor modes and a separate render pass.",
"choose_when": "Select and render documented edge/contour types through FreestyleLineSet.",
"do_not_assume": [
"This is not every Grease Pencil workflow or a guarantee of any cartoon style. Read edge selection, style and engine contracts; the snapshot is not a complete artistic recipe."
],
"evidence": [
{
"ref": "bpy.types.FreestyleLineSet.html#bpy.types.FreestyleLineSet",
"supports": "Select contours, silhouettes, creases and material boundaries and reference a linestyle."
},
{
"ref": "bpy.types.FreestyleSettings.html#bpy.types.FreestyleSettings",
"supports": "Configure Freestyle per ViewLayer with SCRIPT/EDITOR modes and as_render_pass."
}
],
"api_refs": [
"bpy.types.FreestyleLineSet.html",
"bpy.types.FreestyleSettings.html"
],
"next_queries": [
"bpy.types.FreestyleLineSet.html",
"bpy.types.FreestyleSettings.html",
"bpy.types.FreestyleLineStyle.html",
"freestyle.html"
]
},
{
"id": "movie-clip-marker-tracking",
"domain": "tracking",
"label_vi": "Theo dõi marker trong footage",
"label_en": "Movie clip marker tracking",
"intent_aliases": [
"tracking marker",
"theo dõi điểm",
"motion tracking",
"track markers",
"theo dõi footage"
],
"summary": "MovieTracking holds match-moving data; bpy.ops.clip.track_markers tracks selected markers backward or across a sequence rather than one image.",
"choose_when": "Track markers in footage; inspect clip/tracking data before invoking the operator.",
"do_not_assume": [
"Marker tracking is not arbitrary object recognition. It requires suitable context and selection; do not promise background CLI operation without a successful poll in that context."
],
"evidence": [
{
"ref": "bpy.types.MovieTracking.html#bpy.types.MovieTracking",
"supports": "Expose match-moving data for tracking."
},
{
"ref": "bpy.ops.clip.html#bpy.ops.clip.track_markers",
"supports": "Track selected markers backward or across a sequence."
}
],
"api_refs": [
"bpy.types.MovieClip.html",
"bpy.types.MovieTracking.html",
"bpy.ops.clip.html#bpy.ops.clip.track_markers"
],
"next_queries": [
"bpy.types.MovieClip.html",
"bpy.types.MovieTracking.html",
"bpy.types.MovieTrackingTracks.html",
"bpy.ops.clip.html#bpy.ops.clip.track_markers"
]
},
{
"id": "movie-clip-two-dimensional-stabilization",
"domain": "tracking",
"label_vi": "Ổn định footage 2D dựa trên marker",
"label_en": "Marker-based 2D footage stabilization",
"intent_aliases": [
"ổn định video",
"chống rung",
"2D stabilization",
"stabilize footage",
"marker stabilization"
],
"summary": "MovieTrackingStabilization stabilizes footage in 2D using markers, with location/rotation/scale influence, an anchor frame and automatic scaling to cover gaps.",
"choose_when": "Stabilize 2D footage using existing tracking data.",
"do_not_assume": [
"This does not establish correction of all shake or rolling shutter. Suitable tracks and output checks are required; the route does not automatically create tracking input."
],
"evidence": [
{
"ref": "bpy.types.MovieTrackingStabilization.html#bpy.types.MovieTrackingStabilization",
"supports": "Describe marker-based 2D stabilization with anchor frame, location/rotation/scale and autoscale."
}
],
"api_refs": [
"bpy.types.MovieTrackingStabilization.html"
],
"next_queries": [
"bpy.types.MovieTrackingStabilization.html",
"bpy.types.MovieTracking.html",
"bpy.types.CompositorNodeStabilize.html"
]
},
{
"id": "camera-motion-solve-from-tracks",
"domain": "tracking",
"label_vi": "Giải chuyển động camera từ tracks",
"label_en": "Camera motion solving from tracks",
"intent_aliases": [
"camera tracking",
"solve camera",
"match moving",
"giải camera",
"khôi phục chuyển động camera"
],
"summary": "bpy.ops.clip.solve_camera solves camera motion from tracks. MovieTrackingReconstruction stores solved cameras, average_error and is_valid.",
"choose_when": "Solve camera motion from existing tracks and inspect reconstruction validity/error.",
"do_not_assume": [
"The source does not guarantee a solve for all footage or supply complete calibration/background-context requirements. Report success only when the actual operator and reconstruction support it."
],
"evidence": [
{
"ref": "bpy.ops.clip.html#bpy.ops.clip.solve_camera",
"supports": "Solve camera motion from tracks."
},
{
"ref": "bpy.types.MovieTrackingReconstruction.html#bpy.types.MovieTrackingReconstruction",
"supports": "Expose reconstruction cameras, average_error and is_valid."
}
],
"api_refs": [
"bpy.ops.clip.html#bpy.ops.clip.solve_camera",
"bpy.types.MovieTrackingReconstruction.html"
],
"next_queries": [
"bpy.ops.clip.html#bpy.ops.clip.solve_camera",
"bpy.types.MovieTrackingReconstruction.html",
"bpy.types.MovieTrackingSettings.html",
"bpy.types.MovieTrackingCamera.html"
]
}
]
}
references/cli-workflow.md
# Blender CLI and runtime evidence
This workflow begins after reading the complete [catalog overview](catalog/overview.md), the relevant domain file and selected feature cards. The catalog supplies the Blender context before any database query. Missing Blender semantics must remain `insufficient_skill_evidence`; runtime inspection cannot supply an undocumented conceptual recipe.
Use host Python for `scripts/run_blender.py`; the task imports `bpy` inside the installed Blender process. The bundled `info_advanced_blender_as_bpy.html` describes a separate module execution mode. Success in that mode would not establish that this CLI workflow was tested.
## Locate and inspect the selected runtime
Choose names from the selected cards and sources, then ask the bundled probe to inspect those names. Example from the skill directory, after selecting source entries for these identifiers:
```sh
python3 scripts/run_blender.py --blender /path/to/blender \
--script scripts/probe_blender.py -- \
--output /tmp/blender-runtime.json \
--type GeometryNodeTree --operator wm.save_as_mainfile \
--property RenderSettings.engine
```
The wrapper's local implementation gives `--blender` precedence over `BLENDER_BIN`, then searches PATH and conventional macOS app locations. It also accepts a `.app` path. It does not install Blender. Inspect the actual executable's `--help` when a CLI switch needs confirmation for that runtime.
Only the exact bundled `probe_blender.py` path is exempt from `--plan`. A copied probe or any other task script requires a reviewed plan. The exemption authorizes inspection through the supplied helper; it does not make arbitrary operations supported by the source.
Read the saved report. The helper records version/build, background context, build options, requested RNA types/properties, operator registration and `poll()` results. Missing symbols appear as `exists: false`; a false poll records the condition in that particular context. Operator context limitations are described by `info_gotchas_operators.html`. Version equality alone does not establish that all APIs match the snapshot, and a build-option flag does not establish available hardware or successful execution.
The helper writes JSON with `--output`. Stdout also emits `BLENDER_PROBE_JSON=...` amid Blender logs. A zero process status only means the helper completed: inspect `all_requested_symbols_exist` and individual checks. Additional `--type`, `--operator` and `--property` requests must come from supplied source context. The helper accepts `bpy.types.`/`bpy.ops.` prefixes and a `--doc-version major.minor` comparison target.
Keep the report as task evidence. For a dynamic value, cite its documented contract and record the observed value; do not describe it as part of the static API snapshot. The current plan validator verifies static passage hashes, not arbitrary runtime logs. Direct inspection of runtime evidence remains required.
## Read, bind and seal a task
Create the plan from cards already read. `features.py plan` takes repeated `--feature` arguments for combined work. Its source refs come from those cards. Read the necessary refs through `docs.py read REF --plan ...`; continue pagination until each cited passage is complete. Plain `docs.py` reads are maintenance tools and do not record task evidence.
Use [evidence-workflow.md](evidence-workflow.md) for the exact `bindings` schema. Each Blender operation needs a source ref and a statement of the fact that the passage supports. Node sockets, operator requirements, enums and renderer effects must not be filled from Blender knowledge recalled by the model. Keep uncertain facts in `unresolved` and stop dependent implementation until the skill data supports them.
```sh
python3 scripts/evidence.py inspect --script /absolute/path/task.py
python3 scripts/evidence.py seal \
--plan /absolute/path/plan.json --script /absolute/path/task.py
python3 scripts/evidence.py check \
--plan /absolute/path/plan.json --script /absolute/path/task.py
python3 scripts/run_blender.py --script /absolute/path/task.py \
--plan /absolute/path/plan.json \
--blend /absolute/path/input.blend --timeout 900 -- \
--output /absolute/path/result.blend
```
The output argument above is only forwarded to the task script. The script must parse it and perform any documented saving operation itself. This wrapper does not save, constrain or roll back task writes. Choose the output and overwrite behavior from the user's task; a plan is not extra authorization.
Sealing checks recorded source reads, source hashes, selected feature seeds, bindings and unresolved facts, then records the exact script hash. A changed script requires review and resealing; additional reads clear the seal. The runner repeats validation before launching, including for `--dry-run`. Passing these checks proves traceability of the supplied records, not that every claim is semantically supported or the result will render correctly.
## Wrapper behavior and its provenance
The wrapper builds an argument array and does not invoke a shell:
```text
blender --background --factory-startup --disable-autoexec [input.blend]
--python-exit-code 1 --python task.py -- [task arguments]
```
This sequence is part of the bundled wrapper implementation. The existing authoring-supplied CLI summary below is its supplemental source: load the optional `.blend` before running the script and set the Python failure exit code before execution. If no input file is supplied, the wrapper uses factory startup; it does not promise an empty scene. A task needing an empty scene must select and read the relevant documented operation instead of importing a remembered setup snippet.
The authoring summary describes `--disable-autoexec` as suppressing automatic embedded scripts and Python drivers while allowing the explicitly supplied task script. If the user's file depends on those behaviors, record the compatibility issue and investigate through supplied sources/runtime. Do not bypass the evidence workflow to make an unsupported project appear successful.
`--dry-run` prints resolved arguments without launching the child. Output otherwise streams to the terminal. The local wrapper propagates the child's status, returns 124 on timeout and 130 on interruption, and defaults to 300 seconds. Its POSIX timeout handling stops the new process group; its Windows branch stops the Blender process. Set an appropriate timeout for the task; fake-executable tests cover wrapper process behavior only.
## Source-specific decisions and result checks
When needed, select the following source cards before reading the corresponding pages with the plan:
| Decision or limitation | Bundled source |
|---|---|
| Operator context and failed poll | `info_gotchas_operators.html`, `bpy.ops.html` |
| Edit Mode mesh ownership and synchronization | `info_gotchas_meshes.html`, `bmesh.html` |
| Evaluated geometry and temporary meshes | `bpy.types.Depsgraph.html`, `bpy.types.Object.html#bpy.types.Object.to_mesh` |
| Python references after internal data changes | `info_gotchas_internal_data_and_python_objects.html` |
| Blender access and Python threading limitations | `info_gotchas_threading.html` |
| Background scripts and output checks | `info_tips_and_tricks.html` |
| Separate `bpy` module mode | `info_advanced_blender_as_bpy.html` |
Do not replace a context-dependent operator with a remembered API. Discover the alternative through source cards, read its contract and bind its actual use. If the supplied data does not establish a workable alternative, retain the gap.
Check the result against the user's concrete requirements: data values for data tasks, persisted content when saving matters, and rendered output for visual tasks. These are task acceptance checks, not extra Blender capabilities inferred from the catalog. Report exactly which checks ran. File existence, process success or an evidence seal alone does not establish visual fidelity, a completed simulation or correct exported content.
## Authoring record and current proof limits
Supplemental CLI provenance is an **authoring-supplied local summary**, separate from the supplied API corpus. The previous authoring record says the [Blender 5.1 command-line reference](https://docs.blender.org/manual/en/5.1/advanced/command_line/arguments.html) was consulted on 2026-09-05 for background mode, factory startup, auto-execution suppression, Python failure exit codes, argument forwarding and ordered processing. It also records that the equivalent 5.2 page could not be fetched. This document preserves that provenance; it does not claim a fresh retrieval or bundle the full Manual page. Confirm compatibility with the installed executable's help and actual execution.
No Blender executable was available in the standard locations inspected during authoring. Therefore there is no actual Blender/render validation from that environment. Fake-executable runner tests and simulated RNA tests establish only their named helper behavior. The evidence gate is a traceability tool, not a security sandbox or proof about a model's internal knowledge. Reject unsupported Blender claims even if mechanical validation accepts the plan.
references/catalog/routes-motion-pipeline.json
{
"schema_version": 1,
"routes": [
{
"id": "property-keyframes",
"domain": "animation-rigging",
"label_vi": "Đặt keyframe cho thuộc tính",
"label_en": "Property keyframes",
"intent_aliases": [
"keyframe",
"đặt khóa chuyển động",
"animate thuộc tính",
"chuyển động theo frame",
"thay đổi theo mốc thời gian",
"đổi vị trí theo các mốc thời gian",
"property animation"
],
"summary": "Insert a property value at a frame; keyframe_insert creates F-Curves and animation data when needed.",
"choose_when": "Represent a property changing at specified times.",
"do_not_assume": [
"The valid, animatable data_path for the actual object is not yet known; read the property and probe before insertion.",
"Keyframes alone do not prove that motion or rendered images meet the request."
],
"evidence": [
{
"ref": "bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert",
"supports": "Insert a property keyframe, creating F-Curves and animation data as needed; accept data_path and frame."
}
],
"api_refs": [
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert"
],
"next_queries": [
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert",
"bpy.types.Scene.html#bpy.types.Scene.frame_set"
]
},
{
"id": "property-drivers",
"domain": "animation-rigging",
"label_vi": "Điều khiển thuộc tính bằng driver",
"label_en": "Property drivers",
"intent_aliases": [
"driver",
"liên kết tham số",
"thuộc tính phụ thuộc thuộc tính khác",
"scripted expression",
"property relationship"
],
"summary": "A Driver controls a property; DriverVariable supplies inputs from RNA properties, transforms, distances between bones/objects or angles between bones.",
"choose_when": "Make a value depend on another input or expression instead of setting individual keyframes.",
"do_not_assume": [
"The data_path, variable sources and expression execution in the current runtime are not yet verified.",
"Valid expression syntax does not prove the absence of dependency cycles."
],
"evidence": [
{
"ref": "bpy.types.bpy_struct.html#bpy.types.bpy_struct.driver_add",
"supports": "driver_add adds a driver to the property specified by path."
},
{
"ref": "bpy.types.DriverVariable.html#bpy.types.DriverVariable",
"supports": "Driver variables use RNA properties, transforms, angular differences, distances or context properties."
},
{
"ref": "bpy.types.Driver.html#bpy.types.Driver.expression",
"supports": "expression stores a Scripted Expression."
}
],
"api_refs": [
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.driver_add",
"bpy.types.DriverVariable.html",
"bpy.types.Driver.html#bpy.types.Driver.expression"
],
"next_queries": [
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.driver_add",
"bpy.types.DriverVariable.html",
"bpy.types.DriverTarget.html"
]
},
{
"id": "animation-curve-interpolation",
"domain": "animation-rigging",
"label_vi": "Nội suy và đánh giá đường cong chuyển động",
"label_en": "F-Curve interpolation and evaluation",
"intent_aliases": [
"nội suy",
"easing",
"đường cong chuyển động",
"F-Curve",
"interpolation",
"giá trị tại frame"
],
"summary": "Keyframe.interpolation controls interpolation to the next keyframe; FCurve.evaluate returns the value at a frame.",
"choose_when": "Adjust transitions between keyframes or inspect numerical animation values at specific frames.",
"do_not_assume": [
"Do not select interpolation enums from memory; read the linked enum list and verify the runtime.",
"An individual F-Curve value does not prove the final result after constraints, drivers or blending."
],
"evidence": [
{
"ref": "bpy.types.Keyframe.html#bpy.types.Keyframe.interpolation",
"supports": "Set the interpolation method for the F-Curve segment from this keyframe to the next."
},
{
"ref": "bpy.types.FCurve.html#bpy.types.FCurve.evaluate",
"supports": "evaluate(frame) returns the F-Curve value at the requested frame."
}
],
"api_refs": [
"bpy.types.Keyframe.html#bpy.types.Keyframe.interpolation",
"bpy.types.FCurve.html#bpy.types.FCurve.evaluate"
],
"next_queries": [
"bpy.types.Keyframe.html",
"bpy_types_enum_items/beztriple_interpolation_mode_items.html",
"bpy.types.FCurve.html"
]
},
{
"id": "actions-nla-composition",
"domain": "animation-rigging",
"label_vi": "Tổ chức, phối hợp và lặp Action",
"label_en": "Actions and NLA composition",
"intent_aliases": [
"Action",
"NLA",
"clip animation",
"trộn chuyển động",
"lặp chuyển động",
"repeat action",
"blend actions"
],
"summary": "An Action contains F-Curves; NlaStrip references an Action and controls repetition and blending with other strips.",
"choose_when": "Reuse, repeat or combine existing animation segments.",
"do_not_assume": [
"The 5.2 source includes Action slots and layers; do not use a remembered older Action layout.",
"Compatibility of the Action slot with the target and the blending result remain unverified."
],
"evidence": [
{
"ref": "bpy.types.Action.html#bpy.types.Action",
"supports": "An Action is a collection of animation F-Curves."
},
{
"ref": "bpy.types.NlaStrip.html#bpy.types.NlaStrip",
"supports": "NlaStrip references an existing Action and has action_slot."
},
{
"ref": "bpy.types.NlaStrip.html#bpy.types.NlaStrip.repeat",
"supports": "repeat sets the number of repetitions of the Action range."
},
{
"ref": "bpy.types.NlaStrip.html#bpy.types.NlaStrip.blend_type",
"supports": "REPLACE, COMBINE, ADD, SUBTRACT and MULTIPLY combine strip results."
}
],
"api_refs": [
"bpy.types.Action.html",
"bpy.types.NlaStrip.html"
],
"next_queries": [
"bpy.types.Action.html#bpy.types.Action.slots",
"bpy.types.Action.html#bpy.types.Action.layers",
"bpy.types.NlaStrips.html",
"bpy.types.NlaStrip.html"
]
},
{
"id": "armature-bone-hierarchy",
"domain": "animation-rigging",
"label_vi": "Tạo hệ xương Armature",
"label_en": "Armature bone hierarchy",
"intent_aliases": [
"hệ xương",
"rig nhân vật",
"armature",
"bone hierarchy",
"tạo bone",
"skeleton"
],
"summary": "Armature contains a bone hierarchy, commonly used for character rigging; ArmatureEditBones.new creates an edit bone.",
"choose_when": "Create or edit a rig's bone structure.",
"do_not_assume": [
"EditBone belongs to Edit Mode; verify mode/context before creating or editing.",
"A bone structure does not prove mesh deformation bindings or correct weights."
],
"evidence": [
{
"ref": "bpy.types.Armature.html#bpy.types.Armature",
"supports": "An Armature data-block contains a bone hierarchy, commonly used for character rigging."
},
{
"ref": "bpy.types.EditBone.html#bpy.types.EditBone",
"supports": "EditBone is a bone in an Armature data-block's Edit Mode."
},
{
"ref": "bpy.types.ArmatureEditBones.html#bpy.types.ArmatureEditBones.new",
"supports": "new(name) adds a bone and returns EditBone."
}
],
"api_refs": [
"bpy.types.Armature.html",
"bpy.types.EditBone.html",
"bpy.types.ArmatureEditBones.html#bpy.types.ArmatureEditBones.new"
],
"next_queries": [
"bpy.types.Armature.html",
"bpy.types.ArmatureEditBones.html",
"info_gotchas_armatures_and_bones.html"
]
},
{
"id": "bone-pose-control",
"domain": "animation-rigging",
"label_vi": "Điều khiển tư thế bone",
"label_en": "Pose bone control",
"intent_aliases": [
"pose",
"tư thế nhân vật",
"xoay bone",
"pose bone",
"bone transform"
],
"summary": "PoseBone holds bone pose data; matrix_basis accesses location, scale and rotation relative to the parent and the bone's rest state.",
"choose_when": "Set or animate pose data on an existing armature.",
"do_not_assume": [
"Do not equate pose coordinates with world space or EditBone data; read each property's coordinate-space contract.",
"API documentation does not supply scene bone names or joint limits; inspect the actual scene."
],
"evidence": [
{
"ref": "bpy.types.PoseBone.html#bpy.types.PoseBone",
"supports": "PoseBone is a channel defining bone pose data within a Pose."
},
{
"ref": "bpy.types.PoseBone.html#bpy.types.PoseBone.matrix_basis",
"supports": "matrix_basis accesses transforms relative to the parent and the bone's own rest state."
}
],
"api_refs": [
"bpy.types.PoseBone.html",
"bpy.types.PoseBone.html#bpy.types.PoseBone.matrix_basis"
],
"next_queries": [
"bpy.types.Pose.html",
"bpy.types.PoseBone.html",
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert"
]
},
{
"id": "copy-transform-constraint",
"domain": "animation-rigging",
"label_vi": "Ràng buộc sao chép transform",
"label_en": "Copy transforms constraint",
"intent_aliases": [
"copy transforms",
"sao chép transform",
"đi theo đối tượng",
"constraint transform",
"ràng buộc chuyển động"
],
"summary": "CopyTransformsConstraint copies a target's full transform and provides modes for combining it with the existing transform.",
"choose_when": "An object or bone needs the transform of a specified target.",
"do_not_assume": [
"Do not select mix_mode, target space or owner space from memory; read this constraint's contract.",
"The documentation warns that some matrix combinations produce shear with rotation and non-uniform scale."
],
"evidence": [
{
"ref": "bpy.types.CopyTransformsConstraint.html#bpy.types.CopyTransformsConstraint",
"supports": "Copy all transforms; describe mix_mode order and shear caveats."
},
{
"ref": "bpy.types.ObjectConstraints.html#bpy.types.ObjectConstraints.new",
"supports": "ObjectConstraints.new adds a constraint by type."
}
],
"api_refs": [
"bpy.types.CopyTransformsConstraint.html",
"bpy.types.ObjectConstraints.html#bpy.types.ObjectConstraints.new",
"bpy.types.PoseBoneConstraints.html#bpy.types.PoseBoneConstraints.new"
],
"next_queries": [
"bpy.types.CopyTransformsConstraint.html",
"bpy.types.Constraint.html",
"bpy.types.ObjectConstraints.html"
]
},
{
"id": "inverse-kinematics-chain",
"domain": "animation-rigging",
"label_vi": "Điều khiển chuỗi bone bằng IK",
"label_en": "Inverse kinematics constraint",
"intent_aliases": [
"IK",
"inverse kinematics",
"động học ngược",
"chuỗi xương",
"IK constraint"
],
"summary": "KinematicConstraint provides inverse kinematics; chain_count sets the affected bone count and iterations limits solver iterations.",
"choose_when": "Control an IK relationship within a bone chain.",
"do_not_assume": [
"The API establishes IK parameters, not a complete rig for a particular character.",
"Read target, pole, chain and constraint spaces; solver convergence and the desired pose remain unproven."
],
"evidence": [
{
"ref": "bpy.types.KinematicConstraint.html#bpy.types.KinematicConstraint",
"supports": "Describe inverse kinematics; chain_count=0 uses all bones and iterations limits solving."
}
],
"api_refs": [
"bpy.types.KinematicConstraint.html",
"bpy.types.PoseBoneConstraints.html#bpy.types.PoseBoneConstraints.new"
],
"next_queries": [
"bpy.types.KinematicConstraint.html",
"bpy.types.PoseBoneConstraints.html",
"bpy.types.Constraint.html"
]
},
{
"id": "motion-follow-path",
"domain": "animation-rigging",
"label_vi": "Chuyển động theo đường Curve",
"label_en": "Follow path motion",
"intent_aliases": [
"chạy theo đường",
"bay theo curve",
"camera theo đường",
"follow path",
"path animation"
],
"summary": "FollowPathConstraint locks motion to a target Curve, with frame-relative offset or curve-length offset_factor and curve-following orientation.",
"choose_when": "Move an object or camera along a specified Curve.",
"do_not_assume": [
"This route does not supply a Curve, keyframes or axis configuration; establish these from scene data and relevant sources.",
"The name Follow Path does not establish constant speed; measure positions by frame when required."
],
"evidence": [
{
"ref": "bpy.types.FollowPathConstraint.html#bpy.types.FollowPathConstraint",
"supports": "Lock motion to a Curve target; offset_factor follows length and use_curve_follow follows curve heading/banking."
}
],
"api_refs": [
"bpy.types.FollowPathConstraint.html"
],
"next_queries": [
"bpy.types.FollowPathConstraint.html",
"bpy.types.ObjectConstraints.html",
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert"
]
},
{
"id": "shape-key-values",
"domain": "animation-rigging",
"label_vi": "Tạo và điều khiển Shape Key",
"label_en": "Shape key creation and values",
"intent_aliases": [
"shape key",
"blend shape",
"trộn hình dạng",
"animate shape key",
"morph"
],
"summary": "Object.shape_key_add creates a shape key, optionally from the current shape mix; ShapeKey.value gives its value at the current frame.",
"choose_when": "Create or animate shape keys for an identified object.",
"do_not_assume": [
"Object support, compatible topology and the existence of the target shape are not yet established.",
"ShapeKey.points does not support legacy Curve shape keys; choose accessors for the actual data type."
],
"evidence": [
{
"ref": "bpy.types.Object.html#bpy.types.Object.shape_key_add",
"supports": "Add a shape key; from_mix creates the shape from the current mix."
},
{
"ref": "bpy.types.ShapeKey.html#bpy.types.ShapeKey.value",
"supports": "value is the shape-key value at the current frame."
},
{
"ref": "bpy.types.ShapeKey.html#bpy.types.ShapeKey",
"supports": "ShapeKey.points provides optimized access but excludes legacy Curve shape keys."
}
],
"api_refs": [
"bpy.types.Object.html#bpy.types.Object.shape_key_add",
"bpy.types.ShapeKey.html"
],
"next_queries": [
"bpy.types.ShapeKey.html",
"bpy.types.Key.html",
"bpy.types.bpy_struct.html#bpy.types.bpy_struct.keyframe_insert"
]
},
{
"id": "animation-bake-action",
"domain": "animation-rigging",
"label_vi": "Bake chuyển động thành Action",
"label_en": "Bake animation to an Action",
"intent_aliases": [
"bake animation",
"bake constraint",
"chốt chuyển động thành keyframe",
"visual keying",
"bake action"
],
"summary": "nla.bake records selected objects' location/scale/rotation animation into an Action; visual_keying uses final transforms including constraints.",
"choose_when": "Record evaluated motion into an Action over a specified frame range.",
"do_not_assume": [
"This bakes animation, not necessarily simulation caches.",
"clear_constraints, clear_parents and use_current_action modify existing data; use them only within the requested scope.",
"Check selection, mode, poll and the resulting Action after baking."
],
"evidence": [
{
"ref": "bpy.ops.nla.html#bpy.ops.nla.bake",
"supports": "Bake transform animation into an Action; visual_keying uses final transforms; document constraint/parent removal and writing to an existing Action."
}
],
"api_refs": [
"bpy.ops.nla.html#bpy.ops.nla.bake"
],
"next_queries": [
"bpy.ops.nla.html#bpy.ops.nla.bake",
"bpy.ops.html",
"bpy.types.Action.html"
]
},
{
"id": "rigid-body-simulation",
"domain": "simulation",
"label_vi": "Mô phỏng vật thể rắn",
"label_en": "Rigid body simulation",
"intent_aliases": [
"rigid body",
"vật thể rắn",
"vật rơi va chạm",
"rigid collision",
"mô phỏng va chạm"
],
"summary": "RigidBodyObject stores participant settings; RigidBodyWorld contains the simulation environment, participating collection, substeps and solver iterations.",
"choose_when": "Simulate objects with the Rigid Body system, collision settings and a shared environment.",
"do_not_assume": [
"Creating settings does not mean simulation has run or caches have been baked.",
"Check the participating collection, collision shapes, frame range, runtime and evaluated results."
],
"evidence": [
{
"ref": "bpy.types.RigidBodyObject.html#bpy.types.RigidBodyObject",
"supports": "Store rigid-body participant settings including collision shape and damping."
},
{
"ref": "bpy.types.RigidBodyWorld.html#bpy.types.RigidBodyWorld",
"supports": "Define a self-contained environment; collection selects participants, while solver_iterations and substeps_per_frame trade accuracy for speed."
},
{
"ref": "bpy.ops.rigidbody.html#bpy.ops.rigidbody.object_add",
"supports": "Add the active object as a Rigid Body."
}
],
"api_refs": [
"bpy.types.RigidBodyObject.html",
"bpy.types.RigidBodyWorld.html",
"bpy.ops.rigidbody.html#bpy.ops.rigidbody.object_add"
],
"next_queries": [
"bpy.types.RigidBodyObject.html",
"bpy.types.RigidBodyWorld.html",
"bpy.types.PointCache.html",
"bpy.ops.ptcache.html"
]
},
{
"id": "rigid-body-joints",
"domain": "simulation",
"label_vi": "Ràng buộc giữa vật thể rắn",
"label_en": "Rigid body constraints",
"intent_aliases": [
"rigid body constraint",
"khớp vật lý",
"giới hạn góc vật lý",
"ràng buộc có thể đứt",
"physics joints"
],
"summary": "RigidBodyConstraint affects objects in Rigid Body Simulation, with an impulse breaking threshold and angular limits.",
"choose_when": "Create physical constraints between rigid-body simulation participants.",
"do_not_assume": [
"These are distinct from pose/object transform constraints.",
"The route name does not verify joint types, endpoints or a working simulation; read type and probe."
],
"evidence": [
{
"ref": "bpy.types.RigidBodyConstraint.html#bpy.types.RigidBodyConstraint",
"supports": "Constrain rigid-body objects; breaking_threshold is the breaking impulse and angular limits are available."
}
],
"api_refs": [
"bpy.types.RigidBodyConstraint.html"
],
"next_queries": [
"bpy.types.RigidBodyConstraint.html",
"bpy.ops.rigidbody.html",
"bpy.types.RigidBodyWorld.html"
]
},
{
"id": "cloth-simulation",
"domain": "simulation",
"label_vi": "Mô phỏng vải và va chạm vải",
"label_en": "Cloth simulation and collision",
"intent_aliases": [
"cloth",
"vải",
"rèm",
"mô phỏng vải",
"cloth collision",
"self collision"
],
"summary": "ClothSettings defines cloth simulation parameters including bending stiffness; ClothCollisionSettings manages self-collision and collisions with other objects.",
"choose_when": "Use Cloth simulation and adjust its collision response.",
"do_not_assume": [
"A curtain keyword identifies a Cloth candidate; the source does not supply a curtain recipe or real-world material parameters.",
"Verify modifiers, geometry, caches and output frames; settings alone are not simulation proof."
],
"evidence": [
{
"ref": "bpy.types.ClothSettings.html#bpy.types.ClothSettings",
"supports": "Define cloth bending models, stiffness and damping."
},
{
"ref": "bpy.types.ClothCollisionSettings.html#bpy.types.ClothCollisionSettings",
"supports": "Configure self-collision and object collision; collision_quality trades time for quality."
}
],
"api_refs": [
"bpy.types.ClothSettings.html",
"bpy.types.ClothCollisionSettings.html"
],
"next_queries": [
"bpy.types.ClothModifier.html",
"bpy.types.ClothSettings.html",
"bpy.types.ClothCollisionSettings.html",
"bpy.types.PointCache.html"
]
},
{
"id": "soft-body-simulation",
"domain": "simulation",
"label_vi": "Mô phỏng vật thể mềm",
"label_en": "Soft body simulation",
"intent_aliases": [
"soft body",
"vật thể mềm",
"mô phỏng đàn hồi",
"soft body collision"
],
"summary": "SoftBodySettings exposes soft-body simulation settings including bending stiffness, collision damping and aerodynamic interaction.",
"choose_when": "Simulate an object with the Soft Body system.",
"do_not_assume": [
"The settings API does not provide suitable physical parameters for every material or topology.",
"Verify modifiers, colliders, frame evaluation and caches before claiming a working effect."
],
"evidence": [
{
"ref": "bpy.types.SoftBodySettings.html#bpy.types.SoftBodySettings",
"supports": "Define object soft-body settings including bending stiffness, collision damping and aerodynamic interaction."
}
],
"api_refs": [
"bpy.types.SoftBodySettings.html"
],
"next_queries": [
"bpy.types.SoftBodyModifier.html",
"bpy.types.SoftBodySettings.html",
"bpy.types.PointCache.html"
]
},
{
"id": "fluid-liquid-simulation",
"domain": "simulation",
"label_vi": "Mô phỏng chất lỏng",
"label_en": "Liquid fluid simulation",
"intent_aliases": [
"chất lỏng",
"nước",
"liquid",
"fluid simulation",
"inflow",
"outflow"
],
"summary": "FluidDomainSettings provides a LIQUID domain; FluidFlowSettings provides LIQUID flow with inflow, outflow or geometry behavior.",
"choose_when": "Explore liquid simulation using a Fluid domain and flow.",
"do_not_assume": [
"flow_source lists only NONE in this snapshot; do not invent additional enums from memory.",
"Domain/flow configuration does not create a simulation or baked water surface; inspect baking, caches and actual results.",
"A water keyword does not establish a need for simulation; compare supported geometry/material routes for still-image requirements."
],
"evidence": [
{
"ref": "bpy.types.FluidDomainSettings.html#bpy.types.FluidDomainSettings.domain_type",
"supports": "LIQUID creates a liquid domain; GAS creates a gas domain."
},
{
"ref": "bpy.types.FluidFlowSettings.html#bpy.types.FluidFlowSettings",
"supports": "flow_type=LIQUID adds liquid; flow_behavior includes INFLOW, OUTFLOW and GEOMETRY; flow_source lists only NONE."
},
{
"ref": "bpy.ops.fluid.html#bpy.ops.fluid.bake_all",
"supports": "bake_all bakes the entire Fluid Simulation."
}
],
"api_refs": [
"bpy.types.FluidDomainSettings.html",
"bpy.types.FluidFlowSettings.html",
"bpy.ops.fluid.html#bpy.ops.fluid.bake_all"
],
"next_queries": [
"bpy.types.FluidModifier.html",
"bpy.types.FluidDomainSettings.html",
"bpy.types.FluidFlowSettings.html",
"bpy.types.FluidEffectorSettings.html",
"bpy.ops.fluid.html"
]
},
{
"id": "fluid-smoke-fire-simulation",
"domain": "simulation",
"label_vi": "Mô phỏng khói và lửa",
"label_en": "Smoke and fire simulation",
"intent_aliases": [
"khói",
"lửa",
"smoke",
"fire",
"gas simulation",
"fire and smoke"
],
"summary": "Fluid provides a GAS domain and SMOKE, FIRE or BOTH flow; domain parameters control density/heat buoyancy and combustion rate.",
"choose_when": "Simulate smoke or fire over time using Fluid.",
"do_not_assume": [
"Simulation parameters alone do not establish shading or flame appearance.",
"Current build support, completed baking and valid caches are unverified; probe and inspect outputs."
],
"evidence": [
{
"ref": "bpy.types.FluidDomainSettings.html#bpy.types.FluidDomainSettings.domain_type",
"supports": "GAS creates a gas domain."
},
{
"ref": "bpy.types.FluidFlowSettings.html#bpy.types.FluidFlowSettings.flow_type",
"supports": "SMOKE adds smoke, FIRE adds fire and BOTH adds both."
},
{
"ref": "bpy.types.FluidDomainSettings.html#bpy.types.FluidDomainSettings",
"supports": "alpha and beta control buoyancy from smoke density/heat; burning_rate controls combustion rate."
}
],
"api_refs": [
"bpy.types.FluidDomainSettings.html",
"bpy.types.FluidFlowSettings.html#bpy.types.FluidFlowSettings.flow_type"
],
"next_queries": [
"bpy.types.FluidModifier.html",
"bpy.types.FluidDomainSettings.html",
"bpy.types.FluidFlowSettings.html",
"bpy.ops.fluid.html"
]
},
{
"id": "physics-force-fields",
"domain": "simulation",
"label_vi": "Trường lực, gió và nhiễu động",
"label_en": "Physics force fields",
"intent_aliases": [
"gió",
"trường lực",
"wind",
"force field",
"turbulence",
"vortex",
"lực cản"
],
"summary": "FieldSettings.type distinguishes WIND along local Z, TURBULENCE noise, VORTEX rotation and DRAG that reduces movement.",
"choose_when": "Select a candidate force for a compatible simulation system.",
"do_not_assume": [
"Do not assume every object responds to FieldSettings; read the target simulation and effector weights.",
"WIND is described along local Z; inspect transforms and results instead of assuming a world axis."
],
"evidence": [
{
"ref": "bpy.types.FieldSettings.html#bpy.types.FieldSettings.type",
"supports": "Describe WIND, TURBULENCE, VORTEX, DRAG and other force-field enum values."
}
],
"api_refs": [
"bpy.types.FieldSettings.html#bpy.types.FieldSettings.type"
],
"next_queries": [
"bpy.types.FieldSettings.html",
"bpy.types.EffectorWeights.html"
]
},
{
"id": "dynamic-paint-canvas",
"domain": "simulation",
"label_vi": "Dynamic Paint với canvas và brush",
"label_en": "Dynamic Paint canvas and brush",
"intent_aliases": [
"dynamic paint",
"vệt sơn",
"canvas",
"brush simulation",
"wet paint",
"sơn động"
],
"summary": "DynamicPaintSurface is a canvas surface layer with a brush collection, influence and wet-paint color spreading speed.",
"choose_when": "Explore Dynamic Paint brush/canvas interaction.",
"do_not_assume": [
"surface_type lists only PAINT in this snapshot; do not supply other modes from memory.",
"These parameters do not provide a complete paint-trail or baking recipe; read modifier/settings contracts and verify the runtime."
],
"evidence": [
{
"ref": "bpy.types.DynamicPaintSurface.html#bpy.types.DynamicPaintSurface",
"supports": "A canvas surface selects brushes with brush_collection and controls wet-paint mixing with color_spread_speed."
},
{
"ref": "bpy.types.DynamicPaintSurface.html#bpy.types.DynamicPaintSurface.surface_type",
"supports": "The snapshot's surface_type enum contains only PAINT."
}
],
"api_refs": [
"bpy.types.DynamicPaintSurface.html"
],
"next_queries": [
"bpy.types.DynamicPaintModifier.html",
"bpy.types.DynamicPaintCanvasSettings.html",
"bpy.types.DynamicPaintBrushSettings.html",
"bpy.types.DynamicPaintSurface.html",
"bpy.ops.dpaint.html"
]
},
{
"id": "particle-system-settings",
"domain": "simulation",
"label_vi": "Thiết lập hệ hạt Particle",
"label_en": "Particle system settings",
"intent_aliases": [
"particle",
"hệ hạt",
"particle emitter",
"particle hair",
"phát hạt"
],
"summary": "ParticleSettings can be shared across particle systems; the snapshot's type enum includes EMITTER and HAIR.",
"choose_when": "Control a Particle System identified in the supplied source or scene.",
"do_not_assume": [
"Do not equate particle HAIR with all hair systems or Geometry Nodes; read the correct data type.",
"EMITTER/HAIR establish enum values, not motion, rendering or cache recipes for a particular effect."
],
"evidence": [
{
"ref": "bpy.types.ParticleSettings.html#bpy.types.ParticleSettings",
"supports": "Settings can be reused by multiple particle systems."
},
{
"ref": "bpy.types.ParticleSettings.html#bpy.types.ParticleSettings.type",
"supports": "type includes EMITTER and HAIR; the anchor does not explain their workflows."
}
],
"api_refs": [
"bpy.types.ParticleSettings.html",
"bpy.types.ParticleSystem.html"
],
"next_queries": [
"bpy.types.ParticleSettings.html",
"bpy.types.ParticleSystem.html",
"bpy.types.PointCache.html"
]
},
{
"id": "physics-cache-baking",
"domain": "simulation",
"label_vi": "Bake và kiểm tra cache vật lý",
"label_en": "Physics cache baking and inspection",
"intent_aliases": [
"bake physics",
"cache mô phỏng",
"bake cache",
"point cache",
"kiểm tra cache"
],
"summary": "PointCache exposes physics cache paths, frame ranges and is_baked/is_baking; ptcache.bake is a physics baking operator.",
"choose_when": "Execute or verify caches for a simulation using PointCache.",
"do_not_assume": [
"ptcache.bake is not universal; Fluid has separate baking operators.",
"Distinguish FINISHED, is_baked and actual cache/frame data; no single signal proves the complete result."
],
"evidence": [
{
"ref": "bpy.types.PointCache.html#bpy.types.PointCache",
"supports": "PointCache is the active physics cache, with filepath, frame_start/end, is_baked/is_baking and skipped-frame status."
},
{
"ref": "bpy.ops.ptcache.html#bpy.ops.ptcache.bake",
"supports": "The operator is described as Bake physics."
},
{
"ref": "bpy.ops.fluid.html#bpy.ops.fluid.bake_all",
"supports": "Fluid has a separate operator for baking the entire simulation."
}
],
"api_refs": [
"bpy.types.PointCache.html",
"bpy.ops.ptcache.html#bpy.ops.ptcache.bake"
],
"next_queries": [
"bpy.types.PointCache.html",
"bpy.ops.ptcache.html",
"bpy.ops.html"
]
},
{
"id": "blend-file-open-save",
"domain": "files-assets",
"label_vi": "Mở và lưu dự án .blend",
"label_en": "Open and save blend files",
"intent_aliases": [
"mở blend",
"lưu blend",
"save scene",
"open blend file",
"dự án Blender"
],
"summary": "wm.open_mainfile opens a Blender file; wm.save_as_mainfile saves the current file to a specified location.",
"choose_when": "Load a .blend project or save a script's output as .blend.",
"do_not_assume": [
"Opening a file replaces current data; identify the requested input and output files.",
"Do not enable use_scripts or overwrite unrelated files automatically; read load/save options and inspect the created file."
],
"evidence": [
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.open_mainfile",
"supports": "Open a Blender file with load_ui and use_scripts options."
},
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.save_as_mainfile",
"supports": "Save the current file with copy, compress and relative_remap options."
}
],
"api_refs": [
"bpy.ops.wm.html#bpy.ops.wm.open_mainfile",
"bpy.ops.wm.html#bpy.ops.wm.save_as_mainfile"
],
"next_queries": [
"bpy.ops.wm.html#bpy.ops.wm.open_mainfile",
"bpy.ops.wm.html#bpy.ops.wm.save_as_mainfile",
"bpy.path.html"
]
},
{
"id": "blend-library-datablocks",
"domain": "files-assets",
"label_vi": "Link, append và ghi thư viện data-block",
"label_en": "Blend library linking and appending",
"intent_aliases": [
"append",
"link library",
"thư viện blend",
"lấy object từ file khác",
"data-block library"
],
"summary": "BlendDataLibraries.load exposes available data-block names and links/appends selected names when its context ends; write saves selected data-blocks and indirect references.",
"choose_when": "Reuse part of another .blend file or package data-blocks as a library.",
"do_not_assume": [
"Treat context-manager input as read-only and place selected names in its output as documented.",
"Choose link/append and paths according to the request; loading a data-block does not prove collection membership."
],
"evidence": [
{
"ref": "bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.load",
"supports": "The context manager returns input/output; output names are linked or appended on exit and input is read-only."
},
{
"ref": "bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.write",
"supports": "Write data-blocks to a blend file, expanding indirectly referenced data-blocks."
}
],
"api_refs": [
"bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.load",
"bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.write"
],
"next_queries": [
"bpy.types.BlendDataLibraries.html",
"bpy.types.CollectionObjects.html",
"bpy.path.html#bpy.path.abspath"
]
},
{
"id": "asset-metadata-marking",
"domain": "files-assets",
"label_vi": "Đánh dấu asset và gắn metadata",
"label_en": "Asset marking and metadata",
"intent_aliases": [
"asset",
"asset browser",
"tạo thư viện asset",
"asset metadata",
"gắn tag",
"catalog asset"
],
"summary": "ID.asset_mark enables data-block reuse through the Asset Browser; AssetMetaData stores description, author, tags and a catalog identifier.",
"choose_when": "Mark a reusable data-block and prepare asset metadata.",
"do_not_assume": [
"Marking an asset does not establish library configuration or publication.",
"catalog_id must meet the source's UUID requirement; a catalog name is not its ID."
],
"evidence": [
{
"ref": "bpy.types.ID.html#bpy.types.ID.asset_mark",
"supports": "Enable reuse through the Asset Browser with previews, descriptions and tags."
},
{
"ref": "bpy.types.AssetMetaData.html#bpy.types.AssetMetaData",
"supports": "Metadata includes author, description and catalog_id; catalog_id must be an RFC4122 UUID."
}
],
"api_refs": [
"bpy.types.ID.html#bpy.types.ID.asset_mark",
"bpy.types.AssetMetaData.html"
],
"next_queries": [
"bpy.types.ID.html#bpy.types.ID.asset_mark",
"bpy.types.AssetMetaData.html",
"bpy.types.BlendDataLibraries.html"
]
},
{
"id": "obj-stl-exchange",
"domain": "files-assets",
"label_vi": "Nhập và xuất OBJ hoặc STL",
"label_en": "OBJ and STL file exchange",
"intent_aliases": [
"OBJ",
"STL",
"nhập mesh",
"xuất obj",
"xuất stl",
"Wavefront"
],
"summary": "wm.obj_import loads Wavefront OBJ scenes; wm operators import/export OBJ and STL with scale, axis and object-selection parameters.",
"choose_when": "Exchange files in OBJ or STL format.",
"do_not_assume": [
"Successful STL export does not prove printability or watertightness.",
"Read scale, axes and modifier options and verify runtime operators; do not use remembered older operator names."
],
"evidence": [
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.obj_import",
"supports": "Load a Wavefront OBJ scene with scale and forward/up axes."
},
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.obj_export",
"supports": "OBJ export declares export_selected_objects, apply_modifiers, scale and axes."
},
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.stl_import",
"supports": "Import STL as an object."
},
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.stl_export",
"supports": "Save the scene as an STL file."
}
],
"api_refs": [
"bpy.ops.wm.html#bpy.ops.wm.obj_import",
"bpy.ops.wm.html#bpy.ops.wm.obj_export",
"bpy.ops.wm.html#bpy.ops.wm.stl_import",
"bpy.ops.wm.html#bpy.ops.wm.stl_export"
],
"next_queries": [
"bpy.ops.wm.html#bpy.ops.wm.obj_import",
"bpy.ops.wm.html#bpy.ops.wm.obj_export",
"bpy.ops.wm.html#bpy.ops.wm.stl_import",
"bpy.ops.wm.html#bpy.ops.wm.stl_export"
]
},
{
"id": "gltf-file-exchange",
"domain": "files-assets",
"label_vi": "Nhập và xuất glTF 2.0",
"label_en": "glTF 2.0 file exchange",
"intent_aliases": [
"glTF",
"GLB",
"gltf 2.0",
"xuất glb",
"nhập gltf"
],
"summary": "import_scene.gltf loads glTF 2.0; export_scene.gltf exports scenes with documented geometry, material, animation, skin and morph options.",
"choose_when": "Exchange glTF/GLB or inspect glTF 2.0 transfer options.",
"do_not_assume": [
"Export options do not guarantee faithful transfer of every shader, constraint or animation.",
"Verify operator registration, read the actual export_format enum and validate the file in a suitable consumer."
],
"evidence": [
{
"ref": "bpy.ops.import_scene.html#bpy.ops.import_scene.gltf",
"supports": "Import glTF 2.0 with glb/gltf filters."
},
{
"ref": "bpy.ops.export_scene.html#bpy.ops.export_scene.gltf",
"supports": "Export a scene to glTF 2.0 with export_animations, export_skins and export_morph parameters."
}
],
"api_refs": [
"bpy.ops.import_scene.html#bpy.ops.import_scene.gltf",
"bpy.ops.export_scene.html#bpy.ops.export_scene.gltf"
],
"next_queries": [
"bpy.ops.import_scene.html#bpy.ops.import_scene.gltf",
"bpy.ops.export_scene.html#bpy.ops.export_scene.gltf"
]
},
{
"id": "fbx-file-exchange",
"domain": "files-assets",
"label_vi": "Nhập và xuất FBX",
"label_en": "FBX file exchange",
"intent_aliases": [
"FBX",
"xuất fbx",
"nhập fbx",
"fbx animation",
"fbx armature"
],
"summary": "import_scene.fbx loads FBX; export_scene.fbx writes FBX with object, axis, armature and animation-baking options.",
"choose_when": "Exchange files in FBX format.",
"do_not_assume": [
"The documentation warns that some importers do not support scaled armatures; verify the target consumer.",
"Default bake/axis/bone options do not guarantee correctness; read parameters and validate by re-import or target consumer."
],
"evidence": [
{
"ref": "bpy.ops.import_scene.html#bpy.ops.import_scene.fbx",
"supports": "Import FBX with animation and bone-orientation options."
},
{
"ref": "bpy.ops.export_scene.html#bpy.ops.export_scene.fbx",
"supports": "Write FBX with bake_anim and armature options; global_scale warns about importer support for scaled armatures."
}
],
"api_refs": [
"bpy.ops.import_scene.html#bpy.ops.import_scene.fbx",
"bpy.ops.export_scene.html#bpy.ops.export_scene.fbx"
],
"next_queries": [
"bpy.ops.import_scene.html#bpy.ops.import_scene.fbx",
"bpy.ops.export_scene.html#bpy.ops.export_scene.fbx"
]
},
{
"id": "usd-scene-exchange",
"domain": "files-assets",
"label_vi": "Nhập và xuất USD scene",
"label_en": "USD scene exchange",
"intent_aliases": [
"USD",
"USDZ",
"USD stage",
"xuất usd",
"nhập usd"
],
"summary": "wm.usd_import imports a USD stage into the scene; wm.usd_export writes a USD archive with geometry, light, camera, material, animation and unit options.",
"choose_when": "Exchange USD scenes or inspect source-documented USDZ export options.",
"do_not_assume": [
"USDZ parameters do not establish compatibility with every target consumer; read the options and test.",
"Verify USD build support and exported/imported scene content, including units and material conversion."
],
"evidence": [
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.usd_import",
"supports": "Import a USD stage with camera, light, geometry, skeleton and material options."
},
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.usd_export",
"supports": "Export a USD archive; the signature includes export_animation, convert_scene_units and usdz_downscale_size."
}
],
"api_refs": [
"bpy.ops.wm.html#bpy.ops.wm.usd_import",
"bpy.ops.wm.html#bpy.ops.wm.usd_export"
],
"next_queries": [
"bpy.ops.wm.html#bpy.ops.wm.usd_import",
"bpy.ops.wm.html#bpy.ops.wm.usd_export",
"bpy.app.html#bpy.app.build_options"
]
},
{
"id": "alembic-archive-exchange",
"domain": "files-assets",
"label_vi": "Nhập và xuất Alembic archive",
"label_en": "Alembic archive exchange",
"intent_aliases": [
"Alembic",
"ABC",
"xuất abc",
"nhập abc",
"alembic archive"
],
"summary": "wm.alembic_import loads Alembic archives; wm.alembic_export writes scenes with frame ranges, transform/geometry samples and data options.",
"choose_when": "Exchange Alembic files or inspect frame-range scene export to this archive format.",
"do_not_assume": [
"The API does not prove preservation of every Blender data type; verify the required fields.",
"as_background_job does not guarantee operation in every CLI context; probe operators/build and inspect output files."
],
"evidence": [
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.alembic_import",
"supports": "Load an Alembic archive with set_frame_range and as_background_job."
},
{
"ref": "bpy.ops.wm.html#bpy.ops.wm.alembic_export",
"supports": "Export an Alembic archive with start/end, xsamples, gsamples and UV, normal, hair and particle options."
}
],
"api_refs": [
"bpy.ops.wm.html#bpy.ops.wm.alembic_import",
"bpy.ops.wm.html#bpy.ops.wm.alembic_export"
],
"next_queries": [
"bpy.ops.wm.html#bpy.ops.wm.alembic_import",
"bpy.ops.wm.html#bpy.ops.wm.alembic_export",
"bpy.app.html#bpy.app.build_options"
]
},
{
"id": "external-assets-paths-pack",
"domain": "files-assets",
"label_vi": "Đường dẫn và đóng gói tài nguyên ngoài",
"label_en": "External paths and packed resources",
"intent_aliases": [
"pack assets",
"đóng gói texture",
"file phụ thuộc",
"relative path",
"unpack",
"thiếu texture"
],
"summary": "blend_paths lists external .blend references; abspath resolves // paths; pack_all/unpack_all pack or extract .blend resources.",
"choose_when": "Audit resource paths or move between packed and external resources.",
"do_not_assume": [
"A path list does not prove file existence or content correctness; inspect required resources.",
"Unpack modes write external files; use only requested destinations and behavior."
],
"evidence": [
{
"ref": "bpy.utils.html#bpy.utils.blend_paths",
"supports": "List external paths referenced by the loaded .blend."
},
{
"ref": "bpy.path.html#bpy.path.abspath",
"supports": "Resolve // paths relative to the blend file or library."
},
{
"ref": "bpy.ops.file.html#bpy.ops.file.pack_all",
"supports": "Pack used external files into the .blend."
},
{
"ref": "bpy.ops.file.html#bpy.ops.file.unpack_all",
"supports": "Unpack resources using the selected method."
}
],
"api_refs": [
"bpy.utils.html#bpy.utils.blend_paths",
"bpy.path.html#bpy.path.abspath",
"bpy.ops.file.html#bpy.ops.file.pack_all",
"bpy.ops.file.html#bpy.ops.file.unpack_all"
],
"next_queries": [
"bpy.utils.html#bpy.utils.blend_paths",
"bpy.path.html",
"bpy.ops.file.html#bpy.ops.file.pack_all",
"bpy.ops.file.html#bpy.ops.file.unpack_all"
]
},
{
"id": "runtime-build-context-inspection",
"domain": "integration-gpu",
"label_vi": "Kiểm tra runtime, build và background context",
"label_en": "Runtime, build and context inspection",
"intent_aliases": [
"phiên bản Blender",
"background",
"headless",
"build options",
"operator poll",
"kiểm tra runtime"
],
"summary": "bpy.app exposes version, background state and build options; context depends on the accessed area and operators need suitable context.",
"choose_when": "Inspect API, engine and operator availability in the running Blender before CLI implementation.",
"do_not_assume": [
"Documented build_options describe the documentation build; inspect the actual runtime.",
"No exception does not establish success: operators can return CANCELLED without raising."
],
"evidence": [
{
"ref": "bpy.app.html#bpy.app.version",
"supports": "version returns a major/minor/micro tuple."
},
{
"ref": "bpy.app.html#bpy.app.background",
"supports": "background is True when started without a UI using -b."
},
{
"ref": "bpy.app.html#bpy.app.build_options",
"supports": "The snapshot exposes build options including fluid, usd, alembic and cycles."
},
{
"ref": "bpy.ops.html",
"supports": "Wrong context may raise RuntimeError; poll helps check it and CANCELLED may not raise."
},
{
"ref": "bpy.context.html",
"supports": "Available context members depend on the accessed area."
}
],
"api_refs": [
"bpy.app.html",
"bpy.ops.html",
"bpy.context.html"
],
"next_queries": [
"bpy.app.html",
"bpy.ops.html",
"bpy.types.Context.html"
]
},
{
"id": "application-event-handlers",
"domain": "integration-gpu",
"label_vi": "Callback theo sự kiện ứng dụng",
"label_en": "Application event handlers",
"intent_aliases": [
"handler",
"frame change",
"load post",
"callback Blender",
"sự kiện nạp file",
"sự kiện đổi frame"
],
"summary": "bpy.app.handlers provides callback lists; persistent retains callbacks when another file is loaded.",
"choose_when": "Run logic on frame events or Blender load/render lifecycle events.",
"do_not_assume": [
"Handlers are removed on file load by default; persistent is a separate choice.",
"The source warns that simultaneous handler data changes and render/viewport access can crash; read the warning and choose appropriate synchronization."
],
"evidence": [
{
"ref": "bpy.app.handlers.html",
"supports": "Provide callback lists including frame_change_pre/load_post, with warnings about changing data during rendering."
},
{
"ref": "bpy.app.handlers.html#bpy.app.handlers.persistent",
"supports": "A decorator retains callbacks across file loads."
}
],
"api_refs": [
"bpy.app.handlers.html"
],
"next_queries": [
"bpy.app.handlers.html",
"info_gotchas_threading.html"
]
},
{
"id": "application-timer-callbacks",
"domain": "integration-gpu",
"label_vi": "Hẹn và lặp callback trong ứng dụng",
"label_en": "Application timers",
"intent_aliases": [
"timer",
"chạy sau vài giây",
"callback định kỳ",
"application timer",
"lặp callback"
],
"summary": "bpy.app.timers.register calls a function after a delay; return a float to schedule the next call or None to unregister.",
"choose_when": "Schedule callbacks within a Blender process that remains running.",
"do_not_assume": [
"Timers do not run after the CLI process exits and are not an external scheduler.",
"Do not substitute remembered Python threads that access Blender data; read the separate threading limitations."
],
"evidence": [
{
"ref": "bpy.app.timers.html#bpy.app.timers.register",
"supports": "Register a no-argument function with first_interval in seconds; None unregisters and a float sets the next delay."
},
{
"ref": "info_gotchas_threading.html",
"supports": "Python integration is not thread-safe; the source limits threading and discusses multiprocessing for Blender-independent code."
}
],
"api_refs": [
"bpy.app.timers.html#bpy.app.timers.register"
],
"next_queries": [
"bpy.app.timers.html",
"info_gotchas_threading.html"
]
},
{
"id": "rna-property-notifications",
"domain": "integration-gpu",
"label_vi": "Nhận thông báo thay đổi RNA property",
"label_en": "RNA property message bus",
"intent_aliases": [
"message bus",
"msgbus",
"theo dõi property",
"RNA notification",
"property change callback"
],
"summary": "bpy.msgbus receives RNA property-change notifications; subscribe_rna registers callbacks for a property or struct/property pair.",
"choose_when": "Respond to property changes made through the Python data API or UI fields.",
"do_not_assume": [
"Animation and object movement in the 3D Viewport do not trigger msgbus according to the source; select another route for those events.",
"Loading another blend clears subscriptions; msgbus PERSISTENT preserves ID remapping, not file-load subscriptions."
],
"evidence": [
{
"ref": "bpy.msgbus.html",
"supports": "Receive RNA/Python/UI field changes, excluding animation and viewport movement; callbacks are deferred until after operators."
},
{
"ref": "bpy.msgbus.html#bpy.msgbus.subscribe_rna",
"supports": "Subscribe to notifications; file loads clear subscriptions and PERSISTENT preserves ID remapping."
}
],
"api_refs": [
"bpy.msgbus.html#bpy.msgbus.subscribe_rna"
],
"next_queries": [
"bpy.msgbus.html",
"bpy.app.handlers.html"
]
},
{
"id": "custom-operators-properties-ui",
"domain": "integration-gpu",
"label_vi": "Mở rộng operator, property và UI",
"label_en": "Custom operators, properties and UI",
"intent_aliases": [
"custom operator",
"custom property",
"addon panel",
"bảng điều khiển",
"mở rộng Blender",
"đăng ký class"
],
"summary": "bpy.utils.register_class registers Blender subclasses; bpy.props defines their properties; Panel contains UI elements.",
"choose_when": "Create reusable operators/properties or controls inside Blender.",
"do_not_assume": [
"A Panel is UI; class creation does not establish display or interaction in background -b.",
"Assign bpy.props results to registered classes rather than using them directly; property callbacks may run in threaded contexts."
],
"evidence": [
{
"ref": "bpy.utils.html#bpy.utils.register_class",
"supports": "Register supported subclasses including Operator, Panel, PropertyGroup and Node."
},
{
"ref": "bpy.props.html",
"supports": "Define properties for registered classes; avoid direct use and observe callback threading warnings."
},
{
"ref": "bpy.types.Panel.html#bpy.types.Panel",
"supports": "Panel contains UI elements; the snapshot leaves context/region/space combinations as a TODO under bl_context."
}
],
"api_refs": [
"bpy.utils.html#bpy.utils.register_class",
"bpy.props.html",
"bpy.types.Operator.html",
"bpy.types.Panel.html"
],
"next_queries": [
"bpy.utils.html#bpy.utils.register_class",
"bpy.props.html",
"bpy.types.Operator.html",
"bpy.types.Panel.html",
"bpy.ops.html"
]
},
{
"id": "gpu-drawing-offscreen",
"domain": "integration-gpu",
"label_vi": "Vẽ GPU và buffer ngoài màn hình",
"label_en": "GPU drawing and offscreen buffers",
"intent_aliases": [
"GPU offscreen",
"vẽ GPU",
"offscreen buffer",
"shader drawing",
"GPU batch",
"viewport texture"
],
"summary": "gpu exposes GPU wrappers, geometry batches and GPUOffScreen; the 5.2 source includes gpu.init for background initialization.",
"choose_when": "Draw through the GPU API, process offscreen buffers or render a 3D View into a texture.",
"do_not_assume": [
"GPU use is not necessarily UI-only: gpu.init documents background use but may raise SystemError.",
"GPUOffScreen.draw_view3d still requires SpaceView3D and Region; do not assume they exist in -b.",
"Initialize shader uniforms explicitly; freeing offscreen resources makes framebuffer, texture and render objects inaccessible."
],
"evidence": [
{
"ref": "gpu.html",
"supports": "Expose GPU wrappers and geometry batches with vertex/index buffers."
},
{
"ref": "gpu.html#gpu.init",
"supports": "Initialize the GPU for background use; failure raises SystemError."
},
{
"ref": "gpu.types.html#gpu.types.GPUOffScreen",
"supports": "Access offscreen buffers; draw_view3d needs a scene, view layer, SpaceView3D and Region."
},
{
"ref": "gpu.shader.html",
"supports": "Initialize shader uniforms to avoid retaining earlier values."
},
{
"ref": "gpu.types.html#gpu.types.GPUOffScreen.free",
"supports": "Freeing offscreen resources makes associated framebuffer, texture and render objects inaccessible."
}
],
"api_refs": [
"gpu.html#gpu.init",
"gpu.types.html#gpu.types.GPUOffScreen",
"gpu_extras.batch.html#gpu_extras.batch.batch_for_shader"
],
"next_queries": [
"gpu.html",
"gpu.shader.html",
"gpu.types.html#gpu.types.GPUOffScreen",
"gpu_extras.batch.html"
]
},
{
"id": "gpu-compute-dispatch",
"domain": "integration-gpu",
"label_vi": "Compute shader trên GPU",
"label_en": "GPU compute shaders",
"intent_aliases": [
"compute shader",
"GPU compute",
"GLSL compute",
"dispatch GPU",
"tính toán GPU"
],
"summary": "GPUShaderCreateInfo accepts GLSL compute source; create_from_info creates a shader; gpu.compute.dispatch runs workgroup dimensions and capabilities reports support.",
"choose_when": "Use compute shaders directly through Blender's GPU API.",
"do_not_assume": [
"The name GPU does not establish compute availability; check compute_shader_support_get and initialize the runtime.",
"GLSL cross-compilation documentation is linked outside the corpus; do not fill that missing content from memory.",
"A dispatch API does not prove shader correctness, input/output data, synchronization or numerical results."
],
"evidence": [
{
"ref": "gpu.types.html#gpu.types.GPUShaderCreateInfo.compute_source",
"supports": "Accept GLSL compute shader source; include examples and an external cross-compilation documentation link."
},
{
"ref": "gpu.shader.html#gpu.shader.create_from_info",
"supports": "Create GPUShader from GPUShaderCreateInfo."
},
{
"ref": "gpu.compute.html#gpu.compute.dispatch",
"supports": "Dispatch compute work using a shader and x/y/z group counts."
},
{
"ref": "gpu.capabilities.html#gpu.capabilities.compute_shader_support_get",
"supports": "Return whether compute shaders are supported."
}
],
"api_refs": [
"gpu.types.html#gpu.types.GPUShaderCreateInfo.compute_source",
"gpu.shader.html#gpu.shader.create_from_info",
"gpu.compute.html#gpu.compute.dispatch",
"gpu.capabilities.html#gpu.capabilities.compute_shader_support_get"
],
"next_queries": [
"gpu.html#gpu.init",
"gpu.capabilities.html",
"gpu.types.html#gpu.types.GPUShaderCreateInfo",
"gpu.compute.html"
]
}
]
}
references/catalog/domains/uv.md
# UV maps, images and texture baking
Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.
## UV layers and face corner coordinates — `uv-explicit-coordinates`
UVLoopLayers.new adds a UV map; MeshUVLoopLayer.uv holds face-corner UV coordinates associated with mesh loops.
Choose when: Assign known UV coordinates by face corner, or create/inspect a UV layer directly.
Search aliases: tạo UV map, tọa độ UV, gán UV thủ công, UV layer, face corner UV, explicit UV coordinates
Evidence: `bpy.types.UVLoopLayers.html#bpy.types.UVLoopLayers.new` — Add a UV map layer to a Mesh.; `bpy.types.MeshUVLoopLayer.html#bpy.types.MeshUVLoopLayer.uv` — Face-corner UV coordinates form a Float2AttributeValue collection.; `bpy.types.Mesh.html` — Polygons reference loops; corner data such as UVs is attached to loops.
Read next: `bpy.types.UVLoopLayers.html#bpy.types.UVLoopLayers.new`, `bpy.types.MeshUVLoopLayer.html#bpy.types.MeshUVLoopLayer.uv`, `bpy.types.Float2AttributeValue.html`, `bpy.types.Mesh.html`
Limits: UVs belong to face corners; do not assume one UV per vertex without supporting evidence. A read-only uv collection does not mean every contained Float2AttributeValue is immutable; read the value type.
## UV unwrap and smart projection — `uv-unwrap-projection`
uv.unwrap unwraps the mesh being edited; smart_project projection-unwraps selected faces with angle_limit and island spacing.
Choose when: Have Blender compute UVs from a mesh or selected faces instead of supplying coordinates.
Search aliases: trải UV, mở UV, unwrap mesh, smart UV project, projection unwrap, giảm méo UV
Evidence: `bpy.ops.uv.html#bpy.ops.uv.unwrap` — Unwrap the mesh object being edited with the listed methods.; `bpy.ops.uv.html#bpy.ops.uv.smart_project` — Projection-unwrap selected mesh faces; angle_limit controls projection grouping/distortion.; `info_gotchas_operators.html` — Operators use context and can fail poll.
Read next: `bpy.ops.uv.html#bpy.ops.uv.unwrap`, `bpy.ops.uv.html#bpy.ops.uv.smart_project`, `info_gotchas_operators.html`
Limits: unwrap refers to an object being edited and smart_project to selected faces; these operators depend on context and can fail poll.
## Pack UV islands into UV or UDIM space — `uv-pack-islands`
pack_islands transforms UV islands to fill UV/UDIM space, with rotation, scale, margin and packing-target options.
Choose when: Existing UV islands need arrangement in UV or UDIM space.
Search aliases: xếp UV, đóng gói UV islands, pack UV, UV packing, UDIM islands, tối ưu diện tích UV
Evidence: `bpy.ops.uv.html#bpy.ops.uv.pack_islands` — Transform islands to fill UV/UDIM space; describe rotate, scale, margin and udim_source.; `info_gotchas_operators.html` — Operators obtain their targets from context.
Read next: `bpy.ops.uv.html#bpy.ops.uv.pack_islands`, `info_gotchas_operators.html`
Limits: pack_islands transforms islands; it does not prove that the mesh has been unwrapped. This operator depends on context as described in the operator guide.
## Discover all source pages in this domain
`python3 scripts/features.py pages uv` lists 18 source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.
Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.
references/corpus.md
# SQLite API corpus and pre-query capability data
The installed skill uses `api/api.sqlite3` as its only detailed Blender API source. Raw HTML, images, scripts, Sphinx caches and source archives are intentionally not packaged. This reduces installation size without changing the model-facing discovery, lookup or evidence workflow.
Task use begins with the [catalog overview](catalog/overview.md), relevant domain and selected cards. Do not open SQLite or draft Blender code before reading that context. Blender knowledge recalled by the model is not admissible evidence.
## Provenance and coverage
The database was built from a local `blender_python_reference_5_2` Sphinx snapshot beginning at `index.html`:
- 2,192 indexed HTML pages and 33,696 anchor ranges.
- 26,775 root Sphinx inventory entries: 24,381 Python symbols, 2,161 document entries and 233 labels.
- HTML/JS identified API 5.2; root `objects.inv` identified project `Blender 5.2.1 LTS Python API`, version `5.2`.
- The source audit resolved all root inventory targets and local HTML fragments. The sole missing local target was the downloadable source ZIP linked from `index.html`, not an API page.
- External Manual, repository, extension and website links were not imported as task evidence.
These labels do not establish a release date, release status, installed executable or exact upstream build hash. Coverage, inventory headers and source byte/file counts are stored in the database metadata and are reported by `docs.py stats`.
## The layer read before SQLite
The generated catalog has 112 authored feature routes across 18 domains, plus a discovery card for every indexed page. `catalog/symbols.json.gz` exposes all root inventory entries without opening SQLite. These counts describe coverage of the supplied source and authored routing, not every possible Blender workflow.
Each authored route contains bilingual intent aliases, a source-grounded summary, choice criteria, explicit limits, source excerpts/hashes and exact next queries. `documented_route_runtime_unverified` means the source describes the feature; it does not establish an implemented recipe or tested CLI support.
Page cards retain titles, introductory excerpts where available, passage hashes and direct queries. `api_discovery_only` requires a detailed read before claiming behavior. `identifier_only` preserves a missing behavioral description rather than guessing from a name. Domain assignments and aliases are navigation aids, not additional Blender evidence.
From the skill directory:
```sh
python3 scripts/features.py overview
python3 scripts/features.py match "text strip shadow"
python3 scripts/features.py show sequencer-text-drop-shadow
python3 scripts/features.py pages video-audio --limit 35
python3 scripts/features.py symbols TextStrip
```
These commands read Markdown and compressed JSON and work without SQLite, Blender or network access. A match returns candidates to compare, not an automatic implementation verdict. If no route fits, inspect page cards. If the required fact is still absent, report `insufficient_skill_evidence` and stop dependent work.
## Detailed evidence storage and task reads
`api/api.sqlite3` stores page text, headings, anchor ranges, inventory symbols, links, search rows and coverage metadata. Repeated values are normalized behind SQL views. Text formatting is adapted for deterministic terminal display; the database contents are the packaged source of truth.
After selecting cards, create a plan and read the refs they supply:
```sh
python3 scripts/features.py plan --request "Text strip shadow" \
--feature sequencer-text-drop-shadow --output /tmp/blender-plan.json
python3 scripts/docs.py read \
bpy.types.TextStrip.html#bpy.types.TextStrip.use_shadow \
--plan /tmp/blender-plan.json
```
`docs.py` records the canonical ref, passage hash and displayed line ranges. Continue pagination until every cited passage is complete. Reading an exact anchor can keep a passage small. Follow links exposed by completed reads, or select additional catalog cards before expanding scope. Search hits and identifier matches are discovery aids, not behavioral evidence.
FTS5 search is lexical and case-insensitive, with title weighting. Multiple terms default to AND; `--any` uses OR. `read` accepts an exact symbol, page or `page#anchor`; `related` reports main-article links and missing targets. Every Blender operation in a task script must still be bound to supporting evidence as described in [evidence-workflow.md](evidence-workflow.md).
Maintenance checks:
```sh
python3 scripts/docs.py stats
python3 scripts/docs.py verify
```
`verify` checks SQLite integrity, row/count invariants, FTS coverage, the semantic corpus fingerprint and the physical database fingerprint recorded by the catalog. It requires no HTML archive or manifest.
## Rebuild and review a replacement snapshot
Routine task use requires no raw HTML and no rebuild. A maintainer replacing the API snapshot must provide an external local Sphinx HTML tree and install `lxml`:
```sh
python3 scripts/build_corpus.py /absolute/path/new-api-html \
--output /absolute/path/new-corpus
```
Use a new output directory for review. The builder refuses source symlinks and destinations nested inside the source. It traverses from `index.html`, parses articles and definition ranges, indexes root `objects.inv`, validates local targets and writes only `api.sqlite3`; it does not copy the authoring tree, evaluate scripts or deserialize caches.
Review version, provenance, database metadata and coverage differences before placing the database in a separate skill staging directory. Re-audit affected authored `catalog/routes-*.json` claims, then rebuild the pre-query catalog:
```sh
python3 scripts/build_catalog.py --skill /absolute/path/staging/blender-cli
```
The catalog builder validates database references, embeds excerpts and semantic hashes, then regenerates page cards, the compressed symbol inventory, domain files and catalog coverage. A physical SQLite layout change can remain compatible with existing plans when semantic content is identical. A semantic catalog or corpus change invalidates prior plans; recreate selection and reads rather than editing stored hashes.
Run database verification, skill validation and applicable tests against the staged replacement. Reference existence and matching hashes do not establish semantic accuracy: reviewers must compare authored summaries and choice criteria with the actual SQLite passages. Missing facts remain explicit gaps until supported material has been incorporated with provenance.
scripts/probe_blender.py
#!/usr/bin/env python3
"""Run INSIDE Blender to report runtime identity and requested RNA capabilities."""
import argparse
import json
import os
from pathlib import Path
import re
import sys
import tempfile
def normalize_symbol(value, prefix, segments):
name = value.removeprefix(prefix)
parts = name.split(".")
if len(parts) != segments or not all(re.fullmatch(r"[A-Za-z][A-Za-z0-9_]*", part) for part in parts):
raise argparse.ArgumentTypeError("Expected " + prefix + ".".join(["identifier"] * segments))
return name
def json_value(value):
if isinstance(value, bytes):
return value.decode("utf-8", "replace")
if value is None or isinstance(value, (str, int, float, bool)):
return value
if isinstance(value, (list, tuple)):
return [json_value(item) for item in value]
return str(value)
def describe_property(prop):
result = {"identifier": prop.identifier, "type": prop.type}
for key in ("name", "description", "subtype", "is_readonly", "is_required", "is_array", "array_length", "hard_min", "hard_max", "default"):
try:
result[key] = json_value(getattr(prop, key))
except (AttributeError, TypeError):
pass
if prop.type == "ENUM":
# Dynamic/context-dependent enum callbacks may not enumerate every choice.
result["enum_identifiers"] = [item.identifier for item in prop.enum_items]
result["enum_caveat"] = "RNA enumeration may omit dynamic/context-dependent choices."
try:
result["fixed_type"] = prop.fixed_type.identifier
except AttributeError:
pass
return result
def check_type(bpy, name):
result = {"kind": "type", "symbol": "bpy.types." + name, "exists": False}
try:
cls = getattr(bpy.types, name)
rna = cls.bl_rna
result.update(exists=True, rna_identifier=rna.identifier,
properties=[item.identifier for item in rna.properties],
functions=[item.identifier for item in rna.functions])
except (AttributeError, RuntimeError) as error:
result["error"] = str(error)
return result
def check_operator(bpy, name):
result = {"kind": "operator", "symbol": "bpy.ops." + name, "exists": False}
category, identifier = name.split(".")
try:
op = getattr(getattr(bpy.ops, category), identifier)
# bpy.ops resolves lazily; hasattr alone cannot prove registration.
rna = op.get_rna_type()
result.update(exists=True, rna_identifier=rna.identifier,
properties=[describe_property(item) for item in rna.properties if item.identifier != "rna_type"])
try:
result["poll_in_current_context"] = bool(op.poll())
except (RuntimeError, TypeError) as error:
result["poll_error"] = str(error)
except (AttributeError, RuntimeError) as error:
result["error"] = str(error)
return result
def check_property(bpy, name):
result = {"kind": "property", "symbol": "bpy.types." + name, "exists": False}
owner, identifier = name.split(".")
try:
prop = getattr(bpy.types, owner).bl_rna.properties.get(identifier)
if prop is not None:
result.update(exists=True, rna=describe_property(prop))
except (AttributeError, RuntimeError) as error:
result["error"] = str(error)
return result
def write_report(path, report):
destination = Path(path).expanduser().resolve()
destination.parent.mkdir(parents=True, exist_ok=True)
temporary = None
try:
with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=destination.parent, delete=False) as output:
temporary = output.name
json.dump(report, output, ensure_ascii=False, indent=2)
output.write("\n")
os.replace(temporary, destination)
finally:
if temporary and os.path.exists(temporary):
os.unlink(temporary)
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--output", help="Write clean JSON here; Blender stdout also includes its own logs.")
parser.add_argument("--type", action="append", default=[], type=lambda value: normalize_symbol(value, "bpy.types.", 1))
parser.add_argument("--operator", action="append", default=[], type=lambda value: normalize_symbol(value, "bpy.ops.", 2))
parser.add_argument("--property", action="append", default=[], type=lambda value: normalize_symbol(value, "bpy.types.", 2))
parser.add_argument("--doc-version", default="5.2", help="Documentation major.minor for comparison; default 5.2.")
if argv is None:
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
args = parser.parse_args(argv)
try:
import bpy
except ImportError as error:
raise RuntimeError("Run this script with Blender --background --python, not host Python.") from error
try:
doc_version = tuple(int(part) for part in args.doc_version.split("."))
if len(doc_version) != 2:
raise ValueError
except ValueError:
parser.error("--doc-version must have the form major.minor")
runtime = {}
for key in ("version", "version_string", "version_cycle", "build_branch", "build_hash", "build_date", "build_time", "build_platform", "build_type", "binary_path", "background"):
runtime[key] = json_value(getattr(bpy.app, key, None))
build_options = {}
for name in dir(bpy.app.build_options):
if not name.startswith("_"):
value = getattr(bpy.app.build_options, name)
if isinstance(value, bool):
build_options[name] = value
checks = []
types = args.type or (["Object", "Mesh", "Scene"] if not (args.operator or args.property) else [])
checks.extend(check_type(bpy, name) for name in types)
checks.extend(check_operator(bpy, name) for name in args.operator)
checks.extend(check_property(bpy, name) for name in args.property)
report = {
"schema_version": 1,
"documentation_target": list(doc_version),
"runtime": runtime,
"runtime_matches_documentation_major_minor": tuple(bpy.app.version[:2]) == doc_version,
"build_options": build_options,
"context": {"mode": bpy.context.mode, "has_window": bpy.context.window is not None,
"has_area": bpy.context.area is not None, "has_region": bpy.context.region is not None},
"checks": checks,
"all_requested_symbols_exist": all(item["exists"] for item in checks),
"interpretation": "Symbol presence and poll describe this runtime and current context only; they do not prove an operation succeeds, a GPU is usable, or all documentation features are installed.",
}
if args.output:
write_report(args.output, report)
print("BLENDER_PROBE_JSON=" + json.dumps(report, ensure_ascii=False, sort_keys=True), flush=True)
return report
if __name__ == "__main__":
main()
scripts/storage.py
"""Deterministic storage helpers shared by the Blender skill tools."""
import gzip
import hashlib
import json
from pathlib import Path
MAX_JSON_BYTES = 64 * 1024 * 1024
def sha256_bytes(data):
return hashlib.sha256(data).hexdigest()
def sha256_file(path):
checksum = hashlib.sha256()
with Path(path).open('rb') as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b''):
checksum.update(chunk)
return checksum.hexdigest()
def compressed_json_path(path):
path = Path(path)
return path if path.suffix == '.gz' else Path(str(path) + '.gz')
def read_json(path):
"""Read JSON from PATH, falling back to the deterministic .gz variant."""
path = Path(path)
compressed = compressed_json_path(path)
if path != compressed and path.exists() and compressed.exists():
raise ValueError('Ambiguous JSON storage; remove the stale raw or gzip variant: ' + str(path))
candidate = path if path.exists() else compressed
if candidate.suffix == '.gz':
with gzip.open(candidate, 'rb') as stream:
payload = stream.read(MAX_JSON_BYTES + 1)
else:
if candidate.stat().st_size > MAX_JSON_BYTES:
raise ValueError('JSON input exceeds the safety limit: ' + str(candidate))
payload = candidate.read_bytes()
if len(payload) > MAX_JSON_BYTES:
raise ValueError('JSON input exceeds the decompressed safety limit: ' + str(candidate))
return json.loads(payload.decode('utf-8'))
def write_gzip_json(path, value):
"""Write compact UTF-8 JSON in a reproducible gzip container."""
path = compressed_json_path(path)
payload = (json.dumps(value, ensure_ascii=False, separators=(',', ':')) + '\n').encode('utf-8')
temporary = path.with_name(path.name + '.tmp')
with temporary.open('wb') as raw:
with gzip.GzipFile(filename='', mode='wb', fileobj=raw, compresslevel=9, mtime=0) as stream:
stream.write(payload)
temporary.replace(path)
return path
def catalog_meaning_v3(catalog):
"""Schema-v3 meaning, including the now-retired raw-HTML audit hashes."""
return {
'source_version': catalog.get('source', {}).get('version'),
'policy': catalog.get('policy'),
'domains': catalog.get('domains'),
'routes': catalog.get('routes'),
'pages': catalog.get('pages'),
}
def catalog_meaning(catalog):
"""Fields that affect routing, evidence selection, and SQLite discovery."""
routes = []
for original in catalog.get('routes') or []:
route = dict(original)
route['evidence'] = [
{key: value for key, value in evidence.items() if key != 'html_sha256'}
for evidence in route.get('evidence', [])
]
routes.append(route)
pages = [
{key: value for key, value in page.items() if key != 'source_html_sha256'}
for page in catalog.get('pages') or []
]
return {
'source_version': catalog.get('source', {}).get('version'),
'policy': catalog.get('policy'),
'domains': catalog.get('domains'),
'routes': routes,
'pages': pages,
}
def catalog_fingerprint(catalog):
payload = catalog_meaning_v3(catalog) if catalog.get('schema_version') == 3 else catalog_meaning(catalog)
payload['semantic_corpus_sha256'] = catalog.get('source', {}).get('semantic_corpus_sha256')
return sha256_bytes(json.dumps(payload, sort_keys=True, ensure_ascii=False, separators=(',', ':')).encode('utf-8'))
def valid_sha256(value):
return (isinstance(value, str) and len(value) == 64 and
all(char in '0123456789abcdef' for char in value))
def validate_catalog(catalog):
actual = catalog.get('catalog_sha256')
if not valid_sha256(actual):
raise ValueError('Catalog is missing catalog_sha256')
compatible = catalog.get('compatible_catalog_sha256s', [])
if (not isinstance(compatible, list) or not all(valid_sha256(item) for item in compatible) or
len(compatible) != len(set(compatible)) or actual in compatible):
raise ValueError('Catalog has invalid compatible fingerprints')
if catalog.get('schema_version', 0) >= 3:
expected = catalog_fingerprint(catalog)
else:
legacy = dict(catalog)
legacy.pop('catalog_sha256', None)
expected = sha256_bytes(json.dumps(legacy, sort_keys=True, ensure_ascii=False).encode('utf-8'))
if actual != expected:
raise ValueError('Catalog fingerprint does not match its semantic content')
return catalog
def semantic_corpus_fingerprint(db):
"""Hash model-visible corpus data independently of SQLite's physical layout."""
checksum = hashlib.sha256()
queries = [
('pages', 'SELECT path,title,body,category FROM pages ORDER BY path'),
('anchors', 'SELECT page,anchor,start,end FROM anchors ORDER BY page,anchor'),
('symbols', 'SELECT name,role,uri,display FROM symbols ORDER BY name,role,uri,display'),
('links', 'SELECT page,href,available FROM links ORDER BY page,href'),
]
for label, query in queries:
checksum.update((label + '\n').encode('ascii'))
for row in db.execute(query):
checksum.update(json.dumps(tuple(row), ensure_ascii=False, separators=(',', ':')).encode('utf-8'))
checksum.update(b'\n')
return checksum.hexdigest()
scripts/build_corpus.py
#!/usr/bin/env python3
"""Rebuild the SQLite corpus from a local Sphinx HTML tree (requires lxml).
HTML is parsed as data; JavaScript, doctrees, pickles and examples are not run.
The supplied source tree is an authoring input and is not copied into the skill.
"""
import argparse
from collections import Counter, deque
from datetime import datetime, timezone
import json
from pathlib import Path
import posixpath
import re
import sqlite3
from urllib.parse import unquote, urlsplit
import zlib
from lxml import html
def local_target(page, href):
u = urlsplit(href)
if u.scheme or u.netloc:
return None
path = posixpath.normpath(posixpath.join(posixpath.dirname(page), unquote(u.path))) if u.path else page
if path.startswith('../') or path.startswith('/'):
return None
return path, unquote(u.fragment)
class Render:
"""Readable text retaining code, table cells, links, and precise ID ranges."""
def __init__(self):
self.parts, self.offset, self.anchors = [], 0, {}
def emit(self, text):
self.parts.append(text)
self.offset += len(text)
def node(self, el):
tag = el.tag if isinstance(el.tag, str) else ''
if tag in {'script', 'style'} or 'headerlink' in el.get('class', '').split():
return
ident = el.get('id')
start = self.offset
if tag == 'pre':
self.emit('\n\n```\n' + ''.join(el.itertext()).rstrip('\n') + '\n```\n\n')
else:
if re.fullmatch(r'h[1-6]', tag):
self.emit('\n\n' + '#' * int(tag[1]) + ' ')
elif tag in {'p', 'div', 'dl', 'dt', 'dd', 'ul', 'ol', 'table', 'section', 'blockquote'}:
self.emit('\n')
elif tag == 'li':
self.emit('\n- ')
elif tag == 'tr':
self.emit('\n| ')
elif tag == 'br':
self.emit('\n')
if el.text:
self.emit(re.sub(r'\s+', ' ', el.text))
for child in el:
self.node(child)
if child.tail:
self.emit(re.sub(r'\s+', ' ', child.tail))
if tag == 'a' and el.get('href') and ''.join(el.itertext()).strip():
self.emit(' <' + el.get('href') + '>')
if tag in {'td', 'th'}:
self.emit(' | ')
elif tag in {'p', 'div', 'dl', 'dd', 'li', 'table', 'section', 'blockquote', 'dt'} or re.fullmatch(r'h[1-6]', tag):
self.emit('\n')
if ident:
self.anchors[ident] = [start, self.offset]
# A Sphinx API signature's definition is its following dd sibling.
if tag == 'dd':
prev = el.getprevious()
while prev is not None and prev.tag == 'dt':
if prev.get('id') in self.anchors:
self.anchors[prev.get('id')][1] = self.offset
prev = prev.getprevious()
def inventory(raw):
header = raw.split(b'\n', 4)
if len(header) != 5 or b'inventory version 2' not in header[0]:
raise ValueError('Expected Sphinx inventory version 2')
rows = []
for line in zlib.decompress(header[4]).decode('utf-8').splitlines():
name, role, priority, uri, display = line.split(' ', 4)
if uri.endswith('$'):
uri = uri[:-1] + name
rows.append((name, role, uri, display))
return rows
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('source', type=Path)
parser.add_argument('--output', type=Path, default=Path(__file__).resolve().parents[1] / 'references/api')
args = parser.parse_args()
source, out = args.source.resolve(), args.output.resolve()
if source == out or source in out.parents:
parser.error('Output must be outside the source tree')
if not (source / 'index.html').is_file():
parser.error('Source must contain index.html')
out.mkdir(parents=True, exist_ok=True)
files = sorted(p for p in source.rglob('*') if p.is_file())
if any(p.is_symlink() for p in source.rglob('*')):
parser.error('Source symlinks are not supported; supply a regular extracted tree')
names = {p.relative_to(source).as_posix() for p in files}
html_names = {p for p in names if p.endswith('.html')}
print(f'Indexing {len(files)} source files into SQLite...', flush=True)
db_path = out / 'api.sqlite3'
if db_path.exists():
db_path.unlink()
con = sqlite3.connect(db_path)
con.executescript('''
CREATE TABLE pages(id INTEGER PRIMARY KEY, path TEXT NOT NULL UNIQUE, title TEXT, body TEXT, category TEXT);
CREATE TABLE anchor_data(page_id INTEGER NOT NULL, anchor TEXT NOT NULL, start INTEGER, end INTEGER,
PRIMARY KEY(page_id,anchor)) WITHOUT ROWID;
CREATE VIEW anchors AS
SELECT pages.path AS page,anchor_data.anchor,anchor_data.start,anchor_data.end
FROM anchor_data JOIN pages ON pages.id=anchor_data.page_id;
CREATE TABLE link_text(id INTEGER PRIMARY KEY, value TEXT NOT NULL);
CREATE TABLE page_links(page_id INTEGER NOT NULL,href_id INTEGER NOT NULL,target_id INTEGER NOT NULL,
anchor_id INTEGER NOT NULL,available INTEGER NOT NULL,
PRIMARY KEY(page_id,href_id)) WITHOUT ROWID;
CREATE VIEW links AS
SELECT pages.path AS page,href.value AS href,target.value AS target,anchor.value AS anchor,page_links.available
FROM page_links JOIN pages ON pages.id=page_links.page_id
JOIN link_text AS href ON href.id=page_links.href_id
JOIN link_text AS target ON target.id=page_links.target_id
JOIN link_text AS anchor ON anchor.id=page_links.anchor_id;
CREATE TABLE symbols(name TEXT, role TEXT, uri TEXT, display TEXT);
CREATE VIRTUAL TABLE search USING fts5(path UNINDEXED,title,body,content='pages',content_rowid='id');
CREATE TABLE metadata(key TEXT PRIMARY KEY,value TEXT);
''')
queue, seen, reachable = deque(['index.html']), set(), set()
missing = {}
external = set()
empty = []
category_counts = Counter()
link_text_ids = {}
def link_text_id(value):
identifier = link_text_ids.get(value)
if identifier is None:
identifier = len(link_text_ids) + 1
link_text_ids[value] = identifier
con.execute('INSERT INTO link_text VALUES(?,?)', (identifier, value))
return identifier
while queue or html_names - seen:
if not queue:
queue.append(sorted(html_names - seen)[0])
page = queue.popleft()
if page in seen:
continue
seen.add(page)
tree = html.fromstring((source / page).read_bytes())
# Crawl the whole HTML, including navigation, starting from index.html.
for href in sorted(set(tree.xpath('//@href | //@src'))):
target = local_target(page, href)
if target:
dest, anchor = target
if dest in html_names and dest not in seen:
queue.append(dest)
if page == 'index.html' or page in reachable:
reachable.add(dest)
if dest not in names:
missing.setdefault(dest, set()).add(page)
else:
external.add(href)
articles = tree.xpath('//article[@role="main"]')
if not articles:
raise ValueError(f'No main article: {page}')
article = articles[0]
render = Render()
render.node(article)
body = ''.join(render.parts)
if not body.strip():
empty.append(page)
heading = article.xpath('.//h1')
title = ''.join(heading[0].itertext()).replace('¶', '').strip() if heading else ''.join(tree.xpath('//title/text()'))
if page.startswith('bpy.types.'):
category = 'bpy.types'
elif page.startswith('bpy.ops.'):
category = 'bpy.ops'
elif page.startswith('bpy_types_enum_items/'):
category = 'enum-items'
elif page.startswith('info_'):
category = 'guides'
elif page.startswith('genindex') or page in {'index.html', 'py-modindex.html', 'search.html'}:
category = 'indices'
else:
category = 'modules'
category_counts[category] += 1
page_id = con.execute('INSERT INTO pages(path,title,body,category) VALUES(?,?,?,?)',
(page, title, body, category)).lastrowid
con.executemany('INSERT INTO anchor_data VALUES(?,?,?,?)',
[(page_id, key, *bounds) for key, bounds in render.anchors.items()])
for href in sorted(set(article.xpath('.//@href | .//@src'))):
target = local_target(page, href)
if target:
dest, anchor = target
con.execute('INSERT INTO page_links VALUES(?,?,?,?,?)',
(page_id, link_text_id(href), link_text_id(dest), link_text_id(anchor), int(dest in names)))
if len(seen) % 250 == 0:
print(f'Indexed {len(seen)}/{len(html_names)} HTML pages', flush=True)
inventory_raw = (source / 'objects.inv').read_bytes()
inventory_header = [line.decode('utf-8') for line in inventory_raw.split(b'\n', 4)[:4]]
symbols = inventory(inventory_raw)
con.executemany('INSERT INTO symbols VALUES(?,?,?,?)', symbols)
con.execute("INSERT INTO search(search) VALUES('rebuild')")
con.execute("INSERT INTO search(search) VALUES('optimize')")
con.commit()
bad_symbols = []
for name, role, uri, display in symbols:
target = local_target('index.html', uri)
if target:
dest, anchor = target
if dest not in names or (anchor and dest in html_names and not con.execute('SELECT 1 FROM anchors WHERE page=? AND anchor=?', (dest, anchor)).fetchone()):
bad_symbols.append({'name': name, 'role': role, 'uri': uri})
overview = con.execute("SELECT body FROM pages WHERE path='index.html'").fetchone()[0]
version_match = re.search(r'Blender ([\d.]+) Python API Documentation', overview)
version = version_match.group(1) if version_match else 'unknown'
report = {
'schema_version': 1,
'documentation_version': version,
'inventory_header': inventory_header,
'source_label': source.name,
'source_index': 'index.html',
'generated_utc': datetime.now(timezone.utc).isoformat(),
'source_files': len(files),
'source_bytes': sum(path.stat().st_size for path in files),
'html_pages': len(html_names),
'indexed_pages': len(seen),
'reachable_html_from_index': len(reachable | {'index.html'}),
'orphan_html_pages': sorted(html_names - reachable - {'index.html'}),
'empty_main_articles': empty,
'categories': dict(sorted(category_counts.items())),
'inventory_entries': len(symbols),
'inventory_roles': dict(sorted(Counter(x[1] for x in symbols).items())),
'indexed_anchors': con.execute('SELECT count(*) FROM anchors').fetchone()[0],
'extracted_characters': con.execute('SELECT sum(length(body)) FROM pages').fetchone()[0],
'unresolved_inventory_targets': bad_symbols,
'missing_local_targets': [{'target': k, 'referring_pages': len(v), 'examples': sorted(v)[:3]} for k, v in sorted(missing.items())],
'external_link_count': len(external),
'scope': 'All files in the supplied offline Python API snapshot. External websites are not recursively downloaded. Presence in docs does not prove background-mode or runtime support.',
}
con.execute('INSERT INTO metadata VALUES(?,?)', ('coverage', json.dumps(report, ensure_ascii=False)))
con.commit()
con.execute('VACUUM')
con.close()
for retired in ['source-html.zip', 'source-html.tar.xz', 'manifest.json', 'coverage.json', 'external-links.txt']:
(out / retired).unlink(missing_ok=True)
print(json.dumps({k: v for k, v in report.items() if k not in {'unresolved_inventory_targets', 'missing_local_targets'}}, ensure_ascii=False, indent=2))
if __name__ == '__main__':
main()
references/evidence-workflow.md
# Evidence plan for Blender-specific decisions
The catalog provides the initial Blender context. It must be read before API lookup. Ordinary language interpretation and Python programming are available reasoning tools; recalled Blender facts are not an evidence source. Every chosen feature must have a source-backed description or remain explicitly a discovery-only item. A strict traceability workflow cannot remove knowledge from model weights; it can reject unsupported claims and task execution without recorded evidence.
## Where facts come from
| Fact | Admissible source | What it does not prove |
|---|---|---|
| What a feature is for | Catalog evidence with a source excerpt and precise ref | A name alone does not establish purpose |
| API signature, owner, property type/range | Full relevant passage in packaged API | Runtime availability or undocumented effects |
| Which value a user wants | User request or a stated artistic choice | That a Blender enum/property exists |
| Runtime version, available RNA, dynamic values | Recorded output of the bundled probe/authorized source-driven inspection | A complete workflow or render appearance |
| Result correctness | Task-specific output inspection, fresh reopen, actual render | General support for every feature |
The old broad capability map is replaced by the generated overview/domain cards. Earlier examples in repository reports are historical evidence and are not approved recipes for new tasks.
## Discovery before database
`features.py overview`, `match`, `show`, `pages` and `symbols` read only bundled plain files. `match` returns candidates with matched aliases and choice criteria, not an automatic implementation verdict. No match means `insufficient_skill_evidence`; inspect the relevant domain catalog or request the missing source/intent details. A `pages` entry supplies exact source wording, so the agent can discover unfamiliar APIs without remembering their names.
An authored route has a Vietnamese/English label, aliases, capability summary, `choose_when`, `do_not_assume`, cited facts and `next_queries`. All source HTML pages also have generated `api:...` cards. This provides full source discovery coverage while distinguishing pages whose intros offer no sufficient behavioral description. Do not label every class as a supported end-to-end feature.
## Make a plan
Use `features.py plan` after reading the selected cards. It writes schema version 2, catalog digest, user request, selected features, source-derived seed refs, recorded reads, script digest, operation bindings and unresolved facts. It does not execute Blender. The exact seeds are verified against catalog data, so manually appending a guessed seed invalidates the plan.
Read source with:
```sh
python3 scripts/docs.py read 'PAGE.html#ANCHOR' --plan /absolute/path/plan.json
```
The resolved canonical ref and hashes are recorded. Pagination is part of evidence: a partial read is not complete until all displayed lines for that selected page/anchor have been read. Empty anchors cannot count as evidence; read their full page or a nonempty section instead. Prefer precise anchors to loading large classes. Links from a fully read passage permit opening those source pages; arbitrary unrelated pages require selecting the relevant catalog card. SQLite is the packaged source of truth; bare `docs.py` reads without a plan do not count as task-plan receipts.
## Bind code to the evidence actually read
Write the script, then run `evidence.py inspect --script /absolute/path/task.py`. It conservatively lists attribute/dynamic operations that require review and follows simple assignments/iteration over known Blender values. `requires_source: false` means the object type is unknown, not that the operation is general Python; review helper parameters and other aliases manually. Edit `bindings` in the plan to identify source-backed lines and explain the fact used. For example, after reading the `api:bpy.app` card and `bpy.app.html#bpy.app.version_string`, this script:
```python
import bpy
print(bpy.app.version_string)
```
can bind line 2 as:
```json
{
"lines": [2],
"basis": "source",
"refs": ["bpy.app.html#bpy.app.version_string"],
"reason": "The supplied source documents this runtime version string; this line only reads and prints it."
}
```
Bindings may contain several refs when a line composes multiple supported operations. Use `basis: general_python` only for non-Blender helpers such as a list append or `Path.write_text`, with a reason; explicit Blender/dynamic accesses cannot use this basis. A remembered Blender operation cannot be relabeled general Python. Planned colors, positions and artistic values can be chosen from the user's output requirements; their assignment API and allowed value contracts still require source evidence.
Keep unresolved Blender facts as nonempty strings in `unresolved`. Do not clear them without new evidence. If an observed runtime enum/socket is needed, save that probe/inspection output, cite the relevant source contract and explain the observed selection in the binding reason; do not assert that the static source contained it. This version's automatic validator hashes static passages, not arbitrary runtime logs, so the agent must inspect runtime evidence and its provenance directly. If the source has no supporting contract, preserve the gap.
```sh
python3 scripts/evidence.py seal --plan /absolute/path/plan.json --script /absolute/path/task.py
python3 scripts/evidence.py check --plan /absolute/path/plan.json --script /absolute/path/task.py
python3 scripts/run_blender.py --script /absolute/path/task.py --plan /absolute/path/plan.json
```
Sealing validates complete recorded source reads, selected catalog seeds, matching source hashes, bindings and unresolved facts; it binds the exact script bytes. Script changes require review and resealing. New source reads clear the seal. The CLI runner repeats these checks and refuses task scripts without a valid plan. The installed `probe_blender.py` path is the sole exception because it is the skill's provided runtime-inspection helper.
## Limits of the checks
The validator cannot prove the semantic relevance of an arbitrary human/model-written `reason`, infer all Python aliases, verify arbitrary dynamic code, or inspect the model's internal knowledge. It is not a security sandbox. The strict skill contract requires the agent to check every Blender-specific line and reject unsupported inferences even when mechanical validation passes. Do not generate dynamic code, import unreviewed task helpers or launch another Blender process to bypass evidence bindings. If semantic support is uncertain, retain an unresolved entry and stop the dependent implementation.
At task completion report the chosen feature IDs, source refs that establish the implementation, actual runtime/output checks and remaining gaps. A successful catalog lookup or seal is not a render, test of all Blender features, or proof of visual quality.
scripts/build_catalog.py
#!/usr/bin/env python3
"""Generate the pre-query capability layer from bundled evidence. Authoring only.
The generated JSON/Markdown can be read without SQLite, Blender, network or ML.
Domain assignment is navigation metadata, never a claim of task feasibility.
"""
import argparse
from collections import defaultdict
import hashlib
import json
from pathlib import Path
import re
import sqlite3
from storage import (catalog_fingerprint, catalog_meaning, read_json,
semantic_corpus_fingerprint, sha256_file, validate_catalog,
write_gzip_json)
SKILL = Path(__file__).resolve().parents[1]
DOMAIN_ROWS = [
('scene', 'Scenes, objects, collections and transforms', ['cảnh', 'đối tượng', 'vị trí', 'xoay', 'scene', 'object', 'collection', 'transform']),
('geometry', 'Mesh, BMesh and modifiers', ['lưới', 'hình học', 'bo cạnh', 'cắt khối', 'mesh', 'bmesh', 'modifier', 'topology']),
('geometry-nodes', 'Geometry Nodes, fields and instances', ['nút hình học', 'phân bố', 'nhân bản', 'geometry nodes', 'instance', 'field']),
('curves-volumes', 'Curves, 3D text, hair, point clouds and volumes', ['đường cong', 'chữ 3d', 'tóc', 'thể tích', 'curve', 'text geometry', 'hair', 'volume', 'grid']),
('sculpt-paint', 'Sculpting, brushes and painting', ['điêu khắc', 'tô màu', 'trọng số', 'sculpt', 'paint', 'brush', 'weight']),
('uv', 'UV maps, images and texture baking', ['trải uv', 'tọa độ uv', 'nướng texture', 'uv', 'unwrap', 'image', 'bake']),
('shading', 'Materials, shaders, textures and worlds', ['vật liệu', 'bề mặt', 'shader', 'material', 'texture', 'world']),
('lights-shadows', 'Lights, cameras and shadows', ['ánh sáng', 'đèn', 'đổ bóng', 'bóng', 'camera', 'light', 'shadow', 'reflection']),
('render', 'Rendering, passes, color and image output', ['kết xuất', 'render', 'pass', 'màu', 'png', 'output', 'color management']),
('compositor', 'Compositing, masks and image processing', ['hậu kỳ', 'ghép ảnh', 'khử nhiễu', 'compositing', 'mask', 'denoise', 'keying']),
('video-audio', 'Video editing, titles and audio', ['dựng phim', 'chữ video', 'âm thanh', 'video', 'sequencer', 'text strip', 'audio']),
('grease-pencil-freestyle', 'Grease Pencil, 2D strokes and Freestyle', ['vẽ 2d', 'nét vẽ', 'grease pencil', 'freestyle', 'line art', 'stroke']),
('tracking', 'Motion tracking and movie clips', ['bám chuyển động', 'giải camera', 'tracking', 'movie clip', 'camera solve']),
('animation-rigging', 'Keyframes, drivers, rigs and constraints', ['chuyển động', 'khung hình chính', 'xương', 'rig', 'animation', 'keyframe', 'driver', 'constraint']),
('simulation', 'Simulation, physics and caches', ['mô phỏng', 'vải', 'chất lỏng', 'khói', 'vật lý', 'simulation', 'physics', 'fluid', 'cloth', 'rigid body', 'particle']),
('files-assets', 'Files, import/export, libraries and assets', ['tệp', 'nhập', 'xuất', 'tài nguyên', 'file', 'import', 'export', 'library', 'asset']),
('integration-gpu', 'Python integration, math, GPU and UI', ['tích hợp', 'tiện ích', 'giao diện', 'toán', 'python', 'math', 'gpu', 'ui', 'registration']),
('api-guides', 'API guides, enums and source indices', ['tài liệu', 'hướng dẫn', 'enum', 'index', 'api reference', 'gotchas']),
]
# Audited storage-only migrations. Each entry pins both legacy physical inputs
# and the semantic corpus produced by the new layout; unrelated legacy catalogs
# must not gain plan compatibility merely because their route cards look alike.
LEGACY_STORAGE_MIGRATIONS = {
'f7f35890ea31929ab58d2ff69438b5d05ff36762b1662916ef16b6b95d7785f8': {
'database_sha256': '08d18853fc8c312299d19ff6d1962a0211dfe786c2c21297016230fe537f1089',
'manifest_sha256': '7dcf879a5e4e643f8805eed01d434e1a0138e7ffb87b933c9b762b57a69a3581',
'current_database_sha256': '72e8e6908468d884aec5676b0214f748404b707023b7a3865b5842366665da2d',
'semantic_corpus_sha256': '2daab299f0787620df6c173282d4a6dd90114410c33af291fb6ea0c771bb6cb4',
},
}
def digest(data):
return hashlib.sha256(data).hexdigest()
def read_ref(db, ref):
page, _, anchor = ref.partition('#')
row = db.execute('SELECT body FROM pages WHERE path=?', (page,)).fetchone()
if not row:
raise ValueError('Missing page: ' + ref)
body = row[0]
if anchor:
bounds = db.execute('SELECT start,end FROM anchors WHERE page=? AND anchor=?', (page, anchor)).fetchone()
if not bounds:
raise ValueError('Missing anchor: ' + ref)
body = body[bounds[0]:bounds[1]]
return body
def brief(body):
"""Select source prose after a class declaration, with no invented summary."""
lines = [line.strip() for line in body.splitlines() if line.strip()]
class_i = next((i for i, line in enumerate(lines[:10]) if line.startswith('class bpy.types.')), None)
if class_i is not None:
line = lines[class_i + 1] if class_i + 1 < len(lines) else ''
# A member name alone is not a capability description.
if len(line.split()) < 3 or line.startswith(('classmethod ', 'base class', '##')):
return '', 'identifier_only'
return line[:500], 'source_description'
useful = [line for line in lines if not line.startswith(('#', 'base class', '|', '-', 'class '))]
first = ' '.join(useful[:2])[:500]
return first, 'source_excerpt' if first else 'identifier_only'
def domains_for(page, category):
if category in {'guides', 'indices', 'enum-items'}:
return ['api-guides']
name = page.removesuffix('.html').split('.')[-1]
if page.startswith('bpy.ops.'):
groups = {
'scene': 'object collection transform scene world workspace ed'.split(),
'geometry': 'mesh geometry lattice mball'.split(),
'geometry-nodes': ['node'], 'curves-volumes': 'curve curves surface font pointcloud'.split(),
'sculpt-paint': 'sculpt sculpt_curves paint paintcurve brush palette'.split(),
'uv': 'uv image'.split(), 'shading': 'material texture'.split(),
'lights-shadows': ['camera'], 'render': 'render cycles'.split(),
'compositor': ['mask'], 'video-audio': 'sequencer sound'.split(),
'grease-pencil-freestyle': 'gpencil grease_pencil'.split(), 'tracking': ['clip'],
'animation-rigging': 'action anim armature pose poselib nla graph constraint marker'.split(),
'simulation': 'rigidbody fluid cloth dpaint ptcache particle boid cachefile'.split(),
'files-assets': 'wm file asset import_scene export_scene import_anim export_anim import_curve'.split(),
}
found = [key for key, names in groups.items() if name in names]
return found or ['integration-gpu']
if page.startswith(('bmesh',)):
return ['geometry']
if page.startswith(('freestyle',)):
return ['grease-pencil-freestyle']
if page.startswith('aud'):
return ['video-audio']
if not page.startswith('bpy.types.'):
return ['integration-gpu']
rules = [
('geometry-nodes', r'^(GeometryNode|FunctionNode|NodesModifier|NodeTreeInterface|NodeSocket|NodeLink|Nodes$)'),
('compositor', r'^(Compositor|Mask)'),
('shading', r'^(ShaderNode|TextureNode|Material|World|.*Texture)'),
('grease-pencil-freestyle', r'(GreasePencil|GPencil|ShaderFx|Freestyle|LineStyle|Annotation)'),
('video-audio', r'(Strip|Sequence|Sound|Speaker|TextEffect|FFmpeg|Aud)'),
('tracking', r'^(Movie|Track|CameraSolver|FollowTrack|ObjectSolver)'),
('animation-rigging', r'(Action|Anim|FCurve|FModifier|Keyframe|Keying|Driver|Nla|Bone|Armature|Pose|Constraint|ShapeKey|^Key$)'),
('simulation', r'(Fluid|Cloth|SoftBody|RigidBody|Particle|Boid|DynamicPaint|PointCache|Effector|FieldSettings|Collision)'),
('lights-shadows', r'^(Camera|.*Light|.*LightProbe)'),
('render', r'^(Render|Bake|ColorManaged|ImageFormat|AOV|Cryptomatte|SceneEEVEE|ViewLayer)'),
('curves-volumes', r'(Curve|Spline|MetaBall|Volume|PointCloud|TextCurve|VectorFont|Hair)'),
('sculpt-paint', r'(Sculpt|Paint|Brush|Palette|VertexGroup)'),
('uv', r'(UV|^Image|^UDIM)'),
('geometry', r'(Mesh|Modifier|Lattice|Attribute)'),
('files-assets', r'(Library|Asset|File|Packed|BlendData)'),
('scene', r'^(Object|Scene|Collection|LayerCollection|UnitSettings|TransformOrientation)'),
]
for domain, pattern in rules:
if re.search(pattern, name):
return [domain]
return ['integration-gpu']
def write_json(path, value):
path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
def compatible_fingerprints(previous, current):
if not previous or catalog_meaning(previous) != catalog_meaning(current):
return []
same_semantic_corpus = (previous.get('schema_version', 0) >= 3 and
previous.get('source', {}).get('semantic_corpus_sha256') ==
current['source']['semantic_corpus_sha256'])
migration = LEGACY_STORAGE_MIGRATIONS.get(previous.get('catalog_sha256'))
verified_legacy_migration = bool(
migration and
previous.get('source', {}).get('database_sha256') == migration['database_sha256'] and
previous.get('source', {}).get('manifest_sha256') == migration['manifest_sha256'] and
current['source']['database_sha256'] == migration['current_database_sha256'] and
current['source']['semantic_corpus_sha256'] == migration['semantic_corpus_sha256']
)
if not (same_semantic_corpus or verified_legacy_migration):
return []
candidates = [previous.get('catalog_sha256'), *previous.get('compatible_catalog_sha256s', [])]
return list(dict.fromkeys(item for item in candidates if item and item != current['catalog_sha256']))
def build(skill=SKILL):
root = skill / 'references/catalog'
root.mkdir(exist_ok=True)
try:
previous_catalog = validate_catalog(read_json(root / 'catalog.json'))
except FileNotFoundError:
previous_catalog = None
db_path = skill / 'references/api/api.sqlite3'
db = sqlite3.connect(db_path.as_uri() + '?mode=ro', uri=True)
db.row_factory = sqlite3.Row
domains = {key: {'id': key, 'label': label, 'aliases': aliases, 'routes': [], 'pages': []} for key, label, aliases in DOMAIN_ROWS}
routes, seen = [], set()
inputs = sorted(root.glob('routes-*.json'))
if not inputs:
raise ValueError('Missing authored routes-*.json inputs')
for source in inputs:
document = json.loads(source.read_text())
for original in document['routes']:
route = dict(original)
rid = route['id']
if rid in seen or not re.fullmatch('[a-z0-9]+(?:-[a-z0-9]+)*', rid):
raise ValueError('Duplicate/invalid route ID: ' + rid)
seen.add(rid)
if route['domain'] not in domains:
raise ValueError('Unknown domain: ' + route['domain'])
for field in ['label_vi', 'label_en', 'summary', 'choose_when']:
if not isinstance(route.get(field), str) or not route[field].strip():
raise ValueError(f'{rid}: missing text field {field}')
for field in ['intent_aliases', 'api_refs', 'next_queries', 'evidence', 'do_not_assume']:
if not isinstance(route.get(field), list):
raise ValueError(f'{rid}: {field} must be a list')
if not route['evidence'] or not route['api_refs'] or not route['next_queries']:
raise ValueError('Route lacks evidence/API entry point: ' + rid)
evidence = []
for fact in route['evidence']:
body = read_ref(db, fact['ref'])
if not fact.get('supports'):
raise ValueError('Empty source claim: ' + rid)
excerpt = re.sub(r'\s+', ' ', body).strip()
evidence.append({**fact, 'excerpt': excerpt[:1800], 'excerpt_truncated': len(excerpt) > 1800,
'source_text_sha256': digest(body.encode())})
route['evidence'] = evidence
route['status'] = 'documented_route_runtime_unverified'
route['authorship'] = 'Source-grounded editorial summary; Vietnamese aliases are translations, not extra Blender behavior.'
for ref in set(route['api_refs'] + route['next_queries']):
read_ref(db, ref)
routes.append(route)
domains[route['domain']]['routes'].append(rid)
page_routes = defaultdict(set)
for route in routes:
for ref in route['api_refs'] + route['next_queries'] + [e['ref'] for e in route['evidence']]:
page_routes[ref.split('#')[0]].add(route['domain'])
pages = []
for row in db.execute('SELECT path,title,body,category FROM pages ORDER BY path'):
snippet, kind = brief(row['body'])
assigned = sorted(set(domains_for(row['path'], row['category'])) | page_routes[row['path']])
card = {'id': 'api:' + row['path'].removesuffix('.html'), 'page': row['path'], 'title': row['title'],
'domains': assigned, 'source_excerpt': snippet, 'description_status': kind,
'status': 'api_discovery_only', 'source_text_sha256': digest(row['body'].encode()),
'next_queries': [row['path']]}
pages.append(card)
for domain in assigned:
domains[domain]['pages'].append(card['id'])
inventory_count = db.execute('SELECT count(*) FROM symbols').fetchone()[0]
# All root symbols remain available as a source-derived compressed JSON inventory,
# allowing names/roles to be discovered before opening the API database.
symbols = [dict(row) for row in db.execute('SELECT name,role,uri FROM symbols ORDER BY name,role')]
core = {'schema_version': 4, 'source': {'version': '5.2',
'semantic_corpus_sha256': semantic_corpus_fingerprint(db),
'database_sha256': sha256_file(db_path)},
'policy': {'pretrained_blender_knowledge': 'forbidden_as_evidence',
'unknown_intent': 'insufficient_skill_evidence',
'api_discovery_only': 'Read source before making any behavior claim; an API name is not a workflow.'},
'domains': list(domains.values()), 'routes': sorted(routes, key=lambda x: x['id']), 'pages': pages}
core['catalog_sha256'] = catalog_fingerprint(core)
compatible = compatible_fingerprints(previous_catalog, core)
if compatible:
core['compatible_catalog_sha256s'] = compatible
write_gzip_json(root/'catalog.json', core)
write_gzip_json(root/'symbols.json', {'source': 'root objects.inv only', 'symbols': symbols})
(root/'catalog.json').unlink(missing_ok=True)
(root/'symbols.json').unlink(missing_ok=True)
report = {'schema_version': 4, 'authored_routes': len(routes), 'domains': len(domains), 'api_page_cards': len(pages),
'source_html_pages': db.execute('SELECT count(*) FROM pages').fetchone()[0], 'inventory_entries': inventory_count,
'mapped_pages': len({card['page'] for card in pages}), 'unmapped_pages': [],
'cards_without_description': [card['id'] for card in pages if card['description_status']=='identifier_only'],
'evidence_references': sum(len(r['evidence']) for r in routes),
'coverage_meaning': 'All source pages/symbols are discoverable before SQLite. Authored routes are not every possible Blender workflow. Missing semantics remain explicit gaps.',
'semantic_corpus_sha256': core['source']['semantic_corpus_sha256'],
'catalog_sha256': core['catalog_sha256']}
write_json(root/'coverage.json', report)
overview = [
'# Capability catalog before API lookup', '',
'Read this entire page before opening SQLite. This catalog supplies Blender context to the agent; do not add capabilities, APIs, enums or workflows from pretrained Blender knowledge.', '',
f'The catalog contains {len(routes)} source-backed routes, {len(pages)} source-page cards and {inventory_count} inventory entries. An API card is a discovery entry point, not proof of a documented workflow or working CLI implementation.', '',
'| Domain | Search aliases (English / Vietnamese) | Authored routes | Source cards |', '|---|---|---|---|',
]
for domain in domains.values():
overview.append(f"| [{domain['label']}](domains/{domain['id']}.md) | {', '.join(domain['aliases'])} | {len(domain['routes'])} | {len(domain['pages'])} |")
overview += ['', '## Selecting a route', '',
'1. Match the request to the domains above using the supplied language and context. Do not guess API identifiers.',
'2. Read the domain file and compare purpose, selection criteria and gaps. `features.py match` searches English/Vietnamese aliases using JSON only, without opening the database.',
'3. Read selected routes with `features.py show ID` for source excerpts, limits and seed queries. Select multiple routes for combined tasks.',
'4. If no route fits, inspect domain page cards (`features.py pages DOMAIN`) and select only behavior supported by source descriptions. Missing descriptions do not permit inferring behavior from names.',
'5. If evidence is still insufficient, report `insufficient_skill_evidence`, identify the missing fact and request source material or clarification of the output. Do not substitute model memory.', '',
'## Status values', '',
'- `documented_route_runtime_unverified`: a source-backed description and query route; inspect the actual API/runtime before execution.',
'- `api_discovery_only`: a source page/API exists, but this card is not an authored task route; read the source before proceeding.',
'- `identifier_only`: introductory text does not sufficiently describe behavior. Preserve the gap; a class name is not evidence.', '',
'Routes and cards derive from the bundled API corpus. Blender Manual and web content have not been added to this layer. The catalog does not establish background-mode support for every feature.',
]
(root/'overview.md').write_text('\n'.join(overview)+'\n')
directory = root/'domains'
directory.mkdir(exist_ok=True)
by_id = {r['id']: r for r in routes}
for domain in domains.values():
lines = [f"# {domain['label']}", '', 'Select by purpose and evidence below. Identify a route/source card before querying SQLite or proposing API identifiers.', '']
for rid in domain['routes']:
route = by_id[rid]
lines += [f"## {route['label_en']} — `{rid}`", '', route['summary'], '',
f"Choose when: {route['choose_when']}", '', f"Search aliases: {', '.join(route['intent_aliases'])}", '',
'Evidence: ' + '; '.join(f"`{e['ref']}` — {e['supports']}" for e in route['evidence']), '',
'Read next: ' + ', '.join('`'+q+'`' for q in route['next_queries']), '']
if route['do_not_assume']:
lines += ['Limits: ' + ' '.join(route['do_not_assume']), '']
lines += ['## Discover all source pages in this domain', '',
f"`python3 scripts/features.py pages {domain['id']}` lists {len(domain['pages'])} source cards with pagination. Each card retains its source name and description excerpt. Catalog discovery does not require SQLite.", '',
'Source pages remain discoverable even without an authored route. Read their descriptions/definitions before planning; do not supply missing behavior from model knowledge.', '']
(directory/f"{domain['id']}.md").write_text('\n'.join(lines))
db.close()
print(json.dumps({k: v for k,v in report.items() if k!='cards_without_description'}, ensure_ascii=False, indent=2))
return report
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--skill', type=Path, default=SKILL)
build(parser.parse_args().skill.resolve())
scripts/features.py
#!/usr/bin/env python3
"""Read pre-query Blender capability data. Never imports sqlite3 or opens the API DB."""
import argparse
import json
from pathlib import Path
import re
import sys
import unicodedata
from storage import read_json, validate_catalog
SKILL = Path(__file__).resolve().parents[1]
CATALOG = SKILL/'references/catalog/catalog.json'
def normalize(text):
text = re.sub(r'([a-z])([A-Z])', r'\1 \2', text).lower().replace('đ', 'd')
text = ''.join(char for char in unicodedata.normalize('NFD', text) if unicodedata.category(char) != 'Mn')
return ' '.join(re.findall(r'\w+', text))
def load_catalog():
return validate_catalog(read_json(CATALOG))
def find_card(catalog, identifier):
for card in catalog['routes'] + catalog['pages']:
if card['id'] == identifier:
return card
raise ValueError('Unknown feature/card. Read overview or match first: ' + identifier)
def match(catalog, query, limit=10):
q = normalize(query)
words = set(q.split())
ranked = []
for route in catalog['routes']:
aliases = list(route['intent_aliases']) + [route['label_vi'], route['label_en']]
matched, score = [], 0.0
for alias in aliases:
norm = normalize(alias)
alias_words = set(norm.split())
if not alias_words:
continue
overlap = len(words & alias_words)
exact_phrase = (' ' + norm + ' ') in (' ' + q + ' ')
if exact_phrase:
matched.append(alias)
score = max(score, 10 + len(alias_words))
elif overlap >= 2 and overlap == len(alias_words):
# Reordered words are acceptable; omitted feature words are not.
# E.g. 'vật thể' alone must not match the alias 'mask vật thể'.
matched.append(alias)
score = max(score, overlap / len(alias_words) + overlap / max(1,len(words)))
if score:
ranked.append((score, {'id': route['id'], 'label': route['label_en'], 'summary': route['summary'],
'matched_aliases': matched, 'choose_when': route['choose_when'], 'status': route['status']}))
ranked.sort(key=lambda item: (-item[0], item[1]['id']))
return [item[1] for item in ranked[:limit]]
def main():
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest='command', required=True)
sub.add_parser('overview')
p=sub.add_parser('match'); p.add_argument('request'); p.add_argument('--limit', type=int, default=10)
p=sub.add_parser('show'); p.add_argument('id')
p=sub.add_parser('pages'); p.add_argument('domain'); p.add_argument('--offset',type=int,default=0); p.add_argument('--limit',type=int,default=35)
p=sub.add_parser('symbols'); p.add_argument('query'); p.add_argument('--limit',type=int,default=25)
p=sub.add_parser('plan'); p.add_argument('--request',required=True); p.add_argument('--feature',action='append',required=True); p.add_argument('--output',type=Path,required=True)
args=parser.parse_args()
if hasattr(args,'limit') and not 1 <= args.limit <= 1000:
parser.error('--limit must be 1..1000')
if hasattr(args,'offset') and args.offset < 0:
parser.error('--offset must be non-negative')
catalog=load_catalog()
if args.command=='overview':
print((SKILL/'references/catalog/overview.md').read_text())
elif args.command=='match':
candidates=match(catalog,args.request,args.limit)
print(json.dumps({'status':'candidates_require_reading' if candidates else 'insufficient_skill_evidence',
'candidates':candidates,'next':'Read chosen feature cards; if ambiguous clarify desired output. Never invent an API or fallback from model memory.'},ensure_ascii=False,indent=2))
elif args.command=='show':
print(json.dumps(find_card(catalog,args.id),ensure_ascii=False,indent=2))
elif args.command=='pages':
domain=next((d for d in catalog['domains'] if d['id']==args.domain),None)
if not domain:
raise ValueError('Unknown domain; read overview')
cards=[c for c in catalog['pages'] if args.domain in c['domains']]
selected=cards[args.offset:args.offset+args.limit]
print(json.dumps({'domain':args.domain,'total':len(cards),'cards':selected,
'next_offset':args.offset+len(selected) if args.offset+len(selected)<len(cards) else None},ensure_ascii=False,indent=2))
elif args.command=='symbols':
# Discover source identifiers outside SQLite. No semantic expansion.
query=args.query.casefold()
data=read_json(SKILL/'references/catalog/symbols.json')
rows=[s for s in data['symbols'] if query in s['name'].casefold()]
rows.sort(key=lambda s:(s['name'].casefold()!=query,len(s['name']),s['name']))
print(json.dumps({'matches':rows[:args.limit],'total':len(rows),'meaning':'Identifier discovery only; read the source before claiming behavior.'},ensure_ascii=False,indent=2))
elif args.command=='plan':
if args.output.exists():
raise ValueError('Plan already exists; choose a new path or edit it deliberately')
cards=[find_card(catalog,identifier) for identifier in dict.fromkeys(args.feature)]
seeds=sorted({ref for card in cards for ref in card['next_queries']+card.get('api_refs',[])})
plan={'schema_version':2,'request':args.request,'catalog_sha256':catalog['catalog_sha256'],
'selected_features':[c['id'] for c in cards], 'seed_refs':seeds,'reads':[],
'script_sha256':None,'bindings':[],'unresolved':[],
'evidence_policy':'Blender facts must come from bundled source or recorded runtime inspection. Pretrained Blender knowledge is not admissible.',
'review_note':'Select source refs and read them with docs.py --plan before implementing. Each Blender-specific statement must have a supporting source; source IDs alone do not prove semantic support.'}
args.output.parent.mkdir(parents=True,exist_ok=True)
args.output.write_text(json.dumps(plan,ensure_ascii=False,indent=2)+'\n')
print(json.dumps({'plan':str(args.output.resolve()),'selected_features':plan['selected_features'],'read_next':seeds},ensure_ascii=False,indent=2))
return 0
if __name__=='__main__':
try:
raise SystemExit(main())
except (ValueError,KeyError,FileNotFoundError,json.JSONDecodeError,OSError) as exc:
print('Error: '+str(exc),file=sys.stderr)
raise SystemExit(2)
scripts/docs.py
#!/usr/bin/env python3
"""Search/read the bundled Blender API offline. Python standard library only."""
import argparse
import json
from pathlib import Path
import re
import sqlite3
import sys
import posixpath
from urllib.parse import unquote, urlsplit
from storage import semantic_corpus_fingerprint, sha256_file
ROOT = Path(__file__).resolve().parents[1] / 'references/api'
def connect():
db = sqlite3.connect((ROOT / 'api.sqlite3').as_uri() + '?mode=ro', uri=True)
db.row_factory = sqlite3.Row
return db
def resolve(db, target):
target = unquote(target)
page, _, anchor = target.partition('#')
for candidate in (page, page + '.html'):
if db.execute('SELECT 1 FROM pages WHERE path=?', (candidate,)).fetchone():
return candidate, anchor
row = db.execute('SELECT uri FROM symbols WHERE name=? ORDER BY role LIMIT 1', (target,)).fetchone()
if row:
return resolve(db, row['uri'])
raise ValueError(f'Page/symbol not found: {target}. Use search or symbol first.')
def verify():
from features import load_catalog
catalog = load_catalog()
failures = []
counts = {'pages': 0, 'anchors': 0, 'symbols': 0, 'search_rows': 0}
with connect() as db:
if db.execute('PRAGMA integrity_check').fetchone()[0] != 'ok':
failures.append('SQLite integrity check failed')
counts = {
'pages': db.execute('SELECT count(*) FROM pages').fetchone()[0],
'anchors': db.execute('SELECT count(*) FROM anchors').fetchone()[0],
'symbols': db.execute('SELECT count(*) FROM symbols').fetchone()[0],
'search_rows': db.execute('SELECT count(*) FROM search').fetchone()[0],
}
coverage_row = db.execute("SELECT value FROM metadata WHERE key='coverage'").fetchone()
if coverage_row is None:
failures.append('SQLite coverage metadata is missing')
else:
expected = json.loads(coverage_row['value'])
if counts['pages'] != expected['html_pages']:
failures.append('HTML page count mismatch')
if counts['anchors'] != expected['indexed_anchors']:
failures.append('Anchor count mismatch')
if counts['symbols'] != expected['inventory_entries']:
failures.append('Inventory count mismatch')
if counts['search_rows'] != counts['pages']:
failures.append('FTS row count mismatch')
if semantic_corpus_fingerprint(db) != catalog['source']['semantic_corpus_sha256']:
failures.append('SQLite semantic fingerprint mismatch')
if sha256_file(ROOT / 'api.sqlite3') != catalog['source']['database_sha256']:
failures.append('SQLite file fingerprint mismatch')
print(json.dumps({'ok': not failures, 'database': 'api.sqlite3', **counts, 'failures': failures}, indent=2))
return bool(failures)
def main():
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest='command', required=True)
p = sub.add_parser('search', help='Full-text search with ranked page excerpts')
p.add_argument('query')
p.add_argument('--limit', type=int, default=8)
p.add_argument('--any', action='store_true', help='Match any query term instead of all')
p.add_argument('--category', help='Filter by category from stats')
p.add_argument('--plan', type=Path, help='Task evidence plan selected from pre-query catalog')
p = sub.add_parser('symbol', help='Find exact names, then prefixes, then substrings')
p.add_argument('query')
p.add_argument('--limit', type=int, default=20)
p.add_argument('--plan', type=Path)
p = sub.add_parser('read', help='Read a page, page#anchor, or exact symbol')
p.add_argument('target')
p.add_argument('--start', type=int, default=1, help='First line within the selected page/anchor')
p.add_argument('--lines', type=int, default=160)
p.add_argument('--plan', type=Path, help='Record actual displayed source lines in this evidence plan')
p = sub.add_parser('related', help='Follow local links in a main article')
p.add_argument('target')
p.add_argument('--limit', type=int, default=80)
p.add_argument('--plan', type=Path)
sub.add_parser('stats')
sub.add_parser('verify', help='Check database integrity, FTS, counts and catalog fingerprints')
args = parser.parse_args()
if hasattr(args, 'limit') and not 1 <= args.limit <= 1000:
parser.error('--limit must be between 1 and 1000')
if hasattr(args, 'lines') and (args.lines < 1 or args.start < 1):
parser.error('--start and --lines must be positive')
if args.command == 'verify':
return verify()
plan = None
if getattr(args, 'plan', None):
from evidence import read_plan
plan = read_plan(args.plan)
with connect() as db:
if args.command == 'stats':
print(db.execute("SELECT value FROM metadata WHERE key='coverage'").fetchone()[0])
elif args.command == 'search':
tokens = re.findall(r'[\w.]+', args.query, flags=re.UNICODE)
if not tokens:
raise ValueError('Query needs at least one word')
query = (' OR ' if args.any else ' AND ').join('"' + x + '"' for x in tokens)
rows = db.execute('''SELECT pages.path,pages.title,pages.category,
snippet(search,2,'[',']',' … ',36) AS excerpt,bm25(search,0,8,1) AS rank
FROM search JOIN pages ON pages.rowid=search.rowid
WHERE search MATCH ? AND (? IS NULL OR pages.category=?) ORDER BY rank LIMIT ?''',
(query, args.category, args.category, args.limit)).fetchall()
for row in rows:
excerpt = re.sub(r'\s+', ' ', row['excerpt']).strip()
print(f"{row['path']} | {row['title']} [{row['category']}]\n{excerpt}\n")
if not rows:
print('No results. Try fewer English API terms, --any, or symbol.')
elif args.command == 'symbol':
escaped = args.query.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_')
rows = db.execute('''SELECT name,role,uri FROM symbols WHERE name LIKE ? ESCAPE '\\'
ORDER BY CASE WHEN name=? COLLATE NOCASE THEN 0 WHEN name LIKE ? ESCAPE '\\' THEN 1 ELSE 2 END,length(name),name LIMIT ?''',
('%' + escaped + '%', args.query, escaped + '%', args.limit)).fetchall()
for row in rows:
print(f"{row['name']} [{row['role']}] -> {row['uri']}")
if not rows:
print('No symbols found. Try a shorter name or search descriptive terms.')
elif args.command == 'read':
page, anchor = resolve(db, args.target)
if plan:
from evidence import allowed_page
if not allowed_page(plan, page):
raise ValueError('Page is outside selected features and previously read links. Select an evidence-backed feature/card or follow a documented link first.')
row = db.execute('SELECT title,body FROM pages WHERE path=?', (page,)).fetchone()
body = row['body']
if anchor:
bounds = db.execute('SELECT start,end FROM anchors WHERE page=? AND anchor=?', (page, anchor)).fetchone()
if not bounds:
raise ValueError(f'Anchor not found: {page}#{anchor}')
body = body[bounds['start']:bounds['end']]
label = page + ('#' + anchor if anchor else '')
total, last = show_lines(label, body, args.start, args.lines)
if plan:
from evidence import record_read
links = set()
for href in re.findall(r'<([^<>]+)>', body):
parsed = urlsplit(href)
if not parsed.scheme and not parsed.netloc:
linked = posixpath.normpath(posixpath.join(posixpath.dirname(page), unquote(parsed.path))) if parsed.path else page
if db.execute('SELECT 1 FROM pages WHERE path=?', (linked,)).fetchone():
links.add(linked)
record_read(args.plan, label, body, args.start, last, total, sorted(links))
print('Evidence read recorded in: ' + str(args.plan))
elif args.command == 'related':
page, anchor = resolve(db, args.target)
rows = db.execute('SELECT href,available FROM links WHERE page=? ORDER BY available DESC,href LIMIT ?', (page, args.limit + 1)).fetchall()
for row in rows[:args.limit]:
print(('LOCAL ' if row['available'] else 'MISSING ') + row['href'])
if len(rows) > args.limit:
print(f'More links available; increase --limit (current {args.limit}).')
return 0
def formatted_lines(body):
lines, in_code = [], False
for line in body.splitlines():
if line.strip() == '```':
in_code = not in_code
if not in_code:
line = line.rstrip()
if not line and (not lines or not lines[-1]):
continue
lines.append(line)
return lines
def show_lines(label, body, start, count):
lines = formatted_lines(body)
end = min(start + count - 1, len(lines))
print(f'SOURCE: {label} | lines {start}-{end} of {len(lines)}')
for number, line in enumerate(lines[start - 1:end], start):
print(f'{number:5d} {line}')
if end < len(lines):
print(f'CONTINUES: --start {end + 1} --lines {count}')
return len(lines), end
if __name__ == '__main__':
try:
sys.exit(main())
except (ValueError, KeyError, sqlite3.Error, UnicodeDecodeError, FileNotFoundError, OSError) as exc:
print(f'Error: {exc}', file=sys.stderr)
sys.exit(2)
scripts/run_blender.py
#!/usr/bin/env python3
"""Launch a bpy script in Blender; this host script uses only Python's stdlib."""
import argparse
import json
import math
import os
from pathlib import Path
import shutil
import signal
import subprocess
import sys
def executable_path(value):
"""Accept an executable path, PATH command, or macOS .app bundle."""
expanded = Path(value).expanduser()
if expanded.suffix.lower() == ".app" and expanded.is_dir():
for name in ("Blender", "blender"):
candidate = expanded / "Contents" / "MacOS" / name
if candidate.is_file() and os.access(candidate, os.X_OK):
return str(candidate.resolve())
located = shutil.which(str(expanded))
if located:
return str(Path(located).resolve())
if expanded.is_file() and os.access(expanded, os.X_OK):
return str(expanded.resolve())
raise ValueError("Blender executable not found or not executable: " + value)
def discover_blender(explicit=None):
requested = explicit or os.environ.get("BLENDER_BIN")
if requested:
return executable_path(requested)
candidates = ["blender"]
if sys.platform == "darwin":
candidates.extend([
"/Applications/Blender.app",
str(Path.home() / "Applications" / "Blender.app"),
])
for candidate in candidates:
try:
return executable_path(candidate)
except ValueError:
pass
raise ValueError("Blender was not found. Set BLENDER_BIN or pass --blender /path/to/blender.")
def existing_file(value):
path = Path(value).expanduser().resolve()
if not path.is_file():
raise argparse.ArgumentTypeError("File does not exist: " + str(path))
return path
def positive_timeout(value):
number = float(value)
if not math.isfinite(number) or number <= 0:
raise argparse.ArgumentTypeError("Timeout must be a positive, finite number of seconds.")
return number
def build_command(blender, script, blend=None, script_args=()):
# Blender processes options in order. Load data BEFORE executing the script.
command = [blender, "--background", "--factory-startup", "--disable-autoexec"]
if blend is not None:
command.append(str(blend))
command.extend(["--python-exit-code", "1", "--python", str(script)])
if script_args:
command.extend(["--", *script_args])
return command
def stop_process(process):
"""Stop this invocation; on POSIX include children in its new process group."""
if process.poll() is not None:
return
try:
if os.name == "posix":
os.killpg(process.pid, signal.SIGTERM)
else:
process.terminate()
process.wait(timeout=2)
except subprocess.TimeoutExpired:
if os.name == "posix":
os.killpg(process.pid, signal.SIGKILL)
else:
process.kill()
process.wait()
except ProcessLookupError:
process.wait()
def main(argv=None):
arguments = list(sys.argv[1:] if argv is None else argv)
if "--" in arguments:
separator = arguments.index("--")
runner_args, script_args = arguments[:separator], arguments[separator + 1:]
else:
runner_args, script_args = arguments, []
parser = argparse.ArgumentParser(
description=__doc__,
epilog="Script arguments must follow --. The script controls its own outputs; this runner does not save files.",
)
parser.add_argument("--blender", help="Executable or macOS .app; overrides BLENDER_BIN and PATH discovery.")
parser.add_argument("--script", type=existing_file, required=True, help="Python file executed inside Blender.")
parser.add_argument("--blend", type=existing_file, help="Existing .blend to load before the script.")
parser.add_argument("--timeout", type=positive_timeout, default=300.0, help="Maximum seconds; default 300. Increase for long renders.")
parser.add_argument("--dry-run", action="store_true", help="Print the resolved argv as JSON without launching Blender.")
parser.add_argument("--plan", type=existing_file, help="Required evidence plan for task scripts; the bundled read-only probe is exempt.")
args = parser.parse_args(runner_args)
bundled_probe = Path(__file__).resolve().with_name('probe_blender.py')
if args.script != bundled_probe:
if args.plan is None:
parser.error('A task script requires --plan. Read the capability overview, select features, read source and seal an evidence plan first.')
try:
from evidence import validate
validate(args.plan, args.script)
except (ValueError, KeyError, FileNotFoundError, SyntaxError) as error:
parser.error(str(error))
try:
blender = discover_blender(args.blender)
except ValueError as error:
parser.error(str(error))
command = build_command(blender, args.script, args.blend, script_args)
if args.dry_run:
print(json.dumps({"argv": command, "timeout_seconds": args.timeout}, ensure_ascii=False, indent=2))
return 0
print("Blender argv: " + json.dumps(command, ensure_ascii=False), file=sys.stderr, flush=True)
try:
process = subprocess.Popen(command, start_new_session=(os.name == "posix"))
except OSError as error:
print("Could not launch Blender: " + str(error), file=sys.stderr)
return 2
try:
result = process.wait(timeout=args.timeout)
return 128 - result if result < 0 else result
except subprocess.TimeoutExpired:
stop_process(process)
print("Blender exceeded timeout ({} seconds).".format(args.timeout), file=sys.stderr)
return 124
except KeyboardInterrupt:
stop_process(process)
return 130
if __name__ == "__main__":
raise SystemExit(main())
scripts/evidence.py
#!/usr/bin/env python3
"""Evidence-plan checks for the documented Blender workflow.
This validates traceability and stale inputs, not the model's internal knowledge
or whether a cited passage semantically proves an arbitrary Python program.
"""
import argparse
import ast
import hashlib
import json
from pathlib import Path
import sys
from features import find_card, load_catalog
def sha256(data):
return hashlib.sha256(data).hexdigest()
def read_plan(path):
plan = json.loads(Path(path).read_text(encoding='utf-8'))
catalog = load_catalog()
valid_catalogs = {catalog['catalog_sha256'], *catalog.get('compatible_catalog_sha256s', [])}
if plan.get('schema_version') != 2 or plan.get('catalog_sha256') not in valid_catalogs:
raise ValueError('Evidence plan is missing or belongs to a different capability catalog')
ids = plan.get('selected_features', [])
if not ids or not plan.get('request', '').strip():
raise ValueError('Plan must select documented features for a concrete request')
cards = [find_card(catalog, identifier) for identifier in ids]
seeds = sorted({ref for card in cards for ref in card['next_queries'] + card.get('api_refs', [])})
if plan.get('seed_refs') != seeds:
raise ValueError('Plan seed references differ from selected feature data')
return plan
def write_plan(path, plan):
Path(path).write_text(json.dumps(plan, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
def merge_ranges(ranges):
result = []
for start, end in sorted(ranges):
if result and start <= result[-1][1] + 1:
result[-1][1] = max(end, result[-1][1])
else:
result.append([start, end])
return result
def record_read(path, ref, body, first, last, total, links):
if not body.strip() or total < 1 or not 1 <= first <= last <= total:
raise ValueError('No source lines displayed; read the full page or a nonempty anchor before recording evidence')
plan = read_plan(path)
receipts = plan.setdefault('reads', [])
digest = sha256(body.encode('utf-8'))
existing = next((r for r in receipts if r['ref'] == ref and r['source_text_sha256'] == digest), None)
if existing is None:
existing = {'ref': ref, 'source_text_sha256': digest, 'ranges': [], 'total_lines': total, 'links': links}
receipts.append(existing)
existing['ranges'] = merge_ranges(existing['ranges'] + [[first, last]])
existing['complete'] = existing['ranges'] == [[1, total]]
# Reseal after new reads or changed evidence. No script is implicitly approved.
plan['script_sha256'] = None
write_plan(path, plan)
def allowed_page(plan, page):
targets = {ref.split('#')[0] for ref in plan['seed_refs']}
for read in plan['reads']:
targets.add(read['ref'].split('#')[0])
if read.get('complete'):
targets.update(read.get('links', []))
return page in targets
def operation_lines(script):
"""Conservative review list for Blender/imported-object attribute operations.
Every attribute expression is included except obvious standard-library module
access. Alias/object types cannot be inferred completely from arbitrary Python;
use general_python bindings for non-Blender helper lines with a reason.
"""
tree = ast.parse(script)
stdlib = set(getattr(sys, 'stdlib_module_names', ()))
standard_names = set()
blender_names = {'bpy', 'bmesh', 'mathutils', 'gpu', 'gpu_extras', 'bpy_extras', 'aud', 'blf', 'bl_math', 'imbuf', 'idprop', 'freestyle'}
imported_blender = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
root = alias.name.split('.')[0]
name = alias.asname or root
if root in stdlib:
standard_names.add(name)
if root in blender_names:
imported_blender.add(name)
elif isinstance(node, ast.ImportFrom):
root = (node.module or '').split('.')[0]
if root in stdlib:
standard_names.update(alias.asname or alias.name for alias in node.names)
if root in blender_names:
imported_blender.update(alias.asname or alias.name for alias in node.names)
known_blender = imported_blender | blender_names
def uses_blender(expression):
return any(isinstance(part, ast.Name) and part.id in known_blender for part in ast.walk(expression))
# Conservatively propagate ordinary assignments/iteration over known Blender
# objects. This deliberately over-approximates; arbitrary Python remains a
# manual semantic review, including types of external function parameters.
changed = True
while changed:
before = set(known_blender)
for node in ast.walk(tree):
targets, value = [], None
if isinstance(node, (ast.Assign, ast.AnnAssign, ast.NamedExpr)):
targets = node.targets if isinstance(node, ast.Assign) else [node.target]
value = node.value
elif isinstance(node, (ast.For, ast.AsyncFor)):
targets, value = [node.target], node.iter
if value is not None and uses_blender(value):
for target in targets:
if isinstance(target, (ast.Name, ast.Tuple, ast.List)):
known_blender.update(part.id for part in ast.walk(target) if isinstance(part, ast.Name))
changed = before != known_blender
needed, explicit = set(), set()
for node in ast.walk(tree):
if isinstance(node, ast.Attribute):
root = node
while isinstance(root, (ast.Attribute, ast.Subscript, ast.Call)):
root = root.func if isinstance(root, ast.Call) else root.value
if isinstance(root, ast.Name) and root.id in standard_names and root.id not in known_blender:
continue
needed.add(node.lineno)
if isinstance(root, ast.Name) and root.id in known_blender:
explicit.add(node.lineno)
elif isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
if node.func.id in known_blender or node.func.id in {'getattr', 'setattr', 'eval', 'exec', '__import__'}:
needed.add(node.lineno)
explicit.add(node.lineno)
return sorted(needed), explicit
def validate(path, script_path, check_digest=True):
from docs import connect, formatted_lines, resolve
plan = read_plan(path)
if plan.get('unresolved'):
raise ValueError('insufficient_skill_evidence: unresolved facts remain: ' + json.dumps(plan['unresolved'], ensure_ascii=False))
script_bytes = Path(script_path).read_bytes()
if check_digest and plan.get('script_sha256') != sha256(script_bytes):
raise ValueError('Script is unbound or changed since evidence review; bind and seal this exact file')
needed, explicit = operation_lines(script_bytes.decode('utf-8'))
covered = set()
receipts = {item['ref']: item for item in plan.get('reads', []) if item.get('complete')}
if not receipts:
raise ValueError('No complete source reads recorded; use docs.py read --plan')
if not any(ref.split('#')[0] in {s.split('#')[0] for s in plan['seed_refs']} for ref in receipts):
raise ValueError('No selected feature entry point has been read')
with connect() as db:
catalog = load_catalog()
# Refuse a catalog whose selected descriptions no longer match the API.
for identifier in plan['selected_features']:
card = find_card(catalog, identifier)
facts = card.get('evidence', []) if 'page' not in card else [{'ref': card['page'], 'source_text_sha256': card['source_text_sha256']}]
for fact in facts:
page, anchor = resolve(db, fact['ref'])
body = db.execute('SELECT body FROM pages WHERE path=?', (page,)).fetchone()['body']
if anchor:
bounds = db.execute('SELECT start,end FROM anchors WHERE page=? AND anchor=?', (page, anchor)).fetchone()
if bounds is None:
raise ValueError('Catalog evidence anchor no longer exists: ' + fact['ref'])
body = body[bounds['start']:bounds['end']]
if sha256(body.encode('utf-8')) != fact['source_text_sha256']:
raise ValueError('Selected catalog evidence differs from current source: ' + fact['ref'])
for ref, item in receipts.items():
page, anchor = resolve(db, ref)
body = db.execute('SELECT body FROM pages WHERE path=?', (page,)).fetchone()['body']
if anchor:
bounds = db.execute('SELECT start,end FROM anchors WHERE page=? AND anchor=?', (page, anchor)).fetchone()
if bounds is None:
raise ValueError('Evidence anchor no longer exists: ' + ref)
body = body[bounds['start']:bounds['end']]
if sha256(body.encode('utf-8')) != item['source_text_sha256']:
raise ValueError('Source changed since read: ' + ref)
total = len(formatted_lines(body))
if not body.strip() or total < 1 or item.get('total_lines') != total or item.get('ranges') != [[1, total]]:
raise ValueError('Complete evidence needs all nonempty source lines: ' + ref)
for binding in plan.get('bindings', []):
lines = binding.get('lines', [])
if not lines or not all(isinstance(n, int) and n > 0 for n in lines) or not binding.get('reason', '').strip():
raise ValueError('Bindings need positive line numbers and an explanation')
if binding.get('basis') == 'general_python':
if set(lines) & explicit:
raise ValueError('Explicit Blender/dynamic operations cannot be labeled general_python')
elif binding.get('basis') == 'source':
refs = binding.get('refs', [])
if not refs or not all(ref in receipts for ref in refs):
raise ValueError('Binding cites source that has not been completely read')
else:
raise ValueError('Binding basis must be source or general_python; model_memory is rejected')
covered.update(lines)
if set(needed) - covered:
raise ValueError('Operations without evidence bindings at lines: ' + ', '.join(map(str, sorted(set(needed) - covered))))
return {'ok': True, 'selected_features': plan['selected_features'], 'source_reads': len(receipts),
'reviewed_operation_lines': needed, 'script_sha256': sha256(script_bytes),
'scope': 'Traceability, complete recorded reads and unchanged bytes; semantic relevance of each citation and runtime success still require review.'}
def main():
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest='command', required=True)
p = sub.add_parser('inspect'); p.add_argument('--script', type=Path, required=True)
for name in ('seal', 'check'):
p = sub.add_parser(name); p.add_argument('--script', type=Path, required=True); p.add_argument('--plan', type=Path, required=True)
args = parser.parse_args()
if args.command == 'inspect':
needed, explicit = operation_lines(args.script.read_text())
lines = args.script.read_text().splitlines()
print(json.dumps({'review': [{'line': n, 'code': lines[n-1], 'requires_source': n in explicit,
'classification': 'known_blender_or_dynamic' if n in explicit else 'unknown_object_type_review_required'} for n in needed],
'note': 'requires_source=false means type is unknown, not permission to classify a Blender operation as general_python.'}, ensure_ascii=False, indent=2))
return 0
result = validate(args.plan, args.script, check_digest=args.command == 'check')
if args.command == 'seal':
plan = read_plan(args.plan)
plan['script_sha256'] = result['script_sha256']
write_plan(args.plan, plan)
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0
if __name__ == '__main__':
try:
raise SystemExit(main())
except (ValueError, KeyError, FileNotFoundError, SyntaxError, json.JSONDecodeError) as error:
print('Error: ' + str(error), file=sys.stderr)
raise SystemExit(2)