From b8c2fffa3c696147adbdfa09477c49d12443da6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Mon, 1 Jun 2026 15:27:36 -0400 Subject: [PATCH] feat(studio): add PROP_CONSTRAINTS and clampPropertyValue for animation properties --- .../src/components/editor/AnimationCard.tsx | 8 +++++- .../editor/gsapAnimationConstants.ts | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/studio/src/components/editor/AnimationCard.tsx b/packages/studio/src/components/editor/AnimationCard.tsx index 3849ce0483..0ccd4f4446 100644 --- a/packages/studio/src/components/editor/AnimationCard.tsx +++ b/packages/studio/src/components/editor/AnimationCard.tsx @@ -9,9 +9,11 @@ import { METHOD_LABELS, METHOD_TOOLTIPS, PERCENT_PROPS, + PROP_CONSTRAINTS, PROP_LABELS, PROP_TOOLTIPS, PROP_UNITS, + clampPropertyValue, } from "./gsapAnimationConstants"; import { buildTweenSummary } from "./gsapAnimationHelpers"; import { EaseCurveSection } from "./EaseCurveSection"; @@ -27,7 +29,11 @@ function displayValue(prop: string, val: number | string): string { } function adjustedValue(prop: string, raw: string): string { - if (isPercentProp(prop)) return String(Math.max(0, Math.min(1, Number(raw) / 100))); + if (isPercentProp(prop)) return String(clampPropertyValue(prop, Number(raw) / 100)); + const num = Number(raw); + if (!Number.isNaN(num) && PROP_CONSTRAINTS[prop]) { + return String(clampPropertyValue(prop, num)); + } return raw; } diff --git a/packages/studio/src/components/editor/gsapAnimationConstants.ts b/packages/studio/src/components/editor/gsapAnimationConstants.ts index 425c0b8509..35cf9e49bd 100644 --- a/packages/studio/src/components/editor/gsapAnimationConstants.ts +++ b/packages/studio/src/components/editor/gsapAnimationConstants.ts @@ -123,6 +123,33 @@ export function parseCustomEaseFromString(ease: string): { export const PERCENT_PROPS = new Set(["opacity", "autoAlpha"]); +export const PROP_CONSTRAINTS: Record = { + opacity: { min: 0, max: 1, step: 0.01 }, + autoAlpha: { min: 0, max: 1, step: 0.01 }, + scale: { min: -10, max: 10, step: 0.01 }, + scaleX: { min: -10, max: 10, step: 0.01 }, + scaleY: { min: -10, max: 10, step: 0.01 }, + rotation: { step: 1 }, + skewX: { min: -90, max: 90, step: 1 }, + skewY: { min: -90, max: 90, step: 1 }, + width: { min: 0, step: 1 }, + height: { min: 0, step: 1 }, + borderRadius: { min: 0, step: 1 }, + x: { step: 1 }, + y: { step: 1 }, + fontSize: { min: 1, step: 1 }, + letterSpacing: { step: 0.1 }, +}; + +export function clampPropertyValue(prop: string, value: number): number { + const constraint = PROP_CONSTRAINTS[prop]; + if (!constraint) return value; + let clamped = value; + if (constraint.min !== undefined) clamped = Math.max(constraint.min, clamped); + if (constraint.max !== undefined) clamped = Math.min(constraint.max, clamped); + return clamped; +} + export const ADD_METHODS = ["to", "from", "fromTo", "set"] as const; export const ADD_METHOD_LABELS: Record = {