Analysis of recent commits β triggered by @thewtex
Assignee: @copilot
Summary
Two significant duplication patterns were found in the codebase during semantic code analysis:
- Near-identical Niivue initialization functions in
examples/convert/main.ts
- Structurally identical tuple-mapping functions in
fidnii/src/utils/coordinates.ts
Pattern 1: Duplicated Niivue Initialization
Details
- Severity: Medium
- Occurrences: 2
- Locations:
examples/convert/main.ts (lines 261β274) β initNiivue()
examples/convert/main.ts (lines 300β314) β initMinimapNiivue()
Code Sample
// initNiivue (lines 261β274)
function initNiivue(): void {
if (nv) return
nv = new Niivue({
show3Dcrosshair: false,
crosshairWidth: 0,
backColor: [0.384, 0.365, 0.353, 1],
isOrientCube: false,
isOrientationTextVisible: false,
clipPlaneHotKey: "",
})
nv.attachToCanvas(canvas)
nv.addColormap("fast", FAST_COLORMAP)
}
// initMinimapNiivue (lines 300β314)
function initMinimapNiivue(): void {
if (minimapNv) return
minimapNv = new Niivue({
show3Dcrosshair: false,
crosshairWidth: 0,
backColor: [0.384, 0.365, 0.353, 1],
isOrientCube: false,
isOrientationTextVisible: false,
clipPlaneHotKey: "",
})
minimapNv.attachToCanvas(minimapCanvas)
minimapNv.addColormap("fast", FAST_COLORMAP)
minimapNv.addColormap("roi", buildRoiColormap()) // only difference
}
The constructor options object (6 fields) and the first addColormap call are identical across both functions. Only the variable name, canvas reference, and the extra ROI colormap differ.
Refactoring Recommendation
Extract shared Niivue construction into a factory helper:
const SHARED_NV_OPTIONS = {
show3Dcrosshair: false,
crosshairWidth: 0,
backColor: [0.384, 0.365, 0.353, 1] as [number, number, number, number],
isOrientCube: false,
isOrientationTextVisible: false,
clipPlaneHotKey: "",
} as const
function createNiivue(
canvasEl: HTMLCanvasElement,
extraColormaps?: Array<{ name: string; colormap: unknown }>,
): Niivue {
const instance = new Niivue(SHARED_NV_OPTIONS)
instance.attachToCanvas(canvasEl)
instance.addColormap("fast", FAST_COLORMAP)
for (const { name, colormap } of extraColormaps ?? []) {
instance.addColormap(name, colormap)
}
return instance
}
Pattern 2: Structurally Identical Tuple-Mapping Coordinate Functions
Details
- Severity: Low
- Occurrences: 3 (plus one existing
clampPixelCoord of related shape)
- Locations:
fidnii/src/utils/coordinates.ts (lines 233β241) β roundPixelCoord
fidnii/src/utils/coordinates.ts (lines 249β257) β floorPixelCoord
fidnii/src/utils/coordinates.ts (lines 265β273) β ceilPixelCoord
Code Sample
export function roundPixelCoord(pixelCoord: [number, number, number]): [number, number, number] {
return [Math.round(pixelCoord[0]), Math.round(pixelCoord[1]), Math.round(pixelCoord[2])]
}
export function floorPixelCoord(pixelCoord: [number, number, number]): [number, number, number] {
return [Math.floor(pixelCoord[0]), Math.floor(pixelCoord[1]), Math.floor(pixelCoord[2])]
}
export function ceilPixelCoord(pixelCoord: [number, number, number]): [number, number, number] {
return [Math.ceil(pixelCoord[0]), Math.ceil(pixelCoord[1]), Math.ceil(pixelCoord[2])]
}
All three apply a Math rounding function element-wise to a 3-element tuple. The only variation is which Math.* method is used.
Refactoring Recommendation
Introduce a private mapPixelCoord helper and keep the public named exports (for clarity and stable API):
function mapPixelCoord(
pixelCoord: [number, number, number],
fn: (v: number) => number,
): [number, number, number] {
return [fn(pixelCoord[0]), fn(pixelCoord[1]), fn(pixelCoord[2])]
}
export const roundPixelCoord = (c: [number, number, number]) => mapPixelCoord(c, Math.round)
export const floorPixelCoord = (c: [number, number, number]) => mapPixelCoord(c, Math.floor)
export const ceilPixelCoord = (c: [number, number, number]) => mapPixelCoord(c, Math.ceil)
Note: Refactoring the public API is optional β the named exports can remain function declarations for clarity. The key change is centralising the triple-element application logic.
Impact Analysis
| Pattern |
Maintainability |
Bug Risk |
Code Bloat |
| Niivue init |
If the Niivue options need to change (e.g. new flag), both functions must be updated in sync |
Inconsistent NV configs could cause subtle visual differences between main and minimap views |
~12 duplicate lines |
| Pixel coord |
Low β Math methods are stable |
Very low |
~15 duplicate lines across 3 functions |
Implementation Checklist
Analysis Metadata
- Analyzed Files:
fidnii/src/**/*.ts, examples/convert/main.ts, examples/getting-started/main.ts
- Detection Method: Serena semantic code analysis + symbol body inspection
- Analysis Date: 2026-03-25
Generated by Duplicate Code Detector
To install this agentic workflow, run
gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@33cd6c7f1fee588654ef19def2e6a4174be66197
Analysis of recent commits β triggered by
@thewtexAssignee:
@copilotSummary
Two significant duplication patterns were found in the codebase during semantic code analysis:
examples/convert/main.tsfidnii/src/utils/coordinates.tsPattern 1: Duplicated Niivue Initialization
Details
examples/convert/main.ts(lines 261β274) βinitNiivue()examples/convert/main.ts(lines 300β314) βinitMinimapNiivue()Code Sample
The constructor options object (6 fields) and the first
addColormapcall are identical across both functions. Only the variable name, canvas reference, and the extra ROI colormap differ.Refactoring Recommendation
Extract shared Niivue construction into a factory helper:
Pattern 2: Structurally Identical Tuple-Mapping Coordinate Functions
Details
clampPixelCoordof related shape)fidnii/src/utils/coordinates.ts(lines 233β241) βroundPixelCoordfidnii/src/utils/coordinates.ts(lines 249β257) βfloorPixelCoordfidnii/src/utils/coordinates.ts(lines 265β273) βceilPixelCoordCode Sample
All three apply a Math rounding function element-wise to a 3-element tuple. The only variation is which
Math.*method is used.Refactoring Recommendation
Introduce a private
mapPixelCoordhelper and keep the public named exports (for clarity and stable API):Impact Analysis
Implementation Checklist
initNiivue/initMinimapNiivuefindings inexamples/convert/main.tsmapPixelCoordhelper infidnii/src/utils/coordinates.tsbun run build)bun run checkto ensure Biome is satisfiedAnalysis Metadata
fidnii/src/**/*.ts,examples/convert/main.ts,examples/getting-started/main.ts