├── .gitignore ├── .vscode └── launch.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── helpers └── documentation_table.js ├── images └── icon.png ├── package.json ├── snippets └── snippets.json └── vsc-extension-quickstart.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vsix 3 | TABLE.md -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ] 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | TABLE.md 6 | helpers/** 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to the "blender-python-code-templates" extension will be documented in this file. 3 | 4 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 5 | 6 | ## [Unreleased] 7 | - Initial release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 nikorummukainen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # blender-python-code-templates 2 | 3 | Python snippets for Blender python code. 4 | 5 | > [GitHub repository link](https://github.com/nikorummukainen/blender-python-code-templates) 6 | 7 | > [Addon at VScode Marketplace](https://marketplace.visualstudio.com/items?itemName=blenderfreetimeprojects.blender-python-code-templates) 8 | 9 | > [Blender addon for turning files/blender texteditor content into .json snippets](https://github.com/nikorummukainen/blender-snippet-generator) 10 | 11 | ## Snippets 12 | 13 | |Prefixes|Description| 14 | |--------|-----------| 15 | |info addon|Blender addon info| 16 | |license gnu|GNU license| 17 | |license mit|MIT license| 18 | |keymap item|keymap item [More Info](https://docs.blender.org/api/current/bpy.types.KeyMapItem.html#bpy.types.KeyMapItem)| 19 | |keymaps|Register and unregister keymaps| 20 | |menu|Menu| 21 | |operator|Operator function class, without any imports or added functions| 22 | |operator modal|Modal operator function, without any imports or added functions| 23 | |operator modal draw|Modal operator draw function, without any imports or added functions| 24 | |panel|Panel| 25 | |pie menu|Pie Menu| 26 | |register|Register and Unregister Module| 27 | |template addon|Example of addon for adding object| 28 | |template background job|Example of script that shows how you can run blender from the command line (in background mode with no interface) to automate tasks, in this example it creates a text object, camera and light, then renders and/or saves it. This example also shows how you can parse command line options to scripts.| 29 | |template batch|Example of exporting each selected object into its own file| 30 | |template bmesh|Example of to get mesh representation for bmesh from edit-mode and updating it back after bmesh operation.| 31 | |template bmesh|Example of to get mesh representation for bmesh from active object and updating it back after bmesh operation.| 32 | |template keyingset|Example of generating Keying Set| 33 | |template nodes|Example of Implementation of custom nodes from Python| 34 | |template driver|Example of script defining functions to be used directly in drivers expressions to extend the builtin set of python functions.| 35 | |template script|Example of loading script relative to current blend file. This stub runs a python script relative to the currently open blend file, useful when editing scripts externally.| 36 | |template gamelogic|Example of gamelogic module. This module can be accessed by a python controller with its execution method set to 'Module'| 37 | |template gamelogic|Example of Simple gamelogic python script.| 38 | |template gamelogic|Example of gamelogic script this must be assigned to a python controller where it can access the object that owns it and the sensors/actuators that it connects to.| 39 | |template operator|Example of Template for file export operator, operator exports data from blender to .txt file| 40 | |template operator|Example of Template for file import operator, operator imports data from .txt to blender data| 41 | |template operator|Example of operator involving bmesh for creating and adding object to scene| 42 | |template operator|Example of Operator template for editing mesh UV's with bmesh| 43 | |template operator|Example of Blender modal operator function with imports, main function, register, unregister and testcall| 44 | |template ui list|Example of ui list template with adding it to blender with example panel| 45 | |template ui list|Example of simple ui list class with some filtering and bpy import| 46 | |template ui menu|Example of ui menu| 47 | |template ui simple panel|Example of ui panel class with import and register| 48 | |template ui panel|Example of ui panel class ui panel is created with examples of columns, buttons, rows, properties, with import and register, | 49 | |template ui pie menu|Example of 3d viewport pie menu| 50 | |template dynamic enum|This example script demonstrates a dynamic EnumProperty with custom icons.| 51 | |template ui previews|This example script demonstrates how to place a custom icon on a button menu entry.| 52 | 53 | ## Contribution Notes 54 | 55 | If adding or editing a snippet's prefix or description, to keep from having to edit the above table, you can generate it using the documentation_helper script, just `npm run table` and it will write a `TABLE.md` file with the above table so you can just copy and paste it to here. The `TABLE.md` file has been added to the `.gitignore` so it won't get accidently committed. 56 | 57 | ## Release Notes 58 | 59 | ### 0.9.0 beta 60 | now snippets include templates for Blender python api 61 | 62 | ### 0.9.1 63 | removed unnecessary newlines from templates. 64 | 65 | ### 0.9.4 66 | added link to marketplace page to README.md 67 | added github repository to package.json 68 | added link to github repository to README.md 69 | added link to snippet generator addon github repository to README.md 70 | 71 | new snippets: 72 | mit license 73 | 74 | ----------------------------------------------------------------------------------------------------------- 75 | 76 | # Thanks 77 | Alan for his [Blender VS Code Debugger](https://github.com/alanscodelog/blender-debugger-for-vscode) addon, it's awesome! 78 | 79 | Ideasman42 and others who have contributed to [the Blender Wiki](https://wiki.blender.org) for providing instructions on [how to build Blender as python module](https://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule). Now my linter understands Blender. 80 | 81 | Jacques Lucke's awesome Blender addon: [Code Autocomplete](https://www.blendermarket.com/products/code-autocomplete). 82 | 83 | Blender developers! for providing the awesome package known as Blender and the python code templates. -------------------------------------------------------------------------------- /helpers/documentation_table.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | fs.readFile("./snippets/snippets.json", 'utf8', function(err, data) { 4 | if (err) throw err; 5 | sort(data) 6 | }); 7 | 8 | 9 | function sort(data) { 10 | data = JSON.parse(data) 11 | let table = [] 12 | table.push("|Prefixes|Description|") 13 | table.push("|--------|-----------|") 14 | for (i in data) { 15 | var snippet = data[i] 16 | var prefix = "" 17 | var description = "" 18 | prefix = snippet["prefix"] 19 | description = snippet["description"] 20 | line = "|" + prefix.replace(/\s/g, " ") + "|" + description +"|" 21 | 22 | table.push(line) 23 | } 24 | table = table.join("\n") 25 | fs.writeFile("./TABLE.md", table) 26 | } -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikorummukainen/blender-python-code-templates/97c8bfd4324673adf9bbbdfa2f9db4a0bd2406d6/images/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blender-python-code-templates", 3 | "displayName": "Blender Python Code Templates", 4 | "description": "Templates for Blender Addon development. Templates translated are from Blender python templates and from Jacques Lucke's Code Autocomplete addon with my own additions.", 5 | "version": "0.9.4", 6 | "publisher": "blenderfreetimeprojects", 7 | "license": "MIT", 8 | "icon": "images/icon.png", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/nikorummukainen/blender-python-code-templates" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/nikorummukainen/blender-python-code-templates/issues" 15 | }, 16 | "engines": { 17 | "vscode": "^1.19.0" 18 | }, 19 | "categories": [ 20 | "Snippets" 21 | ], 22 | "contributes": { 23 | "snippets": [ 24 | { 25 | "language": "python", 26 | "path": "./snippets/snippets.json" 27 | } 28 | ] 29 | }, 30 | "scripts": { 31 | "table": "node helpers/documentation_table.js" 32 | } 33 | } -------------------------------------------------------------------------------- /snippets/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "addon_info": { 3 | "prefix": "info addon", 4 | "body": [ 5 | "bl_info = {", 6 | "\t\"name\": \"${1:My Addon Name}\",", 7 | "\t\"description\": \"${2:Description of this addon}\",", 8 | "\t\"author\": \"${3:Authors name}\",", 9 | "\t\"version\": (${4:0, 0, 1}),", 10 | "\t\"blender\": (${5:2, 79, 0}),", 11 | "\t\"location\": \"${6:View3D}\",", 12 | "\t\"warning\": \"This addon is still in development.\",", 13 | "\t\"wiki_url\": \"\",", 14 | "\t\"category\": \"${7:Object}\" }", 15 | "\t" 16 | ], 17 | "description": "Blender addon info" 18 | }, 19 | "GNU_license": { 20 | "prefix": "license gnu", 21 | "body": [ 22 | "'''", 23 | "Copyright (C) ${1:2018} ${2:ADDONCREATORNAME}", 24 | "${3:ADDONCREATORNAME@MAIL.COM}", 25 | "", 26 | "Created by ${2:ADDONCREATORNAME}", 27 | "", 28 | "\tThis program is free software: you can redistribute it and/or modify", 29 | "\tit under the terms of the GNU General Public License as published by", 30 | "\tthe Free Software Foundation, either version 3 of the License, or", 31 | "\t(at your option) any later version.", 32 | "", 33 | "\tThis program is distributed in the hope that it will be useful,", 34 | "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of", 35 | "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", 36 | "\tGNU General Public License for more details.", 37 | "", 38 | "\tYou should have received a copy of the GNU General Public License", 39 | "\talong with this program. If not, see .", 40 | "'''" 41 | ], 42 | "description": "GNU license" 43 | }, 44 | "license_MIT": { 45 | "prefix": "license mit", 46 | "body": [ 47 | "MIT License", 48 | "", 49 | "Copyright (c) ${1:2018} ${2:AUTHORSNAME}", 50 | "", 51 | "Permission is hereby granted, free of charge, to any person obtaining a copy", 52 | "of this software and associated documentation files (the \"Software\"), to deal", 53 | "in the Software without restriction, including without limitation the rights", 54 | "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", 55 | "copies of the Software, and to permit persons to whom the Software is", 56 | "furnished to do so, subject to the following conditions:", 57 | "", 58 | "The above copyright notice and this permission notice shall be included in all", 59 | "copies or substantial portions of the Software.", 60 | "", 61 | "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", 62 | "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", 63 | "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", 64 | "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", 65 | "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", 66 | "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", 67 | "SOFTWARE." 68 | ], 69 | "description": "MIT license" 70 | }, 71 | "keymap_item": { 72 | "prefix": "keymap item", 73 | "body": [ 74 | "kmi = km.keymap_items.new(", 75 | "\tname=\"${1:keymapname}\",", 76 | "\tidname=\"${2:Operator.bl_idname}\",", 77 | "\ttype=\"${3:KEYMAP}\",", 78 | "\tvalue=\"${4:PRESS}\",", 79 | "\tshift=${5:False},", 80 | "\tctrl=${6:False},", 81 | "\talt = ${7:False},", 82 | "\toskey=${8:False}", 83 | "\t$0)" 84 | ], 85 | "description": "keymap item [more info](https://docs.blender.org/api/current/bpy.types.KeyMapItem.html#bpy.types.KeyMapItem)" 86 | }, 87 | "keymap": { 88 | "prefix": "keymaps", 89 | "body": [ 90 | "addon_keymaps = []", 91 | "def register_keymaps():", 92 | "\taddon = bpy.context.window_manager.keyconfigs.addon", 93 | "\tkm = addon.keymaps.new(name = \"3D View\", space_type = \"VIEW_3D\")", 94 | "\t# insert keymap items here", 95 | "\taddon_keymaps.append(km)", 96 | "", 97 | "def unregister_keymaps():", 98 | "\twm = bpy.context.window_manager", 99 | "\tfor km in addon_keymaps:", 100 | "\t\tfor kmi in km.keymap_items:", 101 | "\t\t\tkm.keymap_items.remove(kmi)", 102 | "\t\twm.keyconfigs.addon.keymaps.remove(km)", 103 | "\taddon_keymaps.clear()" 104 | ], 105 | "description": "Register and unregister keymaps" 106 | }, 107 | "menu": { 108 | "prefix": "menu", 109 | "body": [ 110 | "class ${1:MenuClassName}(bpy.types.Menu):", 111 | "\tbl_idname = \"${2:view3d.menuname}\"", 112 | "\tbl_label = \"${3:Menu name}\"", 113 | "", 114 | "\tdef draw(self, context):", 115 | "\t\tlayout = self.layout", 116 | "\t\t$0" 117 | ], 118 | "description": "Menu" 119 | }, 120 | 121 | "operator_simple":{ 122 | "prefix": "operator", 123 | "body": [ 124 | "class ${1:MyClassName}(bpy.types.Operator):", 125 | "\tbl_idname = \"${2:my_operator.my_class_name}\"", 126 | "\tbl_label = \"${3:My Class Name}\"", 127 | "\tbl_description = \"${4:Description that shows in blender tooltips}\"", 128 | "\tbl_options = {\"REGISTER\"}", 129 | "", 130 | "\t@classmethod", 131 | "\tdef poll(cls, context):", 132 | "\t\treturn True", 133 | "", 134 | "\tdef execute(self, context):", 135 | "\t\t$0", 136 | "\t\treturn {\"FINISHED\"}", 137 | "" 138 | ], 139 | "description": "Operator function class, without any imports or added functions" 140 | }, 141 | "modal_operator":{ 142 | "prefix": "operator modal", 143 | "body": [ 144 | "class ${1:MyClassName}(bpy.types.Operator):", 145 | "\tbl_idname = \"${2:my_operator.my_class_name}\"", 146 | "\tbl_label = \"${3:My Class Name}\"", 147 | "\tbl_description = \"${4:Description that shows in blender tooltips}\"", 148 | "\tbl_options = {'REGISTER'}", 149 | "", 150 | "\t@classmethod", 151 | "\tdef poll(cls, context):", 152 | "\t\treturn True", 153 | "", 154 | "\tdef invoke(self, context, event):", 155 | "\t\tcontext.window_manager.modal_handler_add(self)", 156 | "\t\treturn {\"RUNNING_MODAL\"}", 157 | "", 158 | "\tdef modal(self, context, event):", 159 | "\t\t", 160 | "\t\tif event.type == \"LEFTMOUSE\":", 161 | "\t\t\treturn {\"FINISHED\"}", 162 | "\t\t", 163 | "\t\tif event.type in {\"RIGHTMOUSE\", \"ESC\"}:", 164 | "\t\t\treturn {\"CANCELLED\"}", 165 | "\t\t$0", 166 | "\t\treturn {\"RUNNING_MODAL\"}", 167 | "" 168 | ], 169 | "description": "Modal operator function, without any imports or added functions" 170 | }, 171 | "modal_operator_draw":{ 172 | "prefix": "operator modal draw", 173 | "body": [ 174 | "class ${1:MyClassName}(bpy.types.Operator):", 175 | "\tbl_idname = \"${2:my_operator.my_class_name}\"", 176 | "\tbl_label = \"${3:My Class Name}\"", 177 | "\tbl_description = \"${4:Description that shows in blender tooltips}\"", 178 | "\tbl_options = {'REGISTER'}", 179 | "", 180 | "\t@classmethod", 181 | "\tdef poll(cls, context):", 182 | "\t\treturn True", 183 | "", 184 | "\tdef invoke(self, context, event):", 185 | "\t\tself._handle = bpy.types.SpaceView3D.draw_handler_add(", 186 | "\t\t\tself.draw_callback_px, args, \"WINDOW\", \"POST_PIXEL\")", 187 | "\t\tcontext.window_manager.modal_handler_add(self)", 188 | "\t\treturn {\"RUNNING_MODAL\"}", 189 | "", 190 | "\tdef modal(self, context, event):", 191 | "\t\t", 192 | "\t\tif event.type == \"LEFTMOUSE\":", 193 | "\t\t\treturn self.finish()", 194 | "\t\t", 195 | "\t\tif event.type in {\"RIGHTMOUSE\", \"ESC\"}:", 196 | "\t\t\treturn self.cancelled()", 197 | "\t\t$0", 198 | "\t\treturn {\"RUNNING_MODAL\"}", 199 | "", 200 | "\tdef finish(self):", 201 | "\t\tbpy.types.SpaceView3D.draw_handler_remove(self._handle, \"WINDOW\")", 202 | "\t\treturn {\"FINISHED\"}", 203 | "", 204 | "\tdef cancelled(self):", 205 | "\t\tbpy.types.SpaceView3D.draw_handler_remove(self._handle, \"WINDOW\")", 206 | "\t\treturn {\"CANCELLED\"}", 207 | "", 208 | "\tdef draw_callback_px(tmp, self, context):", 209 | "\t\tpass", 210 | "" 211 | ], 212 | "description": "Modal operator draw function, without any imports or added functions" 213 | }, 214 | "panel": { 215 | "prefix": "panel", 216 | "body": [ 217 | "class ${1:PanelClassName}(bpy.types.Panel):", 218 | "\tbl_idname = \"${2:panelname}\"", 219 | "\tbl_label = \"${3:Panelname}\"", 220 | "\tbl_space_type = \"${4:VIEW_3D}\"", 221 | "\tbl_region_type = \"${5:TOOLS}\"", 222 | "\tbl_category = \"${6:category}\"", 223 | "", 224 | "\tdef draw(self, context):", 225 | "\t\tlayout = self.layout", 226 | "\t\t$0" 227 | ], 228 | "description": "Panel" 229 | }, 230 | "pie_menu": { 231 | "prefix": "pie menu", 232 | "body": [ 233 | "class ${1:ClassMenuName}(bpy.types.Menu):", 234 | "\tbl_idname = \"${2:view3d.menuname}\"", 235 | "\tbl_label = \"${3:Menuname}\"", 236 | "", 237 | "\tdef draw(self, context):", 238 | "\t\tpie = self.layout.menu_pie()", 239 | "\t\t$0" 240 | ], 241 | "description": "Pie Menu" 242 | }, 243 | "register_functions": { 244 | "prefix": "register", 245 | "body": [ 246 | "def register():", 247 | "\tbpy.utils.register_module(__name__)", 248 | "", 249 | "def unregister():", 250 | "\tbpy.utils.unregister_module(__name__)", 251 | "", 252 | "if __name__ == \"__main__\":", 253 | "\tregister()" 254 | ], 255 | "description": "Register and Unregister Module" 256 | }, 257 | "template_addon_add_object":{ 258 | "prefix": "template addon", 259 | "body": [ 260 | "bl_info = {", 261 | "\t\"name\": \"New Object\",", 262 | "\t\"author\": \"Your Name Here\",", 263 | "\t\"version\": (1, 0),", 264 | "\t\"blender\": (2, 75, 0),", 265 | "\t\"location\": \"View3D > Add > Mesh > New Object\",", 266 | "\t\"description\": \"Adds a new Mesh Object\",", 267 | "\t\"warning\": \"\",", 268 | "\t\"wiki_url\": \"\",", 269 | "\t\"category\": \"Add Mesh\",", 270 | "\t}", 271 | "", 272 | "", 273 | "import bpy", 274 | "from bpy.types import Operator", 275 | "from bpy.props import FloatVectorProperty", 276 | "from bpy_extras.object_utils import AddObjectHelper, object_data_add", 277 | "from mathutils import Vector", 278 | "", 279 | "", 280 | "def add_object(self, context):", 281 | "\tscale_x = self.scale.x", 282 | "\tscale_y = self.scale.y", 283 | "", 284 | "\tverts = [Vector((-1 * scale_x, 1 * scale_y, 0)),", 285 | "\t Vector((1 * scale_x, 1 * scale_y, 0)),", 286 | "\t Vector((1 * scale_x, -1 * scale_y, 0)),", 287 | "\t Vector((-1 * scale_x, -1 * scale_y, 0)),", 288 | "\t ]", 289 | "", 290 | "\tedges = []", 291 | "\tfaces = [[0, 1, 2, 3]]", 292 | "", 293 | "\tmesh = bpy.data.meshes.new(name=\"New Object Mesh\")", 294 | "\tmesh.from_pydata(verts, edges, faces)", 295 | "\t# useful for development when the mesh may be invalid.", 296 | "\t# mesh.validate(verbose=True)", 297 | "\tobject_data_add(context, mesh, operator=self)", 298 | "", 299 | "", 300 | "class OBJECT_OT_add_object(Operator, AddObjectHelper):", 301 | "\t\"\"\"Create a new Mesh Object\"\"\"", 302 | "\tbl_idname = \"mesh.add_object\"", 303 | "\tbl_label = \"Add Mesh Object\"", 304 | "\tbl_options = {'REGISTER', 'UNDO'}", 305 | "", 306 | "\tscale = FloatVectorProperty(", 307 | "\t\t\tname=\"scale\",", 308 | "\t\t\tdefault=(1.0, 1.0, 1.0),", 309 | "\t\t\tsubtype='TRANSLATION',", 310 | "\t\t\tdescription=\"scaling\",", 311 | "\t\t\t)", 312 | "", 313 | "\tdef execute(self, context):", 314 | "", 315 | "\t\tadd_object(self, context)", 316 | "", 317 | "\t\treturn {'FINISHED'}", 318 | "", 319 | "", 320 | "# Registration", 321 | "", 322 | "def add_object_button(self, context):", 323 | "\tself.layout.operator(", 324 | "\t\tOBJECT_OT_add_object.bl_idname,", 325 | "\t\ttext=\"Add Object\",", 326 | "\t\ticon='PLUGIN')", 327 | "", 328 | "", 329 | "# This allows you to right click on a button and link to the manual", 330 | "def add_object_manual_map():", 331 | "\turl_manual_prefix = \"https://docs.blender.org/manual/en/dev/\"", 332 | "\turl_manual_mapping = (", 333 | "\t\t(\"bpy.ops.mesh.add_object\", \"editors/3dview/object\"),", 334 | "\t\t)", 335 | "\treturn url_manual_prefix, url_manual_mapping", 336 | "", 337 | "", 338 | "def register():", 339 | "\tbpy.utils.register_class(OBJECT_OT_add_object)", 340 | "\tbpy.utils.register_manual_map(add_object_manual_map)", 341 | "\tbpy.types.INFO_MT_mesh_add.append(add_object_button)", 342 | "", 343 | "", 344 | "def unregister():", 345 | "\tbpy.utils.unregister_class(OBJECT_OT_add_object)", 346 | "\tbpy.utils.unregister_manual_map(add_object_manual_map)", 347 | "\tbpy.types.INFO_MT_mesh_add.remove(add_object_button)", 348 | "", 349 | "", 350 | "if __name__ == \"__main__\":", 351 | "\tregister()" 352 | ], 353 | "description": "Example of addon for adding object" 354 | }, 355 | "template_background_job":{ 356 | "prefix": "template background job", 357 | "body": [ 358 | "# This script is an example of how you can run blender from the command line", 359 | "# (in background mode with no interface) to automate tasks, in this example it", 360 | "# creates a text object, camera and light, then renders and/or saves it.", 361 | "# This example also shows how you can parse command line options to scripts.", 362 | "#", 363 | "# Example usage for this test.", 364 | "# blender --background --factory-startup --python \\$HOME/background_job.py -- \\", 365 | "# --text=\"Hello World\" \\", 366 | "# --render=\"/tmp/hello\" \\", 367 | "# --save=\"/tmp/hello.blend\"", 368 | "#", 369 | "# Notice:", 370 | "# '--factory-startup' is used to avoid the user default settings from", 371 | "# interfering with automated scene generation.", 372 | "#", 373 | "# '--' causes blender to ignore all following arguments so python can use them.", 374 | "#", 375 | "# See blender --help for details.", 376 | "", 377 | "import bpy", 378 | "", 379 | "", 380 | "def example_function(text, save_path, render_path):", 381 | "", 382 | "\tscene = bpy.context.scene", 383 | "", 384 | "\t# Clear existing objects.", 385 | "\tscene.camera = None", 386 | "\tfor obj in scene.objects:", 387 | "\t\tscene.objects.unlink(obj)", 388 | "", 389 | "\ttxt_data = bpy.data.curves.new(name=\"MyText\", type='FONT')", 390 | "", 391 | "\t# Text Object", 392 | "\ttxt_ob = bpy.data.objects.new(name=\"MyText\", object_data=txt_data)", 393 | "\tscene.objects.link(txt_ob) # add the data to the scene as an object", 394 | "\ttxt_data.body = text # the body text to the command line arg given", 395 | "\ttxt_data.align = 'CENTER' # center text", 396 | "", 397 | "\t# Camera", 398 | "\tcam_data = bpy.data.cameras.new(\"MyCam\")", 399 | "\tcam_ob = bpy.data.objects.new(name=\"MyCam\", object_data=cam_data)", 400 | "\tscene.objects.link(cam_ob) # instance the camera object in the scene", 401 | "\tscene.camera = cam_ob # set the active camera", 402 | "\tcam_ob.location = 0.0, 0.0, 10.0", 403 | "", 404 | "\t# Lamp", 405 | "\tlamp_data = bpy.data.lamps.new(\"MyLamp\", 'POINT')", 406 | "\tlamp_ob = bpy.data.objects.new(name=\"MyCam\", object_data=lamp_data)", 407 | "\tscene.objects.link(lamp_ob)", 408 | "\tlamp_ob.location = 2.0, 2.0, 5.0", 409 | "", 410 | "\tif save_path:", 411 | "\t\tbpy.ops.wm.save_as_mainfile(filepath=save_path)", 412 | "", 413 | "\tif render_path:", 414 | "\t\trender = scene.render", 415 | "\t\trender.use_file_extension = True", 416 | "\t\trender.filepath = render_path", 417 | "\t\tbpy.ops.render.render(write_still=True)", 418 | "", 419 | "", 420 | "def main():", 421 | "\timport sys # to get command line args", 422 | "\timport argparse # to parse options for us and print a nice help message", 423 | "", 424 | "\t# get the args passed to blender after \"--\", all of which are ignored by", 425 | "\t# blender so scripts may receive their own arguments", 426 | "\targv = sys.argv", 427 | "", 428 | "\tif \"--\" not in argv:", 429 | "\t\targv = [] # as if no args are passed", 430 | "\telse:", 431 | "\t\targv = argv[argv.index(\"--\") + 1:] # get all args after \"--\"", 432 | "", 433 | "\t# When --help or no args are given, print this help", 434 | "\tusage_text = (", 435 | "\t\t\t\"Run blender in background mode with this script:\"", 436 | "\t\t\t\" blender --background --python \" + __file__ + \" -- [options]\"", 437 | "\t\t\t)", 438 | "", 439 | "\tparser = argparse.ArgumentParser(description=usage_text)", 440 | "", 441 | "\t# Example utility, add some text and renders or saves it (with options)", 442 | "\t# Possible types are: string, int, long, choice, float and complex.", 443 | "\tparser.add_argument(\"-t\", \"--text\", dest=\"text\", type=str, required=True,", 444 | "\t\t\thelp=\"This text will be used to render an image\")", 445 | "", 446 | "\tparser.add_argument(\"-s\", \"--save\", dest=\"save_path\", metavar='FILE',", 447 | "\t\t\thelp=\"Save the generated file to the specified path\")", 448 | "\tparser.add_argument(\"-r\", \"--render\", dest=\"render_path\", metavar='FILE',", 449 | "\t\t\thelp=\"Render an image to the specified path\")", 450 | "", 451 | "\targs = parser.parse_args(argv) # In this example we wont use the args", 452 | "", 453 | "\tif not argv:", 454 | "\t\tparser.print_help()", 455 | "\t\treturn", 456 | "", 457 | "\tif not args.text:", 458 | "\t\tprint(\"Error: --text=\\\"some string\\\" argument not given, aborting.\")", 459 | "\t\tparser.print_help()", 460 | "\t\treturn", 461 | "", 462 | "\t# Run the example function", 463 | "\texample_function(args.text, args.save_path, args.render_path)", 464 | "", 465 | "\tprint(\"batch job finished, exiting\")", 466 | "", 467 | "", 468 | "if __name__ == \"__main__\":", 469 | "\tmain()" 470 | ], 471 | "description": "Example of script that shows how you can run blender from the command line (in background mode with no interface) to automate tasks, in this example it creates a text object, camera and light, then renders and/or saves it. This example also shows how you can parse command line options to scripts." 472 | }, 473 | "template_batch_export":{ 474 | "prefix": "template batch", 475 | "body": [ 476 | "# exports each selected object into its own file", 477 | "", 478 | "import bpy", 479 | "import os", 480 | "", 481 | "# export to blend file location", 482 | "basedir = os.path.dirname(bpy.data.filepath)", 483 | "", 484 | "if not basedir:", 485 | "\traise Exception(\"Blend file is not saved\")", 486 | "", 487 | "scene = bpy.context.scene", 488 | "", 489 | "obj_active = scene.objects.active", 490 | "selection = bpy.context.selected_objects", 491 | "", 492 | "bpy.ops.object.select_all(action='DESELECT')", 493 | "", 494 | "for obj in selection:", 495 | "", 496 | "\tobj.select = True", 497 | "", 498 | "\t# some exporters only use the active object", 499 | "\tscene.objects.active = obj", 500 | "", 501 | "\tname = bpy.path.clean_name(obj.name)", 502 | "\tfn = os.path.join(basedir, name)", 503 | "", 504 | "\tbpy.ops.export_scene.fbx(filepath=fn + \".fbx\", use_selection=True)", 505 | "", 506 | "\t## Can be used for multiple formats", 507 | "\t# bpy.ops.export_scene.x3d(filepath=fn + \".x3d\", use_selection=True)", 508 | "", 509 | "\tobj.select = False", 510 | "", 511 | "\tprint(\"written:\", fn)", 512 | "", 513 | "", 514 | "scene.objects.active = obj_active", 515 | "", 516 | "for obj in selection:", 517 | "\tobj.select = True" 518 | ], 519 | "description": "Example of exporting each selected object into its own file" 520 | }, 521 | "template_bmesh_simple_editmode":{ 522 | "prefix": "template bmesh", 523 | "body": [ 524 | "# This example assumes we have a mesh object in edit-mode", 525 | "", 526 | "import bpy", 527 | "import bmesh", 528 | "", 529 | "# Get the active mesh", 530 | "obj = bpy.context.edit_object", 531 | "me = obj.data", 532 | "", 533 | "", 534 | "# Get a BMesh representation", 535 | "bm = bmesh.from_edit_mesh(me)", 536 | "", 537 | "bm.faces.active = None", 538 | "", 539 | "# Modify the BMesh, can do anything here...", 540 | "for v in bm.verts:", 541 | "\tv.co.x += 1.0", 542 | "", 543 | "", 544 | "# Show the updates in the viewport", 545 | "# and recalculate n-gon tessellation.", 546 | "bmesh.update_edit_mesh(me, True)" 547 | ], 548 | "description": "Example of to get mesh representation for bmesh from edit-mode and updating it back after bmesh operation." 549 | }, 550 | "template_bmesh_simple_active_object":{ 551 | "prefix": "template bmesh", 552 | "body": [ 553 | "# This example assumes we have a mesh object selected", 554 | "", 555 | "import bpy", 556 | "import bmesh", 557 | "", 558 | "# Get the active mesh", 559 | "me = bpy.context.object.data", 560 | "", 561 | "", 562 | "# Get a BMesh representation", 563 | "bm = bmesh.new() # create an empty BMesh", 564 | "bm.from_mesh(me) # fill it in from a Mesh", 565 | "", 566 | "", 567 | "# Modify the BMesh, can do anything here...", 568 | "for v in bm.verts:", 569 | "\tv.co.x += 1.0", 570 | "", 571 | "", 572 | "# Finish up, write the bmesh back to the mesh", 573 | "bm.to_mesh(me)", 574 | "bm.free() # free and prevent further access" 575 | ], 576 | "description": "Example of to get mesh representation for bmesh from active object and updating it back after bmesh operation." 577 | }, 578 | "template_builtin_keyingset":{ 579 | "prefix": "template keyingset", 580 | "body": [ 581 | "import bpy", 582 | "", 583 | "", 584 | "class BUILTIN_KSI_hello(bpy.types.KeyingSetInfo):", 585 | "\tbl_label = \"Hello World KeyingSet\"", 586 | "", 587 | "\t# poll - test for whether Keying Set can be used at all", 588 | "\tdef poll(ksi, context):", 589 | "\t\treturn context.active_object or context.selected_objects", 590 | "", 591 | "\t# iterator - go over all relevant data, calling generate()", 592 | "\tdef iterator(ksi, context, ks):", 593 | "\t\tfor ob in context.selected_objects:", 594 | "\t\t\tksi.generate(context, ks, ob)", 595 | "", 596 | "\t# generator - populate Keying Set with property paths to use", 597 | "\tdef generate(ksi, context, ks, data):", 598 | "\t\tid_block = data.id_data", 599 | "", 600 | "\t\tks.paths.add(id_block, \"location\")", 601 | "", 602 | "\t\tfor i in range(5):", 603 | "\t\t\tks.paths.add(id_block, \"layers\", i, group_method='NAMED', group_name=\"5x Hello Layers\")", 604 | "", 605 | "\t\tks.paths.add(id_block, \"show_x_ray\", group_method='NONE')", 606 | "", 607 | "", 608 | "def register():", 609 | "\tbpy.utils.register_class(BUILTIN_KSI_hello)", 610 | "", 611 | "", 612 | "def unregister():", 613 | "\tbpy.utils.unregister_class(BUILTIN_KSI_hello)", 614 | "", 615 | "", 616 | "if __name__ == '__main__':", 617 | "\tregister()" 618 | ], 619 | "description": "Example of generating Keying Set" 620 | }, 621 | "template_custom_nodes":{ 622 | "prefix": "template nodes", 623 | "body": [ 624 | "import bpy", 625 | "from bpy.types import NodeTree, Node, NodeSocket", 626 | "", 627 | "# Implementation of custom nodes from Python", 628 | "", 629 | "", 630 | "# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.", 631 | "class MyCustomTree(NodeTree):", 632 | "\t# Description string", 633 | "\t'''A custom node tree type that will show up in the node editor header'''", 634 | "\t# Optional identifier string. If not explicitly defined, the python class name is used.", 635 | "\tbl_idname = 'CustomTreeType'", 636 | "\t# Label for nice name display", 637 | "\tbl_label = 'Custom Node Tree'", 638 | "\t# Icon identifier", 639 | "\tbl_icon = 'NODETREE'", 640 | "", 641 | "", 642 | "# Custom socket type", 643 | "class MyCustomSocket(NodeSocket):", 644 | "\t# Description string", 645 | "\t'''Custom node socket type'''", 646 | "\t# Optional identifier string. If not explicitly defined, the python class name is used.", 647 | "\tbl_idname = 'CustomSocketType'", 648 | "\t# Label for nice name display", 649 | "\tbl_label = 'Custom Node Socket'", 650 | "", 651 | "\t# Enum items list", 652 | "\tmy_items = [", 653 | "\t\t(\"DOWN\", \"Down\", \"Where your feet are\"),", 654 | "\t\t(\"UP\", \"Up\", \"Where your head should be\"),", 655 | "\t\t(\"LEFT\", \"Left\", \"Not right\"),", 656 | "\t\t(\"RIGHT\", \"Right\", \"Not left\")", 657 | "\t]", 658 | "", 659 | "\tmyEnumProperty = bpy.props.EnumProperty(name=\"Direction\", description=\"Just an example\", items=my_items, default='UP')", 660 | "", 661 | "\t# Optional function for drawing the socket input value", 662 | "\tdef draw(self, context, layout, node, text):", 663 | "\t\tif self.is_output or self.is_linked:", 664 | "\t\t\tlayout.label(text)", 665 | "\t\telse:", 666 | "\t\t\tlayout.prop(self, \"myEnumProperty\", text=text)", 667 | "", 668 | "\t# Socket color", 669 | "\tdef draw_color(self, context, node):", 670 | "\t\treturn (1.0, 0.4, 0.216, 0.5)", 671 | "", 672 | "", 673 | "# Mix-in class for all custom nodes in this tree type.", 674 | "# Defines a poll function to enable instantiation.", 675 | "class MyCustomTreeNode:", 676 | "\t@classmethod", 677 | "\tdef poll(cls, ntree):", 678 | "\t\treturn ntree.bl_idname == 'CustomTreeType'", 679 | "", 680 | "", 681 | "# Derived from the Node base type.", 682 | "class MyCustomNode(Node, MyCustomTreeNode):", 683 | "\t# === Basics ===", 684 | "\t# Description string", 685 | "\t'''A custom node'''", 686 | "\t# Optional identifier string. If not explicitly defined, the python class name is used.", 687 | "\tbl_idname = 'CustomNodeType'", 688 | "\t# Label for nice name display", 689 | "\tbl_label = 'Custom Node'", 690 | "\t# Icon identifier", 691 | "\tbl_icon = 'SOUND'", 692 | "", 693 | "\t# === Custom Properties ===", 694 | "\t# These work just like custom properties in ID data blocks", 695 | "\t# Extensive information can be found under", 696 | "\t# http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties", 697 | "\tmyStringProperty = bpy.props.StringProperty()", 698 | "\tmyFloatProperty = bpy.props.FloatProperty(default=3.1415926)", 699 | "", 700 | "\t# === Optional Functions ===", 701 | "\t# Initialization function, called when a new node is created.", 702 | "\t# This is the most common place to create the sockets for a node, as shown below.", 703 | "\t# NOTE: this is not the same as the standard __init__ function in Python, which is", 704 | "\t# a purely internal Python method and unknown to the node system!", 705 | "\tdef init(self, context):", 706 | "\t\tself.inputs.new('CustomSocketType', \"Hello\")", 707 | "\t\tself.inputs.new('NodeSocketFloat', \"World\")", 708 | "\t\tself.inputs.new('NodeSocketVector', \"!\")", 709 | "", 710 | "\t\tself.outputs.new('NodeSocketColor', \"How\")", 711 | "\t\tself.outputs.new('NodeSocketColor', \"are\")", 712 | "\t\tself.outputs.new('NodeSocketFloat', \"you\")", 713 | "", 714 | "\t# Copy function to initialize a copied node from an existing one.", 715 | "\tdef copy(self, node):", 716 | "\t\tprint(\"Copying from node \", node)", 717 | "", 718 | "\t# Free function to clean up on removal.", 719 | "\tdef free(self):", 720 | "\t\tprint(\"Removing node \", self, \", Goodbye!\")", 721 | "", 722 | "\t# Additional buttons displayed on the node.", 723 | "\tdef draw_buttons(self, context, layout):", 724 | "\t\tlayout.label(\"Node settings\")", 725 | "\t\tlayout.prop(self, \"myFloatProperty\")", 726 | "", 727 | "\t# Detail buttons in the sidebar.", 728 | "\t# If this function is not defined, the draw_buttons function is used instead", 729 | "\tdef draw_buttons_ext(self, context, layout):", 730 | "\t\tlayout.prop(self, \"myFloatProperty\")", 731 | "\t\t# myStringProperty button will only be visible in the sidebar", 732 | "\t\tlayout.prop(self, \"myStringProperty\")", 733 | "", 734 | "\t# Optional: custom label", 735 | "\t# Explicit user label overrides this, but here we can define a label dynamically", 736 | "\tdef draw_label(self):", 737 | "\t\treturn \"I am a custom node\"", 738 | "", 739 | "", 740 | "### Node Categories ###", 741 | "# Node categories are a python system for automatically", 742 | "# extending the Add menu, toolbar panels and search operator.", 743 | "# For more examples see release/scripts/startup/nodeitems_builtins.py", 744 | "", 745 | "import nodeitems_utils", 746 | "from nodeitems_utils import NodeCategory, NodeItem", 747 | "", 748 | "", 749 | "# our own base class with an appropriate poll function,", 750 | "# so the categories only show up in our own tree type", 751 | "class MyNodeCategory(NodeCategory):", 752 | "\t@classmethod", 753 | "\tdef poll(cls, context):", 754 | "\t\treturn context.space_data.tree_type == 'CustomTreeType'", 755 | "", 756 | "# all categories in a list", 757 | "node_categories = [", 758 | "\t# identifier, label, items list", 759 | "\tMyNodeCategory(\"SOMENODES\", \"Some Nodes\", items=[", 760 | "\t\t# our basic node", 761 | "\t\tNodeItem(\"CustomNodeType\"),", 762 | "\t\t]),", 763 | "\tMyNodeCategory(\"OTHERNODES\", \"Other Nodes\", items=[", 764 | "\t\t# the node item can have additional settings,", 765 | "\t\t# which are applied to new nodes", 766 | "\t\t# NB: settings values are stored as string expressions,", 767 | "\t\t# for this reason they should be converted to strings using repr()", 768 | "\t\tNodeItem(\"CustomNodeType\", label=\"Node A\", settings={", 769 | "\t\t\t\"myStringProperty\": repr(\"Lorem ipsum dolor sit amet\"),", 770 | "\t\t\t\"myFloatProperty\": repr(1.0),", 771 | "\t\t\t}),", 772 | "\t\tNodeItem(\"CustomNodeType\", label=\"Node B\", settings={", 773 | "\t\t\t\"myStringProperty\": repr(\"consectetur adipisicing elit\"),", 774 | "\t\t\t\"myFloatProperty\": repr(2.0),", 775 | "\t\t\t}),", 776 | "\t\t]),", 777 | "\t]", 778 | "", 779 | "", 780 | "def register():", 781 | "\tbpy.utils.register_class(MyCustomTree)", 782 | "\tbpy.utils.register_class(MyCustomSocket)", 783 | "\tbpy.utils.register_class(MyCustomNode)", 784 | "", 785 | "\tnodeitems_utils.register_node_categories(\"CUSTOM_NODES\", node_categories)", 786 | "", 787 | "", 788 | "def unregister():", 789 | "\tnodeitems_utils.unregister_node_categories(\"CUSTOM_NODES\")", 790 | "", 791 | "\tbpy.utils.unregister_class(MyCustomTree)", 792 | "\tbpy.utils.unregister_class(MyCustomSocket)", 793 | "\tbpy.utils.unregister_class(MyCustomNode)", 794 | "", 795 | "", 796 | "if __name__ == \"__main__\":", 797 | "\tregister()" 798 | ], 799 | "description": "Example of Implementation of custom nodes from Python" 800 | }, 801 | "template_driver_functions":{ 802 | "prefix": "template driver", 803 | "body": [ 804 | "# This script defines functions to be used directly in drivers expressions to", 805 | "# extend the builtin set of python functions.", 806 | "#", 807 | "# This can be executed on manually or set to 'Register' to", 808 | "# initialize thefunctions on file load.", 809 | "", 810 | "", 811 | "# two sample functions", 812 | "def invert(f):", 813 | "\t\"\"\" Simple function call:", 814 | "", 815 | "\t invert(val)", 816 | "\t\"\"\"", 817 | "\treturn 1.0 - f", 818 | "", 819 | "", 820 | "uuid_store = {}", 821 | "", 822 | "", 823 | "def slow_value(value, fac, uuid):", 824 | "\t\"\"\" Delay the value by a factor, use a unique string to allow", 825 | "\t use in multiple drivers without conflict:", 826 | "", 827 | "\t slow_value(val, 0.5, \"my_value\")", 828 | "\t\"\"\"", 829 | "\tvalue_prev = uuid_store.get(uuid, value)", 830 | "\tuuid_store[uuid] = value_new = (value_prev * fac) + (value * (1.0 - fac))", 831 | "\treturn value_new", 832 | "", 833 | "", 834 | "import bpy", 835 | "", 836 | "# Add variable defined in this script into the drivers namespace.", 837 | "bpy.app.driver_namespace[\"invert\"] = invert", 838 | "bpy.app.driver_namespace[\"slow_value\"] = slow_value" 839 | ], 840 | "description": "Example of script defining functions to be used directly in drivers expressions to extend the builtin set of python functions." 841 | }, 842 | "template_external_script_stub":{ 843 | "prefix": "template script", 844 | "body": [ 845 | "# This stub runs a python script relative to the currently open", 846 | "# blend file, useful when editing scripts externally.", 847 | "", 848 | "import bpy", 849 | "import os", 850 | "", 851 | "# Use your own script name here:", 852 | "filename = \"my_script.py\"", 853 | "", 854 | "filepath = os.path.join(os.path.dirname(bpy.data.filepath), filename)", 855 | "global_namespace = {\"__file__\": filepath, \"__name__\": \"__main__\"}", 856 | "with open(filepath, 'rb') as file:", 857 | "\texec(compile(file.read(), filepath, 'exec'), global_namespace)" 858 | ], 859 | "description": "Example of loading script relative to current blend file. This stub runs a python script relative to the currently open blend file, useful when editing scripts externally." 860 | }, 861 | "template_gamelogic_module":{ 862 | "prefix": "template gamelogic", 863 | "body": [ 864 | "# This module can be accessed by a python controller with", 865 | "# its execution method set to 'Module'", 866 | "# * Set the module string to \"gamelogic_module.main\" (without quotes)", 867 | "# * When renaming the script it MUST have a .py extension", 868 | "# * External text modules are supported as long as they are at", 869 | "# the same location as the blendfile or one of its libraries.", 870 | "", 871 | "import bge", 872 | "", 873 | "# variables defined here will only be set once when the", 874 | "# module is first imported. Set object specific vars", 875 | "# inside the function if you intend to use the module", 876 | "# with multiple objects.", 877 | "", 878 | "", 879 | "def main(cont):", 880 | "\town = cont.owner", 881 | "", 882 | "\tsens = cont.sensors['mySensor']", 883 | "\tactu = cont.actuators['myActuator']", 884 | "", 885 | "\tif sens.positive:", 886 | "\t\tcont.activate(actu)", 887 | "\telse:", 888 | "\t\tcont.deactivate(actu)", 889 | "", 890 | "# dont call main(bge.logic.getCurrentController()), the py controller will" 891 | ], 892 | "description": "Example of gamelogic module. This module can be accessed by a python controller with its execution method set to 'Module'" 893 | }, 894 | "template_gamelogic_simple":{ 895 | "prefix": "template gamelogic", 896 | "body": [ 897 | "import bge", 898 | "", 899 | "", 900 | "def main():", 901 | "", 902 | "\tcont = bge.logic.getCurrentController()", 903 | "\town = cont.owner", 904 | "", 905 | "\tsens = cont.sensors['mySensor']", 906 | "\tactu = cont.actuators['myActuator']", 907 | "", 908 | "\tif sens.positive:", 909 | "\t\tcont.activate(actu)", 910 | "\telse:", 911 | "\t\tcont.deactivate(actu)", 912 | "", 913 | "main()" 914 | ], 915 | "description": "Example of Simple gamelogic python script." 916 | }, 917 | "template_gamelogic":{ 918 | "prefix": "template gamelogic", 919 | "body": [ 920 | "# This script must be assigned to a python controller", 921 | "# where it can access the object that owns it and the sensors/actuators that it connects to.", 922 | "", 923 | "import bge", 924 | "", 925 | "# support for Vector(), Matrix() types and advanced functions like Matrix.Scale(...) and Matrix.Rotation(...)", 926 | "# import mathutils", 927 | "", 928 | "# for functions like getWindowWidth(), getWindowHeight()", 929 | "# import Rasterizer", 930 | "", 931 | "", 932 | "def main():", 933 | "\tcont = bge.logic.getCurrentController()", 934 | "", 935 | "\t# The KX_GameObject that owns this controller.", 936 | "\town = cont.owner", 937 | "", 938 | "\t# for scripts that deal with spacial logic", 939 | "\town_pos = own.worldPosition", 940 | "", 941 | "\t# Some example functions, remove to write your own script.", 942 | "\t# check for a positive sensor, will run on any object without errors.", 943 | "\tprint(\"Logic info for KX_GameObject\", own.name)", 944 | "\tinput = False", 945 | "", 946 | "\tfor sens in cont.sensors:", 947 | "\t\t# The sensor can be on another object, we may want to use it", 948 | "\t\town_sens = sens.owner", 949 | "\t\tprint(\" sensor:\", sens.name, end=\" \")", 950 | "\t\tif sens.positive:", 951 | "\t\t\tprint(\"(true)\")", 952 | "\t\t\tinput = True", 953 | "\t\telse:", 954 | "\t\t\tprint(\"(false)\")", 955 | "", 956 | "\tfor actu in cont.actuators:", 957 | "\t\t# The actuator can be on another object, we may want to use it", 958 | "\t\town_actu = actu.owner", 959 | "\t\tprint(\" actuator:\", actu.name)", 960 | "", 961 | "\t\t# This runs the actuator or turns it off", 962 | "\t\t# note that actuators will continue to run unless explicitly turned off.", 963 | "\t\tif input:", 964 | "\t\t\tcont.activate(actu)", 965 | "\t\telse:", 966 | "\t\t\tcont.deactivate(actu)", 967 | "", 968 | "\t# Its also good practice to get sensors and actuators by name", 969 | "\t# rather then index so any changes to their order wont break the script.", 970 | "", 971 | "\t# sens_key = cont.sensors[\"key_sensor\"]", 972 | "\t# actu_motion = cont.actuators[\"motion\"]", 973 | "", 974 | "\t# Loop through all other objects in the scene", 975 | "\tsce = bge.logic.getCurrentScene()", 976 | "\tprint(\"Scene Objects:\", sce.name)", 977 | "\tfor ob in sce.objects:", 978 | "\t\tprint(\" \", ob.name, ob.worldPosition)", 979 | "", 980 | "\t# Example where collision objects are checked for their properties", 981 | "\t# adding to our objects \"life\" property", 982 | "\t\"\"\"", 983 | "\tactu_collide = cont.sensors[\"collision_sens\"]", 984 | "\tfor ob in actu_collide.hitObjectList:", 985 | "\t\t# Check to see the object has this property", 986 | "\t\tif \"life\" in ob:", 987 | "\t\t\town[\"life\"] += ob[\"life\"]", 988 | "\t\t\tob[\"life\"] = 0", 989 | "\tprint(own[\"life\"])", 990 | "\t\"\"\"", 991 | "", 992 | "main()" 993 | ], 994 | "description": "Example of gamelogic script this must be assigned to a python controller where it can access the object that owns it and the sensors/actuators that it connects to." 995 | }, 996 | "template_operator_file_export":{ 997 | "prefix": "template operator", 998 | "body": [ 999 | "import bpy", 1000 | "", 1001 | "", 1002 | "def write_some_data(context, filepath, use_some_setting):", 1003 | "\tprint(\"running write_some_data...\")", 1004 | "\tf = open(filepath, 'w', encoding='utf-8')", 1005 | "\tf.write(\"Hello World %s\" % use_some_setting)", 1006 | "\tf.close()", 1007 | "", 1008 | "\treturn {'FINISHED'}", 1009 | "", 1010 | "", 1011 | "# ExportHelper is a helper class, defines filename and", 1012 | "# invoke() function which calls the file selector.", 1013 | "from bpy_extras.io_utils import ExportHelper", 1014 | "from bpy.props import StringProperty, BoolProperty, EnumProperty", 1015 | "from bpy.types import Operator", 1016 | "", 1017 | "", 1018 | "class ExportSomeData(Operator, ExportHelper):", 1019 | "\t\"\"\"This appears in the tooltip of the operator and in the generated docs\"\"\"", 1020 | "\tbl_idname = \"export_test.some_data\" # important since its how bpy.ops.import_test.some_data is constructed", 1021 | "\tbl_label = \"Export Some Data\"", 1022 | "", 1023 | "\t# ExportHelper mixin class uses this", 1024 | "\tfilename_ext = \".txt\"", 1025 | "", 1026 | "\tfilter_glob = StringProperty(", 1027 | "\t\t\tdefault=\"*.txt\",", 1028 | "\t\t\toptions={'HIDDEN'},", 1029 | "\t\t\tmaxlen=255, # Max internal buffer length, longer would be clamped.", 1030 | "\t\t\t)", 1031 | "", 1032 | "\t# List of operator properties, the attributes will be assigned", 1033 | "\t# to the class instance from the operator settings before calling.", 1034 | "\tuse_setting = BoolProperty(", 1035 | "\t\t\tname=\"Example Boolean\",", 1036 | "\t\t\tdescription=\"Example Tooltip\",", 1037 | "\t\t\tdefault=True,", 1038 | "\t\t\t)", 1039 | "", 1040 | "\ttype = EnumProperty(", 1041 | "\t\t\tname=\"Example Enum\",", 1042 | "\t\t\tdescription=\"Choose between two items\",", 1043 | "\t\t\titems=(('OPT_A', \"First Option\", \"Description one\"),", 1044 | "\t\t\t ('OPT_B', \"Second Option\", \"Description two\")),", 1045 | "\t\t\tdefault='OPT_A',", 1046 | "\t\t\t)", 1047 | "", 1048 | "\tdef execute(self, context):", 1049 | "\t\treturn write_some_data(context, self.filepath, self.use_setting)", 1050 | "", 1051 | "", 1052 | "# Only needed if you want to add into a dynamic menu", 1053 | "def menu_func_export(self, context):", 1054 | "\tself.layout.operator(ExportSomeData.bl_idname, text=\"Text Export Operator\")", 1055 | "", 1056 | "", 1057 | "def register():", 1058 | "\tbpy.utils.register_class(ExportSomeData)", 1059 | "\tbpy.types.INFO_MT_file_export.append(menu_func_export)", 1060 | "", 1061 | "", 1062 | "def unregister():", 1063 | "\tbpy.utils.unregister_class(ExportSomeData)", 1064 | "\tbpy.types.INFO_MT_file_export.remove(menu_func_export)", 1065 | "", 1066 | "", 1067 | "if __name__ == \"__main__\":", 1068 | "\tregister()", 1069 | "", 1070 | "\t# test call", 1071 | "\tbpy.ops.export_test.some_data('INVOKE_DEFAULT')" 1072 | ], 1073 | "description": "Example of Template for file export operator, operator exports data from blender to .txt file" 1074 | }, 1075 | "template_operator_file_import":{ 1076 | "prefix": "template operator", 1077 | "body": [ 1078 | "import bpy", 1079 | "", 1080 | "", 1081 | "def read_some_data(context, filepath, use_some_setting):", 1082 | "\tprint(\"running read_some_data...\")", 1083 | "\tf = open(filepath, 'r', encoding='utf-8')", 1084 | "\tdata = f.read()", 1085 | "\tf.close()", 1086 | "", 1087 | "\t# would normally load the data here", 1088 | "\tprint(data)", 1089 | "", 1090 | "\treturn {'FINISHED'}", 1091 | "", 1092 | "", 1093 | "# ImportHelper is a helper class, defines filename and", 1094 | "# invoke() function which calls the file selector.", 1095 | "from bpy_extras.io_utils import ImportHelper", 1096 | "from bpy.props import StringProperty, BoolProperty, EnumProperty", 1097 | "from bpy.types import Operator", 1098 | "", 1099 | "", 1100 | "class ImportSomeData(Operator, ImportHelper):", 1101 | "\t\"\"\"This appears in the tooltip of the operator and in the generated docs\"\"\"", 1102 | "\tbl_idname = \"import_test.some_data\" # important since its how bpy.ops.import_test.some_data is constructed", 1103 | "\tbl_label = \"Import Some Data\"", 1104 | "", 1105 | "\t# ImportHelper mixin class uses this", 1106 | "\tfilename_ext = \".txt\"", 1107 | "", 1108 | "\tfilter_glob = StringProperty(", 1109 | "\t\t\tdefault=\"*.txt\",", 1110 | "\t\t\toptions={'HIDDEN'},", 1111 | "\t\t\tmaxlen=255, # Max internal buffer length, longer would be clamped.", 1112 | "\t\t\t)", 1113 | "", 1114 | "\t# List of operator properties, the attributes will be assigned", 1115 | "\t# to the class instance from the operator settings before calling.", 1116 | "\tuse_setting = BoolProperty(", 1117 | "\t\t\tname=\"Example Boolean\",", 1118 | "\t\t\tdescription=\"Example Tooltip\",", 1119 | "\t\t\tdefault=True,", 1120 | "\t\t\t)", 1121 | "", 1122 | "\ttype = EnumProperty(", 1123 | "\t\t\tname=\"Example Enum\",", 1124 | "\t\t\tdescription=\"Choose between two items\",", 1125 | "\t\t\titems=(('OPT_A', \"First Option\", \"Description one\"),", 1126 | "\t\t\t ('OPT_B', \"Second Option\", \"Description two\")),", 1127 | "\t\t\tdefault='OPT_A',", 1128 | "\t\t\t)", 1129 | "", 1130 | "\tdef execute(self, context):", 1131 | "\t\treturn read_some_data(context, self.filepath, self.use_setting)", 1132 | "", 1133 | "", 1134 | "# Only needed if you want to add into a dynamic menu", 1135 | "def menu_func_import(self, context):", 1136 | "\tself.layout.operator(ImportSomeData.bl_idname, text=\"Text Import Operator\")", 1137 | "", 1138 | "", 1139 | "def register():", 1140 | "\tbpy.utils.register_class(ImportSomeData)", 1141 | "\tbpy.types.INFO_MT_file_import.append(menu_func_import)", 1142 | "", 1143 | "", 1144 | "def unregister():", 1145 | "\tbpy.utils.unregister_class(ImportSomeData)", 1146 | "\tbpy.types.INFO_MT_file_import.remove(menu_func_import)", 1147 | "", 1148 | "", 1149 | "if __name__ == \"__main__\":", 1150 | "\tregister()", 1151 | "", 1152 | "\t# test call", 1153 | "\tbpy.ops.import_test.some_data('INVOKE_DEFAULT')" 1154 | ], 1155 | "description": "Example of Template for file import operator, operator imports data from .txt to blender data" 1156 | }, 1157 | "template_opertator_mesh_add":{ 1158 | "prefix": "template operator", 1159 | "body": [ 1160 | "import bpy", 1161 | "import bmesh", 1162 | "", 1163 | "", 1164 | "def add_box(width, height, depth):", 1165 | "\t\"\"\"", 1166 | "\tThis function takes inputs and returns vertex and face arrays.", 1167 | "\tno actual mesh data creation is done here.", 1168 | "\t\"\"\"", 1169 | "", 1170 | "\tverts = [(+1.0, +1.0, -1.0),", 1171 | "\t (+1.0, -1.0, -1.0),", 1172 | "\t (-1.0, -1.0, -1.0),", 1173 | "\t (-1.0, +1.0, -1.0),", 1174 | "\t (+1.0, +1.0, +1.0),", 1175 | "\t (+1.0, -1.0, +1.0),", 1176 | "\t (-1.0, -1.0, +1.0),", 1177 | "\t (-1.0, +1.0, +1.0),", 1178 | "\t ]", 1179 | "", 1180 | "\tfaces = [(0, 1, 2, 3),", 1181 | "\t (4, 7, 6, 5),", 1182 | "\t (0, 4, 5, 1),", 1183 | "\t (1, 5, 6, 2),", 1184 | "\t (2, 6, 7, 3),", 1185 | "\t (4, 0, 3, 7),", 1186 | "\t ]", 1187 | "", 1188 | "\t# apply size", 1189 | "\tfor i, v in enumerate(verts):", 1190 | "\t\tverts[i] = v[0] * width, v[1] * depth, v[2] * height", 1191 | "", 1192 | "\treturn verts, faces", 1193 | "", 1194 | "", 1195 | "from bpy.props import (", 1196 | "\t\tBoolProperty,", 1197 | "\t\tBoolVectorProperty,", 1198 | "\t\tFloatProperty,", 1199 | "\t\tFloatVectorProperty,", 1200 | "\t\t)", 1201 | "", 1202 | "", 1203 | "class AddBox(bpy.types.Operator):", 1204 | "\t\"\"\"Add a simple box mesh\"\"\"", 1205 | "\tbl_idname = \"mesh.primitive_box_add\"", 1206 | "\tbl_label = \"Add Box\"", 1207 | "\tbl_options = {'REGISTER', 'UNDO'}", 1208 | "", 1209 | "\twidth = FloatProperty(", 1210 | "\t\t\tname=\"Width\",", 1211 | "\t\t\tdescription=\"Box Width\",", 1212 | "\t\t\tmin=0.01, max=100.0,", 1213 | "\t\t\tdefault=1.0,", 1214 | "\t\t\t)", 1215 | "\theight = FloatProperty(", 1216 | "\t\t\tname=\"Height\",", 1217 | "\t\t\tdescription=\"Box Height\",", 1218 | "\t\t\tmin=0.01, max=100.0,", 1219 | "\t\t\tdefault=1.0,", 1220 | "\t\t\t)", 1221 | "\tdepth = FloatProperty(", 1222 | "\t\t\tname=\"Depth\",", 1223 | "\t\t\tdescription=\"Box Depth\",", 1224 | "\t\t\tmin=0.01, max=100.0,", 1225 | "\t\t\tdefault=1.0,", 1226 | "\t\t\t)", 1227 | "\tlayers = BoolVectorProperty(", 1228 | "\t\t\tname=\"Layers\",", 1229 | "\t\t\tdescription=\"Object Layers\",", 1230 | "\t\t\tsize=20,", 1231 | "\t\t\toptions={'HIDDEN', 'SKIP_SAVE'},", 1232 | "\t\t\t)", 1233 | "", 1234 | "\t# generic transform props", 1235 | "\tview_align = BoolProperty(", 1236 | "\t\t\tname=\"Align to View\",", 1237 | "\t\t\tdefault=False,", 1238 | "\t\t\t)", 1239 | "\tlocation = FloatVectorProperty(", 1240 | "\t\t\tname=\"Location\",", 1241 | "\t\t\tsubtype='TRANSLATION',", 1242 | "\t\t\t)", 1243 | "\trotation = FloatVectorProperty(", 1244 | "\t\t\tname=\"Rotation\",", 1245 | "\t\t\tsubtype='EULER',", 1246 | "\t\t\t)", 1247 | "", 1248 | "\tdef execute(self, context):", 1249 | "", 1250 | "\t\tverts_loc, faces = add_box(self.width,", 1251 | "\t\t self.height,", 1252 | "\t\t self.depth,", 1253 | "\t\t )", 1254 | "", 1255 | "\t\tmesh = bpy.data.meshes.new(\"Box\")", 1256 | "", 1257 | "\t\tbm = bmesh.new()", 1258 | "", 1259 | "\t\tfor v_co in verts_loc:", 1260 | "\t\t\tbm.verts.new(v_co)", 1261 | "", 1262 | "\t\tbm.verts.ensure_lookup_table()", 1263 | "\t\tfor f_idx in faces:", 1264 | "\t\t\tbm.faces.new([bm.verts[i] for i in f_idx])", 1265 | "", 1266 | "\t\tbm.to_mesh(mesh)", 1267 | "\t\tmesh.update()", 1268 | "", 1269 | "\t\t# add the mesh as an object into the scene with this utility module", 1270 | "\t\tfrom bpy_extras import object_utils", 1271 | "\t\tobject_utils.object_data_add(context, mesh, operator=self)", 1272 | "", 1273 | "\t\treturn {'FINISHED'}", 1274 | "", 1275 | "", 1276 | "def menu_func(self, context):", 1277 | "\tself.layout.operator(AddBox.bl_idname, icon='MESH_CUBE')", 1278 | "", 1279 | "", 1280 | "def register():", 1281 | "\tbpy.utils.register_class(AddBox)", 1282 | "\tbpy.types.INFO_MT_mesh_add.append(menu_func)", 1283 | "", 1284 | "", 1285 | "def unregister():", 1286 | "\tbpy.utils.unregister_class(AddBox)", 1287 | "\tbpy.types.INFO_MT_mesh_add.remove(menu_func)", 1288 | "", 1289 | "if __name__ == \"__main__\":", 1290 | "\tregister()", 1291 | "", 1292 | "\t# test call", 1293 | "\tbpy.ops.mesh.primitive_box_add()" 1294 | ], 1295 | "description": "Example of operator involving bmesh for creating and adding object to scene" 1296 | }, 1297 | "template_operator_mesh_uv":{ 1298 | "prefix": "template operator", 1299 | "body": [ 1300 | "import bpy", 1301 | "import bmesh", 1302 | "", 1303 | "", 1304 | "def main(context):", 1305 | "\tobj = context.active_object", 1306 | "\tme = obj.data", 1307 | "\tbm = bmesh.from_edit_mesh(me)", 1308 | "", 1309 | "\tuv_layer = bm.loops.layers.uv.verify()", 1310 | "\tbm.faces.layers.tex.verify() # currently blender needs both layers.", 1311 | "", 1312 | "\t# adjust UVs", 1313 | "\tfor f in bm.faces:", 1314 | "\t\tfor l in f.loops:", 1315 | "\t\t\tluv = l[uv_layer]", 1316 | "\t\t\tif luv.select:", 1317 | "\t\t\t\t# apply the location of the vertex as a UV", 1318 | "\t\t\t\tluv.uv = l.vert.co.xy", 1319 | "", 1320 | "\tbmesh.update_edit_mesh(me)", 1321 | "", 1322 | "", 1323 | "class UvOperator(bpy.types.Operator):", 1324 | "\t\"\"\"UV Operator description\"\"\"", 1325 | "\tbl_idname = \"uv.simple_operator\"", 1326 | "\tbl_label = \"Simple UV Operator\"", 1327 | "", 1328 | "\t@classmethod", 1329 | "\tdef poll(cls, context):", 1330 | "\t\treturn (context.mode == 'EDIT_MESH')", 1331 | "", 1332 | "\tdef execute(self, context):", 1333 | "\t\tmain(context)", 1334 | "\t\treturn {'FINISHED'}", 1335 | "", 1336 | "", 1337 | "def register():", 1338 | "\tbpy.utils.register_class(UvOperator)", 1339 | "", 1340 | "", 1341 | "def unregister():", 1342 | "\tbpy.utils.unregister_class(UvOperator)", 1343 | "", 1344 | "", 1345 | "if __name__ == \"__main__\":", 1346 | "\tregister()", 1347 | "", 1348 | "\t# test call", 1349 | "\tbpy.ops.uv.simple_operator()" 1350 | ], 1351 | "description": "Example of Operator template for editing mesh UV's with bmesh" 1352 | }, 1353 | "template_operator_simple":{ 1354 | "prefix": "template operator", 1355 | "body": [ 1356 | "import bpy", 1357 | "", 1358 | "", 1359 | "def main(context):", 1360 | "\tfor ob in context.scene.objects:", 1361 | "\t\tprint(ob)", 1362 | "", 1363 | "", 1364 | "class SimpleOperator(bpy.types.Operator):", 1365 | "\t\"\"\"Tooltip\"\"\"", 1366 | "\tbl_idname = \"object.simple_operator\"", 1367 | "\tbl_label = \"Simple Object Operator\"", 1368 | "", 1369 | "\t@classmethod", 1370 | "\tdef poll(cls, context):", 1371 | "\t\treturn context.active_object is not None", 1372 | "", 1373 | "\tdef execute(self, context):", 1374 | "\t\tmain(context)", 1375 | "\t\treturn {'FINISHED'}", 1376 | "", 1377 | "", 1378 | "def register():", 1379 | "\tbpy.utils.register_class(SimpleOperator)", 1380 | "", 1381 | "", 1382 | "def unregister():", 1383 | "\tbpy.utils.unregister_class(SimpleOperator)", 1384 | "", 1385 | "", 1386 | "if __name__ == \"__main__\":", 1387 | "\tregister()", 1388 | "", 1389 | "\t# test call", 1390 | "\tbpy.ops.object.simple_operator()" 1391 | ], 1392 | "description": "Example of Blender modal operator function with imports, main function, register, unregister and testcall" 1393 | }, 1394 | "template_ui_list_w_panel":{ 1395 | "prefix": "template ui list", 1396 | "body": [ 1397 | "import bpy", 1398 | "", 1399 | "", 1400 | "class MATERIAL_UL_matslots_example(bpy.types.UIList):", 1401 | "\t# The draw_item function is called for each item of the collection that is visible in the list.", 1402 | "\t# data is the RNA object containing the collection,", 1403 | "\t# item is the current drawn item of the collection,", 1404 | "\t# icon is the \"computed\" icon for the item (as an integer, because some objects like materials or textures", 1405 | "\t# have custom icons ID, which are not available as enum items).", 1406 | "\t# active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the", 1407 | "\t# active item of the collection).", 1408 | "\t# active_propname is the name of the active property (use 'getattr(active_data, active_propname)').", 1409 | "\t# index is index of the current item in the collection.", 1410 | "\t# flt_flag is the result of the filtering process for this item.", 1411 | "\t# Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't", 1412 | "\t# need them.", 1413 | "\tdef draw_item(self, context, layout, data, item, icon, active_data, active_propname):", 1414 | "\t\tob = data", 1415 | "\t\tslot = item", 1416 | "\t\tma = slot.material", 1417 | "\t\t# draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.", 1418 | "\t\tif self.layout_type in {'DEFAULT', 'COMPACT'}:", 1419 | "\t\t\t# You should always start your row layout by a label (icon + text), or a non-embossed text field,", 1420 | "\t\t\t# this will also make the row easily selectable in the list! The later also enables ctrl-click rename.", 1421 | "\t\t\t# We use icon_value of label, as our given icon is an integer value, not an enum ID.", 1422 | "\t\t\t# Note \"data\" names should never be translated!", 1423 | "\t\t\tif ma:", 1424 | "\t\t\t\tlayout.prop(ma, \"name\", text=\"\", emboss=False, icon_value=icon)", 1425 | "\t\t\telse:", 1426 | "\t\t\t\tlayout.label(text=\"\", translate=False, icon_value=icon)", 1427 | "\t\t\t# And now we can add other UI stuff...", 1428 | "\t\t\t# Here, we add nodes info if this material uses (old!) shading nodes.", 1429 | "\t\t\tif ma and not context.scene.render.use_shading_nodes:", 1430 | "\t\t\t\tmanode = ma.active_node_material", 1431 | "\t\t\t\tif manode:", 1432 | "\t\t\t\t\t# The static method UILayout.icon returns the integer value of the icon ID \"computed\" for the given", 1433 | "\t\t\t\t\t# RNA object.", 1434 | "\t\t\t\t\tlayout.label(text=\"Node %s\" % manode.name, translate=False, icon_value=layout.icon(manode))", 1435 | "\t\t\t\telif ma.use_nodes:", 1436 | "\t\t\t\t\tlayout.label(text=\"Node \", translate=False)", 1437 | "\t\t\t\telse:", 1438 | "\t\t\t\t\tlayout.label(text=\"\")", 1439 | "\t\t# 'GRID' layout type should be as compact as possible (typically a single icon!).", 1440 | "\t\telif self.layout_type in {'GRID'}:", 1441 | "\t\t\tlayout.alignment = 'CENTER'", 1442 | "\t\t\tlayout.label(text=\"\", icon_value=icon)", 1443 | "", 1444 | "", 1445 | "# And now we can use this list everywhere in Blender. Here is a small example panel.", 1446 | "class UIListPanelExample(bpy.types.Panel):", 1447 | "\t\"\"\"Creates a Panel in the Object properties window\"\"\"", 1448 | "\tbl_label = \"UIList Panel\"", 1449 | "\tbl_idname = \"OBJECT_PT_ui_list_example\"", 1450 | "\tbl_space_type = 'PROPERTIES'", 1451 | "\tbl_region_type = 'WINDOW'", 1452 | "\tbl_context = \"object\"", 1453 | "", 1454 | "\tdef draw(self, context):", 1455 | "\t\tlayout = self.layout", 1456 | "", 1457 | "\t\tobj = context.object", 1458 | "", 1459 | "\t\t# template_list now takes two new args.", 1460 | "\t\t# The first one is the identifier of the registered UIList to use (if you want only the default list,", 1461 | "\t\t# with no custom draw code, use \"UI_UL_list\").", 1462 | "\t\tlayout.template_list(\"MATERIAL_UL_matslots_example\", \"\", obj, \"material_slots\", obj, \"active_material_index\")", 1463 | "", 1464 | "\t\t# The second one can usually be left as an empty string. It's an additional ID used to distinguish lists in case you", 1465 | "\t\t# use the same list several times in a given area.", 1466 | "\t\tlayout.template_list(\"MATERIAL_UL_matslots_example\", \"compact\", obj, \"material_slots\",", 1467 | "\t\t obj, \"active_material_index\", type='COMPACT')", 1468 | "", 1469 | "", 1470 | "def register():", 1471 | "\tbpy.utils.register_class(MATERIAL_UL_matslots_example)", 1472 | "\tbpy.utils.register_class(UIListPanelExample)", 1473 | "", 1474 | "", 1475 | "def unregister():", 1476 | "\tbpy.utils.unregister_class(MATERIAL_UL_matslots_example)", 1477 | "\tbpy.utils.unregister_class(UIListPanelExample)", 1478 | "", 1479 | "", 1480 | "if __name__ == \"__main__\":", 1481 | "\tregister()" 1482 | ], 1483 | "description": "Example of ui list template with adding it to blender with example panel" 1484 | }, 1485 | "template_ui_list":{ 1486 | "prefix": "template ui list", 1487 | "body": [ 1488 | "import bpy", 1489 | "", 1490 | "", 1491 | "class MESH_UL_mylist(bpy.types.UIList):", 1492 | "\t# Constants (flags)", 1493 | "\t# Be careful not to shadow FILTER_ITEM (i.e. UIList().bitflag_filter_item)!", 1494 | "\t# E.g. VGROUP_EMPTY = 1 << 0", 1495 | "", 1496 | "\t# Custom properties, saved with .blend file. E.g.", 1497 | "\t# use_filter_empty = bpy.props.BoolProperty(name=\"Filter Empty\", default=False, options=set(),", 1498 | "\t# description=\"Whether to filter empty vertex groups\")", 1499 | "", 1500 | "\t# Called for each drawn item.", 1501 | "\tdef draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):", 1502 | "\t\t# 'DEFAULT' and 'COMPACT' layout types should usually use the same draw code.", 1503 | "\t\tif self.layout_type in {'DEFAULT', 'COMPACT'}:", 1504 | "\t\t\tpass", 1505 | "\t\t# 'GRID' layout type should be as compact as possible (typically a single icon!).", 1506 | "\t\telif self.layout_type in {'GRID'}:", 1507 | "\t\t\tpass", 1508 | "", 1509 | "\t# Called once to draw filtering/reordering options.", 1510 | "\tdef draw_filter(self, context, layout):", 1511 | "\t\t# Nothing much to say here, it's usual UI code...", 1512 | "\t\tpass", 1513 | "", 1514 | "\t# Called once to filter/reorder items.", 1515 | "\tdef filter_items(self, context, data, propname):", 1516 | "\t\t# This function gets the collection property (as the usual tuple (data, propname)), and must return two lists:", 1517 | "\t\t# * The first one is for filtering, it must contain 32bit integers were self.bitflag_filter_item marks the", 1518 | "\t\t# matching item as filtered (i.e. to be shown), and 31 other bits are free for custom needs. Here we use the", 1519 | "\t\t# first one to mark VGROUP_EMPTY.", 1520 | "\t\t# * The second one is for reordering, it must return a list containing the new indices of the items (which", 1521 | "\t\t# gives us a mapping org_idx -> new_idx).", 1522 | "\t\t# Please note that the default UI_UL_list defines helper functions for common tasks (see its doc for more info).", 1523 | "\t\t# If you do not make filtering and/or ordering, return empty list(s) (this will be more efficient than", 1524 | "\t\t# returning full lists doing nothing!).", 1525 | "", 1526 | "\t\t# Default return values.", 1527 | "\t\tflt_flags = []", 1528 | "\t\tflt_neworder = []", 1529 | "", 1530 | "\t\t# Do filtering/reordering here...", 1531 | "", 1532 | "\t\treturn flt_flags, flt_neworder" 1533 | ], 1534 | "description": "Example of simple ui list class with some filtering and bpy import" 1535 | }, 1536 | "template_ui_menu_simple":{ 1537 | "prefix": "template ui menu", 1538 | "body": [ 1539 | "import bpy", 1540 | "", 1541 | "", 1542 | "class SimpleCustomMenu(bpy.types.Menu):", 1543 | "\tbl_label = \"Simple Custom Menu\"", 1544 | "\tbl_idname = \"OBJECT_MT_simple_custom_menu\"", 1545 | "", 1546 | "\tdef draw(self, context):", 1547 | "\t\tlayout = self.layout", 1548 | "", 1549 | "\t\tlayout.operator(\"wm.open_mainfile\")", 1550 | "\t\tlayout.operator(\"wm.save_as_mainfile\")", 1551 | "", 1552 | "", 1553 | "def register():", 1554 | "\tbpy.utils.register_class(SimpleCustomMenu)", 1555 | "", 1556 | "", 1557 | "def unregister():", 1558 | "\tbpy.utils.unregister_class(SimpleCustomMenu)", 1559 | "", 1560 | "if __name__ == \"__main__\":", 1561 | "\tregister()", 1562 | "", 1563 | "\t# The menu can also be called from scripts", 1564 | "\tbpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)" 1565 | ], 1566 | "description": "Example of ui menu" 1567 | }, 1568 | "template_ui_panel_simple":{ 1569 | "prefix": "template ui simple panel", 1570 | "body": [ 1571 | "import bpy", 1572 | "", 1573 | "", 1574 | "class HelloWorldPanel(bpy.types.Panel):", 1575 | "\t\"\"\"Creates a Panel in the Object properties window\"\"\"", 1576 | "\tbl_label = \"Hello World Panel\"", 1577 | "\tbl_idname = \"OBJECT_PT_hello\"", 1578 | "\tbl_space_type = 'PROPERTIES'", 1579 | "\tbl_region_type = 'WINDOW'", 1580 | "\tbl_context = \"object\"", 1581 | "", 1582 | "\tdef draw(self, context):", 1583 | "\t\tlayout = self.layout", 1584 | "", 1585 | "\t\tobj = context.object", 1586 | "", 1587 | "\t\trow = layout.row()", 1588 | "\t\trow.label(text=\"Hello world!\", icon='WORLD_DATA')", 1589 | "", 1590 | "\t\trow = layout.row()", 1591 | "\t\trow.label(text=\"Active object is: \" + obj.name)", 1592 | "\t\trow = layout.row()", 1593 | "\t\trow.prop(obj, \"name\")", 1594 | "", 1595 | "\t\trow = layout.row()", 1596 | "\t\trow.operator(\"mesh.primitive_cube_add\")", 1597 | "", 1598 | "", 1599 | "def register():", 1600 | "\tbpy.utils.register_class(HelloWorldPanel)", 1601 | "", 1602 | "", 1603 | "def unregister():", 1604 | "\tbpy.utils.unregister_class(HelloWorldPanel)", 1605 | "", 1606 | "", 1607 | "if __name__ == \"__main__\":", 1608 | "\tregister()" 1609 | ], 1610 | "description": "Example of ui panel class with import and register" 1611 | }, 1612 | "template_ui_panel":{ 1613 | "prefix": "template ui panel", 1614 | "body": [ 1615 | "import bpy", 1616 | "", 1617 | "", 1618 | "class LayoutDemoPanel(bpy.types.Panel):", 1619 | "\t\"\"\"Creates a Panel in the scene context of the properties editor\"\"\"", 1620 | "\tbl_label = \"Layout Demo\"", 1621 | "\tbl_idname = \"SCENE_PT_layout\"", 1622 | "\tbl_space_type = 'PROPERTIES'", 1623 | "\tbl_region_type = 'WINDOW'", 1624 | "\tbl_context = \"scene\"", 1625 | "", 1626 | "\tdef draw(self, context):", 1627 | "\t\tlayout = self.layout", 1628 | "", 1629 | "\t\tscene = context.scene", 1630 | "", 1631 | "\t\t# Create a simple row.", 1632 | "\t\tlayout.label(text=\" Simple Row:\")", 1633 | "", 1634 | "\t\trow = layout.row()", 1635 | "\t\trow.prop(scene, \"frame_start\")", 1636 | "\t\trow.prop(scene, \"frame_end\")", 1637 | "", 1638 | "\t\t# Create an row where the buttons are aligned to each other.", 1639 | "\t\tlayout.label(text=\" Aligned Row:\")", 1640 | "", 1641 | "\t\trow = layout.row(align=True)", 1642 | "\t\trow.prop(scene, \"frame_start\")", 1643 | "\t\trow.prop(scene, \"frame_end\")", 1644 | "", 1645 | "\t\t# Create two columns, by using a split layout.", 1646 | "\t\tsplit = layout.split()", 1647 | "", 1648 | "\t\t# First column", 1649 | "\t\tcol = split.column()", 1650 | "\t\tcol.label(text=\"Column One:\")", 1651 | "\t\tcol.prop(scene, \"frame_end\")", 1652 | "\t\tcol.prop(scene, \"frame_start\")", 1653 | "", 1654 | "\t\t# Second column, aligned", 1655 | "\t\tcol = split.column(align=True)", 1656 | "\t\tcol.label(text=\"Column Two:\")", 1657 | "\t\tcol.prop(scene, \"frame_start\")", 1658 | "\t\tcol.prop(scene, \"frame_end\")", 1659 | "", 1660 | "\t\t# Big render button", 1661 | "\t\tlayout.label(text=\"Big Button:\")", 1662 | "\t\trow = layout.row()", 1663 | "\t\trow.scale_y = 3.0", 1664 | "\t\trow.operator(\"render.render\")", 1665 | "", 1666 | "\t\t# Different sizes in a row", 1667 | "\t\tlayout.label(text=\"Different button sizes:\")", 1668 | "\t\trow = layout.row(align=True)", 1669 | "\t\trow.operator(\"render.render\")", 1670 | "", 1671 | "\t\tsub = row.row()", 1672 | "\t\tsub.scale_x = 2.0", 1673 | "\t\tsub.operator(\"render.render\")", 1674 | "", 1675 | "\t\trow.operator(\"render.render\")", 1676 | "", 1677 | "", 1678 | "def register():", 1679 | "\tbpy.utils.register_class(LayoutDemoPanel)", 1680 | "", 1681 | "", 1682 | "def unregister():", 1683 | "\tbpy.utils.unregister_class(LayoutDemoPanel)", 1684 | "", 1685 | "", 1686 | "if __name__ == \"__main__\":", 1687 | "\tregister()" 1688 | ], 1689 | "description": "Example of ui panel class ui panel is created with examples of columns, buttons, rows, properties, with import and register, " 1690 | }, 1691 | "template_ui_pie_menu":{ 1692 | "prefix": "template ui pie menu", 1693 | "body": [ 1694 | "import bpy", 1695 | "from bpy.types import Menu", 1696 | "", 1697 | "# spawn an edit mode selection pie (run while object is in edit mode to get a valid output)", 1698 | "", 1699 | "", 1700 | "class VIEW3D_PIE_template(Menu):", 1701 | "\t# label is displayed at the center of the pie menu.", 1702 | "\tbl_label = \"Select Mode\"", 1703 | "", 1704 | "\tdef draw(self, context):", 1705 | "\t\tlayout = self.layout", 1706 | "", 1707 | "\t\tpie = layout.menu_pie()", 1708 | "\t\t# operator_enum will just spread all available options", 1709 | "\t\t# for the type enum of the operator on the pie", 1710 | "\t\tpie.operator_enum(\"mesh.select_mode\", \"type\")", 1711 | "", 1712 | "", 1713 | "def register():", 1714 | "\tbpy.utils.register_class(VIEW3D_PIE_template)", 1715 | "", 1716 | "", 1717 | "def unregister():", 1718 | "\tbpy.utils.unregister_class(VIEW3D_PIE_template)", 1719 | "", 1720 | "", 1721 | "if __name__ == \"__main__\":", 1722 | "\tregister()", 1723 | "", 1724 | "\tbpy.ops.wm.call_menu_pie(name=\"VIEW3D_PIE_template\")" 1725 | ], 1726 | "description": "Example of 3d viewport pie menu" 1727 | }, 1728 | "template_dynamic_enum":{ 1729 | "prefix": "template dynamic enum", 1730 | "body": [ 1731 | "# This sample script demonstrates a dynamic EnumProperty with custom icons.", 1732 | "# The EnumProperty is populated dynamically with thumbnails of the contents of", 1733 | "# a chosen directory in 'enum_previews_from_directory_items'.", 1734 | "# Then, the same enum is displayed with different interfaces. Note that the", 1735 | "# generated icon previews do not have Blender IDs, which means that they can", 1736 | "# not be used with UILayout templates that require IDs,", 1737 | "# such as template_list and template_ID_preview.", 1738 | "#", 1739 | "# Other use cases:", 1740 | "# - make a fixed list of enum_items instead of calculating them in a function", 1741 | "# - generate isolated thumbnails to use as custom icons in buttons", 1742 | "# and menu items", 1743 | "#", 1744 | "# For custom icons, see the template \"ui_previews_custom_icon.py\".", 1745 | "#", 1746 | "# For distributable scripts, it is recommended to place the icons inside the", 1747 | "# script directory and access it relative to the py script file for portability:", 1748 | "#", 1749 | "#\tos.path.join(os.path.dirname(__file__), \"images\")", 1750 | "", 1751 | "", 1752 | "import os", 1753 | "import bpy", 1754 | "", 1755 | "", 1756 | "def enum_previews_from_directory_items(self, context):", 1757 | "\t\"\"\"EnumProperty callback\"\"\"", 1758 | "\tenum_items = []", 1759 | "", 1760 | "\tif context is None:", 1761 | "\t\treturn enum_items", 1762 | "", 1763 | "\twm = context.window_manager", 1764 | "\tdirectory = wm.my_previews_dir", 1765 | "", 1766 | "\t# Get the preview collection (defined in register func).", 1767 | "\tpcoll = preview_collections[\"main\"]", 1768 | "", 1769 | "\tif directory == pcoll.my_previews_dir:", 1770 | "\t\treturn pcoll.my_previews", 1771 | "", 1772 | "\tprint(\"Scanning directory: %s\" % directory)", 1773 | "", 1774 | "\tif directory and os.path.exists(directory):", 1775 | "\t\t# Scan the directory for png files", 1776 | "\t\timage_paths = []", 1777 | "\t\tfor fn in os.listdir(directory):", 1778 | "\t\t\tif fn.lower().endswith(\".png\"):", 1779 | "\t\t\t\timage_paths.append(fn)", 1780 | "", 1781 | "\t\tfor i, name in enumerate(image_paths):", 1782 | "\t\t\t# generates a thumbnail preview for a file.", 1783 | "\t\t\tfilepath = os.path.join(directory, name)", 1784 | "\t\t\tthumb = pcoll.load(filepath, filepath, 'IMAGE')", 1785 | "\t\t\tenum_items.append((name, name, \"\", thumb.icon_id, i))", 1786 | "", 1787 | "\tpcoll.my_previews = enum_items", 1788 | "\tpcoll.my_previews_dir = directory", 1789 | "\treturn pcoll.my_previews", 1790 | "", 1791 | "", 1792 | "class PreviewsExamplePanel(bpy.types.Panel):", 1793 | "\t\"\"\"Creates a Panel in the Object properties window\"\"\"", 1794 | "\tbl_label = \"Previews Example Panel\"", 1795 | "\tbl_idname = \"OBJECT_PT_previews\"", 1796 | "\tbl_space_type = 'PROPERTIES'", 1797 | "\tbl_region_type = 'WINDOW'", 1798 | "\tbl_context = \"object\"", 1799 | "", 1800 | "\tdef draw(self, context):", 1801 | "\t\tlayout = self.layout", 1802 | "\t\twm = context.window_manager", 1803 | "", 1804 | "\t\trow = layout.row()", 1805 | "\t\trow.prop(wm, \"my_previews_dir\")", 1806 | "", 1807 | "\t\trow = layout.row()", 1808 | "\t\trow.template_icon_view(wm, \"my_previews\")", 1809 | "", 1810 | "\t\trow = layout.row()", 1811 | "\t\trow.prop(wm, \"my_previews\")", 1812 | "", 1813 | "", 1814 | "# We can store multiple preview collections here,", 1815 | "# however in this example we only store \"main\"", 1816 | "preview_collections = {}", 1817 | "", 1818 | "", 1819 | "def register():", 1820 | "\tfrom bpy.types import WindowManager", 1821 | "\tfrom bpy.props import (", 1822 | "\t\t\tStringProperty,", 1823 | "\t\t\tEnumProperty,", 1824 | "\t\t\t)", 1825 | "", 1826 | "\tWindowManager.my_previews_dir = StringProperty(", 1827 | "\t\t\tname=\"Folder Path\",", 1828 | "\t\t\tsubtype='DIR_PATH',", 1829 | "\t\t\tdefault=\"\"", 1830 | "\t\t\t)", 1831 | "", 1832 | "\tWindowManager.my_previews = EnumProperty(", 1833 | "\t\t\titems=enum_previews_from_directory_items,", 1834 | "\t\t\t)", 1835 | "", 1836 | "\t# Note that preview collections returned by bpy.utils.previews", 1837 | "\t# are regular Python objects - you can use them to store custom data.", 1838 | "\t#", 1839 | "\t# This is especially useful here, since:", 1840 | "\t# - It avoids us regenerating the whole enum over and over.", 1841 | "\t# - It can store enum_items' strings", 1842 | "\t# (remember you have to keep those strings somewhere in py,", 1843 | "\t# else they get freed and Blender references invalid memory!).", 1844 | "\timport bpy.utils.previews", 1845 | "\tpcoll = bpy.utils.previews.new()", 1846 | "\tpcoll.my_previews_dir = \"\"", 1847 | "\tpcoll.my_previews = ()", 1848 | "", 1849 | "\tpreview_collections[\"main\"] = pcoll", 1850 | "", 1851 | "\tbpy.utils.register_class(PreviewsExamplePanel)", 1852 | "", 1853 | "", 1854 | "def unregister():", 1855 | "\tfrom bpy.types import WindowManager", 1856 | "", 1857 | "\tdel WindowManager.my_previews", 1858 | "", 1859 | "\tfor pcoll in preview_collections.values():", 1860 | "\t\tbpy.utils.previews.remove(pcoll)", 1861 | "\tpreview_collections.clear()", 1862 | "", 1863 | "\tbpy.utils.unregister_class(PreviewsExamplePanel)", 1864 | "", 1865 | "", 1866 | "if __name__ == \"__main__\":", 1867 | "\tregister()" 1868 | ], 1869 | "description": "This example script demonstrates a dynamic EnumProperty with custom icons." 1870 | }, 1871 | "template_ui_previews_custom_icon":{ 1872 | "prefix": "template ui previews", 1873 | "body": [ 1874 | "# This sample script demonstrates how to place a custom icon on a button or", 1875 | "# menu entry.", 1876 | "#", 1877 | "# IMPORTANT NOTE: if you run this sample, there will be no icon in the button", 1878 | "# You need to replace the image path with a real existing one.", 1879 | "# For distributable scripts, it is recommended to place the icons inside the", 1880 | "# addon folder and access it relative to the py script file for portability", 1881 | "#", 1882 | "#", 1883 | "# Other use cases for UI-previews:", 1884 | "# - provide a fixed list of previews to select from", 1885 | "# - provide a dynamic list of preview (eg. calculated from reading a directory)", 1886 | "#", 1887 | "# For the above use cases, see the template 'ui_previews_dynamic_enum.py\"", 1888 | "", 1889 | "", 1890 | "import os", 1891 | "import bpy", 1892 | "", 1893 | "", 1894 | "class PreviewsExamplePanel(bpy.types.Panel):", 1895 | "\t\"\"\"Creates a Panel in the Object properties window\"\"\"", 1896 | "\tbl_label = \"Previews Example Panel\"", 1897 | "\tbl_idname = \"OBJECT_PT_previews\"", 1898 | "\tbl_space_type = 'PROPERTIES'", 1899 | "\tbl_region_type = 'WINDOW'", 1900 | "\tbl_context = \"object\"", 1901 | "", 1902 | "\tdef draw(self, context):", 1903 | "\t\tlayout = self.layout", 1904 | "\t\tpcoll = preview_collections[\"main\"]", 1905 | "", 1906 | "\t\trow = layout.row()", 1907 | "\t\tmy_icon = pcoll[\"my_icon\"]", 1908 | "\t\trow.operator(\"render.render\", icon_value=my_icon.icon_id)", 1909 | "", 1910 | "\t\t# my_icon.icon_id can be used in any UI function that accepts", 1911 | "\t\t# icon_value # try also setting text=\"\"", 1912 | "\t\t# to get an icon only operator button", 1913 | "", 1914 | "", 1915 | "# We can store multiple preview collections here,", 1916 | "# however in this example we only store \"main\"", 1917 | "preview_collections = {}", 1918 | "", 1919 | "", 1920 | "def register():", 1921 | "", 1922 | "\t# Note that preview collections returned by bpy.utils.previews", 1923 | "\t# are regular py objects - you can use them to store custom data.", 1924 | "\timport bpy.utils.previews", 1925 | "\tpcoll = bpy.utils.previews.new()", 1926 | "", 1927 | "\t# path to the folder where the icon is", 1928 | "\t# the path is calculated relative to this py file inside the addon folder", 1929 | "\tmy_icons_dir = os.path.join(os.path.dirname(__file__), \"icons\")", 1930 | "", 1931 | "\t# load a preview thumbnail of a file and store in the previews collection", 1932 | "\tpcoll.load(\"my_icon\", os.path.join(my_icons_dir, \"icon-image.png\"), 'IMAGE')", 1933 | "", 1934 | "\tpreview_collections[\"main\"] = pcoll", 1935 | "", 1936 | "\tbpy.utils.register_class(PreviewsExamplePanel)", 1937 | "", 1938 | "", 1939 | "def unregister():", 1940 | "", 1941 | "\tfor pcoll in preview_collections.values():", 1942 | "\t\tbpy.utils.previews.remove(pcoll)", 1943 | "\tpreview_collections.clear()", 1944 | "", 1945 | "\tbpy.utils.unregister_class(PreviewsExamplePanel)", 1946 | "", 1947 | "", 1948 | "if __name__ == \"__main__\":", 1949 | "\tregister()" 1950 | ], 1951 | "description": "This example script demonstrates how to place a custom icon on a button menu entry." 1952 | } 1953 | 1954 | } 1955 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | * This folder contains all of the files necessary for your extension. 5 | * `package.json` - this is the manifest file that defines the location of the snippet file 6 | and specifies the language of the snippets. 7 | * `snippets/snippets.json` - the file containing all snippets. 8 | 9 | ## Get up and running straight away 10 | * Press `F5` to open a new window with your extension loaded. 11 | * Create a new file with a file name suffix matching your language. 12 | * Verify that your snippets are proposed on intellisense. 13 | 14 | ## Make changes 15 | * You can relaunch the extension from the debug toolbar after making changes to the files listed above. 16 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 17 | 18 | ## Install your extension 19 | * To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. 20 | * To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension. 21 | --------------------------------------------------------------------------------