Files
lemonspace_app/docs/plans/2026-04-14-mixer-resize-crop.md

5.9 KiB

Mixer Resize/Crop Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Correct mixer interactions so resize scales the overlay proportionally while crop trims visible content from any side without changing displayed image size.

Architecture: Split displayed overlay geometry from source crop geometry. Keep overlayX/Y/Width/Height for display frame placement and size. Introduce explicit crop-edge semantics so preview, compare, and bake all trim the same source region and map it into the unchanged frame.

Tech Stack: Next.js 16, React 19, @xyflow/react, Vitest, local node preview state via useNodeLocalData, image pipeline source-loader.


Task 1: Add failing tests for the approved resize/crop semantics

Files:

  • Modify: components/canvas/__tests__/mixer-node.test.tsx
  • Modify: tests/image-pipeline/source-loader.test.ts
  • Modify: tests/lib/canvas-mixer-preview.test.ts

Step 1: Write the failing tests

Add tests that prove:

  • frame resize keeps aspect ratio locked
  • crop handle drag trims edges without changing displayed overlay frame size
  • crop drag inside crop box repositions crop region only
  • resize does not mutate crop fields
  • crop does not mutate overlayWidth / overlayHeight

Step 2: Run tests to verify RED

Run:

pnpm exec vitest run components/canvas/__tests__/mixer-node.test.tsx tests/image-pipeline/source-loader.test.ts tests/lib/canvas-mixer-preview.test.ts

Expected: failures showing current crop behavior still behaves like zoom/scale instead of edge trimming.

Step 3: Commit

git add components/canvas/__tests__/mixer-node.test.tsx tests/image-pipeline/source-loader.test.ts tests/lib/canvas-mixer-preview.test.ts
git commit -m "test(canvas): cover mixer resize and crop semantics"

Task 2: Replace zoom-like content fields with crop-edge normalization

Files:

  • Modify: lib/canvas-mixer-preview.ts
  • Modify: lib/canvas-utils.ts
  • Modify: lib/canvas-node-templates.ts
  • Modify: components/canvas/nodes/mixer-node.tsx

Step 1: Implement minimal normalized crop model

Prefer explicit crop trims:

type MixerCropData = {
  cropLeft: number;
  cropTop: number;
  cropRight: number;
  cropBottom: number;
};

Normalization rules:

  • clamp each crop edge to 0..1
  • enforce minimum remaining source width/height
  • preserve display frame fields separately
  • map legacy contentX/Y/Width/Height into equivalent crop trims during normalization if needed

Step 2: Run focused tests

Run:

pnpm exec vitest run tests/lib/canvas-mixer-preview.test.ts

Expected: GREEN for normalization and backward-compatibility cases.

Step 3: Commit

git add lib/canvas-mixer-preview.ts lib/canvas-utils.ts lib/canvas-node-templates.ts components/canvas/nodes/mixer-node.tsx tests/lib/canvas-mixer-preview.test.ts
git commit -m "feat(canvas): add explicit mixer crop edge model"

Task 3: Fix mixer node interactions

Files:

  • Modify: components/canvas/nodes/mixer-node.tsx
  • Modify: components/canvas/__tests__/mixer-node.test.tsx

Step 1: Implement proportional resize

  • use display frame aspect ratio as the locked ratio
  • corner drag scales frame proportionally
  • side handles either hide in resize mode or preserve ratio while scaling
  • resize mutates only overlay*

Step 2: Implement classic crop handles

  • render 8 crop handles in crop mode
  • edge handles trim one side
  • corner handles trim two sides
  • dragging inside crop box repositions crop region
  • crop mutates only crop fields

Step 3: Run focused tests

Run:

pnpm exec vitest run components/canvas/__tests__/mixer-node.test.tsx

Expected: GREEN for resize and crop semantics.

Step 4: Commit

git add components/canvas/nodes/mixer-node.tsx components/canvas/__tests__/mixer-node.test.tsx
git commit -m "feat(canvas): separate mixer resize and crop interactions"

Task 4: Align compare and bake semantics

Files:

  • Modify: components/canvas/nodes/compare-surface.tsx
  • Modify: lib/image-pipeline/source-loader.ts
  • Modify: tests/image-pipeline/source-loader.test.ts
  • Modify: tests/lib/canvas-render-preview.test.ts
  • Optional modify: components/canvas/__tests__/compare-node.test.tsx

Step 1: Implement crop-edge sampling everywhere

  • compare preview uses crop edges, not zoom-like content scaling
  • bake path samples cropped source region into overlay frame
  • non-mixer behavior stays unchanged

Step 2: Run focused tests

Run:

pnpm exec vitest run tests/image-pipeline/source-loader.test.ts tests/lib/canvas-render-preview.test.ts components/canvas/__tests__/compare-node.test.tsx

Expected: GREEN with preview/bake parity.

Step 3: Commit

git add components/canvas/nodes/compare-surface.tsx lib/image-pipeline/source-loader.ts tests/image-pipeline/source-loader.test.ts tests/lib/canvas-render-preview.test.ts components/canvas/__tests__/compare-node.test.tsx
git commit -m "fix(canvas): align mixer crop semantics across preview and bake"

Task 5: Final verification

Files:

  • Modify only if docs or small follow-up fixes are needed

Step 1: Run the verification suite

pnpm exec vitest run components/canvas/__tests__/mixer-node.test.tsx tests/lib/canvas-mixer-preview.test.ts tests/lib/canvas-render-preview.test.ts tests/image-pipeline/source-loader.test.ts components/canvas/__tests__/compare-node.test.tsx
pnpm lint
pnpm build

Expected: all green.

Step 2: Commit docs/follow-ups if needed

git add components/canvas/CLAUDE.md convex/CLAUDE.md
git commit -m "docs(canvas): document mixer resize and crop semantics"

Notes

  • Keep nodrag and nopan on every interactive surface and handle.
  • Prefer the smallest migration path from legacy content* fields into crop trims.
  • Do not broaden into rotation, masks, or non-uniform scaling.