fix(ComparisonView): fix character morphing thresholds and add tracking support

This commit is contained in:
Ilia Mashkov
2026-04-20 10:52:28 +03:00
parent f9f96e2797
commit 141126530d
4 changed files with 138 additions and 91 deletions
@@ -48,6 +48,7 @@ $effect(() => {
<span
class="char-wrap"
style:font-size="{typography.renderedSize}px"
style:margin-right="{typography.spacing}em"
style:will-change={proximity > 0 ? 'transform' : 'auto'}
>
{#each [0, 1] as s (s)}
@@ -53,6 +53,7 @@ const isMobile = $derived(responsive?.isMobile ?? false);
let isDragging = $state(false);
let isTypographyMenuOpen = $state(false);
let containerWidth = $state(0);
// New high-performance layout engine
const comparisonEngine = new CharacterComparisonEngine();
@@ -127,6 +128,7 @@ $effect(() => {
const _weight = typography.weight;
const _size = typography.renderedSize;
const _height = typography.height;
const _spacing = typography.spacing;
if (container && fontA && fontB) {
// PRETEXT API strings: "weight sizepx family"
@@ -137,14 +139,17 @@ $effect(() => {
const width = container.offsetWidth;
const padding = isMobile ? 48 : 96;
const availableWidth = width - padding;
const lineHeight = _size * 1.2; // Approximate
const lineHeight = _size * _height;
containerWidth = width;
layoutResult = comparisonEngine.layout(
_text,
fontAStr,
fontBStr,
availableWidth,
lineHeight,
_spacing,
_size,
);
}
});
@@ -157,12 +162,15 @@ $effect(() => {
if (container && fontA && fontB) {
const width = container.offsetWidth;
const padding = isMobile ? 48 : 96;
containerWidth = width;
layoutResult = comparisonEngine.layout(
comparisonStore.text,
`${typography.weight} ${typography.renderedSize}px "${fontA.name}"`,
`${typography.weight} ${typography.renderedSize}px "${fontB.name}"`,
width - padding,
typography.renderedSize * 1.2,
typography.renderedSize * typography.height,
typography.spacing,
typography.renderedSize,
);
}
};
@@ -239,11 +247,15 @@ const scaleClass = $derived(
my-auto
"
>
{#each layoutResult.lines as line, lineIndex}
{#each layoutResult.lines as line}
{@const lineStates = comparisonEngine.getLineCharStates(line, sliderPos, containerWidth)}
<Line chars={line.chars}>
{#snippet character({ char, index })}
{@const { proximity, isPast } = comparisonEngine.getCharState(lineIndex, index, sliderPos, container?.offsetWidth ?? 0)}
<Character {char} {proximity} {isPast} />
<Character
{char}
proximity={lineStates[index]?.proximity ?? 0}
isPast={lineStates[index]?.isPast ?? false}
/>
{/snippet}
</Line>
{/each}