Skip to content
Open
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
24 changes: 14 additions & 10 deletions src/features/ai/AiAgentPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ export function AiAgentPanel({ onOpenSettings }: AiAgentPanelProps) {
const parsed = JSON.parse(raw)
if (!Array.isArray(parsed)) return []
return parsed.slice(-MAX_MESSAGES)
} catch {
} catch (err) {
console.warn('[AiAgentPanel] failed to load stored messages, starting fresh:', err)
return []
}
}
Expand All @@ -89,16 +90,16 @@ export function AiAgentPanel({ onOpenSettings }: AiAgentPanelProps) {
try {
const trimmed = msgs.length > MAX_MESSAGES ? msgs.slice(-MAX_MESSAGES) : msgs
localStorage.setItem(STORAGE_KEY, JSON.stringify(trimmed))
} catch {
// localStorage full or unavailable
} catch (err) {
console.warn('[AiAgentPanel] failed to persist messages (storage full or unavailable):', err)
}
}

function clearStoredMessages() {
try {
localStorage.removeItem(STORAGE_KEY)
} catch {
// ignore
} catch (err) {
console.warn('[AiAgentPanel] failed to clear stored messages:', err)
}
}

Expand All @@ -121,7 +122,10 @@ export function AiAgentPanel({ onOpenSettings }: AiAgentPanelProps) {
if (!user) return
fetchAiConfig()
.then(({ config: cfg }) => setConfig(cfg))
.catch(() => setConfig(null))
.catch((err) => {
console.debug('[AiAgentPanel] failed to load AI config:', err)
setConfig(null)
})
}, [user])

useEffect(() => {
Expand Down Expand Up @@ -207,8 +211,8 @@ export function AiAgentPanel({ onOpenSettings }: AiAgentPanelProps) {
}
}
}
} catch {
// ignore malformed lines
} catch (err) {
console.debug('[AiAgentPanel] skipping malformed SSE line:', trimmed, err)
}
}
return { content, toolCalls: Object.values(toolCallsRef.current) }
Expand All @@ -222,8 +226,8 @@ export function AiAgentPanel({ onOpenSettings }: AiAgentPanelProps) {
let args: Record<string, unknown> = {}
try {
args = JSON.parse(call.arguments)
} catch {
// ignore
} catch (err) {
console.warn(`[AiAgentPanel] failed to parse arguments for tool "${call.name}":`, err)
}
const result = await executeTool(call.name, args, toolContext)
call.status = result.success ? 'success' : 'error'
Expand Down
4 changes: 2 additions & 2 deletions src/features/ai/agentTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ function parseVector(raw: string | unknown[] | undefined, defaultValue: number[]
if (Array.isArray(parsed) && parsed.every((v) => typeof v === 'number')) {
return parsed
}
} catch {
// ignore
} catch (err) {
console.debug('[agentTools] failed to parse vector argument, using default:', raw, err)
}
}
return defaultValue
Expand Down
6 changes: 4 additions & 2 deletions src/features/auth/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ function getStoredUser(): User | null {
try {
const raw = window.localStorage.getItem(USER_KEY)
return raw ? (JSON.parse(raw) as User) : null
} catch {
} catch (err) {
console.warn('[AuthProvider] failed to parse stored user, ignoring it:', err)
return null
}
}
Expand All @@ -40,8 +41,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
setUser(currentUser)
window.localStorage.setItem(USER_KEY, JSON.stringify(currentUser))
})
.catch(() => {
.catch((err) => {
if (cancelled) return
console.warn('[AuthProvider] session validation failed, signing out:', err)
window.localStorage.removeItem(TOKEN_KEY)
window.localStorage.removeItem(USER_KEY)
setToken(null)
Expand Down
28 changes: 22 additions & 6 deletions src/features/recording/RecordingExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,37 @@ import type { RecordingState } from '@/features/sandbox/sandboxStore'
*/
export function exportRecordingAsWebM(recording: RecordingState): void {
const { frames } = recording
if (frames.length === 0) return
if (frames.length === 0) {
console.warn('[RecordingExporter] no frames to export as WebM')
return
}

const canvas = document.createElement('canvas')
canvas.width = 1280
canvas.height = 720
const ctx = canvas.getContext('2d')
if (!ctx) return
if (!ctx) {
console.error('[RecordingExporter] could not obtain 2D canvas context; WebM export aborted')
return
}

const stream = canvas.captureStream(30)
const chunks: Blob[] = []

const mediaRecorder = new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp9',
videoBitsPerSecond: 5000000,
})
let mediaRecorder: MediaRecorder
try {
mediaRecorder = new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp9',
videoBitsPerSecond: 5000000,
})
} catch (err) {
console.error('[RecordingExporter] MediaRecorder is not supported for this format:', err)
return
}

mediaRecorder.onerror = (e) => {
console.error('[RecordingExporter] MediaRecorder error while capturing WebM:', e)
}

mediaRecorder.ondataavailable = (e) => {
if (e.data.size > 0) {
Expand Down
6 changes: 5 additions & 1 deletion src/features/sandbox/SandboxJoints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ function createJoint(
default:
return null
}
} catch {
} catch (err) {
console.warn(
`[SandboxJoints] failed to create "${joint.type}" joint (${joint.id}) between ${joint.bodyA} and ${joint.bodyB}:`,
err
)
return null
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/features/sandbox/sceneStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ export function loadStoredScene(): SandboxScene | null {
try {
const parsed = JSON.parse(raw) as unknown
return migrateScene(parsed)
} catch {
} catch (err) {
console.warn('[sceneStorage] failed to load stored scene, discarding it:', err)
return null
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/features/settings/physicsSettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ function loadStoredSettings(): Partial<PhysicsSettingsState> {
if (!raw) return {}
const parsed = JSON.parse(raw) as Partial<PhysicsSettingsState>
return parsed
} catch {
} catch (err) {
console.warn('[physicsSettingsStore] failed to parse stored settings, using defaults:', err)
return {}
}
}
Expand Down Expand Up @@ -101,5 +102,9 @@ export const usePhysicsSettingsStore = create<PhysicsSettingsState>((set, get) =

usePhysicsSettingsStore.subscribe((state) => {
if (typeof window === 'undefined') return
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state))
try {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state))
} catch (err) {
console.warn('[physicsSettingsStore] failed to persist settings:', err)
}
})