{"record":{"id":"fd6367177f635fdf","repo":"remotion-dev/remotion","slug":"blackpoint-must-be-less-than-whitepoint-but-g","errorCode":null,"errorMessage":"\"blackPoint\" must be less than \"whitePoint\", but got ${JSON.stringify(blackPoint)} and ${JSON.stringify(whitePoint)}","messagePattern":"\"blackPoint\" must be less than \"whitePoint\", but got (.+?) and (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/levels.ts","lineNumber":93,"sourceCode":"\nconst resolve = (params: LevelsParams): LevelsResolved => ({\n\tblackPoint: params.blackPoint ?? DEFAULT_BLACK_POINT,\n\twhitePoint: params.whitePoint ?? DEFAULT_WHITE_POINT,\n\tgamma: params.gamma ?? DEFAULT_GAMMA,\n});\n\nconst validateLevelsParams = (params: LevelsParams): void => {\n\tassertEffectParamsObject(params, 'Levels');\n\tassertOptionalFiniteNumber(params.blackPoint, 'blackPoint');\n\tassertOptionalFiniteNumber(params.whitePoint, 'whitePoint');\n\tassertOptionalFiniteNumber(params.gamma, 'gamma');\n\n\tconst {blackPoint, whitePoint, gamma} = resolve(params);\n\tvalidateUnitInterval(blackPoint, 'blackPoint');\n\tvalidateUnitInterval(whitePoint, 'whitePoint');\n\n\tif (blackPoint >= whitePoint) {\n\t\tthrow new TypeError(\n\t\t\t`\"blackPoint\" must be less than \"whitePoint\", but got ${JSON.stringify(blackPoint)} and ${JSON.stringify(whitePoint)}`,\n\t\t);\n\t}\n\n\tif (gamma < MIN_GAMMA) {\n\t\tthrow new TypeError(\n\t\t\t`\"gamma\" must be >= ${MIN_GAMMA}, but got ${JSON.stringify(gamma)}`,\n\t\t);\n\t}\n\n\tif (gamma > MAX_GAMMA) {\n\t\tthrow new TypeError(\n\t\t\t`\"gamma\" must be <= ${MAX_GAMMA}, but got ${JSON.stringify(gamma)}`,\n\t\t);\n\t}\n};\n\nconst VERTEX_SHADER = /* glsl */ `#version 300 es","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/levels.ts#L75-L111","documentation":"Thrown by the `levels()` WebGL2 effect's parameter validator when `blackPoint` is not strictly less than `whitePoint`. Both values are unit-interval [0,1] tonal endpoints (analogous to Photoshop's Levels), and an inverted or equal range would produce a degenerate (fully clipped or NaN) tonal remap, so the library rejects it eagerly with a TypeError before touching the GPU.","triggerScenarios":"Calling `levels({blackPoint: 0.5, whitePoint: 0.5})`, `levels({blackPoint: 0.8, whitePoint: 0.2})`, or omitting `whitePoint` while setting `blackPoint` to 1 (since the default `whitePoint` is 1, equality trips the `>=` check). Also triggered by any computed/slider value where the two cross.","commonSituations":"Studio Visual Mode sliders dragged past each other; animation where `blackPoint`/`whitePoint` are interpolated with `interpolate()` and the keyframes cross; copy-pasted config from a node-based editor that allows inverted ranges; setting `blackPoint: 1` to clip everything without also raising `whitePoint`.","solutions":["Ensure `blackPoint` is strictly less than `whitePoint` (e.g. blackPoint: 0.1, whitePoint: 0.9).","If animating both, clamp or re-order keyframes so the curves never cross at any frame.","If you intentionally want full clipping, leave `blackPoint` at 0 and only lower `whitePoint`, or vice versa.","Double-check that a missing `whitePoint` (default 1) is still greater than your chosen `blackPoint`."],"exampleFix":"// before\nlevels({blackPoint: 0.8, whitePoint: 0.2})\n\n// after\nlevels({blackPoint: 0.2, whitePoint: 0.8})","handlingStrategy":"validation","validationCode":"const isValidLevels = (p) =>\n  (p.blackPoint ?? 0) >= 0 &&\n  (p.blackPoint ?? 0) <= 1 &&\n  (p.whitePoint ?? 1) >= 0 &&\n  (p.whitePoint ?? 1) <= 1 &&\n  (p.blackPoint ?? 0) < (p.whitePoint ?? 1);\n\nif (!isValidLevels(params)) throw new Error('blackPoint must be < whitePoint');","typeGuard":"const isLevelsSafe = (p: {\n  blackPoint?: number;\n  whitePoint?: number;\n}): boolean =>\n  (p.blackPoint ?? 0) < (p.whitePoint ?? 1);","tryCatchPattern":null,"preventionTips":["Derive blackPoint and whitePoint from a single 'range' value so they can never cross.","When animating, design both keyframe curves together and verify the gap at every frame.","Wrap user-supplied values in a clamp that guarantees blackPoint < whitePoint before calling levels()."],"tags":["levels","validation","webgl2","effect-params","tone-mapping"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}