Commit Graph
14529 Commits
Author SHA1 Message Date
Tanish MankuandClaude Opus 4.7 94fdb4ac2f webapp pagescene: per-token scene cache with original snapshot
Reworks scene-cache-store from a single playground-scoped string to a
Record<string, { original?, current }> keyed by sceneToken (with a
PLAYGROUND_KEY constant for the no-token slot). Visiting /edit-3d/A,
editing, jumping to /edit-3d/B, then coming back to /edit-3d/A
restores A's in-progress state — the cache hit short-circuits the
server fetch inside Editor.initialize.

The adapter's loadSceneViaApi seeds `original` on first server fetch
so the lib's "Reset to original" menu item has the snapshot it needs.
resetToOriginal pulls that snapshot, hands it to editor.applyJson
(which replaces the scene and clears undo history), and mirrors
`current = original` so a pre-serialization reload can't drag the
discarded edits back.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 15:42:52 -07:00
Tanish MankuandClaude Opus 4.7 a09f1c5cfd pagescene: add applyJson + Reset-to-original menu item
Adds Editor.applyJson(jsonString) that delegates to the existing
save_manager.loadCache JSON-deserialize path and additionally clears
the undo stack and emits SceneResetEvent. Used by the new Reset flow
so the user can't "undo" a reset back into their discarded edits.

PageSceneAdapter gains an optional resetToOriginal() hook. When the
host implements it AND a sceneToken is loaded, the File menu shows a
destructive "Reset to original" item that opens a confirm modal and
then defers to the host (which knows where to find the original
snapshot — the webapp's per-token cache lands in a follow-up commit).
Tauri leaves the hook off so nothing changes there.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 15:18:01 -07:00
Tanish MankuandClaude Opus 4.7 14ad3d387b pagescene: route Save through Save-copy + confirm modal for visitors
A visitor of someone else's scene now sees the File menu's primary
"Save scene" item relabeled to "Save copy". Click → opens the existing
Save-as-copy dialog (name input + Save button) which forks the scene to
the visitor's own account via the existing saveAsCopy code path. Anon
visitors still get the signup CTA on click instead of the dialog.

The standalone "Save scene as copy" entry is hidden when visiting so
the two paths don't read as redundant for owners. canSave is loosened
to always-true for visitors so forking an unmodified scene
("favorite to my account") works as well.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 15:11:18 -07:00
Tanish MankuandClaude Opus 4.7 55e470d2ca pagescene: drop view-only mutation gates + rename selector
Visitors can now fully interact with someone else's scene — move objects,
add shapes, edit colors, etc. The previous strict view-only mode is gone.
Save remains the only auth/ownership-gated action; its rewiring lands in
a follow-up.

Renames computeIsViewOnly to computeIsVisitingOthersScene to reflect the
remaining role (it only drives the PreviewBox today; Save-copy label and
Reset button consume it next). Drops getIsViewOnly()/useIsViewOnly()
early-returns from engine actions, drag-drop, gizmo attach, keybinds,
and the Outliner row controls. Strips !isViewOnly wrappers from chrome
in Stage3DBody so the prompt box, controls, panel, and model selector
show for everyone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 15:09:05 -07:00
Tanish Manku 5465aac4bc pagescene: silence webapp first-paint console errors
Two unrelated noise sources after wiring the editor into the webapp:

1. FontLoader was fetching /resources/fonts/CarterOneRegular.json,
   which exists in the Tauri public/ but not in the webapp's. Vite's
   SPA fallback returns index.html (200, HTML body), the FontLoader's
   progress callback fires "Font Loaded: 1" three times as it streams,
   then JSON.parse chokes on the leading `<` — surfaces as an
   unhandled promise rejection from LoadingPlaceHolderManager.
   Copy the same font asset into the webapp's public/ tree (same
   pattern Tauri and editor3d already use).

