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
5 changes: 4 additions & 1 deletion .claude/skills/e2e-verify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,15 @@ const value = await page.evaluate(() =>
- `goto(url, { waitUntil: 'domcontentloaded' })` (NOT networkidle — peerjs sockets never
idle), ~4s wait, then `waitForFunction(() => window.__stores?.moduleSDK)`.
- UI anchors: bottom nav `p[title="Object list (O)"]` / `p[title="Node editor (N)"]`;
play `i.fa-play`; object rows `#object-list p[id]`; search `#object-search`;
play `#play-button`; object rows `#object-list p[id]`; search `#object-search`;
modules manager via `#open-modules-manager` (drawer: `closeMenu.set(false)` first)
or `modulesOpen.set(true)`; module cards `#module-card-<id>`; draw `#draw-toolbar`;
dungeon `#dungeon-panel`; script editor close `#script-panel-close`.
- Programmatic scene setup: `__stores.commandsHandler.sceneCommand('/create box')`
(geometry names are capitalized THREE types — box/sphere/Button…, NOT "cube").
- Icons are `@lucide/svelte` `<svg>` components (Font Awesome removed): select
`svg` not `i`, and read classes via `getAttribute('class')` — svg `className`
is an SVGAnimatedString object, `.includes()` on it throws/fails silently.
- Flow graphs: set `flowNodes`/`flowEdges` locally **and broadcast** `nodecreate`/
`edgecreate` per node/edge like the UI does — relying on the 10s nodesync heal is
slow and rate-limited (30s) → flaky.
Expand Down
3 changes: 0 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,5 @@ updates:
update-types: [version-update:semver-major]
- dependency-name: typescript
update-types: [version-update:semver-major]
# icon class names change across majors; bump deliberately
- dependency-name: '@fortawesome/fontawesome-free'
update-types: [version-update:semver-major]
# physics solver behavior can shift on 0.x bumps (rapier revolute-axis gotcha)
- dependency-name: '@dimforge/rapier3d-compat'
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
per release, newest first. HTML comments like this one are stripped before
rendering, so maintainer notes stay out of the user-facing window. -->

## 1.1.0 — A sharper coat of paint 🎨

- ✒️ **New icon system** — crisp SVG icons (Lucide) everywhere, with meaningful
colors: amber folders, tinted file types, red for anything destructive. Every
theme (including 8-bit and your custom ones) controls the palette.
- 🖐️ **Trackpad navigation** — two-finger swipes pan the camera, pinch zooms,
and the page itself never zooms by accident. Direction, pan and pinch are all
configurable in Settings.
- ⏳ **Loading feedback** — dropping a pack model shows a loading toast, pack
lists show a spinner on first open (no more stale flashes), and attribution
opens instantly.
- ▶️ **Play button polish** — cleaner look, whole-button hover, and its
neighbors no longer lose clicks to it.

## 1.0.1 — Going public 🌍

The engine is now open source (MIT): [github.com/theprototype-app/core](https://github.com/theprototype-app/core).
Expand Down
19 changes: 18 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,13 @@ loadable play content. Everything a user does must be visible to connected peers
'joint' history kind, sender-side delete cascade, sessions persist),
`inputRuntime` (#12: store-only SDK input — key codes + VR axes published by
vrControls, claims 'keys'/'locomotion' gate PointerLockControls/editorNavigation/
VR stick; module bindings list in Settings), `possess` (#12: tank-controls drive of
VR stick; module bindings list in Settings), `trackpadNav` (QW launch polish:
window-capture wheel — two-finger trackpad swipes PAN via cloned-vector
OrbitControls math with a STATEFUL 250ms gesture window (fast flicks stay pans);
pinch/ctrl-wheel page-zoom guards (iOS gesturestart + body touch-action
pan-x pan-y — the CANVAS gets touch-action:none or Chromium axis-latches pans);
Settings: mode auto/on/off, reverse pan, pan + pinch-zoom enable toggles —
all LOCAL prefs), `possess` (#12: tank-controls drive of
any object + chase/orbit camera; possessing = selecting; ONE undo per ride),
`handModels` (#12: custom hand GLB = IDENTITY — hash on `handmodel` msg + handshake,
assetShare pull, rigid-at-wrist render), `terrainSculpt` (#12: brush raise/lower/
Expand Down Expand Up @@ -545,6 +551,17 @@ loadable play content. Everything a user does must be visible to connected peers
annotation in it hard-breaks `npm run build` with a useless
`error during build: undefined` (svelte-check never runs; vite dev 500s too).
Same trap in any non-TS component: JSDoc for types, never TS syntax (#13-B3).
- **Icons = `@lucide/svelte` SVG components** (Font Awesome fully REMOVED post-1.0.1
— never add `fa-` classes). Static markup imports named components
(`import { Play } from '@lucide/svelte'`; sizes 16 inline/menu, 18-20 toolbar/
header, 24 the play FAB; `aria-hidden="true"` when decorative); DATA-DRIVEN icon
names (Explorer KIND_ICONS, menu-item defs) render via `components/ui/Icon.svelte`
(kebab lucide names). Icons inherit `currentColor` — never hardcode grays;
semantic colors come from the `--icon-*` theme tokens. TWO TRAPS: a `class` passed
to a lucide component lands on the CHILD-scope `<svg>`, so scoped CSS targeting it
needs `:global(...)` (bit cx-chevron/tp-toast-icon/role-caret — silent style loss,
sometimes without even an unused-selector warning); svg `className` is an
SVGAnimatedString — e2e reads `getAttribute('class')` and selects `svg`, not `i`.

## Verification (mandatory before commit)

Expand Down
25 changes: 13 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"dependencies": {
"@codemirror/lang-javascript": "^6.2.5",
"@dimforge/rapier3d-compat": "^0.19.3",
"@fortawesome/fontawesome-free": "^6.7.2",
"@lucide/svelte": "^1.27.0",
"@threlte/core": "^8.0.0-next.38",
"@threlte/extras": "^9.0.0-next.51",
"@threlte/xr": "^1.0.0-next.15",
Expand Down
1 change: 0 additions & 1 deletion scripts/deps-check.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const FROZEN = [
'vite',
'@sveltejs/vite-plugin-svelte',
'typescript',
'@fortawesome/fontawesome-free',
'@dimforge/rapier3d-compat'
];

Expand Down
10 changes: 7 additions & 3 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import { startNetworkQuality } from '$lib/networkQuality'
import { startWhatsNew } from '$lib/whatsNew'
import { startUpdateCheck } from '$lib/updateCheck'
import { startTrackpadNav } from '$lib/trackpadNav'
import { startCloudPlugin } from '$lib/cloudPlugin'
import { importFile, load } from '$lib/fileHandler.svelte'
import { showToast } from './stores/appStore'
Expand Down Expand Up @@ -75,6 +76,8 @@
startUpdateCheck()
// open-core (M1): load a configured cloud plugin (no-op in the OSS build)
startCloudPlugin()
// QW: trackpad two-finger pan + pinch page-zoom guards (desktop + mobile)
startTrackpadNav()
// store access for automated tests, opt-in via localStorage
if (localStorage.getItem('debugStores')) {
Promise.all([
Expand Down Expand Up @@ -160,9 +163,10 @@
import('./lib/particlePresets'),
import('./lib/version'),
import('./lib/whatsNew'),
import('./lib/confirmDialog')
]).then(([sceneStore, appStore, flowStore, meshEdit, vrControls, autosave, voiceChat, annotationsHandler, flowRuntime, history, materialsHandler, objectActions, commandsHandler, moduleSDK, drawModeLib, pathCapture, lockControl, prefabsLib, physics, jointsLib, possessLib, handModelsLib, terrainSculptLib, userModulesLib, environmentLib, sceneMusicLib, animatedImports, fileHandler, fileWindowsLib, sceneBounds, cameraClip, ping, sessionsLib, geometryEdit, lightParams, shadowDefaultsLib, paletteLib, viewModeLib, inputRuntimeLib, shortcutsLib, themesLib, vrRadialMenu, vrPaletteLib, vrWindowPosesLib, vrKeyboardLib, faceEditLib, avatarModelLib, explorerLib, bottomDock, explorerDrop, assetShare, soundRuntime, dungeonPlay, sceneAssetsLib, THREE, GLTFExporterModule, snappingLib, flowSocketsLib, networkQualityLib, packsLib, customNodesLib, nodesHandlerLib, nodeCatalogLib, objectMenuLib, animationPreviewLib, aiProvidersLib, aiToolsLib, aiAssistantLib, meshProvidersLib, meshJobsLib, flowGraphsLib, objectFlowLib, peerServerLib, cloudHooksLib, cloudPluginLib, connectionStateLib, peerApprovalLib, particleRuntimeLib, particleActionsLib, particlePresetsLib, versionLib, whatsNewLib, confirmDialogLib]) => {
window.__stores = { ...sceneStore, ...appStore, ...flowStore, meshEdit, vrControls, autosave, voiceChat, annotationsHandler, flowRuntime, history, materialsHandler, objectActions, commandsHandler, moduleSDK, drawMode: drawModeLib, pathCapture, lockControl, prefabs: prefabsLib, physics, joints: jointsLib, possess: possessLib, handModels: handModelsLib, terrainSculpt: terrainSculptLib, userModules: userModulesLib, environment: environmentLib, sceneMusic: sceneMusicLib, animatedImports, fileHandler, fileWindows: fileWindowsLib, sceneBounds, cameraClip, ping, sessions: sessionsLib, geometryEdit, lightParams, shadowDefaults: shadowDefaultsLib, palette: paletteLib, viewModeCtl: viewModeLib, inputRuntime: inputRuntimeLib, shortcutsRegistry: shortcutsLib, themes: themesLib, vrRadialMenu, vrPalette: vrPaletteLib, vrWindowPoses: vrWindowPosesLib, vrKeyboard: vrKeyboardLib, faceEdit: faceEditLib, avatarModel: avatarModelLib, explorer: explorerLib, bottomDock, explorerDrop, assetShare, soundRuntime, dungeonPlay, sceneAssets: sceneAssetsLib, THREE, GLTFExporterModule, snapping: snappingLib, flowSockets: flowSocketsLib, networkQuality: networkQualityLib, packs: packsLib, customNodes: customNodesLib, nodesHandler: nodesHandlerLib, nodeCatalog: nodeCatalogLib, objectMenu: objectMenuLib, animationPreview: animationPreviewLib, aiProviders: aiProvidersLib, aiTools: aiToolsLib, aiAssistant: aiAssistantLib, meshProviders: meshProvidersLib, meshJobs: meshJobsLib, flowGraphsCtl: flowGraphsLib, objectFlow: objectFlowLib, peerServer: peerServerLib, cloudHooks: cloudHooksLib, cloudPlugin: cloudPluginLib, connectionState: connectionStateLib, peerApproval: peerApprovalLib, particleRuntime: particleRuntimeLib, particleActions: particleActionsLib, particlePresets: particlePresetsLib, version: versionLib, whatsNew: whatsNewLib, confirmDialog: confirmDialogLib }
import('./lib/confirmDialog'),
import('./lib/trackpadNav')
]).then(([sceneStore, appStore, flowStore, meshEdit, vrControls, autosave, voiceChat, annotationsHandler, flowRuntime, history, materialsHandler, objectActions, commandsHandler, moduleSDK, drawModeLib, pathCapture, lockControl, prefabsLib, physics, jointsLib, possessLib, handModelsLib, terrainSculptLib, userModulesLib, environmentLib, sceneMusicLib, animatedImports, fileHandler, fileWindowsLib, sceneBounds, cameraClip, ping, sessionsLib, geometryEdit, lightParams, shadowDefaultsLib, paletteLib, viewModeLib, inputRuntimeLib, shortcutsLib, themesLib, vrRadialMenu, vrPaletteLib, vrWindowPosesLib, vrKeyboardLib, faceEditLib, avatarModelLib, explorerLib, bottomDock, explorerDrop, assetShare, soundRuntime, dungeonPlay, sceneAssetsLib, THREE, GLTFExporterModule, snappingLib, flowSocketsLib, networkQualityLib, packsLib, customNodesLib, nodesHandlerLib, nodeCatalogLib, objectMenuLib, animationPreviewLib, aiProvidersLib, aiToolsLib, aiAssistantLib, meshProvidersLib, meshJobsLib, flowGraphsLib, objectFlowLib, peerServerLib, cloudHooksLib, cloudPluginLib, connectionStateLib, peerApprovalLib, particleRuntimeLib, particleActionsLib, particlePresetsLib, versionLib, whatsNewLib, confirmDialogLib, trackpadNavLib]) => {
window.__stores = { ...sceneStore, ...appStore, ...flowStore, meshEdit, vrControls, autosave, voiceChat, annotationsHandler, flowRuntime, history, materialsHandler, objectActions, commandsHandler, moduleSDK, drawMode: drawModeLib, pathCapture, lockControl, prefabs: prefabsLib, physics, joints: jointsLib, possess: possessLib, handModels: handModelsLib, terrainSculpt: terrainSculptLib, userModules: userModulesLib, environment: environmentLib, sceneMusic: sceneMusicLib, animatedImports, fileHandler, fileWindows: fileWindowsLib, sceneBounds, cameraClip, ping, sessions: sessionsLib, geometryEdit, lightParams, shadowDefaults: shadowDefaultsLib, palette: paletteLib, viewModeCtl: viewModeLib, inputRuntime: inputRuntimeLib, shortcutsRegistry: shortcutsLib, themes: themesLib, vrRadialMenu, vrPalette: vrPaletteLib, vrWindowPoses: vrWindowPosesLib, vrKeyboard: vrKeyboardLib, faceEdit: faceEditLib, avatarModel: avatarModelLib, explorer: explorerLib, bottomDock, explorerDrop, assetShare, soundRuntime, dungeonPlay, sceneAssets: sceneAssetsLib, THREE, GLTFExporterModule, snapping: snappingLib, flowSockets: flowSocketsLib, networkQuality: networkQualityLib, packs: packsLib, customNodes: customNodesLib, nodesHandler: nodesHandlerLib, nodeCatalog: nodeCatalogLib, objectMenu: objectMenuLib, animationPreview: animationPreviewLib, aiProviders: aiProvidersLib, aiTools: aiToolsLib, aiAssistant: aiAssistantLib, meshProviders: meshProvidersLib, meshJobs: meshJobsLib, flowGraphsCtl: flowGraphsLib, objectFlow: objectFlowLib, peerServer: peerServerLib, cloudHooks: cloudHooksLib, cloudPlugin: cloudPluginLib, connectionState: connectionStateLib, peerApproval: peerApprovalLib, particleRuntime: particleRuntimeLib, particleActions: particleActionsLib, particlePresets: particlePresetsLib, version: versionLib, whatsNew: whatsNewLib, confirmDialog: confirmDialogLib, trackpadNav: trackpadNavLib }
})
}
})
Expand Down
Loading