Docs are under construction. Content may be incomplete or change.

Live Scene Control

Page type: Reference · Generated from src/script/apiDocs · Verified 2026-07-13T00:00:00.000Z
On this page

Every call in this namespace crosses the worker→host RPC bridge and MUTATES the live application state the user is currently looking at — the active selection highlights, the layer tree, annotations/measurements, the camera, trajectory playback, which project tab is open, and undo history itself. That is the opposite of tako.structure.*, whose verbs are pure functions that return a new, independent Structure copy and touch nothing on screen. Reach for tako.select/tako.layers/tako.annotations/etc. specifically when the goal is to inspect, stage, or present the scene the user sees (select the atoms a result is about, label a key distance, frame the camera before tako.ui.capture()) rather than to compute a new structure.

Most structural edits here — layer changes, annotations, constraints, named selections — go through the same auto-commit path as manual editing and are undoable through tako.history.*. A few things are deliberately excluded from that history: atom/tag selection, camera position, and trajectory-playback state are never recorded, so undo/redo/checkout never moves the camera or reverts a selection. Each project tab (tako.project.*) also carries its own independent undo history and camera — switching tabs swaps both in, so tako.history.* always operates on whichever project is currently active.

tako.select.set

await tako.select.set(ids: number[]) => { atoms: number[]; tags: string[] }

Replace the atom selection with exactly these atom ids.

ParameterTypeDefaultContract
idsnumber[]Stable Atom.id values (not array indices); ids that do not exist in the current structure are dropped before selecting.

Returns: { atoms, tags } — the resulting selection: atoms is the new selected-atom-id list, tags is the (unchanged, unless cleared — see notes) selected-tag-id list.

  • Also clears the tag/annotation selection (tags becomes []) in the app’s default selection-click mode. If the UI is currently in ‘onlyAdd’ selection mode (a sticky click-mode toggle the user can leave on, off by default), ids are added to the existing selection instead of replacing it.
  • If ‘select across layers’ is off in the UI (on by default), ids outside the active layer/group are silently dropped too.
const { atoms } = await tako.select.set([12, 13, 14]);

tako.select.add

await tako.select.add(ids: number[]) => { atoms: number[]; tags: string[] }

Add these atom ids to the current atom selection.

ParameterTypeDefaultContract
idsnumber[]Ids to add; ids not present in the structure are dropped, ids already selected are left as-is.

Returns: { atoms, tags } — the selection after the union.

  • Unlike select.set, this does not filter by the active layer/group selection scope and does not touch the tag selection.
  • This is a set union, not a toggle — re-adding an already-selected id is a no-op for that id.

tako.select.remove

await tako.select.remove(ids: number[]) => { atoms: number[]; tags: string[] }

Remove these atom ids from the current atom selection.

ParameterTypeDefaultContract
idsnumber[]Ids to drop from the selection; ids not currently selected are ignored.

Returns: { atoms, tags } — the selection after removal.

  • Only affects atoms; the tag selection is untouched.

tako.select.clear

await tako.select.clear() => { atoms: number[]; tags: string[] }

Clear both the atom and tag/annotation selection.

Returns: { atoms: [], tags: [] }.

tako.select.all

await tako.select.all() => { atoms: number[]; tags: string[] }

Select every atom in the structure.

Returns: { atoms, tags } — atoms is every atom id in the structure.

  • Ignores the active layer/group selection scope and the ‘select across layers’ setting — always selects every atom in the live structure.
  • Leaves the tag selection untouched.

tako.select.invert

await tako.select.invert() => { atoms: number[]; tags: string[] }

Invert the atom selection across the whole structure.

Returns: { atoms, tags } — atoms is every atom id that was NOT previously selected.

  • Inversion is over the entire structure regardless of layer scope: previously-selected atoms become unselected and vice versa.
  • Leaves the tag selection untouched.

tako.select.byElement

await tako.select.byElement(element: string, mode?: 'replace' | 'add' | 'remove' | 'invert') => { atoms: number[]; tags: string[] }

