Release 1.0 launch polish: packs CDN, versioning V2-V8, deps safe-bump, launch fixes - #56
Merged
Merged
Conversation
- vite.config.ts: define __APP_VERSION__ (package.json) + __COMMIT_SHA__ (git rev-parse --short HEAD, try/catch -> unknown); define reaches dev, build and prerender so there is no second code path. - src/app.d.ts: ambient consts inside the existing declare global block. - NEW src/lib/version.js: zero-import leaf exporting APP_VERSION / COMMIT_SHA / IS_DEV / versionString(); typeof guards keep it safe when define never ran. Zero-import because peerHandler, moduleSDK, sessions and UI all read it and an import here could close a history.js cycle. - package.json stays 0.0.1 until the release ritual bumps it (V6). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Badge, not popup: a version change only dots the logo menu and shows one auto-dismissing toast. The changelog opens in a floating window. A first visit shows the welcome overlay INSTEAD - never both. - NEW src/lib/whatsNew.js: welcome/whatsNew open state, the unseen marker, two persisted prefs, and startWhatsNew() called once from App.svelte. A first visit also marks the current version seen, so no badge lands on top of the welcome overlay. - NEW Welcome.svelte: first-visit card (pitch + Start building / demo / GitHub, version line from V1, show-on-start checkbox). - NEW WhatsNew.svelte: floating window (ui-panel + dragWindow + focusStack) rendering root CHANGELOG.md through a tiny markdown subset. Input is escaped BEFORE the inline rules run, HTML comments are stripped (maintainer notes stay out of the user-facing window), and the leading h1 is dropped because the window header already says it. - NEW CHANGELOG.md: public, GitHub-rendered, emoji-led 1.0.0 entry. - Sidebar: a dot on the logo plus a What is new row. Both cues are CLASS toggles, not if-blocks - clicking the row closes the menu, and destroying a nested branch inside the subtree being destroyed in the same flush crashes the Svelte 5 sibling walk (hit exactly that: destroy_effect/get_next_sibling). - Settings: two toggles in the Scene section + an About row to reopen the changelog. - Replaced the dead News.svelte stub (empty body, inverted hasSeenModal flag). - helpers.cjs seeds hasSeenWelcome so the overlay cannot cover the UI in every other e2e suite. tests/e2e/whats-new.test.cjs: 24 checks, ALL PASS. svelte-check 484 errors / 66 warnings (was 485/72 - the deleted stub carried some of the difference). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The repo goes public at 1.0.0, so the README IS the landing page. The old one was
19 lines of stale self-signed-cert dev steps with no feature list and no images.
- README.md rewritten: centred hero (logo, one-line hook, badges, try/docs/video
links), what-it-is with the no-backend explanation, feature list grouped by
what you do with it, quick start (hosted + npm install --legacy-peer-deps +
build/check/e2e), extend-it pointers to MODULES/NODES/PACKS/OPEN-CORE and the
modules repo, project layout table, contributing, support, license.
- NEW .github/assets/{hero,flow,welcome}.jpg + whats-new.png - captured from a
REAL app, not mocked. 463 KB total (1600x940 at scale 1, jpeg for the 3D
renders, png for the flat UI panel).
- NEW scripts/capture-screenshots.cjs regenerates them, so they cannot drift
into showing UI that no longer exists. Builds a scene, opens the panels worth
showing, clears transient toasts/badges per frame, and points the peer config
at the real signalling box so the pill shows a genuine session ID.
- NEW .github/FUNDING.yml + issue templates (bug/feature/config). The bug form
asks for the Settings-About version string and whether peers were connected -
most replication bugs need both sides.
Verified: every claim checked against the code (env var names against
.env.example, scripts against package.json). No link points at a page that does
not exist yet - sponsorship refers to the repo Sponsor button rather than
hardcoding an account URL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
It builds its own context (clipboard permissions) instead of using h.setupPage, so a virgin profile now opens the welcome overlay and its backdrop swallows the Shift+A menu interactions. Seeds the same first-run flags setupPage does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… checks) User-reported: pressing Shift+A to open the Add menu lurched the viewport LEFT first. editorNavigation's keydown filtered ctrlKey and metaKey but not shiftKey, so the A of Shift+A entered the WASD fly set - and moved at 3x, because Shift is also the fly speed modifier. Measured 1.500 units of drift per press. - editorNavigation.js: ignore a key when its Shift+<key> combo is a REGISTERED shortcut (read live from the shortcuts registry, so any Shift+<key> command added later is covered). Shift alone stays the 3x modifier, so Shift+W/S/D/Q/E keep flying fast - only actual commands are excluded. Shift+A is the sole collision today; the W-A-S-D and Q/E registry rows are documentation entries with no action, which is why the check requires s.action. No new dependency edge: editorNavigation already reached shortcuts through inputRuntime, and nothing in lib/ imports editorNavigation, so no cycle. - NEW tests/e2e/fly-shortcut-keys.test.cjs: asserts Shift+A opens the menu AND leaves the camera still, that plain A/W still fly, and that Shift+W is still ~3x. Verified failing-first: without the fix the camera moves 1.500. Two stale e2e checks fixed while in here - both were TEST bugs, the app was correct, which is why manual testing found nothing: - connect-states: looked for [data-testid="connect-pending"], which exists NOWHERE in src - the CN drawer redesign never carried it over, so the check could only ever fail. Now asserts what the pill actually renders while pending: the disabled input reading "Requesting <ID>". - add-menu: checked #add-search-input visibility after a fixed 300ms wait. The Shift+A action dynamically imports appStore, and with two peers rendering at full rAF that resolved later than 300ms - the feature worked, the wait was too tight. Now waits for the element. This was the only reason the suite failed (the following locator.hover timeout was a cascade). Verified: fly-shortcut-keys 5/5, add-menu 11/11, connect-states 19/19. Build green, svelte-check holds 484/66. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shift+A opened a centred box and spawned at the object's default spot. It now
behaves like the right-click Add menu: anchored to the cursor, spawning what you
pick under the cursor.
- appStore: NEW addMenuOpener seam, mirroring viewportMenuOpener. Scene owns the
raycaster, so the ray logic stays there and shortcuts stays dumb.
- Scene.svelte: remember the cursor on pointermove; NEW scenePointAt() resolves a
screen position to a world point (object hit, else the ground plane, else the
origin - the same resolution the right-click Add menu uses); publish an opener
that anchors the popover to the cursor and spawns there. It declines in VR /
play / spectator mode, and before the pointer has ever moved.
- shortcuts: Shift+A calls the opener and falls back to a centred box with the
default spawn spot when it declines (fresh load / keyboard-only).
Clamping (the popover could hang off the edge, and a drag could shove it off):
- AddMenu: position is state, not a hardcoded guess. It opens below-right of the
anchor, FLIPS to the other side when there is no room, then clamps so no edge
leaves the viewport. The size is MEASURED - the box grows and shrinks with the
results list, so the old fixed 270x320 estimate both pushed a short box up
needlessly and let a tall one overflow. A ResizeObserver re-places it as the
list filters, and window resize re-clamps it.
- A right-dragged box keeps the position the user chose (only re-clamped, never
re-anchored), so filtering after a drag no longer snaps it back.
- searchMenuUx.rightDragMove: clamp BOTH axes. It only pinned left/top >= 0, so a
drag could push either box off the right/bottom (which also grows the document
- see the off-the-right-edge gotcha). This fixes the node-search box too.
GOTCHA HIT (documented in CLAUDE.md, cost real time): the placement $effect called
place(), which READS pos and whose ResizeObserver WRITES pos - the effect then
depended on its own output and tripped effect_update_depth_exceeded, which killed
the component's reactivity so positioning silently froze (a later resize did
nothing). place() is now called through untrack(), and the drag flag is a plain
let rather than $state. Also: <svelte:window> cannot live inside an {#if}.
- NEW tests/e2e/add-menu-cursor.test.cjs, 16 checks: opens at the cursor, spawns
under it, a different cursor spawns elsewhere, all four screen corners stay
fully inside, a drag past the edge clamps but still moves, filtering keeps a
dragged box put, the document never grows, and a window resize re-clamps.
- add-menu: rightTap now retries. A right TAP only opens the menu when the press
is under 400ms (longer = a right-DRAG that pans), and Playwright's separate
down/up CDP round-trips measured 360-410ms with two peers at full rAF - right
on the threshold, so the menu appeared only about half the time. One step in
that suite is still flaky and is now marked: verified to reproduce WITHOUT any
of these changes (stashed them and it failed twice), so it is pre-existing.
Verified: add-menu-cursor 16/16, fly-shortcut-keys 5/5, search-menus 10/10.
Build green, svelte-check holds 484/66.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- the {#key rerenderInput} recreate detached the file input while the
native picker was open; Svelte 5's delegated oninput never fires on a
detached element, so importFile was never called (regression from the
203 sidebar rewrite, where legacy on:input attached directly)
- re-pick-same-file now works by clearing input.value before .click()
instead of destroying/recreating the element (shared pickFile helper)
- Load accept list tidied: dropped .scene (no code path handles it) and
.gltf (legacy additive path that overlaps Import); Load = .json/.tpscene
- new e2e suite import-button (4 checks) drives the real button through
Playwright's filechooser, incl. same-file re-pick
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Settings: the What's new button moves from the About section to the modal footer, next to Reset settings / Clear saved session (same about-whats-new id kept) - whatsNew.startWhatsNew: a welcome-on-start opt-in returned before the version check every boot, so that user never saw update badges; the early return (and open-time markSeen) now applies only to the true first visit -- pref-opened welcome still gets the dot, toast stays suppressed while the overlay is up (badge-not-popup) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 5.4.21) - svelte 5.1.3 -> 5.56.8, @sveltejs/kit 2.8.1 -> 2.70.1, vite 5.4.10 -> 5.4.21, vite-plugin-svelte 4.0.4, adapter-static 3.0.10, svelte-check 4.7.4, typescript 5.9.3, tailwindcss 3.4.19, playwright 1.62.0 (needs npx playwright install chromium), postprocessing 6.39, peerjs 1.5.5, fontawesome 6.7.2, prettier 3.9.6 + plugins, autoprefixer/gh-pages/mkcert - deliberately NOT bumped (planned post-1.0 migrations, see cloud repo plans-core/pending/deps-migrations-post-1.0.md): three, @threlte/* (-next pins), @xyflow/svelte, flowbite*, tailwind 4, vite majors, TS 7, rapier - svelte 5.5x fallout fixed: <svelte:self> -> self-import (Objects), quoted Progressbar attribute (Toasts), state_referenced_locally ignores for intentional one-time prop reads (WindowShell, Section) - Toasts: the live-toast each is now KEYED - svelte 5.5x node reuse in the unkeyed each migrated text across rows when a neighbour expired and left a stuck duplicate toast (found via sessions e2e decline check; two-peer pre/post-bump baseline runs proved every other failing suite pre-existing and identical on old deps) - new svelte-check baseline 476 errors / 62 warnings (was 484/66); CLAUDE.md baseline + deps-policy notes updated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- .github/dependabot.yml: monthly, one grouped PR for minor+patch; majors separate; the deliberately frozen migration deps (three/threlte/xyflow/ flowbite/tailwind/vite/TS/fontawesome/rapier) are ignored until their planned migrations execute - scripts/deps-check.cjs + npm run deps:check: non-blocking npm-outdated report split into safe drift / unplanned majors / frozen-pending-migration (0.x minors count as breaking); the cloud repo deploy build now calls it with --if-present as a pre-deploy warning Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- entering Sculpt Terrain detaches the gizmo and keeps it off (a visible gizmo mid-stroke invited accidental terrain moves); resets OFF on every sculpt entry - new SculptToolbar 'Gizmo' toggle re-attaches it deliberately - gate lives in applySelectionSet via a new sceneStore.gizmoSuppressed (leaf store - objectActions cannot import terrainSculpt without closing an import cycle) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- new enableShiftAdd pref (persisted, default false) gates the Shift+A shortcut action; Shift doubles as camera strafe in fly mode so the shortcut only exists for users who enable it - Settings row 'Shift+A quick add' next to the other viewport toggles; shortcut list label points at Settings - add-menu-cursor asserts the default is inert, then both suites seed the pref before driving Shift+A Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- PACKS_BASE -> cdn.jsdelivr.net/gh/theprototype-app/packs@v1; the pack list is the repo's index.json, with the bundled static/library starter (logo + duck, ~460KB, now committed) as the offline fallback - normalizeDefault prefixes listUrl/attributionUrl/zip with PACKS_BASE for remote rows (the latent unprefixed-listUrl bug); absolute item glb/screenshot URLs pass through - the khronos pack is metadata-only, bytes come straight from KhronosGroup/glTF-Sample-Assets (all 21 entries HEAD-verified) - thumbnails lead with the committed screenshot (thumb.webp probing spammed CDN 404s); index 'source' -> sourceUrl + Source button in the pack Properties panel (github slug label) and an Open-source row action - packs e2e rewritten for the CDN model (mocked index, absolute-URL passthrough, fallback, Source button); PACKS.md documents index.json + the upstream-fetch pattern - packs repo published: default / cube_diorama (real labels) / khronos-sample-assets (index only) / audio-essentials (23 CC0 sounds, Kenney + OpenGameArt, installable .zip) - tagged v1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tes, release flow, update toast - V2: About shows the baked version string; CLOUD_HOOKS_VERSION + cloudPluginInfo store + api.setPluginInfo (About Cloud-plugin row); startCloudPlugin fails CLOSED when a plugin declares compatibleHooks NEWER than the app (strictly greater - new-app + old-plugin stays fine) - V3: app version + sha ride the modules handshake; checkPeerAppVersion toasts once per differing version per session (warned-Set, reconnects cannot re-spam) - V4: SESSION_FORMAT=1 + appVersion stamped into session payloads; NEW confirmDialog.js (promise showConfirm) + ConfirmModal.svelte; importSession/ importSessionZip confirm a NEWER format BEFORE any asset/pack restore and resolve null on cancel (call sites treat null as silent cancel); older or absent formats load silently - V5: MODULE_FORMAT=1 - installZip/installUrl confirm a newer manifest format; install records carry appVersion - V6: .github/workflows/release.yml (v* tag -> build + svelte-check baseline gate 476/62 + zip + GitHub Release w/ notes) + RELEASING.md + CLAUDE.md pointer (npm version is the single source of truth) - V8: emitVersionJson vite plugin writes static/version.json (gitignored); updateCheck.js polls it every 15 min + on tab focus, one reload toast per session, dev skips - NEW e2e version.test.cjs (8 checks) all green; sessions/session-zip/ tpscene/modules-manager/whats-new suites green Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ad end)
- opening a zip-only pack (no item list) showed an empty 'This pack has no
items' view - the only install path was a right-click row, invisible on
touch; the open view now IS the install prompt (#pack-install button,
shared installZipPack with the row action)
- loadPacks: an INSTALLED zip pack shadows its default-list row (installing
audio-essentials listed the pack twice after reload)
- loadPackItems short-circuits zip-only packs (fetch('') grabbed the page)
- installZipPack loads items explicitly after install - the activeFolder
effect does not re-fire when the same pack was already open (svelte 5
same-value equality)
- packs e2e: zip row in the mocked index + install-card checks; verified
LIVE against jsDelivr (real install pulls 23 sounds, dedupe survives
reload)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- importPackZip creates (or reuses) a root library folder named after the pack and stores every item in it - 23 audio-essentials sounds no longer dump into the library root; content-hash dedupe still wins for items already stored elsewhere - packs e2e asserts the folder placement Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release-runway batch for v1.0.0:
🤖 Generated with Claude Code