Refactor/reacrhitecture to fsd+ #49

Merged
ilia merged 70 commits from refactor/reacrhitecture-to-fsd+ into main 2026-06-03 09:55:47 +00:00
Showing only changes of commit f13dfe1caf - Show all commits
@@ -35,6 +35,19 @@ export interface LineRenderModel {
rightText: string;
}
/**
* Slices a laid-out line into three regions around the slider's split index:
* a fontA bulk run, an N-char crossfade window, and a fontB bulk run.
*
* Pure and allocation-bounded: two strings plus a `windowSize`-length array per call.
* Safe to invoke per slider frame; `line.chars` is treated as read-only.
*
* @param line Line from `DualFontLayout.layout()`. Empty `chars` yields an empty model.
* @param sliderPos Slider position in percent of `containerWidth`, range 0..100.
* @param containerWidth Container width in pixels, used to translate `sliderPos` to a threshold x.
* @param windowSize Number of chars in the crossfade window. Clamped to `[0, line.chars.length]`.
* At line edges the window is shifted (not shrunk) to keep its size.
*/
export function computeLineRenderModel(
line: ComparisonLine,
sliderPos: number,
@@ -66,9 +79,13 @@ export function computeLineRenderModel(
}
/**
* Walks chars left-to-right computing the per-char threshold using prefix sums
* of widthA (past chars, fontA) and suffix sums of widthB (future chars, fontB).
* Returns the count of chars whose threshold the slider has passed.
* Returns the count of chars whose flip threshold the slider has crossed.
*
* For each candidate split `i`, the line's hypothetical width at that moment is
* `prefA[i] + widthA[i] + sufB[i+1]` (past chars in fontA, char `i` flipping, future
* chars in fontB). The threshold is the x of char `i`'s center in the centered line.
* Thresholds are monotonically non-decreasing in `i`, so the scan short-circuits on
* the first miss.
*/
function findSplitIndex(
chars: ComparisonChar[],
@@ -101,6 +118,9 @@ function findSplitIndex(
return split;
}
/**
* Clamps `value` into the inclusive range `[lo, hi]`. Assumes `lo <= hi`.
*/
function clamp(value: number, lo: number, hi: number): number {
if (value < lo) {
return lo;