{"record":{"id":"39314d620b734eb6","repo":"heygen-com/hyperframes","slug":"color-curve-inputs-must-be-strictly-increasing","errorCode":null,"errorMessage":"Color curve inputs must be strictly increasing","messagePattern":"Color curve inputs must be strictly increasing","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/colorGradingCurves.ts","lineNumber":83,"sourceCode":"    const beforeWeight = 2 * afterSpan + beforeSpan;\n    const afterWeight = afterSpan + 2 * beforeSpan;\n    result[index] = (beforeWeight + afterWeight) / (beforeWeight / before + afterWeight / after);\n  }\n  return result;\n}\n\nfunction validateCurvePoints(points: readonly HfColorCurvePoint[], size: number): void {\n  if (points.length < 2) throw new RangeError(\"A color curve requires at least two points\");\n  if (!Number.isInteger(size) || size < 2) {\n    throw new RangeError(\"Curve LUT size must be at least 2\");\n  }\n  let previousInput = Number.NEGATIVE_INFINITY;\n  for (const [input, output] of points) {\n    if (!Number.isFinite(input) || !Number.isFinite(output)) {\n      throw new TypeError(\"Color curve points must be finite\");\n    }\n    if (input <= previousInput) {\n      throw new RangeError(\"Color curve inputs must be strictly increasing\");\n    }\n    previousInput = input;\n  }\n}\n\nfunction validateOutputRange(\n  points: readonly HfColorCurvePoint[],\n  outputMin: number,\n  outputMax: number,\n): void {\n  if (!Number.isFinite(outputMin) || !Number.isFinite(outputMax) || outputMin >= outputMax) {\n    throw new RangeError(\"Curve output bounds must be finite and increasing\");\n  }\n  if (points.some(([, output]) => output < outputMin || output > outputMax)) {\n    throw new RangeError(`Curve outputs must be between ${outputMin} and ${outputMax}`);\n  }\n}\n","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/core/src/colorGradingCurves.ts#L65-L101","documentation":"validateCurvePoints() requires the input (first element) of each point to be strictly greater than the previous point's input. Equal or decreasing inputs are rejected because they produce zero or negative spans, which break the slope math (division by span) and create ambiguous segments. The check seeds previousInput at -Infinity so the first real point always passes.","triggerScenarios":"Two points with the same input (e.g. [[0,0],[0.5,0.2],[0.5,0.8],[1,1]]); inputs out of order ([[0,0],[1,1],[0.5,0.5]]); duplicate endpoints.","commonSituations":"A curve editor that lets two control points share an x coordinate; copy-paste duplicating a point; an unsorted array passed directly.","solutions":["Sort points by input ascending and deduplicate exact-input collisions before compiling.","Prevent the UI from letting two points occupy the same x (snap/nudge on drop)."],"exampleFix":"// before\ncompileHfColorCurve([[0, 0], [0.5, 0.2], [0.5, 0.8], [1, 1]]); // duplicate input 0.5\n\n// after — sort + dedupe by input\nconst dedup = new Map<number, number>();\nfor (const [i, o] of pts) dedup.set(i, o);\nconst sorted = [...dedup].sort((a, b) => a[0] - b[0]);\ncompileHfColorCurve(sorted);","handlingStrategy":"validation","validationCode":"const sorted = [...new Map(points.map(([i,o]) => [i,o]))].sort((a,b) => a[0]-b[0]);\n// sorted now has strictly increasing inputs","typeGuard":"function inputsStrictlyIncreasing(points: readonly (readonly [number, number)[]): boolean {\n  for (let i = 1; i < points.length; i++) if (points[i][0] <= points[i-1][0]) return false;\n  return true;\n}","tryCatchPattern":"try { compileHfColorCurve(pts); }\ncatch (err) { if (/strictly increasing/.test(String(err))) { /* sort + dedupe by input */ } else throw err; }","preventionTips":["Sort points by input and deduplicate equal inputs before compiling.","Snap/nudge in the UI so two points cannot share an x coordinate."],"tags":["color-grading","curve","validation","range","ordering"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}