Stands up PageMoodboardHtml alongside PageMoodboard — renders the same
moodboard content (image/text/group nodes) entirely with absolutely-
positioned divs, CSS transforms, and pointer events. Shares the store
with PageMoodboard so switching tabs preserves the board.
- New page at app/src/pages/PageMoodboardHtml with HTML-only stage,
background grid, nodes, overlay transformer (8 resize handles + 1
rotate), marquee + lasso selection, viewport pan/zoom, paste and
gallery drop handlers, and a shortcut-aware text edit overlay.
- Reuses MoodboardStore, layout utilities, MoodboardToolbar,
TextEditOverlay, and the non-render interaction hooks from the
existing Konva moodboard unchanged.
- Experimental flag `moodboardHtmlPageEnabled` gates a new apps-menu
entry and a Settings → Experimental toggle.
- PageEditor: gallery drop targets the HTML stage element when the
MOODBOARD_HTML tab is active.
## Moodboard polish
A pass to make the Moodboard feel consistent with the rest of the app.
### What's new
- **Floating toolbar** shared between the 3D Editor and Moodboard -
centered and no longer glued to the top edge.
- **Moodboard toolbar** rebuilt to match: mode picker (Select / Lasso /
Text), a primary `+` dropdown for **Upload Image** and **Pick from
Library**, plus Group, Fit-to-grid, Pack, Auto-group, Undo / Redo,
Delete.
- **Empty state CTA** in the center of a blank moodboard with the same
Select Image / Pick from Library flow PageDraw uses.
- **Theme support** across the moodboard - background, grid dots,
toolbar, and empty-state card all adapt to light / gray / black / aurora
/ sunset themes.
- **Platform-aware shortcut hints** in toolbar tooltips - `⌘G` on Mac,
`Ctrl+G` on Windows / Linux.
- **Topbar titles** added for Moodboard and Storyboard tabs.
Every other tab applies its `h-[calc(100vh-56px)]` on its own root div;
the PageEditor wrappers stay bare. Moodboard was the outlier — wrapper
had `w-screen` + inline height of `calc(100vh - 68px)` (wrong 68px,
causing a 12px gap at the bottom). Move the class into `Moodboard.tsx`'s
root and drop the wrapper styling so it matches the rest.
Lifts `viewport` (zoom/pan) and `canvasSize` into the moodboard store so
overlays and a future minimap can read the camera without drilling refs.
Adds a recenter pill in the bottom-right that appears when nothing in the
current viewport intersects any content, and a translucent shortcut
cheatsheet that appears after holding Ctrl/Cmd alone for 3s.
New Figma-style shortcuts: V/L/T tool switches, Cmd/Ctrl+A select all,
Cmd/Ctrl+G group, Cmd/Ctrl+Shift+G ungroup, Shift+1 zoom-to-fit.
Consolidates all previously-duplicated rect / AABB / clamp / viewport math
into `layout/geometry.ts` (removes private copies from useSelection,
useViewportControls, MoodboardStore, and packCollage). Exports include
`computeContentBounds`, `computeVisibleRect`, `anyContentVisible`,
`fitViewportToBounds`, `panToCenterOn`, `ZOOM_MIN/MAX` — everything a
future minimap overlay will need.
Canvas perf pass:
- Level-of-detail dotted grid (doubles effective spacing as you zoom out
so dot count stays bounded; dot radius tracks screen pixels).
- React.memo on ImageNode, TextNode, GroupNode, MoodboardBackground.
- Stable onSelect contract (children receive (id, e) and call a single
parent callback, letting memo skip children on camera/selection-only
renders).
- GroupNode subscribes only to its own children via useShallow, not the
full nodes map.
- TextNode's editingTextId selector collapsed to a per-node boolean.
- MoodboardStage's transient subscription narrowed to {marquee, lassoPath}
so setIsPanning / setEditingText don't churn the whole Stage.
- visibleViewport memoized so marquee/lasso drags don't force the
background sceneFunc to re-run.
New Konva-based 2D canvas for collaging reference imagery, gated behind an
experimental flag mirroring Storyboard. Supports drag-drop from OS, gallery,
and clipboard; rectangle marquee and lasso selection; grouping with
group-local coordinates so rotation/scale transforms children correctly;
fit-to-grid, justified-rows collage pack, and DBSCAN proximity auto-group;
wheel-zoom around cursor and middle-mouse / spacebar pan; per-item dashed
outlines to distinguish grouped vs individually-selected; 50-entry snapshot
undo/redo. Also fixes a pre-existing bug where disabling the experimental
flag didn't reset gated page state.
## Website bug fixes: Seedance Fast + Characters + Toasts
### Create Video page
- Switching between Seedance and Seedance Fast no longer loses your
attached references
- Seedance Fast now supports Characters (was missing from the UI)
- Characters work in both Keyframe and Reference modes
- Fixed a bug where typing `@Bob2` could accidentally attach an older
character named `@Bob`
### Task queue notifications
- No more ghost "job complete" toasts every time you reload the site
- Cleaner wording: "Image creation complete" instead of "Image complete
— Image Generation"
- Character jobs now say "Character" instead of the generic "Task"
### Toast redesign
- Matches the prompt box style instead of the old bright green
- Success = green circle with a white checkmark, error = red circle with
a white exclamation
- Centered on mobile, stays top-right on desktop
- Message no longer awkwardly wraps onto multiple lines on mobile
Should have done this all along for ease of development.
- Gets rid of refs between data structures.
- Clones won't impact our SLA or performance at our scale, this isn't
systems programming.
getCurrentAspectRatioIcon() was reading from aspectRatioList (useState),
which is only updated on manual picker clicks, not external store
writes. Reading aspectRatio from the store directly fixes the stale
icon.
## Video reference library picker
- Added "Pick from library" option to the Video Ref slot, with gallery
filtered to videos
- Added loading state to "Use selected" button in gallery modal
- Enforced seedance-2 limits (max 3 videos / 15s total) for both upload
and library flows, with a deduped video-ref-limit toast so users see a
warning on count overflow, duration overflow, or submitting when already
at max
Two bugs were preventing @image / @video / @character references from
being tagged in prompts written with Chinese, Japanese, or Korean text:
1. The mention-highlight regex was built with just the "g" flag, so a
user-typed "@image6" never matched the canonical label "@Image6" and the
reference was rendered as plain text. Make the regex case-insensitive
and do the colorMap lookup via a lowercase-keyed table so "@image6"
still finds the color for "@Image6".
2. detectMention required the character immediately before "@" to match
/\s/, which never matches CJK characters. Typing "@" right after a
Chinese character like "从" therefore never opened the autocomplete
dropdown, leaving users to type the mention by hand (which then hit bug
1). Replace the whitespace check with a "not an ASCII identifier char"
check so CJK, quotes, and punctuation all count as valid word boundaries
before an @mention.
- **Characters for Seedance 2.0** - Character creation/selection modal,
@-mention support with colored inline highlights via contentEditable
MentionTextarea, character tokens sent in video generation API requests
- **Mobile responsive navbar** - Hamburger menu with slide-down panel,
all nav items accessible, credits/library/sign out included
- **Mobile responsive PromptBox** - Tighter padding, stacked toolbar on
small screens, flex-wrap for option buttons
- **Mobile responsive library** - Proper sticky header offset, icon-only
filter tabs on mobile
- **Task queue overhaul** - Prompt text with marquee hover, copy button,
model creator icons, detailed failure reasons on all card types
(matching desktop app)
- **Gallery improvements** - 512px thumbnails (was 250px), 12px grid
gap, model + media type badges on hover, model icon + prompt on
in-progress cards
- **Quality selector** - QualityPicker for image models
(High/Medium/Low), wired to cost estimate and generation API
- **Video batch enqueue** - Multiple videos enqueue as separate jobs so
each completes independently
- **Form consistency** - All auth pages use shared `<Input>` component,
`<form onSubmit>` for Enter key, consistent styling
- **Bug fixes** - Lightbox type error, library carousel disabled,
popover icon alignment, end frame library picker, image ref max default
(1 → 6), task queue mobile overflow, clear session button removed
- **Mobile model selector** - Model picker now appears in the PromptBox
toolbar on mobile/tablet (`lg:hidden`), since the floating bottom-left
selector is desktop-only
- **Responsive image prompt row** - Start frame and end frame sections
stack vertically on mobile with a horizontal divider, instead of
side-by-side
- **Responsive lightbox** - Stacks vertically on mobile (media top, info
below), nav arrows always visible (not hover-only), sidebar goes
full-width, darker backdrop (`bg-black/80`)
- **Safari video inline playback** - Lightbox videos use
`disablePictureInPicture`, `controlsList` restrictions, and
vendor-prefixed attributes to prevent fullscreen/PiP pop-out on Safari