Position, rotation, and scale
Move, rotate, and scale created, found, or selected BDEngine objects with setPosition, setRotation, and setScale: units, coordinates, and editor updates.
To move a block display you created or an object from the selection, call the methods on that object. They work with built-in editor objects; you do not need to create a custom class.
Which objects can you transform?
BlockDisplay, ItemDisplay, TextDisplay, and regular Collection groups inherit transform methods from Selectable. Get a live object through editorAPI.add, editorAPI.find, or editorAPI.getSelectedObjects and call the method on it. The operation is the same regardless of how you obtained the object.
For example, create a regular block display and set its position, rotation, and scale:
const block = await editorAPI.add( 'stone', 'BlockDisplay', null, true);if (block) { block.setPosition({ x: 2, y: 1, z: 0 }); block.setRotation({ y: 90 }); block.setScale({ x: 0.5, y: 0.5, z: 0.5 }); editorAPI.update(true);}Or move one selected block display by one unit along its local Y axis:
const block = editorAPI.getSelectedObjects() .find(object => object.isBlockDisplay && !object.isStructureBlock);if (block) { const position = block.getPosition(); block.setPosition({ y: position.y + 1 }); editorAPI.update(true);}These examples assume the editor is ready and in normal editing mode.
Real StructureBlock objects have different rules: integer positions and
disabled rotation and scaling. Rotation and scale of structure groups depend
on the structure preview mode. Having a method does not mean that every
utility object supports the same operation.
editorAPI remains the stable public entry point. Methods on a returned object belong to editor classes; obtaining the object through editorAPI does not make all of its properties part of the stable API. See editorAPI and the internal editor for this distinction. Custom classes and geometry are covered separately in Custom objects and dependencies.
Coordinates and general rules
The setters and getters below are synchronous. Position, rotation, and scale are local to the parent. By default, setters mark changed geometry, selection frames, and raycast data for an update, but do not create an Undo command, broadcast the transform to Share Party, or update every panel.
The setters have a skipDirty = false parameter. Keep the default in a typical
plugin. Setting it to true skips internal change tracking and requires you
to manage updates yourself.
setPosition, setRotation, and setScale accept a partial set of axes:
an omitted axis or one set to undefined remains unchanged.
Supplied values must be finite numbers. Strings, NaN, and infinities
throw a ProjectValidationError; invalid input does not apply a partial
set of changes.
With a rotated or scaled parent, local Y may not match world up, and moving
by 1 does not necessarily move the object by one block in the world. A setter
sets the final local value; to offset the current position, read getPosition()
first, as in the example above.
The objPos parameter of editorAPI.add has a different contract: it is an
initial offset in world coordinates. Do not treat it as equivalent to setPosition.
Position
setPosition
object.setPosition({ x, y, z }, skipDirty = false) changes the local position.
Values use BDEngine scene units; for regular displays, one unit corresponds
to one Minecraft block. Values are rounded to object.stepPosition
(default 0.000625). Returns undefined.
object.setPosition({ x: 2, z: -1 }); // Y stays unchanged.getPosition
object.getPosition() returns a new plain { x, y, z } object containing
rounded local coordinates. Changing this result does not change the original
position. The getter itself does not overwrite the position.
const position = object.getPosition();object.setPosition({ y: position.y + 1 });Rotation
setRotation
object.setRotation({ x, y, z }, skipDirty = false) takes degrees,
rounds to object.stepRotation (default 0.01), and updates the corresponding
Three.js angles. Returns undefined.
object.setRotation({ y: 90 });By contrast, the standard Three.js object.rotation property contains radians.
Do not assign degrees directly to object.rotation.y.
getRotation
object.getRotation() returns { x, y, z } in degrees.
If the internal representation has not been created yet, it is calculated
from the current rotation.
Unlike getPosition(), this returns a reference to the internal
customRotation. Copy it when you need a snapshot. Manually changing this
reference does not recalculate the Three.js rotation or notify the editor
of a change:
const rotation = { ...object.getRotation() };object.setRotation({ y: rotation.y + 15 });Angles may retain accumulated turns. Do not assume that they are always
normalized to the range from -180 to 180.
setQuaternionRotation
object.setQuaternionRotation(quaternion, skipDirty = false) copies the
quaternion and updates the rotation representation in degrees using the change
relative to the previous quaternion. Returns undefined; an empty argument
does not change anything.
Pass a normalized THREE.Quaternion. Validation requires finite x/y/z/w
components and a nonzero length, but the method does not automatically
normalize the assigned quaternion. An invalid quaternion throws
a ProjectValidationError.
const quaternion = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3(0, 1, 0), Math.PI / 2);object.setQuaternionRotation(quaternion);The angle in setFromAxisAngle is in radians, while getRotation() still
returns degrees. A quaternion describes orientation, but does not itself
store the number of complete turns, so do not use it as a replacement
for animation keys with multiple revolutions.
Scale
setScale
object.setScale({ x, y, z }, skipDirty = false) sets scale factors.
Values are rounded to stepScale (default 0.0001) and clamped to a minimum
of minScale (default 0.0011). Returns undefined.
For a particle, it also updates the scale of its gizmo.
object.setScale({ x: 2, y: 2, z: 2 });A zero or negative scale does not create a zero size or a reflection:
it is raised to the minimum positive value. Supported objects use the
separate setMirrorX method for reflection.
getScale
object.getScale() returns a new { x, y, z } object.
The getter may change the original object: if the current scale does not
meet the rounding or minimum constraints, it calls setScale and updates
the local and world matrices. It is therefore not always a read without
side effects.
Shear, reflection, and matrices
Affine transforms are enabled for objects whose isDisplay or isCollection
is true. They are not enabled for a plain custom Selectable subclass.
Do not assign these flags just to get the effect: other editor systems
expect the corresponding built-in type.
The table describes the base Selectable methods. Specialized types may
override them: for example, StructureBlock does not apply shear or reflection,
and structure groups disable these operations as well.
| Method | Contract |
|---|---|
supportsAffineTransform() |
Returns a boolean indicating whether shear and reflection are supported |
getShear() |
Returns a copy of { xy, xz, yz }, with angles in radians |
setShear({ xy, xz, yz }, skipDirty = false, updateMatrix = true) |
Updates the supplied components. Each must be a finite angle strictly between -Math.PI / 2 and Math.PI / 2; an invalid angle returns false without a change, success returns true |
getMirrorX() |
Returns a boolean indicating reflection along local X |
setMirrorX(value, skipDirty = false, updateMatrix = true) |
Converts the value to a boolean and updates the matrix and internal state according to the flags. Returns undefined |
setFromAffineMatrix(matrix, options = {}) |
Decomposes a THREE.Matrix4 into components and returns the object itself |
applyMatrix4(matrix) |
Premultiplies the local matrix by the supplied matrix and returns the object itself |
updateMatrix() |
Rebuilds the local matrix, including supported shear and reflection; returns undefined |
setShear accepts a partial set of axes. Values very close to the boundary
are additionally clamped to a magnitude of Math.PI / 2 - 0.000001.
setFromAffineMatrix accepts referenceRotation = null (a reference
THREE.Euler), skipDirty = false, and updateWorld = true.
For an object without affine support, the matrix is decomposed into standard
position, quaternion, and scale.
if (object.supportsAffineTransform()) { object.setShear({ xy: THREE.MathUtils.degToRad(10) }); object.setMirrorX(true); editorAPI.update(true);}Updates, history, and collaboration
After direct changes, call editorAPI.update. Pass true if you changed a selected object or the selection itself, so that the editor also rebuilds the transform controller’s temporary selection. For a series of changes, one call after all the setters is enough:
const block = editorAPI.getSelectedObjects() .find(object => object.isBlockDisplay && !object.isStructureBlock);if (block) { block.setPosition({ x: 2 }); block.setRotation({ y: 45 }); block.setScale({ x: 1.5, y: 1.5, z: 1.5 }); editorAPI.update(true);}Setters mark data for an update, but do not create a separate Undo/Redo command
or broadcast arbitrary changes to Share Party participants. editorAPI.update
does not do that either, and does not save a file. Even if you created an object
through add with history enabled, subsequent direct transforms do not
automatically become separate undoable actions.
If your plugin needs custom history commands or synchronization, implement them through internal editor mechanisms and check them when updating the editor. For programmatic selection, see the selected property.