This file contains guidance for agents that generate code for the Cinema 4D Python SDK.
ALWAYS follow the Guidelines when generating code for the Cinema 4D Python SDK.
- Vocabulary: Contains the vocabulary that is used to organize this SDK. When you do not find a direct skill instruction below, you can use this vocabulary to find code examples for your task.
- Assets: Learn how to create, read, or modify assets in Cinema 4D, such as textures, materials, and models.
- Debugging: Learn how to inspect scene data, check assumptions, trace and time code, test Script Manager scripts through the VS Code Cinema 4D Connector, and track down crashes caused by threading violations.
- Nodes: Learn how to create, read, or modify nodes in a node graph. For node materials, ask whether to use Graph Description API or Nodes API; for Scene Nodes, always use Nodes API.
- Node Spaces: Contains dumped node space metadata. You will need this information when building material or scene nodes graphs.
- Scaffolds: Learn how to scaffold plugins (dialog, command, object, tag, preference, message, shader, tool, scene and image loader and saver plugins, and render tokens) in the
projects/folder. Use it first for any request to create, build, or implement a plugin or tool, including informal requests such as "create a plugin" or "create a tool." It describes which questions you must ask the user in a chat selection menu before generating any files. - Scene: Learn how to create, read, or modify scenes, and which operations are allowed on which thread.
- For scripts intended for Cinema 4D's Script Manager, use the VS Code Cinema 4D Connector to execute in the user's already-running Cinema 4D instance. Do not use
c4dpyas the default: it starts a separate process, is often slower, does not test the active document, and its output is not in the connected app'sCinema 4DOutput channel. Ac4dpyrun orpy_compilepass alone is not live Script Manager validation. - Check that the
maxonc4dsdk.cinema4d-connectorextension is installed and enabled. In VS Code,C4D ✓with aConnected to: ...tooltip means connected;C4D Xmeans disconnected. UseC4D: Toggle Connection with Cinema 4Dto connect, then verify the status again. - Save the intended script and make it the active editor. Run
C4D: Execute in Cinema 4D as a Script in Script Manager(command IDcinema4d-connector.execute_in_c4d). Read Python output and exceptions in the VS Code Output panel, selecting theCinema 4Dchannel. A successful dispatch alone is not a pass: inspect the output and confirm the expected result in Cinema 4D. - If the agent's VS Code command tool cannot invoke that command, do not conclude the Connector is unavailable or tell the user to run it. Check the configured WebSocket endpoint (
c4d.IPandc4d.port, defaults127.0.0.1:7788) using subprotocolc4d_py_code_exchange. A response to{"action":"idea2c4d.get_pid"}confirms the live app connection. Then send{"action":"idea2c4d.execute","script_path":"empty","value":"<script source>","debug":false}and readc4d2ide.consolemessages. Report clearly that this was direct Connector protocol execution, not invocation of the VS Code command. If neither path works, report runtime validation as pending and ask for user assistance only when needed to restore the connection. - Use
c4dpyonly when the user specifically asks for headless testing or the code is suited to isolated execution.
- Start at https://developers.maxon.net/docs/py, which always points to the newest Python SDK documentation.
- Search that site for the exact manual title, API symbol, or topic named by the relevant agent file. Verify the result against the current Cinema 4D version before applying it.
- Do not construct or keep version-pinned documentation URLs. When referring an agent to documentation, provide the current documentation root and the search terms to use.
examples/is read-only reference material. Read, search, and run examples to understand SDK patterns, but never create, edit, delete, rename, reformat, or otherwise modify files underexamples/.projects/is the writable destination for new SDK code. When a request asks to create or implement code and does not identify an existing target file or project, create a new file or project underprojects/. Do not use an example file as the target, even when the requested feature resembles one.- When a request identifies an existing file under
projects/, work in that project. Never overwrite existing files or expand into unrelated files without a clear need. - Treat projects as user-owned work. Do not add
__copyright__or__license__fields, copyright/license notices, or statements claiming or implying that Maxon owns the project's intellectual property. Do not copy those headers from examples into projects. - Whenever you can predict even one plausible answer to a question, present a multiple-choice or multi-select input with that answer as a recommended option and an explicit
Other (enter a custom answer)option when custom answers are valid. Do this for names, descriptions, and behavior as well as finite technical choices. Use a text-only input only when no plausible answer can be predicted or the value must be supplied exactly (for example, a registered plugin ID). Do not offerOtherfor strict API enums that cannot accept custom values; explain that the choices are constrained. - Requests for information or examples do not authorize code changes. Examples can be used to explain or inform an implementation in
projects/. - Use absolute filesystem paths unless the user explicitly requests relative paths. Do not assume a relative path resolves from the script's directory or the workspace; if an input path is unknown, ask the user or use a file picker and use its absolute result.
- IMPORTANT: Never delete or overwrite existing files without user confirmation.
- IMPORTANT: Follow PEP8 coding style and naming conventions in all Python code. The maximum line length is 100 characters.
- IMPORTANT: Use 4 spaces for indentation, do not use tabs.
- IMPORTANT: In the Cinema API camel case is used for class names, functions, methods, attributes, and variables. Use camel case for all identifiers in your code. Do not use snake case. Classes, functions, and methods start with a capital letter, attributes and variables start with a lowercase letter. Global constants are all uppercase with underscores.
- IMPORTANT: Never use
multiprocessing, the Cinema 4D Python VM does not support interpreter parallelism and will crash if you try to use it.subprocess.run([sys.executable, “my_script.py”], …)is therefore also off limits. Do not usethreading. Usec4d.threadinginstead. - IMPORTANT: Avoid abstraction/helper functions when writing Nodes, Graph Description, or Asset API code. Use literals such
file://C:/Users/username/Documents/scene.c4dinstead ofos.path.join(os.path.expanduser("~"), "Documents", "scene.c4d"). Especially graph descriptions should be as literal as possible to avoid unnecessary complexity. Only start abstracting when the user is explicitly asking for a more compressed solution. - Use type hinting for all function parameters, return types, class attributes, and variables where possible.
- Avoid using Python std lib modules other than
os,sys,math,typing,re,itertools,functools,collections, andjson, andlogging. - Avoid using
typingin favour of modern built-in types (e.g., uselistinstead ofList,dictinstead ofDict, etc.). - Use Google style doc strings for all functions, classes, and modules. Doc strings end in line break. Avoid documenting arguments and return types in favour of verbose short descriptions and detailed descriptions. But generally documentation should be sparse. E.g.:
def collapse(obj: c4d.BaseObject, moveTags: bool = False) -> c4d.BaseObject:
"""Collapse the given #obj into a single object and returns the result.
When #moveTags is True, all tags in the input hierarchy of #obj will be moved to the resulting object.
"""
...- *.pyp is the Cinema 4D Python SDK plugin extension, it is equivalent to a normal *.py file.
- Script Manager scripts have the active document auto exposed as
docand the active object auto exposed asop. Do not usec4d.documents.GetActiveDocument()ordoc.GetActiveObject(), instead use thedocandophints. The active document is always ac4d.documents.BaseDocument, the active object is always ac4d.BaseObjector None. - For other script forms such as plugin or scripting elements, this is not the case.
An example should always have at least a main() function that is invoked in the __main_ block. Functions should not be much longer than 100 lines. When an example breaks into multiple sub-examples, each sub-example should be its own function. Avoid overly short examples that split into dozens of files (e.g., container_get_string.py, container_get_int.py, container_get_float.py, etc.). Instead, combine them into a single example with multiple functions (e.g., container_get.py). Only add the doc and op hints when you use them. Never manually get the active document or active object in an example. Use the doc and op hints instead.
Structure of an example:
An example should also have a doc string at the top of the file that describes what the example does. The doc string should be sparse. It should have a short description of the example, optionally a longer description when more complex topics or ideas must be explained, always usage instructions (are there run-time requirements, how to run the example, etc.), and a list of topics that the example covers. The topics should be a bulleted list of short phrases that describe the concepts covered in the example. The topics should be used to generate the table of contents for the SDK documentation.
Finally, an example should have a header with the author, copyright, license, and version information. The author should be {ModelName}, the copyright should be Copyright (C) {Year} MAXON Computer GmbH, the license should be Apache-2.0 License, and the version should be {Version}. {ModelName} is the name of the model that generated the example, {Year} is the current year, and {Version} is the version of the Cinema 4D Python SDK that generated the example.
"""Demonstrates how to get and set values in a BaseContainer.
You can run this example by executing it in the Script Manager of Cinema 4D. It will create multiple
BaseContainer objects, set values in them, and print the values to the console.
Topics:
- Creating a BaseContainer
- Reading values from a BaseContainer
"""
__author__ = "{ModelName}"
__copyright__ = "Copyright (C) {Year} MAXON Computer GmbH"
__license__ = "Apache-2.0 License"
__version__ = "{Version}"
doc: c4d.documents.BaseDocument # The active document
op: c4d.BaseObject | None # The active object, can be None.
def create_container() -> c4d.BaseContainer:
"""Creates a BaseContainer and sets some values in it.
"""
# And example function should have at least ten lines of code, but not more than 100 lines of code. Split up longer
# functions into logical blocks.
...
def read_container(container: c4d.BaseContainer) -> None:
"""Reads values from the given BaseContainer and prints them to the console.
"""
...
def main() -> None:
"""Runs the example.
"""
# Create a BaseContainer and then read values from it.
container: c4d.BaseContainer = create_container()
read_container(container)
if __name__ == "__main__":
main()Use a clustered and sparse comment style in all code. Comments should be analytical and not just repeat function or class names that are invoked.
NO:
# Create a cube.
cube: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Ocube))
# Create a phong tag on the cube.
phongTag: c4d.BaseTag = mxutils.CheckType(cube.MakeTag(c4d.Tphong))
# Create a null object.
null: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Onull))
# Insert the cube under the null object.
sphere.InsertUnder(null)
# Insert the null object into the scene.
doc.InsertObject(null)YES:
# Create a cube object with a phong tag and insert it under a null object, which is then inserted
# into the scene.
cube: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Ocube))
phongTag: c4d.BaseTag = mxutils.CheckType(cube.MakeTag(c4d.Tphong))
null: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Onull))
cube.InsertUnder(null)