Skip to content

V3: Mesh Gradient rework (presets, canvas points, shuffle, simple distortion, looping motion) - #201

Merged
git-chad merged 2 commits into
git-chad/shader-lab-v3-planfrom
git-chad/v3-mesh-gradient
Oct 13, 2026
Merged

git-chad merged 2 commits into
git-chad/shader-lab-v3-planfrom
git-chad/v3-mesh-gradient

Conversation

@git-chad

Copy link
Copy Markdown
Collaborator

Stacked on #150.

What changes

  • Presets: eight new smooth presets (Peach, Lagoon, Dusk, Citrus, Mint, Aurora, Ink, Basement) with exact colors (no tonemap) and light grain. New gradients start from Peach. The old ones read as oily blotches and their names didn't match.
  • Color points on the canvas: while the layer is selected each point shows in its own color. Drag to move (Shift locks the axis), double-click to pick the color, Alt-drag to change its reach. Each edit is one undo step.
  • Shuffle (replaces Randomize): a harmonious OKLCH palette (analogous, split complementary, triad or monochrome, with a dark and a light anchor) or a preset palette, with evenly spread points. Distortion, motion and finish stay.
  • Simple distortion: Softness, Warp and Detail; the eight raw controls move under Advanced. Points get a soft core in Simple mode, so low-weight points no longer form hard dots.
  • Motion styles: Drift, Breathe, Swirl and Flow, built from whole harmonics of the timeline duration so video exports loop without a seam. Passes receive the duration through a new updateTimelineDuration hook (editor and runtime).

Compatibility

Saved gradients migrate to Advanced with their Original motion and old preset ids fall back to Custom, so they render exactly as before. The runtime treats gradients without the new params the same way.

Verified

  • All eight presets rendered on the GPU and reviewed (no hard dots after the soft-core change).
  • Canvas points: drag moved point 1, Alt-drag raised point 3's weight 0.9 → 1.37, double-click color set point 2 to #00ff88; Shuffle changed the palette and kept softness, warp and motion.
  • A legacy project (preset sunset, no new params) loads as Advanced / Original / Custom.
  • Typecheck (app and runtime), lint (0 errors), MCP reference snapshot unchanged.

CI does not run on stacked PRs; it runs once this lands in #150.

🤖 Generated with Claude Code

…e, simple distortion and looping motion

The old presets were high-frequency warps with tonemapped colors, so they read
as oily blotches rather than a mesh gradient, and the names did not match the
results. Eight new presets (Peach, Lagoon, Dusk, Citrus, Mint, Aurora, Ink,
Basement) are soft color fields with exact colors and light grain, and a new
gradient now starts from Peach.

Each color point shows on the canvas while the layer is selected: drag to
move it (Shift locks the axis), double-click to pick its color, Alt-drag to
change its reach. Shuffle replaces Randomize: it builds a harmonious OKLCH
palette (analogous, split complementary, triad or monochrome with a dark and
a light anchor) or reuses a preset palette, lays the points out evenly, and
keeps distortion, motion and finish.

Distortion gains a Simple mode with Softness, Warp and Detail, which give each
point a soft core so low-weight points no longer form hard dots; the raw
controls live under Advanced. Motion gets styles (Drift, Breathe, Swirl,
Flow) built from whole harmonics of the timeline duration, which passes now
receive through updateTimelineDuration in the editor and the runtime, so a
video export loops without a seam.

Saved gradients migrate to Advanced with their Original motion and old preset
ids fall back to Custom, so they render exactly as before.
@vercel

vercel Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
shader-lab Ready Ready Preview Oct 13, 2026 6:54pm UTC

…otif colors, and mark Mesh Gradient as reworked

- Painted brush masks stay inside their saved bounds, and an empty brush mask hides the layer
- The runtime accepts every inner effect the editor offers, so exported Blob Tracking projects keep them
- Pattern motif images rebuild when the palette changes
- Mesh Gradient shows the orange reworked dot
@git-chad
git-chad merged commit f399bde into git-chad/shader-lab-v3-plan Oct 13, 2026
2 of 4 checks passed
@greptile-apps

greptile-apps Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Medium impact] Mesh gradient feature expansion with presets and motion styles.

Fix the changed appearance of legacy disabled gradients and the motion at zero Speed before merging.