Select atoms of one element.

ParameterTypeDefaultContract
elementstringExact, case-sensitive match against atom.element (e.g. “Fe”).
mode'replace' | 'add' | 'remove' | 'invert''replace'’replace’ sets the selection to just the matches; ‘add’ unions them in; ‘remove’ drops them from the current selection; ‘invert’ toggles just the matched atoms.

Returns: { atoms, tags } — the selection after applying the mode.

  • Matching ignores layer scope/visibility/lock state entirely — it filters purely on atom.element across the whole structure.
await tako.select.byElement('O');
await tako.select.byElement('H', 'add');

tako.select.byFilter

await tako.select.byFilter(filter: { query?: string; element?: string; layerId?: string; selected?: boolean; constrained?: 'any' | 'constrained' | 'free'; visible?: boolean; locked?: boolean }, mode?: 'replace' | 'add' | 'remove' | 'invert') => { atoms: number[]; tags: string[] }

Select atoms matching a filter predicate.

ParameterTypeDefaultContract
filter.querystringCase-insensitive substring match against a haystack of id, element, layerId, the layer’s name, label, and x/y/z/fx/fy/fz (stringified).
filter.elementstringExact match on atom.element.
filter.layerIdstringExact match on atom.layerId.
filter.selectedbooleanMatches the atom’s selection state BEFORE this call is applied.
filter.constrained'any' | 'constrained' | 'free''any' (field omitted)’constrained’ = atom has at least one fixed axis; ‘free’ = no fixed axis; ‘any’/omitted = no filtering on constraint state.
filter.visiblebooleanMatches whether the atom’s layer (and its layer group) is currently visible.
filter.lockedbooleanMatches whether the atom’s layer is locked.
mode'replace' | 'add' | 'remove' | 'invert''replace'Same semantics as select.byElement’s mode.

Returns: { atoms, tags } — the selection after applying the mode.

  • Filter fields are ANDed together; an empty object {} matches every atom (so byFilter({}, ‘invert’) behaves like select.invert()).
  • Ignores layer scope the same way select.byElement/all/invert do — it is not restricted by the active-layer selection scope.
await tako.select.byFilter({ element: 'C', constrained: 'free' });

tako.select.get

await tako.select.get() => { atoms: number[]; tags: string[] }

Read the current selection without changing it.

Returns: { atoms, tags } — the current selected atom ids and selected tag/annotation ids.

tako.select.tags

await tako.select.tags(ids: string[], mode?: 'replace' | 'add') => { atoms: number[]; tags: string[] }

Select text tags (annotations) by id.

ParameterTypeDefaultContract
idsstring[]Annotation ids to select. Only text-kind annotations are selectable as tags — distance/angle measurement ids and unknown ids are silently filtered out.
mode'replace' | 'add''replace'’replace’ sets the tag selection to exactly these (valid) ids. ‘add’ toggles each given id individually: one not currently selected is added, one already selected is removed.

Returns: { atoms, tags } — tags reflects the new tag selection.

  • In ‘replace’ mode, if none of the given ids are valid text tags, the tag selection is cleared to [].
  • Unlike clicking a tag in the UI (which replaces the whole selection with just that tag), this call never touches the atom selection — atoms is unaffected either way.

tako.select.save

await tako.select.save(name: string) => { id: string; name: string; atomIds: number[] } | null

Save the current atom selection as a named selection.

ParameterTypeDefaultContract
namestringDisplay name; if it trims to empty, an auto-generated name like ‘Selection N’ is used instead.

Returns: The new named selection, or null if there is no active structure. Saved from the CURRENT atom selection (not an argument), deduplicated and filtered to atoms that still exist.

  • Records an undo step (‘Create named selection’) and persists it into the active project.
  • Named selections only ever store atom ids — the tag selection is not part of them.
await tako.select.set([0, 1, 2]);
const saved = await tako.select.save('active site');

tako.select.applyNamed

await tako.select.applyNamed(id: string) => { atoms: number[]; tags: string[] }

