feat(studio): add Blur and Pixelate effect sliders

This commit is contained in:
Vance Ingalls
2026-07-14 15:51:52 -07:00
parent 93f3bf5945
commit 80dc7c49f6
2 changed files with 66 additions and 0 deletions
@@ -344,3 +344,29 @@ describe("FlatColorGradingSection — Vignette and Grain", () => {
act(() => root.unmount());
});
});
describe("FlatColorGradingSection — Effects", () => {
it("renders Blur and Pixelate sliders under an Effects micro-label", () => {
const { host, root } = renderInto(<FlatColorGradingSection {...neutralPropsBase()} />);
expect(host.textContent).toContain("Effects");
const rows = host.querySelectorAll('[data-flat-grade-effect="true"]');
expect(rows).toHaveLength(2);
act(() => root.unmount());
});
it("commits a dragged Pixelate value on slider track pointerdown, scaled from percent to the 0..1 effect range", () => {
const onCommitColorGrading = vi.fn();
const { host, root } = renderInto(
<FlatColorGradingSection
{...neutralPropsBase()}
onCommitColorGrading={onCommitColorGrading}
/>,
);
const pixelateRow = findRowByText(host, '[data-flat-grade-effect="true"]', "Pixelate");
// min=0, max=100, step=1, ratio=0.75 -> raw=75 -> commit(75) -> effects.pixelate = 75/100 = 0.75
dragSliderTrack(pixelateRow, 75, 100);
expect(onCommitColorGrading).toHaveBeenCalledTimes(1);
expect(onCommitColorGrading.mock.calls[0][0].effects.pixelate).toBe(0.75);
act(() => root.unmount());
});
});
@@ -5,6 +5,7 @@ import {
normalizeHfColorGrading,
type HfColorGradingAdjustKey,
type HfColorGradingDetailKey,
type HfColorGradingEffectKey,
type NormalizedHfColorGrading,
} from "@hyperframes/core/color-grading";
import { Compare, Plus, RotateCcw, Settings } from "../../icons/SystemIcons";
@@ -132,6 +133,11 @@ const VIGNETTE_TUNE_KEYS: HfColorGradingDetailKey[] = [
];
const GRAIN_TUNE_KEYS: HfColorGradingDetailKey[] = ["grainSize", "grainRoughness"];
const EFFECT_SLIDERS: Array<{ key: HfColorGradingEffectKey; label: string }> = [
{ key: "blur", label: "Blur" },
{ key: "pixelate", label: "Pixelate" },
];
// fallow-ignore-next-line complexity
export function FlatColorGradingSection({
grading,
@@ -384,6 +390,40 @@ export function FlatColorGradingSection({
</div>
)}
</div>
<div className="space-y-0.5 border-t border-panel-hairline pt-1.5">
<div className="mb-1 text-[9px] font-semibold uppercase tracking-[0.12em] text-panel-text-5">
Effects
</div>
{EFFECT_SLIDERS.map((slider) => {
const value = grading.effects[slider.key];
const isSet = value > 1e-6;
return (
<div key={slider.key} data-flat-grade-effect="true">
<FlatSlider
label={slider.label}
value={Math.round(value * 100)}
min={0}
max={100}
tier={isSet ? "explicitCustom" : "default"}
displayValue={`${Math.round(value * 100)}%`}
onCommit={(next) =>
onCommitColorGrading({
...grading,
effects: { ...grading.effects, [slider.key]: next / 100 },
})
}
onReset={() =>
onCommitColorGrading({
...grading,
effects: { ...grading.effects, [slider.key]: 0 },
})
}
/>
</div>
);
})}
</div>
</div>
);
}