Skip to content
Draft
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
2 changes: 1 addition & 1 deletion client/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ func DrawNurbs(nurbs shapes.Nurbs, color string, name string) error {
"Weights": nurbs.Weights,
"Knots": nurbs.Knots,
"Color": colorutil.NamedColorToHex(color),
"name": name,
"Name": name,
}

finalJSON, err := json.Marshal(wrappedData)
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
"@testing-library/jest-dom": "6.8.0",
"@testing-library/svelte": "5.2.8",
"@thi.ng/paths": "5.2.21",
"@threlte/core": "8.1.5",
"@threlte/extras": "9.5.4",
"@threlte/rapier": "3.1.5",
"@threlte/core": "8.3.0",
"@threlte/extras": "9.7.0",
"@threlte/rapier": "3.2.0",
"@threlte/xr": "1.0.8",
"@types/bun": "1.2.21",
"@types/lodash-es": "4.17.12",
Expand All @@ -56,7 +56,7 @@
"@typescript-eslint/parser": "8.42.0",
"@viamrobotics/prime-core": "0.1.5",
"@viamrobotics/sdk": "0.55.0",
"@viamrobotics/svelte-sdk": "0.7.1",
"@viamrobotics/svelte-sdk": "0.7.3",
"@vitejs/plugin-basic-ssl": "2.1.0",
"@vitest/coverage-v8": "^3.2.4",
"@zag-js/svelte": "1.22.1",
Expand All @@ -68,14 +68,15 @@
"globals": "16.3.0",
"idb-keyval": "6.2.2",
"jsdom": "26.1.0",
"koota": "^0.5.2",
"lodash-es": "4.17.21",
"lucide-svelte": "0.542.0",
"prettier": "3.6.2",
"prettier-plugin-svelte": "3.4.0",
"prettier-plugin-tailwindcss": "0.6.14",
"publint": "0.3.12",
"runed": "0.31.1",
"svelte": "5.43.0",
"svelte": "5.43.13",
"svelte-check": "4.3.1",
"svelte-virtuallists": "1.4.2",
"tailwindcss": "4.1.13",
Expand Down
238 changes: 128 additions & 110 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

26 changes: 14 additions & 12 deletions src/hooks.client.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { handleErrorWithSentry, replayIntegration } from '@sentry/sveltekit'
import * as Sentry from '@sentry/sveltekit'

Sentry.init({
dsn: 'https://[email protected]/4509599892897792',
if (import.meta.env.PROD) {
Sentry.init({
dsn: 'https://[email protected]/4509599892897792',

tracesSampleRate: 1.0,
tracesSampleRate: 1.0,

// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,
// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,

// If the entire session is not sampled, use the below sample rate to sample
// sessions when an error occurs.
replaysOnErrorSampleRate: 1.0,
// If the entire session is not sampled, use the below sample rate to sample
// sessions when an error occurs.
replaysOnErrorSampleRate: 1.0,

// If you don't want to use Session Replay, just remove the line below:
integrations: [replayIntegration()],
})
// If you don't want to use Session Replay, just remove the line below:
integrations: [replayIntegration()],
})
}

// If you have a custom error handler, pass it to `handleErrorWithSentry`
export const handleError = handleErrorWithSentry()
217 changes: 96 additions & 121 deletions src/lib/FrameConfigUpdater.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Frame } from './frame'
import type { WorldObject } from './lib'
import { createPose } from './transform'
import type { Geometries } from './WorldObject.svelte'
import type { Entity } from 'koota'
import type { Pose } from '@viamrobotics/sdk'
import type { Frame } from '$lib/frame'
import { createPose } from '$lib/transform'
import { traits } from '$lib/ecs'

