agents
A scene an agent can use. Each <tosi-b3d> offers tools under its own
prefix, b3d_<scene>_…: its settings panel as named controls an agent reads,
sets and presses through each control's own path, exactly as a hand would.
Nothing runs until a tool is called, and nothing is offered until the page
says so: closed by default, as tosijs's agent surface is.
Demo
import { b3d, b3dSkybox, b3dSun, b3dGround, b3dBox, b3dBeacon, slider3d } from 'tosijs-3d'
import { orbitCam } from 'tosijs-3d/demo-utils'
import { elements } from 'tosijs'
const { div, button, pre } = elements
const sky = b3dSkybox({ timeOfDay: 10, realtimeScale: 0 })
const sceneEl = b3d(
{
id: 'harbour-demo',
agent: 'on',
panelTitle: 'Harbour',
style: 'width:100%;height:100%',
scenePanel: () => [
slider3d({ label: 'time of day', value: sky.timeOfDay, min: 0, max: 24,
handleChange: (v) => (sky.timeOfDay = v) }),
],
sceneCreated(el) {
orbitCam(el, { alphaDeg: -70, betaDeg: 60, radius: 30, target: [0, 0, 0] })
},
},
sky,
b3dSun(),
b3dGround({ size: 60, color: '#4a5a46' }),
b3dBox({ id: 'crate', x: 4, y: 0.5, z: 2, color: '#b07840' }),
b3dBeacon({ name: 'harbour', follow: 'off', x: 18, y: 1, z: 12 }),
b3dBeacon({ name: 'gate', follow: 'off', x: -10, y: 1, z: -4 })
)
const out = pre({ class: 'readout' }, 'press a tool')
const tool = (label, name, input) =>
button({
onClick: async () => {
const answer = await window.b3dAgent.call(`b3d_harbour_demo_${name}`, input)
out.textContent = `${name} ${input ? JSON.stringify(input) : ''}\n` +
JSON.stringify(answer, null, 1).slice(0, 1200)
},
}, label)
preview.append(
sceneEl,
div({ class: 'tools' },
tool('places', 'places'),
tool('panel', 'panel'),
tool('make it night', 'panel_set', { control: 'time of day', value: 22 }),
tool('make it day', 'panel_set', { control: 'time of day', value: 10 })),
out
)
.preview { display: flex; flex-direction: column; height: 100%; }
tosi-b3d { flex: 1; min-height: 0; width: 100%; }
.tools { display: flex; gap: 6px; padding: 6px 0; flex-wrap: wrap; }
.readout {
margin: 0;
max-height: 30%;
overflow: auto;
padding: 4px 10px;
font-size: 12px;
color: #fff;
background: #0009;
}
The buttons are what an agent does: each calls one of the scene's tools on
window.b3dAgent and shows the answer. places lists the two beacons and the
crate with where they are from the camera; make it night sets the panel's
slider through its own path, so the sky follows and the open panel shows it.
The scene opted itself in with agent: 'on'; nothing else on the page is
offered.
Using it
import { enableSceneAgents } from 'tosijs-3d'
enableSceneAgents({ expose: 'all' }) // every scene: read, set and press
// or per scene: <tosi-b3d agent="read"> (read only) / agent="on" / agent="off"
const a = window.b3dAgent
a.tools().map((t) => t.name)
// ['b3d_scenes', 'b3d_city_drive_panel', 'b3d_city_drive_panel_set', …]
await a.call('b3d_city_drive_panel_set', { control: 'Sky/time of day', value: 21 })
Where the browser offers WebMCP (document.modelContext.registerTool), the
same tools are registered there, so a browser's assistant sees them. A host
that only has provideContext is declined with a console note: that call
replaces the page's whole tool set, which would blank every other script's.
The tools
| tool | what it does |
|---|---|
b3d_scenes |
the page's scenes: name, which has input focus, what each offers |
b3d_<scene>_scene |
you (the controllable in focus), the camera, time of day, daylight, the weather here, and every named thing: kind, position, heading, distance, a proximity word, bearing |
b3d_<scene>_places |
named places to go to, nearest first: named beacons and named things |
b3d_<scene>_snapshot |
{ width? }: a PNG of what the camera sees |
b3d_<scene>_control_go |
{ place } or { x, z }, speed?, wait?: drive the vehicle in focus there with its own controls; it reports arrived, or stuck when it stops making progress |
b3d_<scene>_control_hold |
{ input, seconds }: hold controls (forward, turn, jump…) for a time |
b3d_<scene>_control_status / _control_stop |
what the command is doing (wait to wait for it), or end it |
b3d_<scene>_panel |
the settings panel as a tree of named controls (role, name, path, value, options, range) and any name problems |
b3d_<scene>_panel_set |
{ control, value }: set a control by its path (Sky/time of day) |
b3d_<scene>_panel_activate |
{ control }: press a button, open a section, pick a list item |
A NAMED thing is any scene element with an id (or a name, as a
<tosi-b3d-beacon name="harbour"> has) and a mesh. Positions are world metres,
y up, with the floating origin's moves added back, so a place keeps its
coordinates when the scene rebases. Headings are degrees, 0 facing +z and 90
facing +x; a bearing is the turn from where you face (negative is left).
Distances come with world-topology's proximity rung (reach, obvious,
noticeable, present), the words the world-sim contract uses.
The controls are driven the way a player drives: the
agent driver turns a command into ControlInput each frame,
in place of the player's, so the car keeps its grip, walls and traffic. The
player's own deliberate input cancels the command at once. go drives a
straight line (no route finding yet) and ground vehicles only, so far.
A control is addressed by its path of names; see widget semantics. A path that names nothing, or more than one control, is refused with the list of what is there.
When the panel is open the tools read the panel on screen (its folded sections and any popup open from it); when it is closed they read the panel's rows unfolded, so nothing has to be opened first.
Exposure
page (enableSceneAgents) / scene (agent) |
tools |
|---|---|
| nothing said (default) | none |
'read' |
b3d_scenes and the read tools |
'all' / "on" |
everything |
agent="off" |
none for that scene, whatever the page says |
A scene's own agent attribute wins over the page's setting.
The same names serve a screen reader
An agent and a screen reader need the same thing from a panel: every control
named, with a role and a value, and a way to set it that is not a pointer
coordinate. So they share it. The panel tree the tools read is also drawn as
real, visually hidden HTML controls for a screen reader (the
aria mirror), on by default for every flat settings panel and
not affected by agent. And nameProblems (the name test) reports a control
with no name, or two with one path, which breaks both at once: icons first,
but never nameless.