2. Editor.initialize() reads sceneContainerEl.offsetWidth/offsetHeight
   to size the WebGLRenderer + post-processing pipeline. On the
   webapp the flex chain (SidebarInset → wrapper → SceneContainer)
   isn't always laid out by first call, so the dimensions are
   transiently 0×0. setSize(0,0) then configureMain(0,0) allocates
   six post-process framebuffer attachments at 0 size, each emitting
   INVALID_FRAMEBUFFER_OPERATION until the next window.resize event
   cascades through and resizes them properly. Clamp the initial
   container offset to ≥1 (Math.max(1, ...)) and replace the
   `?? 0` fallbacks on the canvas dimensions with `|| 1`. First
   frame renders into a harmless 1×1, next resize fixes everything.
2026-05-13 14:37:30 -07:00
Tanish Manku 0e2594cbe9 webapp pagescene: persist editor state across SPA navigation
The 3D editor lib already exposes cacheJsonString + onSceneSerialized
props (Tauri wires them through useTabStore so per-tab scene state
survives tab switches). The webapp wasn't using them, so navigating
to /gallery, /create-image, etc. and back blew away whatever the user
had been building in the playground.

Add a small zustand store (mirrors enter-to-generate-store.ts) backed
by sessionStorage so the serialized JSON survives both SPA navigation
and tab reloads. Read cacheJsonString once via getState() on mount so
re-renders don't restart the engine; write back via the lib's
onSceneSerialized callback on unmount.