Re-apply a previously saved named selection by id.

ParameterTypeDefaultContract
idstringId returned by tako.select.save.

Returns: { atoms, tags } — the selection after applying (or the unchanged current selection if id is unknown).

  • Re-resolves the saved atom ids against the LIVE structure at apply time, dropping any that no longer exist (e.g. atoms deleted since the selection was saved).
  • An unknown id is a silent no-op: the current selection is returned unchanged, with no error.
  • Replaces the atom selection outright (like select.set) and does not affect the tag selection.

tako.layers.list

await tako.layers.list() => Array<{ id: string; name: string; kind: 'layer' | 'group'; visible: boolean; locked: boolean; groupId?: string | null; active: boolean }>

List every layer and layer group (folder) in the active structure.

Returns: Groups (folders) first, then every layer — including layers nested inside a group — as one flat array.

  • A layer’s groupId names its parent folder (null/absent at the top level); group entries (kind: ‘group’) have no groupId field.
  • active marks the current UI-focused layer or group; it is independent of the atom selection.

tako.layers.create

await tako.layers.create(options?: { name?: string; group?: string | null }) => { id: string; name: string; kind: 'layer'; visible: boolean; locked: boolean; groupId?: string | null; active: boolean }

Create a new (empty) layer.

ParameterTypeDefaultContract
options.namestringIf given, renames the new layer after creation; otherwise it gets an auto-numbered name like ‘Layer N’.
options.groupstring | nullthe currently active group in the UIParent folder id. An id that does not match a real group is accepted without validation — the layer is simply tagged with it.

Returns: The created layer’s info.

  • The new layer becomes the active layer and the sole selected layer.
  • If name is given, this records TWO undo steps (‘Add layer’ then ‘Rename layer’).
const layer = await tako.layers.create({ name: 'Adsorbate' });

tako.layers.rename

await tako.layers.rename(id: string, name: string) => void

Rename a layer or a layer group (folder).

ParameterTypeDefaultContract
idstringA layer id or a group id (checked against groups first).
namestringNew name; trimmed. An empty (after trim) name is ignored.

Returns: void.

  • An id that matches neither a layer nor a group is a silent no-op on the tree, but the layer-rename path still sets it as the ‘active layer’ and unconditionally records an undo step (‘Rename layer’) — so a bogus id can add a no-op entry to tako.history.list().

tako.layers.remove

await tako.layers.remove(id: string) => void

Delete a layer or ungroup a layer group (folder).

ParameterTypeDefaultContract
idstringA layer id or a group id.

Returns: void.

  • Deleting a group ungroups its layers (they become top-level) rather than deleting their atoms; deleting a layer reassigns its atoms to another existing layer — atoms are never deleted by this call.
  • The last remaining layer cannot be removed (silently refused) — there is always at least one layer.
  • An unknown id is a silent no-op on the tree, but (like rename) it still becomes the ‘active layer’ first and unconditionally records an undo step, which can also reassign the active-layer pointer to an arbitrary fallback layer.

tako.layers.setVisible

await tako.layers.setVisible(id: string, visible: boolean) => void

Show or hide a layer or layer group.

ParameterTypeDefaultContract
idstringA layer id or a group id.
visiblebooleanTarget visibility.

Returns: void.

  • Cleanly no-ops (no undo step) for an unknown id or when visible already matches the current state — unlike rename/remove, this path is properly existence-guarded.

tako.layers.moveAtoms

await tako.layers.moveAtoms(ids: number[], layerId: string) => void

Move atoms into a layer.

ParameterTypeDefaultContract
idsnumber[]Atom ids to move; subject to the same existence/active-layer-scope filtering as select.set, since it is implemented by selecting the atoms first.
layerIdstringDestination layer id; must already exist.

Returns: void.

  • If layerId does not match an existing layer, or no atoms end up selected after filtering, this is a silent no-op with no undo step.
  • On success this reassigns atom.layerId (a structure edit) and records an undo step; it also makes layerId the active layer.

tako.layers.group

