Fixes three review findings:
1. Sticky creation no longer zoom-adapts — always creates at M preset
(28px/260w) in world space. Consistent at any zoom level.
2. Preset definitions extracted to stickyPresets.ts (shared domain module).
TextFormatToolbar and tools.ts both import from there — no more
canvas→component dependency inversion.
3. TextEditor.onLiveResize callback syncs spatial index and transform
box as sticky background grows during typing.
Each S/M/L/XL/XXL preset now sets both fontSize and card width:
S(20px/200w), M(28px/260w), L(36px/320w), XL(48px/400w), XXL(60px/480w).
Creation picks preset based on zoom, toolbar toggle updates both.
Wider size toggle buttons for XL/XXL labels, font name maxWidth 110px.
Backward compatible — existing stickies keep original width.
Stickies are now fixed-width cards — no resize handles shown.
Text size controlled via 5 presets (10/14/18/24/32px).
On creation, zoom-aware screenToWorld snaps to nearest preset.
Height auto-adjusts from content. Plain text resize unchanged.
Removes: sticky width bake, live reflow drag, min width constraint.
Backward compatible — existing stickies map to nearest preset.
Sticky UX overhaul — clear separation between card resize and text size:
- S/M/L toggle (12/14/18px) in contextual toolbar for sticky text size
- TransformBox: horizontal-only resize for stickies with live text
reflow during drag (no more stretch-then-snap)
- Hide vertical handles (tc/bc) for sticky-only selections
- Minimum sticky width of 80px enforced in both drag and bake
- TextEditor: sticky background auto-resizes as user types
- textLimits.ts comment corrected to match actual usage
Plain text unchanged: resize gesture scales fontSize via bake.
Fully backward compatible — existing stickies map to nearest preset.
TextCore.ts: shared text rendering with dirty-check caching, zoom-bucket
resolution, and optional word-wrap. TextSprite and StickySprite now
compose TextCore instead of duplicating text logic.
Sticky resize now bakes width only (fontSize stays stable), so dragging
a sticky wider/narrower reflows text with auto-adjusted height — like
a resizable text box.
Sticky text was blurry after scaling because sx/sy stretched the
texture without re-rasterizing. Now bakes fontSize and card width
on drag-end (same as plain text), so StickySprite recomputes layout
at native resolution.
Single source of truth for font-size constraints (text 6–160, sticky
8–96) used by creation defaults, resize-bake, and any future mutation
paths. Replaces scattered hardcoded min/max values.
Add TextSharpnessManager for crisp text rendering at all zoom levels:
- Discrete zoom buckets (0.5–3x) avoid texture churn on small zoom changes
- Initial bucket applied to all items on setup and newly created items
via SceneManager.onItemCreated callback (fixes blurry-on-load)
- Visibility check uses getItemWorldBounds for correct grouped item coords
- TextSprite/StickySprite gain setZoomBucket() for resolution control
Remove fontSize +/- controls from contextual toolbar — font size is now
controlled purely through direct manipulation (resize → bake).
- Remove persistent font-size slider from main toolbar (tools only)
- Lock in zoom-aware creation defaults as named constants
- Split contextual toolbar by object type: text vs sticky
- Text: fontSize + fontFamily + text color
- Sticky: fontSize + fontFamily + text color + note fill color
- Mixed selection: hide toolbar
- Bake scale into fontSize on text resize (reset sx/sy to 1)
- Sticky resize stays layout-driven (no font change)
extract.canvas(viewport) snapshots the entire viewport to a WebGL
texture on the main thread. When viewport dimensions × devicePixelRatio
exceed GPU limits, this causes texImage2D errors and ~1000ms stalls
that block focus, typing, and scroll. Thumbnails can be generated on
idle or server-side instead.
queueMicrotask fires before the click event settles, causing the
textarea to blur immediately and trigger empty-text cleanup.
requestAnimationFrame waits one paint frame — enough for the pointer
event to fully resolve without the sluggishness of setTimeout(50).
Replace setTimeout(50) with queueMicrotask for TEXT tool editor open
(matching STICKY tool). Add screenToWorld helper for zoom-aware font
sizes and sticky card dimensions. Remove unused Text/TextStyle imports.
- Replace 50ms setTimeout with queueMicrotask for editor open
- Skip updateFromData() entirely when no inputs changed
- Cache background redraw inputs, skip Graphics clear+redraw when shape unchanged
- Separate text-only, style-only, and bg-only update paths
Clear editor state before scene callbacks to prevent blur timer or
startEditing re-entry from calling updateFromData on a destroyed sprite.
Guard all display object access with .destroyed checks.
New reviewTargeting.ts provides resolveReviewTargetAtPoint() which:
- descends into groups to find the deepest commentable child under the click
- walks children in z-order (front-to-back) for correct visual stacking
- handles nested groups recursively
- returns null if no valid child exists under the point
Editor.tsx review click handler now delegates to the resolver instead of
raw queryRegion + topmost-z pick. Defensive guard rejects group objectIds
before draft creation.
Existing group-anchored threads continue to render and open normally.