Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions src/components/menu/Inspector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import { LIGHT_PARAMS, SHADOW_TYPES, SHADOW_SIZES, setShadowMapSize, cappedShadowSize } from '$lib/lightParams';
import { animatedObjects, setAnimationState } from '$lib/animatedImports';
import { moveObjectToGroup, selectObject } from '$lib/objectActions';
import { listPhysicsObjects, enablePhysicsOnSelection, PHYSICS_MATERIALS, physicsShapeChanged } from '$lib/physics';
import { listPhysicsObjects, enablePhysicsOnSelection, setPhysicsFor, PHYSICS_MATERIALS } from '$lib/physics';
import { sceneGravity, setSceneGravity, resetSceneGravity, DEFAULT_GRAVITY } from '$lib/scenePhysics';
import { showColliders, colliderVizObjects, setColliderViz } from '$lib/colliderHelpers';
import { enterColliderEdit } from '$lib/colliderEdit';
Expand Down Expand Up @@ -364,13 +364,9 @@

/** @param {any} patch */
function setPhysics(patch) {
const before = $selectedObject.userData.physics ? { ...$selectedObject.userData.physics } : null;
const next = { mode: 'auto', ...($selectedObject.userData.physics ?? {}), ...patch };
$selectedObject.userData.physics = next;
recordEntry({ kind: 'props', uuid: $selectedObject.uuid, before: { physics: before }, after: { physics: next } });
$peers.send({ type: 'objectParameters', parameter: 'physics', uuid: $selectedObject.uuid, physics: next });
objectsGroup.update((v) => v); // collider viz re-syncs from the poke
physicsShapeChanged($selectedObject.uuid); // CL-A A2: live mid-sim rebuild
// shared write path — replicates, records props undo, pokes the collider
// viz and live-rebuilds mid-sim colliders (CL-A A2) for EVERY caller
setPhysicsFor($selectedObject.uuid, patch);
selectedObject.update((v) => v);
}

Expand Down
17 changes: 17 additions & 0 deletions src/components/menu/Settings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
let aiFormKey = '';
let aiFormModel = '';
let aiFormStream = true;
let aiFormPhysics = false;
let aiFormTemp = '';
let aiTesting = false;
let aiTestResult: { ok: boolean; detail: string; modelOk?: boolean | null; model?: string } | null = null;
Expand Down Expand Up @@ -141,6 +142,7 @@
aiApplyPreset();
aiFormKey = '';
aiFormStream = true;
aiFormPhysics = false;
aiFormTemp = '';
aiTestResult = null;
aiFormModels = [];
Expand All @@ -157,6 +159,7 @@
aiFormKey = p.apiKey;
aiFormModel = p.model;
aiFormStream = p.stream !== false;
aiFormPhysics = p.physicsTools === true;
aiFormTemp = typeof p.temperature === 'number' ? String(p.temperature) : '';
aiTestResult = null;
aiFormModels = Array.isArray(p.models) ? p.models : [];
Expand All @@ -179,6 +182,7 @@
apiKey: aiFormKey,
model: aiFormModel,
stream: aiFormStream,
physicsTools: aiFormPhysics,
temperature: Number.isFinite(temp) ? temp : undefined,
models: aiFormModels
};
Expand Down Expand Up @@ -862,6 +866,19 @@
<input type="checkbox" bind:checked={aiFormStream} />
Stream responses
</label>
<label class="flex items-center gap-2 text-[13px] text-gray-300">
<input id="ai-physics-tools" type="checkbox" bind:checked={aiFormPhysics} />
Physics tools (advanced)
</label>
<span class="text-[11px] leading-snug text-gray-400">
Lets the assistant set physics bodies, attach joints and start the simulation.
Multi-step physics is hard for small local models (4B) — recommended for 14B+
or hosted models.
<button
class="underline hover:text-gray-200"
on:click={() => window.open('https://docs.theprototype.app/ai/local-models/', '_blank')}
>Local &amp; small models guide</button>
</span>
<input class="ui-input" placeholder="Temperature (blank = server default)" bind:value={aiFormTemp} />
<span class="text-[11px] leading-snug text-gray-400">
Turn streaming OFF for a self-hosted server whose tool calls only work unstreamed —
Expand Down
21 changes: 19 additions & 2 deletions src/lib/ai/assistant.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ function toolStatusLabel(name, args) {
if (name === 'group_objects') return 'Grouping objects';
if (name === 'clear_scene') return 'Clearing the scene';
if (name === 'list_scene') return 'Reading the scene';
if (name === 'create_flow_nodes') return 'Adding ' + (args?.nodes?.length ?? 0) + ' behavior node(s)';
if (name === 'update_flow_nodes') {
const removing = args?.remove?.length ?? 0;
const updating = args?.updates?.length ?? 0;
if (removing && !updating) return 'Removing ' + removing + ' behavior node(s)';
return 'Updating ' + updating + ' behavior node(s)';
}
if (name === 'set_physics') return 'Setting physics on ' + (args?.updates?.length ?? 0) + ' object(s)';
if (name === 'create_joints') return 'Attaching ' + (args?.joints?.length ?? 0) + ' joint(s)';
if (name === 'control_simulation') return 'Simulation: ' + (args?.action ?? '…');
return name;
}

Expand All @@ -105,16 +115,23 @@ function toolStatusLabel(name, args) {
*/
function tallyChanges(name, result, tally) {
if (name === 'list_scene' || !result || typeof result !== 'object') return;
// read-only-style: starting/stopping the sim changes no scene content
if (name === 'control_simulation') return;
/** @param {any[]} list */
const addAll = (list) => {
for (const entry of list) {
if (!entry || entry.error) continue;
if (typeof entry.uuid === 'string') tally.uuids.add(entry.uuid);
else tally.other += 1;
else tally.other += 1; // flow nodes / joints have no object uuid
}
};
if (Array.isArray(result.created)) return addAll(result.created);
if (Array.isArray(result.updated)) return addAll(result.updated);
if (Array.isArray(result.updated)) {
addAll(result.updated);
if (typeof result.removed === 'number') tally.other += result.removed;
return;
}
if (Array.isArray(result.joints)) return addAll(result.joints);
if (typeof result.deleted === 'number') {
tally.other += result.deleted;
return;
Expand Down
Loading