Custom classes in the editor

In SimVX a scene is Python source: a node is an instance of a class, a class lives in a .py file, and the editor’s refactorings rewrite those files for you. This guide covers the editor actions for giving nodes classes of their own. It assumes you know the basics from the editor tutorial.

Convert a node to a class

To give a built-in node (Sprite2D, Node3D, …) its own behaviour, select it and click Convert to Custom Class next to the type name in the Properties panel, or right-click it in the scene tree and choose the same entry. The dialog asks for:

  • A class name, defaulting to the node’s name.

  • A template. Empty writes a class with nothing in it; the others write what a node of that kind usually needs (the character templates add movement and a collider, Timer connects its timeout). Only templates for a class the node already descends from are offered, and the new class extends the node’s own type.

  • Where the class goes. By default a new file, <project>/<class_files_dir>/<snake_case>.py, where class_files_dir is set under [editor] in simvx.toml (default src). An existing file gains the class beside what it holds. Inline in parent scene file puts the class at the top of the scene file instead.

On accept the editor writes the class, changes the node’s construction in the scene source to the new class (keeping its arguments and comments, and adding the import), saves the scene and reloads it. The node is now an instance of the new class, and the file opens in the code workspace.

Once a node has a class of your own, the Properties header shows its module and file and an Edit class file button instead.

Converting the scene root rebases the class the scene file defines onto the new class.

The conversion refuses, writing nothing, when it would have to guess:

Refused when

What to do

the scene has never been saved

save it first

the class has two bases, or a dotted base such as simvx.core.Node3D

edit the class by hand

the node is built by a line a save does not rewrite (a factory call, a name bound elsewhere)

build that node with the class by hand

the node is deeper than a save writes (a save writes the root and its own children)

write the class by hand

the module name is one Python already finds (a class Json would become json, the standard library’s)

pick another name

From the editor a node is converted once. To extend a class of your own with another, call simvx.editor.convert_node_to_class from code.

Duplicate a node

Ctrl+D, or Duplicate in the scene tree’s context menu, adds another instance with the same arguments. Duplicate… opens a dialog with three choices:

Choice

Result

New Instance (default)

another <SameClass>(...) with the original’s arguments

Subclass

a new file holding class <Name>(<Original>): pass, and an instance of it

Detached Copy

a new class with the original’s body copied, extending the original’s base rather than the original; for a built-in node it is the same as Subclass

New files go in class_files_dir.

Rename a class

Right-click an instance of your class and choose Rename Class…. Every file in the project is rewritten in one step, and a failure rolls all of them back:

  • the class definition;

  • every from <module> import <ClassName>, keeping an alias;

  • every base-class reference, instantiation, isinstance check and annotation.

Tick Also rename file to match to move the defining file (or package folder) to the new snake_case name, with importers’ module paths updated.

Split and merge class files

In the file browser, right-click a .py file holding several classes and choose Extract classes to folder. The file becomes a package of the same name with one class per file and an __init__.py that re-exports them, so existing imports keep working. It refuses a file with fewer than two classes, one with top-level statements other than classes and imports, or one whose target folder already exists.

Inline folder to file, on a folder with an __init__.py, is the inverse: it concatenates the classes back into one file. It refuses module-level side effects, conditional imports and free functions.