await tako.layers.group(layerIds: string[], name?: string) => void

Group these layers into a new folder.

ParameterTypeDefaultContract
layerIdsstring[]Layer ids to fold into a new group.
namestringName for the new folder; auto-numbered (‘Folder N’) if omitted.

Returns: void.

  • If none of layerIds match existing layers (including an empty array), this still creates a new EMPTY folder rather than failing.
  • The new folder becomes the active group; records an undo step.

tako.layers.merge

await tako.layers.merge(layerIds: string[]) => void

Merge these layers into one.

ParameterTypeDefaultContract
layerIdsstring[]Layers to merge. The first id is the merge target; the rest are absorbed into it (their atoms’ layerId is reassigned, then the source layers are deleted). If only one id is given, the currently-active layer is used as the target instead.

Returns: void.

  • A no-op if fewer than two distinct target/source ids result (e.g. an empty or single-element array with no active layer to fall back to).
  • Source ids that don’t match a real layer still count toward ‘there is something to merge’: merge([‘realLayer’, ‘bogus’]) still records an undo step (‘Merge layers’) even though nothing observable changed.

tako.annotations.add

await tako.annotations.add(input: { text?: string; atomId?: number; position?: { x: number; y: number; z: number }; style?: { color?: string; size?: number; weight?: number } }) => string

Add a text annotation (tag) to the scene.

ParameterTypeDefaultContract
input.textstring'Text'Label text.
input.atomIdnumberAnchor the label to an atom: it live-follows that atom’s current position and is hidden while the atom doesn’t exist.
input.position{ x: number; y: number; z: number }(0,0,0), or the anchor atom’s position if atomId is setWorld position (Å); used as the creation-time fallback, especially when atomId is absent.
input.style{ color?: string; size?: number; weight?: number }size is clamped to [8, 32]px.

Returns: The new annotation’s id.

  • An atomId that doesn’t match any atom in the structure is accepted without error — the label is created but stays hidden until an atom with that id exists.
  • Records an undo step (‘Add annotation’).
const id = await tako.annotations.add({ atomId: 3, text: 'active site' });

tako.annotations.list

await tako.annotations.list() => Array<{ id: string; kind: string; text: string; atomId?: number; position?: { x: number; y: number; z: number } }>

List every text annotation (tag) currently on the structure.

Returns: One entry per text annotation; kind is always ‘text’.

  • Distance/angle measurements are excluded — see tako.measure.list.
  • position reflects where the label was created/last explicitly placed in world space, not a live-tracked atom position — for atom-anchored labels (atomId set) the actual on-screen position instead follows the atom live and can differ from this field.

tako.annotations.update

await tako.annotations.update(id: string, patch: { text?: string; style?: { color?: string; size?: number; weight?: number } }) => void

Edit an annotation’s text or style.

ParameterTypeDefaultContract
idstringAny annotation id — text tag or measurement.
patch.textstringNew label text.
patch.style{ color?: string; size?: number; weight?: number }Only applies to text-kind annotations; ignored for measurements.

Returns: void.

  • IMPORTANT: on a distance or angle measurement id, a patch.text that parses as a leading number is NOT a relabel — it re-solves the measurement to that value by MOVING an atom (mirroring dragging the measurement handle in the UI) and records a structure-edit undo step (‘Set distance’/‘Set angle’). Use a non-numeric string, or target a text tag, to just change display text.
  • An unknown id is a silent no-op — no error, no undo step.

tako.annotations.remove

await tako.annotations.remove(id: string) => void

Remove an annotation.

ParameterTypeDefaultContract
idstringAny annotation id — text tag or measurement.

Returns: void.

  • Works uniformly across text tags and distance/angle measurements. Unknown id: silent no-op, no undo step.

tako.annotations.move

await tako.annotations.move(id: string, dx: number, dy: number) => void

Nudge a label’s on-screen offset.

ParameterTypeDefaultContract
idstringAnnotation id.
dxnumberPixel offset delta added to the label’s current screen-space offset.
dynumberPixel offset delta (screen space, not world units).

