refactor(comparison): switch to 3-section render model via DualFontLayout
Rewrite Line.svelte to render leftText / windowChars / rightText regions from a LineRenderModel. Bulk regions render as native shaped text runs so the browser applies kerning and ligatures; per-char DOM is reserved for the N-char crossfade window straddling the slider. Slim Character.svelte: drop the unused proximity prop and the redundant font-size/font-weight/letter-spacing styles now inherited from the line container. Switch SliderArea.svelte to instantiate DualFontLayout and derive each line's render model via computeLineRenderModel(line, sliderPos, containerWidth, WINDOW_SIZE).
This commit is contained in:
@@ -9,10 +9,12 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import {
|
||||
CharacterComparisonEngine,
|
||||
type ComparisonResult,
|
||||
DualFontLayout,
|
||||
MULTIPLIER_L,
|
||||
MULTIPLIER_M,
|
||||
MULTIPLIER_S,
|
||||
computeLineRenderModel,
|
||||
} from '$entities/Font';
|
||||
import { TypographyMenu } from '$features/AdjustTypography';
|
||||
import { typographySettingsStore } from '$features/AdjustTypography/model';
|
||||
@@ -30,7 +32,6 @@ import {
|
||||
getPretextFontString,
|
||||
} from '../../lib';
|
||||
import { comparisonStore } from '../../model';
|
||||
import Character from '../Character/Character.svelte';
|
||||
import Line from '../Line/Line.svelte';
|
||||
import Thumb from '../Thumb/Thumb.svelte';
|
||||
|
||||
@@ -95,10 +96,15 @@ let isDragging = $state(false);
|
||||
let isTypographyMenuOpen = $state(false);
|
||||
let containerWidth = $state(0);
|
||||
|
||||
// New high-performance layout engine
|
||||
const comparisonEngine = new CharacterComparisonEngine();
|
||||
const layout = new DualFontLayout();
|
||||
|
||||
let layoutResult = $state<ReturnType<typeof comparisonEngine.layout>>({ lines: [], totalHeight: 0 });
|
||||
let layoutResult = $state<ComparisonResult>({ lines: [], totalHeight: 0 });
|
||||
|
||||
/**
|
||||
* N-window size for the per-char crossfade zone around the slider split.
|
||||
* Tuned so chars complete their 100ms opacity crossfade before exiting the window.
|
||||
*/
|
||||
const WINDOW_SIZE = 5;
|
||||
|
||||
// Track container width changes (window resize, sidebar toggle, etc.)
|
||||
$effect(() => {
|
||||
@@ -249,7 +255,7 @@ $effect(() => {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
layoutResult = comparisonEngine.layout(
|
||||
layoutResult = layout.layout(
|
||||
_text,
|
||||
fontAStr,
|
||||
fontBStr,
|
||||
@@ -328,17 +334,9 @@ $effect(() => {
|
||||
my-auto
|
||||
"
|
||||
>
|
||||
{#each layoutResult.lines as line}
|
||||
{@const lineStates = comparisonEngine.getLineCharStates(line, sliderPos, containerWidth)}
|
||||
<Line chars={line.chars}>
|
||||
{#snippet character({ char, index })}
|
||||
<Character
|
||||
{char}
|
||||
proximity={lineStates[index]?.proximity ?? 0}
|
||||
isPast={lineStates[index]?.isPast ?? false}
|
||||
/>
|
||||
{/snippet}
|
||||
</Line>
|
||||
{#each layoutResult.lines as line, lineIdx (lineIdx)}
|
||||
{@const model = computeLineRenderModel(line, sliderPos, containerWidth, WINDOW_SIZE)}
|
||||
<Line {model} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user