### Outage handling
- Show an error toast when the OmniGen service is unavailable (5xx)
instead of failing silently.
- Distinct messages for the two failure points: couldn't load the model
list vs. couldn't enqueue a generation.
- Model-fetch toast fires once per failed attempt (singleton fetch +
message dedup); generation toast is gated to 5xx so content-policy/4xx
rejections still just show the failed card and 402 still opens the
credits modal.
### Prompt box
- Fix prompt box overflowing past the viewport at some desktop widths
(Generate button hidden) - removed `w-full` so it sizes to the content
area beside the sidebar (create-image + create-video).
### Recreate action
- Add **Recreate** to in-progress jobs in the create-page gallery (grid
+ list) and the task queue - previously only on completed/failed.
- Task queue had no Recreate at all; added it to all three states
(in-progress/completed/failed) for consistency.
- Recreate on the in-progress grid card sits bottom-right inline with
the prompt; in-progress list row reveals it on hover (matching completed
rows).
- Extract shared `useRecreateFromPromptToken` hook; refactor
FailedCard/FailedRow onto it (DRY).
### Model display names
- Consolidate to a single source of truth: webapp `getModelDisplayName`
now delegates to `@storyteller/model-list` (removed the duplicate local
map). Gallery, task queue, and lightbox now agree.
- Fix missing names: `gpt_image_1` (gallery) and Midjourney in the
lightbox - added `midjourney_7` / `midjourney_7_niji` / `midjourney_8`
to the model-list name + creator-icon maps; aligned `veo_2` → "Google
Veo 2".
### Sticky prompt settings across model switches
- Prompt-box settings no longer reset when switching models - the user's
choice persists and is resolved against the new model (kept if
supported, else falls back for display/generation only, without losing
the preference).
- Covers aspect ratio, count, resolution, quality (image) and aspect
ratio, resolution, count, duration, sound (video).
- Add `lib/resolve-model-setting.ts` (`resolveModelOption` /
`resolveModelCount`); `handleModelChange` now only switches the model (+
capability-bound input mode on video).
The frontend migrated to pnpm workspaces in #1606, which introduced
"workspace:*" dependencies. npm cannot resolve that protocol, so the
macOS and Windows publish workflows fail at "npm ci" with
EUNSUPPORTEDPROTOCOL, breaking production release builds on main.
Add a pinned pnpm setup step and replace the npm install block with
"pnpm install --frozen-lockfile". Verified the frozen install resolves
cleanly against the committed pnpm-lock.yaml.
---------
Co-authored-by: bflatastic <bombayapirat@gmail.com>
- Renamed the "Supercharge Credits" button to **Use on Web** (globe
icon) in the hero and bottom CTA. Routes subscribers to the webapp
homepage, everyone else to `/pricing`.
- Removed the "Create image / Create video" links from both sections.
- Split Discord + GitHub into a separate "Open source &
community-driven" CTA (subtle container) above the "Ready to craft?"
CTA.
MentionTextarea's DOM-sync effect rewrote innerHTML under the live caret
whenever buildHTML's identity changed, detaching the cursor on iOS
Safari mid-typing. Skip the rewrite when focused and the DOM already
matches value, and memoize colorMap in MobilePromptForm to stop the
per-render churn.
After Google sign-in, brand-new accounts now land on /welcome instead of
the set-password page; returning users go to their normal destination.
"New user" is detected via the SSO response's
username_not_yet_customized (forced to false by the backend for
returning Google logins, so repeat logins never re-trigger it). A
per-user-token localStorage marker guards against the rare
email→Google-link edge case so welcome shows at most once per account.
- session.ts: add consumeNewUserWelcome(isNewUser) helper
- login / signup-form / signup-cta-modal: route via the helper
On mobile Safari, opening any overlay (mobile menu, signup modal) over the
create pages froze the UI for 5-10s. Cause: the fixed prompt box uses the
`.glass` class (`backdrop-filter: blur`), and iOS Safari re-evaluates a
backdrop-filter against the newly composited overlay content, hanging the
main thread. Desktop was unaffected.
- Disable every `backdrop-filter` on mobile (<= 639px) via a universal reset.
- Make `.glass` fully opaque on mobile so dropping the blur is invisible.
- Revert the earlier Google Sign-In deferral attempt in GoogleLoginButton
(it didn't address the real cause).
**Problem:** On mobile Safari, tapping "Sign up to create" on the create pages froze for 5–10s before the signup modal appeared. Desktop was fine.
**Cause:** The modal mounts Google's GSI sign-in widget (`<GoogleLogin>`), which boots a cross-site iframe to `accounts.google.com`. Mobile Safari's tracking prevention (ITP) throttles that cross-site init for several seconds, and because the widget mounted synchronously when the modal opened, the modal's first paint was blocked behind it. The login/signup pages didn't show this because they mount the widget during a route change, hiding the cost.
**Fix:** Defer mounting the real GSI iframe until after first paint (`useEffect` + `requestAnimationFrame`). The custom "Continue with Google" button shows instantly; the actual Google button hydrates a frame later, off the critical path. The container has a fixed height, so there's no layout shift.
- Centralized in `GoogleLoginButton`, so the login/signup pages benefit too.
- Tradeoff: the Google button becomes clickable ~1 frame later (imperceptible).
- No behavior change on desktop.
## Signup, credits, and pricing polish
A round of UX improvements around signing up, running out of credits,
and the pricing page.
**Signup**
- Refreshed the signup prompt copy and added a "Continue with Google"
option (same flow as the login/signup pages)
- Added a "Sign up to create" button on the image and video pages for
logged-out visitors
**Create pages**
- Punchier empty-state headlines ("Describe anything. See it in
seconds." for images, "Describe a scene. See it in motion." for video)
- Added a subtle background pattern behind the empty state
**Out of credits**
- New modal that appears when a generation is blocked by not enough
credits
- Subscribers see "Upgrade plan" (hidden if they're already on the top
plan) plus "Buy credits"
- People without a plan get a "Choose a plan" prompt instead
**Pricing page**
- Existing subscribers get a "Buy more credits" shortcut at the top of
the page
- "Contact Us" now opens a small menu to copy the email or open your
mail app
**Cleanup**
- Removed the "Seedance 2.0 is in Early Alpha" warning from the task
queue
**Buy credits modal**
- Restyled the buy credits modal to be more appealing
## Login & Signup improvements + Google sign-in
- **Refreshed login & signup pages** - cleaner two-panel design with a
looping
Seedance 2.0 showcase video alongside the form, the ArtCraft logo, and a
back
button. Tidied up the related password-reset and welcome screens to
match.
- **Sign in with Google** - added a "Continue with Google" button to
both the
login and signup pages.
- **Set a password after Google sign-up** - first-time Google users are
guided to
create a password (so they can also sign in on the desktop app), then
continue
to the welcome/pricing page. Returning users go straight in.
- **Account settings** - the password option now says "Set" for accounts
that
don't have a password yet (and skips asking for a current one), and
"Change"
otherwise.
- remove small plan text on pricing page
- persist prompt/settings across reloads, add frontend lightbox
references media (audio/video)
- remove topbar for edit 3d page, reclaim vertical space and relocate
scene title rename/right topbar actions
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>