Returns: void.

  • Additive: nudges the existing on-screen offset by (dx, dy) pixels; call repeatedly to accumulate a move.
  • Unknown id: fully silent no-op, no undo step.

tako.measure.distance

await tako.measure.distance(i: number, j: number) => { id: string; kind: 'distance'; atomIds: number[]; label: string; value: number; unit: 'Å' }

Place a persistent distance measurement between two atoms.

ParameterTypeDefaultContract
inumberFirst atom id.
jnumberSecond atom id. Order doesn’t matter — atomIds are stored sorted ascending.

Returns: { id, kind, atomIds, label, value, unit } — value is the live distance in Å, recomputed from current atom positions on every call (even if the stored label string is stale). unit is ‘Å’.

  • Idempotent by atom pair: if a distance measurement already exists between these two atoms (regardless of call order), the existing annotation is returned rather than creating a duplicate.
  • Throws (‘Cannot measure missing atoms.’) if either atom id doesn’t exist in the structure.

tako.measure.angle

await tako.measure.angle(i: number, j: number, k: number) => { id: string; kind: 'angle'; atomIds: number[]; label: string; value: number; unit: '°' }

Place a persistent angle measurement between three atoms.

ParameterTypeDefaultContract
inumberFirst atom id.
jnumberVertex atom id.
knumberThird atom id.

Returns: { id, kind, atomIds, label, value, unit } — value is the live angle in degrees at vertex j, recomputed on every call. unit is ’°’.

  • Unlike measure.distance, atomIds preserve call order (not sorted) — measuring the same three atoms in a different order creates a distinct measurement rather than reusing one.
  • Adding an angle measurement removes any existing distance measurement between its first two atoms (i, j) — the angle supersedes it visually.
  • Throws if any of the three atoms doesn’t exist.

tako.measure.list

await tako.measure.list() => Array<{ id: string; kind: 'distance' | 'angle'; atomIds: number[]; label: string; value: number; unit: string }>

List every persistent distance/angle measurement.

Returns: One entry per measurement.

  • value is always recomputed from the atoms’ current positions (accurate even if the structure changed after the measurement was created); label is the last text explicitly set on the annotation and can lag behind if the geometry changed some other way.
  • Text annotations (tags) are excluded — see tako.annotations.list.

tako.measure.clear

await tako.measure.clear() => void

Remove every distance/angle measurement (text tags are left alone).

Returns: void.

  • Each removal records its own undo step (‘Remove measurement’) rather than one batched step.

tako.constraints.fix

await tako.constraints.fix(ids: number[], options?: { axes?: string | boolean }) => void

Fix atoms along the given axes.

ParameterTypeDefaultContract
idsnumber[]Atom ids to fix.
options.axesstring | booleantrue (all axes)Omitted or true fixes all of x/y/z; false fixes none (equivalent to freeing); a string is matched case-insensitively for the letters it contains — e.g. ‘z’ fixes only z, ‘xy’ fixes x and y and leaves the other axis free.

Returns: void.

  • Ids in a locked layer are silently dropped (locked atoms can’t be edited); if none remain, this is a no-op.
  • Implemented via the same tako.structure.fix verb the pure structure API uses, so this is exactly what later tako.optimize/tako.molecularDynamics calculations read as fixed degrees of freedom.
  • Records an undo step (‘Set constraints’).
await tako.constraints.fix(bottomLayerIds, { axes: 'z' });

tako.constraints.free

await tako.constraints.free(ids: number[]) => void

Free atoms (remove all constraints).

ParameterTypeDefaultContract
idsnumber[]Atom ids to fully release.

Returns: void.

  • Equivalent to constraints.fix(ids, { axes: false }); removes the constraint field entirely rather than leaving an explicit all-free marker.
  • Same locked-layer filtering as constraints.fix.

tako.constraints.list

await tako.constraints.list() => Array<{ atomId: number; fixed: [boolean, boolean, boolean] }>