type UpdateFrameCallback = {
(componentName: string, referenceFrame: string, pose: Pose, geometry?: Frame['geometry']): void
Expand All @@ -13,46 +13,41 @@ type RemoveFrameCallback = {
}

export class FrameConfigUpdater {
private object: () => WorldObject<Geometries> | undefined
private entity: () => Entity | undefined
private referenceFrame: () => string
private updateFrame: UpdateFrameCallback
private removeFrame: RemoveFrameCallback

constructor(
object: () => WorldObject<Geometries> | undefined,
entity: () => Entity | undefined,
updateFrame: UpdateFrameCallback,
removeFrame: RemoveFrameCallback,
referenceFrame: () => string
) {
this.referenceFrame = referenceFrame
this.object = object
this.entity = entity
this.updateFrame = updateFrame
this.removeFrame = removeFrame
}

public updateLocalPosition = ({ x, y, z }: { x?: number; y?: number; z?: number }) => {
const object = this.object()
if (!object) return
const entity = this.entity()
if (!entity) return

x = this.sanatizeFloatValue(x)
y = this.sanatizeFloatValue(y)
z = this.sanatizeFloatValue(z)

if (x === undefined && y === undefined && z === undefined) return

object.localEditedPose.x = x ?? object.localEditedPose.x
object.localEditedPose.y = y ?? object.localEditedPose.y
object.localEditedPose.z = z ?? object.localEditedPose.z

this.updateFrame(object.name ?? '', this.referenceFrame(), {
x: x ?? object.localEditedPose.x,
y: y ?? object.localEditedPose.y,
z: z ?? object.localEditedPose.z,
oX: object.localEditedPose.oX,
oY: object.localEditedPose.oY,
oZ: object.localEditedPose.oZ,
theta: object.localEditedPose.theta,
})
entity.set(traits.EditedPose, { x, y, z })

const name = entity.get(traits.Name)?.name
const updatedPose = entity.get(traits.EditedPose)

if (name && updatedPose) {
this.updateFrame(name, this.referenceFrame(), updatedPose)
}
}

public updateLocalOrientation = ({
Expand All @@ -66,138 +61,118 @@ export class FrameConfigUpdater {
oZ?: number
theta?: number
}) => {
const object = this.object()
if (!object) return
const entity = this.entity()
if (!entity) return

oX = this.sanatizeFloatValue(oX)
oY = this.sanatizeFloatValue(oY)
oZ = this.sanatizeFloatValue(oZ)
theta = this.sanatizeFloatValue(theta)

if (oX === undefined && oY === undefined && oZ === undefined && theta === undefined) return

object.localEditedPose.oX = oX ?? object.localEditedPose.oX
object.localEditedPose.oY = oY ?? object.localEditedPose.oY
object.localEditedPose.oZ = oZ ?? object.localEditedPose.oZ
object.localEditedPose.theta = theta ?? object.localEditedPose.theta

this.updateFrame(object.name ?? '', this.referenceFrame(), {
oX: oX ?? object.localEditedPose.oX,
oY: oY ?? object.localEditedPose.oY,
oZ: oZ ?? object.localEditedPose.oZ,
theta: theta ?? object.localEditedPose.theta,
x: object.localEditedPose.x,
y: object.localEditedPose.y,
z: object.localEditedPose.z,
})
if (oX === undefined && oY === undefined && oZ === undefined && theta === undefined) {
return
}

entity.set(traits.EditedPose, { oX, oY, oZ, theta })

const name = entity.get(traits.Name)?.name
const updatedPose = entity.get(traits.EditedPose)

if (name && updatedPose) {
this.updateFrame(name, this.referenceFrame(), updatedPose)
}
}

public updateGeometry = (geometry: Partial<Frame['geometry']>) => {
const object = this.object()
if (!object) return

let geometryObject: Frame['geometry']
const entity = this.entity()
if (!entity) return

if (geometry?.type === 'box') {
const currentGeometry = object.geometry?.geometryType.value as {
dimsMm: { x: number; y: number; z: number }
}
geometry.x = this.sanatizeFloatValue(geometry.x)
geometry.y = this.sanatizeFloatValue(geometry.y)
geometry.z = this.sanatizeFloatValue(geometry.z)
const x = this.sanatizeFloatValue(geometry.x)
const y = this.sanatizeFloatValue(geometry.y)
const z = this.sanatizeFloatValue(geometry.z)

if (x === undefined && y === undefined && z === undefined) return

if (geometry.x === undefined && geometry.y === undefined && geometry.z === undefined) return
entity.set(traits.Box, { x, y, z })

geometryObject = {
type: 'box',
x: geometry.x ?? currentGeometry?.dimsMm?.x,
y: geometry.y ?? currentGeometry?.dimsMm?.y,
z: geometry.z ?? currentGeometry?.dimsMm?.z,
const name = entity.get(traits.Name)?.name
const box = entity.get(traits.Box)
const pose = entity.get(traits.EditedPose)

if (name && box && pose) {
this.updateFrame(name, this.referenceFrame(), pose, { type: 'box', ...box })
}
} else if (geometry?.type === 'sphere') {
const currentGeometry = object.geometry?.geometryType.value as { radiusMm: number }
geometry.r = this.sanatizeFloatValue(geometry.r)
if (geometry.r === undefined) return
const r = this.sanatizeFloatValue(geometry.r)
if (r === undefined) return

entity.set(traits.Sphere, { r })

const name = entity.get(traits.Name)?.name
const sphere = entity.get(traits.Sphere)
const pose = entity.get(traits.EditedPose)

geometryObject = {
type: 'sphere',
r: geometry.r ?? currentGeometry?.radiusMm,
if (name && sphere && pose) {
this.updateFrame(name, this.referenceFrame(), pose, { type: 'sphere', ...sphere })
}
} else if (geometry?.type === 'capsule') {
const currentGeometry = object.geometry?.geometryType.value as {
radiusMm: number
lengthMm: number
}
geometry.r = this.sanatizeFloatValue(geometry.r)
geometry.l = this.sanatizeFloatValue(geometry.l)
if (geometry.r === undefined && geometry.l === undefined) return

geometryObject = {
type: 'capsule',
r: geometry.r ?? currentGeometry?.radiusMm,
l: geometry.l ?? currentGeometry?.lengthMm,
const r = this.sanatizeFloatValue(geometry.r)
const l = this.sanatizeFloatValue(geometry.l)
if (r === undefined && l === undefined) return

entity.set(traits.Capsule, { r, l })

const name = entity.get(traits.Name)?.name
const capsule = entity.get(traits.Capsule)
const pose = entity.get(traits.EditedPose)

if (name && capsule && pose) {
this.updateFrame(name, this.referenceFrame(), pose, { type: 'sphere', ...capsule })
}
}

this.updateFrame(
object.name ?? '',
this.referenceFrame(),
createPose(object.localEditedPose),
geometryObject
)
}

public setFrameParent = (parentName: string) => {
const object = this.object()
if (!object) return
this.updateFrame(object.name ?? '', parentName, createPose(object.localEditedPose))
const entity = this.entity()
if (!entity) return

const name = entity.get(traits.Name)?.name
const pose = entity.get(traits.EditedPose)

if (name && pose) {
this.updateFrame(name, parentName, pose)
}
}

public deleteFrame = () => {
const object = this.object()
if (!object) return
this.removeFrame(object.name ?? '')
const entity = this.entity()
if (!entity) return

const name = entity.get(traits.Name)?.name

if (name) {
this.removeFrame(name)
}
}

public setGeometryType = (type: 'none' | 'box' | 'sphere' | 'capsule') => {
const object = this.object()
if (!object) return
const entity = this.entity()
if (!entity) return

const name = entity.get(traits.Name)?.name
const pose = entity.get(traits.EditedPose)

if (!name || !pose) return

if (type === 'none') {
this.updateFrame(
object.name ?? '',
this.referenceFrame(),
createPose(object.localEditedPose),
{ type: 'none' }
)
this.updateFrame(name, this.referenceFrame(), pose, { type: 'none' })
} else if (type === 'box') {
this.updateFrame(
object.name ?? '',
this.referenceFrame(),
createPose(object.localEditedPose),
{ type: 'box', x: 100, y: 100, z: 100 }
)
this.updateFrame(name, this.referenceFrame(), pose, { type: 'box', x: 100, y: 100, z: 100 })
} else if (type === 'sphere') {
this.updateFrame(
object.name ?? '',
this.referenceFrame(),
createPose(object.localEditedPose),
{ type: 'sphere', r: 100 }
)
this.updateFrame(name, this.referenceFrame(), pose, { type: 'sphere', r: 100 })
} else if (type === 'capsule') {
this.updateFrame(
object.name ?? '',
this.referenceFrame(),
{
x: object.localEditedPose.x,
y: object.localEditedPose.y,
z: object.localEditedPose.z,
oX: object.localEditedPose.oX,
oY: object.localEditedPose.oY,
oZ: object.localEditedPose.oZ,
theta: object.localEditedPose.theta,
},
{ type: 'capsule', r: 20, l: 100 }
)
this.updateFrame(name, this.referenceFrame(), pose, { type: 'capsule', r: 20, l: 100 })
}
}

Expand Down
Loading