{"record":{"id":"5561662912ca0007","repo":"heygen-com/hyperframes","slug":"a-hue-curve-requires-at-least-three-points","errorCode":null,"errorMessage":"A hue curve requires at least three points","messagePattern":"A hue curve requires at least three points","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/colorGradingCurves.ts","lineNumber":177,"sourceCode":"    throw new RangeError(`A color curve supports at most ${HF_COLOR_CURVE_MAX_POINTS} points`);\n  }\n  if (points.some(([input]) => input < 0 || input > 1)) {\n    throw new RangeError(\"Color curve inputs must be between 0 and 1\");\n  }\n  if (points[0]?.[0] !== 0 || points[points.length - 1]?.[0] !== 1) {\n    throw new RangeError(\"Color curves must include input endpoints 0 and 1\");\n  }\n  return compileCurveSamples(points, size, (index) => index / (size - 1), 0, 1);\n}\n\n/** Samples a periodic hue curve without duplicating the 0/360-degree texel. */\nexport function compileHfHueCurve(\n  points: readonly HfHueCurvePoint[],\n  outputMin: number,\n  outputMax: number,\n  size = HF_COLOR_CURVE_LUT_SIZE,\n): Float32Array {\n  if (points.length < 3) throw new RangeError(\"A hue curve requires at least three points\");\n  if (points.length > HF_COLOR_CURVE_MAX_POINTS) {\n    throw new RangeError(`A hue curve supports at most ${HF_COLOR_CURVE_MAX_POINTS} points`);\n  }\n  const sorted = [...points].sort((a, b) => a[0] - b[0]);\n  for (let index = 0; index < sorted.length; index += 1) {\n    const point = sorted[index];\n    if (!point || point[0] < 0 || point[0] >= 360) {\n      throw new RangeError(\"Hue curve inputs must be from 0 up to 360 degrees\");\n    }\n    if (index > 0 && point[0] === sorted[index - 1]?.[0]) {\n      throw new RangeError(\"Hue curve inputs must be unique\");\n    }\n  }\n  const before = sorted.slice(-2).map(([hue, delta]) => [hue - 360, delta] as const);\n  const after = sorted.slice(0, 2).map(([hue, delta]) => [hue + 360, delta] as const);\n  const periodic = [...before, ...sorted, ...after];\n  validateCurvePoints(periodic, size);\n  return compileCurveSamples(periodic, size, (index) => (index / size) * 360, outputMin, outputMax);","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/core/src/colorGradingCurves.ts#L159-L195","documentation":"compileHfHueCurve samples a periodic hue curve around the 0/360-degree circle. Unlike a flat color curve, periodic interpolation needs at least three control points so the spline has interior knots to wrap across the seam. The throw at line 177 rejects arrays with fewer than three points.","triggerScenarios":"Calling compileHfHueCurve(points, outputMin, outputMax) with points.length of 0, 1, or 2. Note: validateCurvePoints is only reached later (after sorting and the periodic padding), so length < 3 fails here first.","commonSituations":"Initializing a hue shift with a single default point; passing an empty array as a 'no-op' placeholder; downgrading a dense hue preset to two anchors expecting linear interpolation.","solutions":["Provide at least three [hueDegrees, delta] points spread across the 0..<360 range.","For a no-op hue curve, supply three or more points with delta = 0 (e.g. [[0, 0], [180, 0], [359, 0]]).","Validate length upstream with validateHueCurve() from @hyperframes/parsers/color-grading-contract, which enforces the same 3..16 range."],"exampleFix":"// before\ncompileHfHueCurve([], -1, 1);\ncompileHfHueCurve([[0, 0.1], [180, -0.1]], -1, 1);\n\n// after — at least three points\ncompileHfHueCurve([[0, 0.1], [120, 0.0], [240, -0.1]], -1, 1);","handlingStrategy":"validation","validationCode":"function assertHueCurveMinPoints(points: readonly unknown[]): void {\n  if (points.length < 3) {\n    throw new Error(`Hue curve needs >= 3 points, got ${points.length}`);\n  }\n}\n\nassertHueCurveMinPoints(points);\ncompileHfHueCurve(points, -1, 1);","typeGuard":"function isHueCurveWithMinPoints(points: readonly unknown[]): points is [number, number][] {\n  return Array.isArray(points) && points.length >= 3 && points.length <= 16;\n}","tryCatchPattern":"try {\n  compileHfHueCurve(points, -1, 1);\n} catch (err) {\n  if (err instanceof RangeError && err.message === 'A hue curve requires at least three points') {\n    // fall back to an identity hue curve (>= 3 zero-delta points)\n    compileHfHueCurve([[0, 0], [180, 0], [359, 0]], -1, 1);\n  } else throw err;\n}","preventionTips":["Default new hue curves to a 3-point identity ([0,0],[180,0],[359,0]).","Bound authoring UI to refuse < 3 entries.","Run validateHueCurve() upstream — it enforces the 3..16 range."],"tags":["color-grading","hue-curve","validation","range-error"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}