Per-atom fixed-axis mask for currently-constrained atoms.

Returns: fixed[k] is true where that axis (x, y, z) is fixed.

  • Only atoms with at least one fixed axis are listed — fully free atoms (never constrained, or freed back to all-free) don’t appear at all.

tako.trajectory.frame

await tako.trajectory.frame(n?: number) => number

Get the current trajectory frame index, or set it when n is given.

ParameterTypeDefaultContract
nnumberIf given, jumps to this frame index (floored, then clamped into [0, frameCount - 1]); if omitted, just reads the current index.

Returns: The resulting current frame index.

  • Throws (‘No active calculation with a trajectory. Open a calculation project first.’) if no calculation project tab is currently active — including the getter form (frame() with no argument).
  • If the active calculation has zero trajectory frames, setting n is a silent no-op (the index is unaffected) rather than throwing.

tako.trajectory.count

await tako.trajectory.count() => number

Number of frames in the active calculation’s trajectory.

Returns: 0 if there’s no active calculation or it has no frames.

  • Unlike the other trajectory.* calls, this never throws when there’s no active calculation — it just returns 0.

tako.trajectory.play

await tako.trajectory.play() => void

Start trajectory playback for the active calculation.

Returns: void.

  • Throws the same ‘no active calculation’ error as trajectory.frame.
  • Playback state is not part of the undo history.

tako.trajectory.pause

await tako.trajectory.pause() => void

Pause trajectory playback.

Returns: void.

  • Throws the same ‘no active calculation’ error as trajectory.frame.

tako.trajectory.loop

await tako.trajectory.loop(on: boolean) => void

Set whether trajectory playback loops back to the range start.

ParameterTypeDefaultContract
onbooleanWhether playback loops after reaching the end of its range.

Returns: void.

  • Throws the same ‘no active calculation’ error as trajectory.frame.

tako.trajectory.range

await tako.trajectory.range(start: number, end: number | null) => void

Set the trajectory playback range.

ParameterTypeDefaultContract
startnumberFirst frame of the playback range.
endnumber | nullLast frame of the range; null means through the last available frame.

Returns: void.

  • Both bounds are clamped into the valid frame range, and the current frame index is re-clamped into the new range too.
  • Throws the shared ‘no active calculation’ error, or is a no-op if the active calculation has zero frames.

tako.trajectory.mode

await tako.trajectory.mode(modeIndex: number) => void

Jump playback to a named mode group within the trajectory (e.g. one vibrational/phonon normal mode).

ParameterTypeDefaultContract
modeIndexnumberSelects a frame group tagged with this mode index at calculation time.

Returns: void.

  • Jumps the current frame to that mode’s first frame and sets the playback range to exactly that mode’s frame span.
  • An unrecognized modeIndex (or a trajectory with no mode-tagged frames, e.g. a plain MD/optimization run) is a silent no-op.
  • Throws the shared ‘no active calculation’ error.

tako.trajectory.rate

await tako.trajectory.rate(framesPerSecond: number) => void

Set the trajectory playback rate.

ParameterTypeDefaultContract
framesPerSecondnumberRounded and clamped to [1, 60].

Returns: void.

  • Throws the shared ‘no active calculation’ error.

tako.trajectory.skip

await tako.trajectory.skip(skipFrames: number) => void

Set how many extra frames playback advances per tick.

ParameterTypeDefaultContract
skipFramesnumber0 advances one frame at a time; clamped to [0, 120].

Returns: void.

  • Throws the shared ‘no active calculation’ error.

tako.project.list

await tako.project.list() => Array<{ id: string; name: string; kind: 'structure' | 'calculation'; pinned: boolean; active: boolean }>

List every open project tab.

Returns: One entry per project tab.

tako.project.active

await tako.project.active() => { id: string; name: string; kind: 'structure' | 'calculation'; pinned: boolean; active: boolean } | null

Read the currently active project tab.

Returns: The active project’s info, or null (there is normally always at least one project tab open).

tako.project.create

