Use when changing Tiny World Builder selection placement, freehand drawing, asset clipboard, cut/copy/paste/duplicate, saved templates, or Stamps panel navigation.
68
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Use the existing board intent contract:
world[x][z] is intent and cellMeshes['x,z'] is render state.
New asset edits must flow through setCell(x, z, opts) or helpers that call it.
Selection state is exposed through window.__tinyworldSelection; use worldCoords(), materialize(), and replaceWorldCoords(). Do not parse raw selectedCells keys in new code.
Select-tool dragging of an already-selected cell/object should be preview-first: clone the current rendered object/extras into a separate hologram group, update only that virtual offset during pointermove, and commit the real cut/paste once on pointerup. Do not call shiftSelectedCellIntent() repeatedly from pointermove, because intermediate cut/paste steps can wipe cells along the drag path.
The dedicated Build Brush dock is intentionally top-centered under the world selector/top chrome, not near the bottom toolbar, so users can find it before painting.
Brush shape modes should keep the same safety contract: Single may use the existing live freehand draw path, but Line/Rectangle/Fill/Scatter must render a holographic footprint first and commit through applyToolToCell() only on pointer-up. Fill previews a bounded flood fill of matching connected cells; Scatter previews a deterministic organic subset inside the dragged rectangle. Keep the current brush mode in window.__tinyworldBrushModes so the mode indicator and UI stay in sync. Non-single brush modes should still feel like paint: selecting one from Select/Island/non-drawable tools (and pressing the canvas while one is active) must switch to a safe drawable fallback, the brush pointer path must win over editable-island widgets and orbit fallback, the ground footprint should update during pointermove before the drag threshold, and release should apply the paint without requiring a second click.
Duplicate, paste, and latest-template placement should be preview-first: copy/normalize the payload into a pending placement state, show a holographic representation following hover (clone live meshes when available; otherwise use a lightweight clipboard footprint), and commit only on the next board click. Keep Escape as a cancel path and keep any immediate helper explicitly opt-in/fallback-only.
Radial color changes should be preview-first: swatches should arm a tinted hologram for the selected object/cells and commit through updateSelectedBoardObjects() only on the next board click; Escape cancels.
Radial Generate should be contextual: summarize the current selection/selected object into the generator prompt/status instead of opening a blank generic modal. Do not imply a scoped apply unless the generator actually supports one; phrase it as context for the preview.
Generate should be preview-first: after the model returns validated world JSON, stage it as a holographic diff overlay with Apply / Regenerate / Discard controls. Do not call applyState() until the user applies the preview; discard must dispose preview geometries/materials.
Selected-cell rotation should be preview-first too: radial/keyboard rotate arms a holographic rotated clone, commits the real sel.rotate() on the next board click, and cancels with Escape. Keep immediate rotation as an explicit fallback only.
Contextual selected-object menus:
engine/world/33-radial-menu.js; prefer extending that radial menu over adding a second floating menu for object actions.duplicateActiveCellIntent(), deleteActiveCellIntent(), openGenerateModal(), selection API methods) rather than writing directly to world.data-pos-type="danger"; keep generation/AI actions on tertiary/orange styling so users can distinguish “create” from “mutate/delete”.Placement rules:
applyTool() path once per selected world coord with { skipSelectionBulk: true }. This preserves tool variants, terrain overrides, ghost transforms, fence logic, model stamp settings, and existing setCell side effects.Actions row can expose an Apply tool command; it should reuse the same bulk-placement helper rather than duplicating placement logic.dragMode === 'draw', drawVisitedCells, drawLastWorldCoord, and applyDrawToolToHit(). Drawing should not repeatedly stack terrain, bridges, or same-kind objects while the pointer crosses the same cell.kind: 'fence'; use fenceSide plus floors. Wall starts at level 4, boundary at level 5. Drawing a higher-level fence over an existing same-side fence should upgrade to that base level, not silently no-op. This also applies when the fence is stored as an extras entry beside another occupant.fenceSide from each draw step direction, not from the final pointer edge copied onto every skipped cell. The fence tool is now a single icon with no variant flyout. The placement hologram previews the auto fenceSide from hover (nearest tile edge), and repeat-clicking the same side levels it up 1→2→3→4→5 (wood → taller → wire → stone wall → steel boundary), so Wall/Boundary are reached by re-clicking rather than separate tool variants. The old fixed-direction variants (north, east, center-x, …) and the Edge/Wall/Boundary type variants were removed; the underlying fenceSide values (n/e/s/w/center-x/center-z) and floors levels are still valid for stored/rendered cells.Clipboard and templates:
{ version, origin, size, cells: [{ dx, dz, cell }] }.cloneCellIntent() so terrain, terrain height, kind, floors, building type, fence side, extras, rotation, offsetX/Y/Z, appearance, and waterFlow survive copy/paste and saved templates.tinyworld:asset-templates.v1 in localStorage. Keep these world-intent templates separate from model stamps and voxel build stamps.replaceWorldCoords() with placed cells so the pasted region stays selected for immediate follow-up edits.Templates; selecting one should place from its one-shot template payload and preserve the user's explicit copy/cut clipboard.localStorage entry, refreshes Stamps counts/cards, and clears stale selected-template tool state.Delete/Backspace should clear the active selection or hovered cell without writing to the asset clipboard; keep this separate from cut/copy semantics.Actions row should expose the same non-clipboard Delete path so mouse users can clear selected assets without using Cut.Shift+Arrow shifts selected cells through the internal move path without replacing the user's explicit clipboard, while arrows without an active selection keep camera/ghost behavior.Selection properties:
Edit, Transform, Appearance, Ground) so dense multi-selection actions stay scannable.?ai=0 / html.ai-disabled); hide prompt/chat controls, not the selected-object properties surface, and open selected objects directly to Properties so the property rows are visible.selectionAction so behavior remains centralized.applySelectionProperty().tinyworld:selection-props-active-tab.v1); keep the durable row keys/actions intact underneath tabbed Edit/Transform/Appearance/Ground views.tinyworld:selection-props-collapsed.v1; toggling sections must not remove or rename underlying row keys/actions.aria-label/title; the glyph is visual shorthand, not the action contract.currentValue plus aria-pressed/.active on property chips when a selected value is uniform, and leave mixed selections unpressed.bodyColor/topColor for any supported built-in kind, not just buildings. Expand applyAppearanceToObject() material buckets when exposing new colour rows so the world render and selection preview actually change.Default option that clears only the matching bodyColor/topColor override while preserving materials, style, transform, and the other colour row.objectScale, scaleX, scaleY, or scaleZ, preserving materials, colours, model IDs, and style.offsetX/Y/Z, preserving rotation, scale, materials, colours, model IDs, and style.new-island tool should select/create an editable island
board and route gizmo movement/rotation to the island group, while normal
object transform rows continue to operate on selected cells only.window.__tinyworldSelection.replaceWorldCoords(), not by
mutating selection internals, and should refresh from tinyworld:selection-changed,
tinyworld:world-changed, and tinyworld:grid-changed events.window.__tinyworldSelection.clear() / clearSelection(). That clear path
must deselect cells, editable-island engines, and whole editable islands
(selectEditableIsland(null)), not merely hide the radial DOM.window.__tinyworldSubEdit, not a
parallel inspector state. Layers should show part rows from
__tinyworldSubEdit.hierarchy(), select them with selectPart(partKey), and
refresh from tinyworld:sub-selection-changed. The shared transform gizmo can
target __tinyworldSubEdit.selectedGizmoTarget(); use movePart(..., { snap: !shiftKey }), scalePart(), and rotatePart() so keyboard, Properties, and
in-scene handles stay consistent.isVoxelSubEditableKind().
Radial menu and Properties must use that helper instead of maintaining
separate kind lists. When a supported built-in object enters sub-edit,
renderCellObjectImpl() forces the voxel renderer for that active cell so
rock/fence/crop/animal/micro voxel objects get real part keys. Entering edit
should not auto-explode; explicit Explode remains a user action. A plain
canvas click that misses a selectable part exits sub-edit and must not fall
through to cell selection or placement on the same click.voxel-build / customParts objects are editable through the same
Layers / Properties appearance rows as built-ins: All material, Body material,
Top material, Body/Top colour, and matching material-scale resets. Keep
model-stamp excluded from Body/Top material rows, but do not exclude
voxel-build.Stamps panel:
stampBuilderAllTools() builds model, voxel, and built-in stamp tools; filtering combines active category and search text.tuft; do not leave toolbar-only assets out of the searchable stamp library.Recent stamps category is derived from tinyworld:stamp-builder-recent.v1 and should use the same stampBuilderSelectionKey() values as selected-card state. Keep it ordered by most recent selection and remove deleted template keys.Recent; ignore Select, Erase, Auto, hidden tools, and other non-stamps so stale keys do not crowd out real stamps.tinyworld:stamp-builder-hidden.v1, normal category/recent/flyout rendering
must exclude hidden tools, and the Hidden category is the only normal place
to show them again. Manage cards can hide/unhide removable tools and delete
local templates, voxel-build stamps, and dropped model stamps.window.__tinyworldOwnerToolsAllowed() so non-owner builders can still use
the shared asset library without importing arbitrary local files.mtllib and map_Kd lines. VoxEdit-style Tr 1.000000 should not make a textured model fully transparent; treat it as opaque unless a d dissolve value says otherwise.clone(true) can leave skeletons tied to the cached source scene when multiple stamps are placed.gltf.animations in the model-stamp asset cache. Runtime systems such as crowd character replacements use those clips after cloning the cached scene.43-drag-drop-import.js. Model files register through
window.__tinyworldRegisterDroppedModelStamps, including local sidecars and
object URLs, while chat attachments expose window.__tinyworldAgentDropAttachments
for image/model prompt context. Canvas model drops must still place via setCell()
and keep selection sync through window.__tinyworldSelection.modelStampId: the
prompt context should use MUST-level wording, and generated model-stamp
cells should be repaired to the attached id before applyState() /
applyStatePatch() when there is exactly one attached model.window.__tinyworldModelStampLoadState; do not leave the generic
model-stamp placeholder as the only feedback.ready
before calling setCell(). If the GLB/GLTF fails, show the loader error and
do not stamp the placeholder into the world.appearance.modelStampId, but shared/exported world JSON must embed the
referenced droppedModelStamps records so another browser can resolve the
same model id instead of rendering the generic placeholder.Validation:
npm test, and npm run build.1/E, R/F, clear, perspective toggle, and console errors.32-layers-panel.js + #layers-panel. Styled like the blocks panel: a grab-cue
drag bar (no title), a block-style Layers / Properties tab bar, glass +
resize: both. The tree is island-grouped — collectIslands() builds a top-level
<details> per board (Home Island + each editableIslands entry) whose
children are that board's terrain cells -> objects/extras (world coords as the
cell id). Clicking a tree item selects its cell and switches to the Properties
tab, which relocates the shared #agent-selection-properties node (rendered
by module 28) into #layers-props-host; switching back to Layers / closing the
panel restores that node to the agent panel (selPropsHome). Keep the tree dense
(small summary padding, 14px branch indent, 1px gaps).
The old agent-panel Preview/Properties selection dialog has been retired: module
28 renders the shared properties node as a hidden staging element, while radial
More/Style/Move and multi-cell selection should open window.openLayersPropertiesPanel().
Because that staging element is hidden, updateSelectionPreview(target) must
clear the preview and avoid starting the preview WebGL requestAnimationFrame
loop unless the preview UI is genuinely visible again.
Canvas selection and Layers selection must stay visually synced. The tree should
derive selected rows from window.__tinyworldSelection.worldCoords(), include a
selected default grass tile even when it would otherwise be omitted as an empty
cell, highlight matching child object rows as well as the terrain parent, force
the selected branch open, and scroll the selected row into view when the panel is
open.
Brush modes should be discoverable in the dedicated floating #brush-mode-dock as well as any compact appbar copy. Both use data-brush-mode, so _brushInitToolbar() and _brushSetMode() update every visible copy together. If users report not seeing Brush, prioritize the floating dock's position/visibility before adding more hidden appbar controls.
Brush shapes are modifiers for the active paint/build tool, not standalone Select actions. If a user chooses Line/Rect/Fill/Scatter while still in Select, auto-switch to a safe paint tool (Grass) so dragging the board starts a holographic brush preview instead of orbiting/spinning the island.
039a20a
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.