Scoped to the no-token playground: when sceneToken is in the URL the
server-loaded scene is the source of truth, so we neither restore
from cache (would override a shared scene) nor write the session back
into it (would later resurrect a stranger's scene as the playground).
2026-05-13 14:01:40 -07:00
Tanish Manku 67d1e73208 promptbox: route webapp Generate through OmniGenApi (fix 404)
PromptBox3D's handleWebEnqueue was POSTing to /v1/image_studio/prompt
via PromptsApi.enqueueImageGeneration, but that endpoint does not exist
on the Rust backend — image_studio_routes.rs only registers
/scene_snapshot and /update_job_status under /v1/image_studio (the
remaining routes live under legacy_routes/). The webapp's /create-image
and other generation flows already use OmniGenApi.generateImage hitting
/v1/omni_gen/image/generate; this commit aligns the 3D editor with that
modern path.

- Snapshot upload still goes through PromptsApi.uploadSceneSnapshot
  (that endpoint is the one image_studio route still in use).
- The returned snapshot media token is prepended to image_media_tokens
  ahead of the user's reference images, matching how the Tauri path
  treats the scene snapshot as the primary input.
- aspect_ratio uses commonAspectRatio for models that support the new
  shape, falling back to getCurrentAspectRatio() otherwise.
- On success: toast "Image added to queue" plus the same
  __storeTaskEnqueueMeta telemetry the Tauri path fires.
- Failure path routes through the existing handleError modal.
- Drops a dead 2-second setTimeout that delayed the success toast.

Tauri path unchanged — IsDesktopApp() still gates handleTauriEnqueue,
which goes through Tauri IPC and bypasses storyteller-web entirely.
2026-05-13 13:53:03 -07:00
Tanish Manku 37723f8602 pagescene: fix color picker not opening in Safari
The Color section in ControlPanelSceneObject had two issues that
compounded into a "no picker shows up" symptom in Safari:

1. setColor(editorEngine?.selected?.userData.color) wrote `undefined`
   into React state for shapes that never had a color set, which made
   <input value={undefined}> uncontrolled and gave the Button no inline
   background color (it fell back to the primary variant, so the swatch
   looked like a generic button instead of a white swatch).
2. The hidden <input type="color"> was a sibling of the swatch
   <label htmlFor={id}>, with h-0 w-0 opacity-0. Safari refuses to open
   the native color picker when the label's target input has no layout
   box — Chrome/Firefox tolerate it, Safari doesn't.

Fixes:
- Default the color state to "#ffffff" when userData.color is unset
  (both at setColor time and at value={} time for belt-and-braces).
- Seed userData.color = "#ffffff" at shape creation in addShape so
  the default carries through save/load roundtrips too.
- Move the <input type="color"> to be a CHILD of the Button label
  and position it absolute inset-0 over the swatch. Click lands
  directly on the input (no label[htmlFor] indirection Safari is
  flaky about) and the input now has a real full-size layout box.
2026-05-13 10:29:00 -07:00
Tanish Manku f977500553 Merge branch 'feature/webapp-pagescene' of github.com:storytold/storyteller-rust into feature/webapp-pagescene
# Conflicts:
#	frontend/apps/artcraft-webapp/src/pages/pagescene/pagescene.tsx
#	frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
#	frontend/libs/components/promptbox/src/lib/PromptBox3D.tsx
2026-05-13 09:36:17 -07:00
Tanish Manku 008fcfeaa7 pagescene: finish anonymous-use polish
- Gate File → Load my scene for anon: route through promptSignup
  instead of opening a dialog that would just error-toast on the
  silent listUserMediaFiles failure.
- Remove dead SettingsModal mount in Controls3D (no UI ever triggered
  it). Drops the @storyteller/ui-settings-modal import from this file.
- New AnonHintChip pill in the top-right corner of the playground
  ("Sign up to save"). Renders only when currentUserToken is undefined
  AND not in view-only mode; click routes to promptSignup. Tauri users
  never see it.
- Scaffolding for view-only PreviewBox: new component renders a small
  card with the author's generation result; returns null when no URL
  is supplied. Mounted in Stage3DBody under the isViewOnly guard,
  reading sceneMeta.previewImageUrl (new optional field). Data-path
  wiring (populating previewImageUrl from adapter.loadScene's
  response) is the next step — leaving the UI plumbing in place so
  that follow-up is purely data, not layout surgery.
2026-05-13 09:08:43 -07:00
bflatastic 52787c7fc0 add initial model selection on edit 3d 2026-05-13 21:57:09 +07:00
bflatastic 4deeb5e299 webapp: fix control panel sometimes renders overflowing right side 2026-05-13 20:41:10 +07:00
bflatastic cf95e4ce27 webapp: render model selector inside promptbox 2026-05-13 20:34:08 +07:00
bflatastic 572de13881 mobile gate edit 3d page, hold shift to boost movement speed 2026-05-13 20:22:43 +07:00
bflatastic e49c70b852 styling updates 2026-05-13 20:14:04 +07:00
bflatastic 076552fda4 webapp: fix flickering on threejs scene when sidebar collapsing/expanding, added edit 3d to homepage 2026-05-13 13:07:19 +07:00
Tanish Manku a9fa8d710a pagescene AssetMenu: fix featured Sets/Creatures never loading
useFeaturedObjects' auto-fetch effect synchronously flipped
firstFetch.current to IN_PROGRESS before calling fetchFeaturedObjects.
On AssetModal's first mount the EngineContext editor is null, so the
fetch bailed at `if (!editor) return`. When the editor later became
available the effect re-fired (editor is in fetchFeaturedObjects'
useCallback deps), but the IN_PROGRESS guard blocked it — the network
request never fired for any featured category. CHARACTER/OBJECT tabs
appeared populated only because they're merged with local demo arrays
inside AssetModal's assetTabs useMemo; Sets and Creatures have no demo
fallback so the bug was visible there.

Move the editor check into the auto-fetch effect itself and add editor
to its deps, so IN_PROGRESS isn't burned on the no-op call. Regression
from PR #1492.
2026-05-12 18:27:59 -07:00
Tanish Manku e120d009ae pagescene: add view-only mode + anon signup CTA
- view-only mode (driven by ownerToken !== currentUserToken): gates
  engine mutators (add/delete/toggle/transform/color), gizmo attach,
  delete/undo/redo keybinds, drag-to-add; hides editor chrome
  (OnboardingHelper, Controls3D, ControlsTopButtons, PromptBox3D,
  ControlPanelSceneObject, Outliner row toggles, model/cost buttons).
- new optional adapter.promptSignup; webapp adapter wires to existing
  useSignupCta modal. Save / Save-as-copy / Generate / Upload buttons
  call it when currentUserToken is undefined, so anon visitors hit a
  signup modal instead of silent failures.
- PromptBox3D gains onBeforeSubmit?: () => boolean hook; Stage3DBody
  uses it to route anon Generate clicks through promptSignup, since
  the Generate flow bypasses adapter.enqueueGeneration today.
2026-05-12 17:41:18 -07:00
Tanish MankuandClaude Opus 4.7 fcb0ddec56 webapp pagescene: fix top blank space; de-topbar shared lib layout
- styles.css: move .glass into @layer components so Tailwind's
  .absolute utility wins the cascade. OnboardingHelper was rendering
  position: relative and pushing the editor down on first paint until
  clicking dismissed it.
- SceneContainer + Stage3DBody: drop hardcoded calc(100vh - 68px) and
  height - 56 topbar offsets; the lib now fills its parent container.
- Webapp adapter: drop the +56 getViewportSize compensation now that
  the lib doesn't subtract a topbar from the supplied height.
- Tauri PageScene: wrap Stage3D in a calc(100vh - 56px) container
  (matching .topbar-spacer) so its shape is preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 14:20:27 -07:00
bflatastic 3bb188eaf7 sidebar autocollapse edit 3d, positioning, page scrolling fix 2026-05-13 01:02:28 +07:00
Tanish Manku 2178afd736 webapp: mount pagescene at /pagescene with sidebar-aware viewport
Adds /pagescene (and /pagescene/:sceneToken) under the webapp's public
chrome (inside ProtectedLayout, outside RequireAuth) so anonymous users
can view scenes too. Adapter implementation mirrors the website's, with
two webapp-specific tweaks: imports the local useSession / showToast /
invalidateSession helpers, and getViewportSize returns the wrapper's
live ResizeObserver-measured rect so DnD hit-testing matches the visible
canvas (not window.innerWidth).

Sidebar handling: the lib's position-fixed UI is scoped to a wrapper
div with transform: translateZ(0), which creates a new containing block.
The wrapper renders inside SidebarInset's flex flow, so the editor sits
naturally to the right of the sidebar and below the topbar; expanded-
sidebar behavior is deferred (currently shrinks the page further per the
flex layout).

Sidebar nav gets an "Edit 3D" entry between Image and Video. Tailwind
config gets brand-primary/secondary/tertiary, action color, red/green/
blue DEFAULTs; styles.css adds .bg-ui-panel-gradient, .prevent-select,
.dot-typing — same gap-fills landed on the website.

No new endpoints. tsconfig churn from nx sync.
2026-05-12 09:18:13 -07:00
Tanish Manku 61c1aa720d artcraft host: import upload modals from @storyteller/ui-upload-modal
useTauriPageSceneAdapter, GlobalFileDropHandler, and UploadImagesButton
now pull UploadModal3D/Image/Splat from the shared lib. Removes the
host-local UploadModal3D/UploadModalImage/UploadModalSplat directories
since they're no longer referenced anywhere.

UploadModalMedia/ stays — it backs the host-only image-plane upload
adapter helpers, not the modal slots.
2026-05-12 09:11:11 -07:00
Tanish Manku 2d6af20d0b ui-upload-modal: lift UploadModal3D/Image/Splat into shared lib
Hoists the three feature-specific upload modals out of the artcraft
Tauri host into @storyteller/ui-upload-modal so the website (and any
future host) can render the same flows through PageScene's adapter
slots. Replaces direct `~/Classes/ApiManager` calls with @storyteller/api's
MediaUploadApi/MediaFilesApi.

Removes the old lib-internal UploadModal/UploadFiles/uploadAssets
placeholders (unused) and inlines the host-local enums
(MediaFileAnimationType, UploaderState/States, file-type enums) into
Types.ts. Adds UploadSpzFile to @storyteller/api's MediaUploadApi and
the SPLAT variant to FilterEngineCategories.
2026-05-12 09:11:11 -07:00
BFlat 0c2dd82161 unprotect webapp pages and signup cta on generate (#1504)
- public viewable pages
- signup cta on generate if not logged in
2026-05-12 22:57:10 +07:00
bflatastic 9ddf603ac8 webapp netlify redirects update 2026-05-12 21:57:39 +07:00
bflatastic 58b6b9c93f webapp netlify build fix 2026-05-12 21:52:25 +07:00
bflatastic 0246676dff fixed webapp netlify build script 2026-05-12 21:47:34 +07:00
BFlat 11a2547beb separate web marketing and web app (#1503)
cloned to webapp project and ripped out marketing stuff
2026-05-12 21:45:36 +07:00
Brandon Thomas d2dbef249c tauri providers - fal api key support (#1502) 2026-05-12 00:02:41 -04:00
Brandon Thomas 0efafe8043 FAL polling APIs + additional API bindings (#1501) 2026-05-11 21:12:10 -04:00
Brandon Thomas 25b2be92c8 artcraft router: image pipeline v2 w/ some fal models for testing (#1500) 2026-05-11 12:24:42 -04:00
BFlat 89f6015e3f Fix aspect ratio picker losing label after model switch (#1499)
When the stored `commonAspectRatio` (e.g. `SquareHd`) isn't in the
newly-selected model's `aspectRatios`, `PopoverMenu` toggle mode found
no selected item and collapsed the trigger to icon-only.

Reset to `model.defaultAspectRatio` from inside `AspectRatioPicker` so
the fix applies to all three callers (image/edit/3D). Drops the
duplicate workaround from `PromptBox3D`.
2026-05-11 20:24:01 +07:00
BFlat 3b889b6fdb website: make video button (#1498)
- added make video button to the create image page gallery card action
button row and the lightbox modal
- clicking it will redirect to the create video page and insert the
image as a reference automatically
2026-05-11 18:59:11 +07:00
Brandon Thomas 3ab2974d89 new fal client design to handle webhooks + queued requests with same API (#1497) 2026-05-10 07:48:13 -04:00
Brandon Thomas 220cf66dfc fal_client refactors ahead of a bigger one (#1496) 2026-05-09 19:46:32 -04:00
Tanish Manku 2d18a07843 3D PageScene: Componentize and big refactor (#1492) 2026-05-09 14:26:42 -07:00
Tanish Manku 369c552096 PageDraw: Generate fixes and performance boost (#1494) 2026-05-09 13:51:25 -07:00
Brandon Thomas 13a5dad3a5 beeble improvements, don't 500 on bad input (#1493) 2026-05-09 10:49:05 -04:00
bflatastic f8be6ea4c9 website: hide resolution picker, progress timer 5 mins 2026-05-09 16:35:18 +07:00
bflatastic 5f70776afe website: unified credits chip for mobile and desktop view 2026-05-09 09:28:23 +07:00
bflatastic 5c5a7d1182 credits in top navbar mobile 2026-05-09 09:12:20 +07:00
Brandon Thomas d0e5a05253 frontend api stuff (#1491) 2026-05-08 22:01:21 -04:00
Brandon Thomas 72e052fe7e add redirects for netlify 2026-05-08 21:44:01 -04:00
Brandon Thomas 7471259d28 fix frontend errors (missing vite config, type errors) (#1490) 2026-05-08 21:40:46 -04:00
Brandon Thomas ffde0b06c0 beeble webhook (#1489) 2026-05-08 20:06:09 -04:00
BFlat b4da753346 video background change feature (#1480)
- both app and website
2026-05-09 02:31:54 +07:00
Brandon Thomas 312c603cef remount 2026-05-08 13:45:18 -04:00
Brandon Thomas bdfa31421f beeble endpoint (#1488) 2026-05-08 13:44:41 -04:00
Brandon Thomas c78442cf71 beeble client (#1487) 2026-05-08 12:49:15 -04:00
Brandon ThomasandTanish Manku 58b64b694c Big tauri refactor: new consolidated commands, deprecate and remove duplication (#1486)
Co-authored-by: Tanish Manku <tanish2k09.dev@gmail.com>
2026-05-08 09:29:25 -04:00