Skip to content

Objects and groups

Everything you place in a level is a scene object. Each object has a stable numeric ID, a name, a kind, a transform and a set of components. Groups are objects that carry other objects, so you can move, rotate and scale an assembly as one.

Kind Description
Group A transform parent with no surface or collider of its own
Tree, Rock, Cottage, Crystal Built-in stylised props
Cube, Sphere, Plane Built-in primitives
Model An imported GLB model; see Assets

Add objects from the toolbar’s Add menu, the Content Browser, or the viewport’s right-click Add here menu.

Every object has a transform, an appearance, a physics component and behaviours. Everything else is optional and added with Details → + Add Component.

Component Purpose
Transform Position, rotation and scale
Appearance Base colour, roughness, metallic, emission and unlit mode for built-in objects. Models use their embedded materials
Physics Body type, collider, friction, bounce, mass, centre of mass and sensor; see Physics
Behaviours Spin, bobbing and collectible scoring, with no code
Script, Blueprint Gameplay programs; see Scripting and Blueprints
Optional components Light, sound, animation, effect, decal, fog volume, water, force field, thruster, spawner, joint, cloth, boat, vehicle, terrain cutter, destructible, door, switch, pickup, container, fluid container, fluid source, fluid pool, and tags with an interaction prompt

An object’s ID never changes while it exists. Scripts, Blueprints and commands refer to objects by this ID.

Field Unit Notes
Position Metres For root objects, height is measured above the terrain. For Group children, the position is local to the parent
Rotation Degrees in Details; radians in project data and commands Local to the parent for children
Scale Multiplier Groups use one uniform value

The viewport gizmo uses world axes by default; switch to local axes with the axis button above the viewport. Snap settings for movement, rotation and scale are next to it.

  1. Click the folder button in the Outliner, or choose Add → Group.
  2. Select an object and choose a Group in Details → Transform → Parent. Changing the parent keeps the object’s world position, rotation and scale.
  3. Choose Scene root to detach it again.
  4. Move, rotate or uniformly scale the Group to transform the whole assembly.

Groups can be nested. Duplicating or removing a Group includes its whole subtree, as one undo step. Group scripts, Blueprints, spin and bobbing carry their children with them.

A Group selected in the Outliner and Details, with a nested child Group and a uniform Scale

  • Only a Group can be a parent.
  • Groups need a positive, uniform scale.
  • Dynamic and Kinematic bodies must stay at the scene root.
  • Hierarchies can be at most 32 levels deep, and cycles are rejected.
  • Groups have no collider or surface; their children provide collision and appearance.

Script functions such as position(), translate() and set_position() always work in world coordinates, even on children.

You’ll build a two-part signpost inside a Group, then move and turn the Group so both parts follow. Start from a new project (File → New project…).

  1. Choose Add → Group. In Details, set Name to Signpost and leave Location at 0, 0, 0.
  2. Choose Add → Cube and name it Post. In Details → Transform, set Parent to Signpost, then set Local location to 0, 1, 0 and Scale to 0.2, 2, 0.2.
  3. Choose Add → Cube again and name it Board. Set Parent to Signpost, Local location to 0, 1.8, 0 and Scale to 1.2, 0.4, 0.1.
  4. Select Signpost in the Outliner. Set Location to 10, 0, -5 and Rotation ° to 0, 45, 0. The post and board move and turn with it.
  5. Press F to frame the Group and both children.

Set Parent before typing the local values: changing the parent keeps the object where it is in the world and rewrites its local transform to match.

Do the same from the command line. One scene.batch builds the assembly as a single undo step; IDs 1–3 assume a project with no objects yet:

Terminal window
feather-cli --workspace ./signpost command project.create \
--json '{"name":"Signpost"}' --save project.feather.json
feather-cli --workspace ./signpost --project project.feather.json command scene.batch --json '{
"commands": [
{"command": "scene.add", "arguments": {"kind": "Group", "name": "Signpost", "position": [0, 0, 0]}},
{"command": "scene.add", "arguments": {"kind": "Cube", "name": "Post", "parent_id": 1, "position": [0, 1, 0]}},
{"command": "scene.update", "arguments": {"id": 2, "patch": {"scale": [0.2, 2, 0.2]}}},
{"command": "scene.add", "arguments": {"kind": "Cube", "name": "Board", "parent_id": 1, "position": [0, 1.8, 0]}},
{"command": "scene.update", "arguments": {"id": 3, "patch": {"scale": [1.2, 0.4, 0.1]}}}
]
}' --save project.feather.json
# Rotation is in radians in commands: 0.7854 is 45°.
feather-cli --workspace ./signpost --project project.feather.json command scene.update \
--json '{"id":1,"patch":{"position":[10,0,-5],"rotation":[0,0.7854,0]}}' --save project.feather.json

Check it worked. scene.get shows that the board’s authored values are still local to the Group:

Terminal window
feather-cli --workspace ./signpost --project project.feather.json command scene.get --json '{"id":3}'

It reports "parent_id": 1 and "position": [0.0, 1.8, 0.0]. To see world poses, run game.simulate with {"frames":1}: every object’s initial.position has X 10 and Z −5, and all three share the Group’s rotation.

To find a field quickly, type in Search details at the top of the Details panel (or press Cmd/Ctrl+F with the pointer over it). A section whose title matches stays whole; in the others, only the properties whose names match stay visible. Escape or the clear button shows everything again.

  • Select objects in the viewport or the Outliner. Search filters the Outliner but keeps parent Groups of each match visible.
  • Cmd/Ctrl+D duplicates; Delete removes; End drops a root object or Group to the terrain.
  • Cmd/Ctrl+C and Cmd/Ctrl+V copy and paste objects, including Group subtrees of up to 128 objects. Each paste gets fresh IDs and is one undo step.
Command Shortcut Result
Frame → Selected object F Fits the selection; a Group frames all of its descendants
Frame → All authored objects Shift+F Fits every object in the level
Frame → Reset view Returns to the default camera

Framing keeps the current viewing angle and accounts for rotation, scale and the visible area of the viewport. A model that is still loading is framed by its collider; frame it again once it has loaded.

  • Up to 100,000 objects per project.
  • Groups must be nested no more than 32 deep.
  • Copy and paste, duplicate and prefab capture handle up to 128 objects at a time.
Terminal window
# Add a Group and a cube inside it, then move the cube out while keeping its world pose.
# The project already holds object 1, so the Group receives ID 2 and the cube ID 3.
feather-cli --workspace ./my-game --project project.feather.json command scene.batch --json '{
"commands": [
{"command": "scene.add", "arguments": {"kind": "Group", "name": "Assembly", "position": [0, 0, 0]}},
{"command": "scene.add", "arguments": {"kind": "Cube", "name": "Part", "parent_id": 2, "position": [1, 0, 0]}}
]
}' --save project.feather.json
feather-cli --workspace ./my-game --project project.feather.json command scene.reparent \
--json '{"id":3,"parent_id":null,"preserve_world":true}' --save project.feather.json

scene.batch applies up to 64 commands as one undo step, or none of them if any fails. In a live editor, viewport.focus and viewport.frame_scene frame objects; see MCP setup.