Repro (v2.0.6, both CLI and any node-version)
node node_modules/@playcanvas/splat-transform/bin/cli.mjs \
input.ply \
--filter-sphere 0,1.6,0,15 \
output.ply
✗ Error: Value must be >= 2, got 0
at parseNumber (.../dist/cli.mjs:29410:19)
at Array.map (<anonymous>)
at parseArguments (.../dist/cli.mjs:29635:42)
Any --filter-sphere x,y,z,r invocation where z is less than 2 (or y < 1, or r < 3) throws.
Cause
src/cli/index.ts line 477:
case 'filter-sphere': {
const parts = t.value.split(',').map((p: string) => p.trim());
if (parts.length !== 4) {
throw new Error(`Invalid filter-sphere value: ${t.value}`);
}
const values = parts.map(parseNumber); // ← BUG: passes (element, index) to parseNumber
...
}
Array.prototype.map calls the callback as (element, index, array). parseNumber is defined at line 236 as:
const parseNumber = (value: string, min?: number): number => {
...
if (min !== undefined && result < min) {
throw new Error(`Value must be >= ${min}, got ${value}`);
}
...
};
So parts.map(parseNumber) evaluates:
parseNumber(parts[0], 0) → x must be ≥ 0
parseNumber(parts[1], 1) → y must be ≥ 1
parseNumber(parts[2], 2) → z must be ≥ 2
parseNumber(parts[3], 3) → radius must be ≥ 3
Which is obviously wrong — sphere centers can legitimately have negative coordinates.
Comparison: filter-box parses correctly
The neighbouring filter-box case (lines 449-463) uses an explicit for-loop with single-arg calls and is unaffected:
for (let i = 0; i < 6; ++i) {
if (parts[i] === '' || parts[i] === '-') {
values[i] = defaults[i];
} else {
values[i] = parseNumber(parts[i]); // ← single-arg, correct
}
}
Suggested fix (one line)
Replace line 477:
const values = parts.map(parseNumber);
with:
const values = parts.map((p: string) => parseNumber(p));
(Or apply the same defaults-aware for-loop pattern used by filter-box for consistency.)
Happy to send a PR if useful.
Environment
- @playcanvas/splat-transform 2.0.6 (commit aa3dbae on main)
- Node v22 / macOS 25.4.0 / darwin-arm64
- Real-world scene: filtering a 528K-gaussian splat by sphere around
(0, 1.6, 0) to remove far-out floaters that explode the AABB; --filter-box is a working workaround but spheres are a more natural shape for many interiors.
Repro (v2.0.6, both CLI and any node-version)
Any
--filter-sphere x,y,z,rinvocation wherezis less than2(ory < 1, orr < 3) throws.Cause
src/cli/index.tsline 477:Array.prototype.mapcalls the callback as(element, index, array).parseNumberis defined at line 236 as:So
parts.map(parseNumber)evaluates:parseNumber(parts[0], 0)→ x must be ≥ 0parseNumber(parts[1], 1)→ y must be ≥ 1parseNumber(parts[2], 2)→ z must be ≥ 2parseNumber(parts[3], 3)→ radius must be ≥ 3Which is obviously wrong — sphere centers can legitimately have negative coordinates.
Comparison: filter-box parses correctly
The neighbouring
filter-boxcase (lines 449-463) uses an explicit for-loop with single-arg calls and is unaffected:Suggested fix (one line)
Replace line 477:
with:
(Or apply the same defaults-aware for-loop pattern used by filter-box for consistency.)
Happy to send a PR if useful.
Environment
(0, 1.6, 0)to remove far-out floaters that explode the AABB;--filter-boxis a working workaround but spheres are a more natural shape for many interiors.