await tako.project.create(options?: { structure?: Structure; title?: string }) => { id: string; name: string; kind: 'structure' | 'calculation'; pinned: boolean; active: boolean } | null

Open a new project tab, or a blank one.

ParameterTypeDefaultContract
options.structureStructureIf given, opens it as the project’s structure.
options.titlestringTab name; defaults to the structure’s own title or an auto-generated name.

Returns: The resulting active project’s info.

  • Without structure, opens a blank project tab.
  • Reuses the CURRENT tab instead of opening a new one if it’s already blank (no structure/layers) — so this doesn’t always create a brand-new tab.
  • Always creates a kind: ‘structure’ tab; calculation tabs (kind: ‘calculation’) are created by running a calculation operation (tako.optimize, etc.), not by this call.
  • Switches the active project to the new/reused tab.

tako.project.switch

await tako.project.switch(id: string) => void

Switch the active project tab.

ParameterTypeDefaultContract
idstringTarget project id.

Returns: void.

  • Silently no-ops for an unknown id, an empty id, or the already-active id.
  • Saves the outgoing tab’s full scene snapshot (structure, layers, annotations, camera, undo history, …) before switching, and restores the target tab’s own independent undo history and camera — tako.history.* after switching operates on the NEW tab’s history, not a shared global one.

tako.project.close

await tako.project.close(id?: string) => void

Close a project tab.

ParameterTypeDefaultContract
idstringthe currently active projectProject id to close.

Returns: void.

  • Silently no-ops for an unknown id.
  • Closing the last remaining tab doesn’t leave zero tabs — it’s replaced by a fresh blank project (there is always at least one).
  • Discards that tab’s in-memory scene state and undo history; there is no confirmation step at this layer.

tako.project.rename

await tako.project.rename(id: string, name: string) => void

Rename a project tab.

ParameterTypeDefaultContract
idstringProject id.
namestringNew name; trimmed.

Returns: void.

  • Silent no-op for an unknown id, or a name that trims to empty.

tako.project.pin

await tako.project.pin(id: string) => void

Pin a project tab.

ParameterTypeDefaultContract
idstringProject id.

Returns: void.

  • No-op if id is unknown or already pinned.
  • Pinned tabs are moved to the front of the tab order (grouped together); there is no unpin call in this API surface.

tako.history.undo

await tako.history.undo() => void

Step one entry back in the active project’s undo history.

Returns: void.

  • A no-op at the start of history (nothing to undo).
  • Restores the ENTIRE scene snapshot at that point — structure, layers/groups, components, annotations, named selections, visualization settings, periodic-boundary flags — and always clears the current atom selection as part of the restore (the tag selection is left as-is). Camera position is NOT part of this snapshot, so undo never moves the camera.

tako.history.redo

await tako.history.redo() => void

Step one entry forward in the active project’s undo history.

Returns: void.

  • A no-op at the end of history (nothing to redo).
  • Same full-snapshot restore semantics as undo: everything except camera is restored, and the atom selection is always cleared.

tako.history.checkout

await tako.history.checkout(index: number) => void

Jump directly to an arbitrary history entry.

ParameterTypeDefaultContract
indexnumberAbsolute history entry index, as listed by tako.history.list; may jump more than one step in either direction.

Returns: void.

  • An out-of-range index (negative or >= history length) is a silent no-op.
  • Same full-snapshot restore semantics as undo/redo (camera untouched, atom selection cleared).

tako.history.list

await tako.history.list() => Array<{ index: number; current: boolean; title: string }>

List the auto-commit history entries recorded for the active project.

Returns: One entry per recorded edit.

  • Each entry corresponds to one auto-recorded edit (the same auto-commit that fires for most structure/layer/annotation/constraint mutations in this namespace) — not every scene mutation creates one: selection, camera, and trajectory-playback changes are excluded from history.
  • current marks the entry the workspace is presently sitting at (after undo/redo/checkout).
  • Empty until the project’s first recorded edit — a freshly opened structure with no edits yet has no history entries.

Return to the Tako Script API index.