Summary

Adds eight Mesh Gradient presets, canvas point editing, palette shuffle, Simple distortion controls, and motion styles tied to the timeline duration.

  • New gradients open with one of eight ready-made looks.
  • Shuffle gives gradients fresh palettes and point layouts.
  • Selected gradients show editable color points on the canvas.
  • Simple mode gives mesh gradients three easy shape controls.
  • Mesh gradients move in styles that loop with the timeline.
  • Older saved gradients keep their familiar look when reopened.

Reviews (1) · Last reviewed commit: "Rework the Mesh Gradient layer: smooth p..." · Reviewed by Greptile

Comment on lines +537 to +539
let offset: Node = vec2(0, 0)
if (original) offset = legacyOffset
else if (drift) offset = driftOffset

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Saved gradients change appearance

Legacy gradients with animate: false now use off, which drops the fixed point offsets the old shader applied even at time zero. Reopening those gradients moves their colors and breaks the promised saved appearance. Preserve the old offsets for legacy disabled animation in both the editor and runtime.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/renderer/gradient-pass.ts
Line: 537-539

Comment:
**Saved gradients change appearance**

Legacy gradients with `animate: false` now use `off`, which drops the fixed point offsets the old shader applied even at time zero. Reopening those gradients moves their colors and breaks the promised saved appearance. Preserve the old offsets for legacy disabled animation in both the editor and runtime.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +369 to +370
const cycles = Math.max(1, Math.round((this.motionSpeed * this.loopSeconds) / 2))
this.loopPhaseUniform.value = (Math.PI * 2 * cycles) / this.loopSeconds

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Zero speed still moves

Setting motionSpeed to zero does not stop Drift, Breathe, Swirl, or Flow. updateLoopPhase still assigns one full cycle, while needsContinuousRender reports no animation. With another animated layer present, the gradient keeps moving; otherwise it can jump when an edit redraws the canvas. Set the phase rate to zero at zero speed in both copies.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/renderer/gradient-pass.ts
Line: 369-370

Comment:
**Zero speed still moves**

Setting `motionSpeed` to zero does not stop Drift, Breathe, Swirl, or Flow. `updateLoopPhase` still assigns one full cycle, while `needsContinuousRender` reports no animation. With another animated layer present, the gradient keeps moving; otherwise it can jump when an edit redraws the canvas. Set the phase rate to zero at zero speed in both copies.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +127 to +128
useEditorStore.getState().beginInteractiveEdit()
event.currentTarget.setPointerCapture(event.pointerId)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Interrupted drags leave edits open

The overlay closes a point drag only through pointer events. If the selected layer changes, the overlay becomes disabled, or the component unmounts during a drag, removing the captured circle can leave the edit open. Later changes then stop getting separate undo steps. Add cleanup that calls endInteractiveEdit for an unfinished drag, as GeometryHandles already does.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/editor/gradient-points-overlay.tsx
Line: 127-128

Comment:
**Interrupted drags leave edits open**

The overlay closes a point drag only through pointer events. If the selected layer changes, the overlay becomes disabled, or the component unmounts during a drag, removing the captured circle can leave the edit open. Later changes then stop getting separate undo steps. Add cleanup that calls `endInteractiveEdit` for an unfinished drag, as `GeometryHandles` already does.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +280 to +284
const order = shuffled(colors, random)
const positions = spreadPoints(5, random)
const params: LayerParameterValues = { preset: "custom", activePoints: count }
for (let index = 0; index < 5; index += 1) {
params[`point${index + 1}Color`] = order[index] ?? "#ffffff"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Shuffle drops a palette anchor

Four-point shuffles can discard the dark or light anchor. The generated palette has five colors, then shuffled can put either anchor in point five even though activePoints is four. This leaves some palettes with less contrast. Keep both anchors among the active points before shuffling their positions.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/editor/mesh-gradient.ts
Line: 280-284

Comment:
**Shuffle drops a palette anchor**

Four-point shuffles can discard the dark or light anchor. The generated palette has five colors, then `shuffled` can put either anchor in point five even though `activePoints` is four. This leaves some palettes with less contrast. Keep both anchors among the active points before shuffling their positions.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

This branch was successfully deployed

1 active deployment
Preview — beffef70 Deployed Oct 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant