Improve mobile momentum scrolling and layout fixes

- Remove console.log performance logging for cleaner output
- Fix layout spacer positioning with proper flexbox structure
- Improve momentum scrolling responsiveness for rapid flicks
- Cancel existing momentum animations when new touch starts
- Amplify initial velocity and adjust friction curves for better feel

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mario Zechner 2025-06-18 03:03:12 +02:00
parent 21d0f710f1
commit 1c7894e15d
2 changed files with 26 additions and 17 deletions

View file

@ -83,13 +83,15 @@
main { main {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
display: flex;
flex-direction: column;
} }
/* Ensure the terminal element takes full height of its container */ /* Ensure the terminal element takes available height minus spacer */
vibe-terminal { vibe-terminal {
display: block; display: block;
width: 100%; width: 100%;
height: 100%; flex: 1;
box-sizing: border-box; box-sizing: border-box;
font-family: 'Fira Code', monospace; font-family: 'Fira Code', monospace;
} }
@ -128,6 +130,7 @@
rows="40" rows="40"
show-controls="false"> show-controls="false">
</vibe-terminal> </vibe-terminal>
<div style="height: 20px;"></div>
</main> </main>
<!-- Load XTerm.js --> <!-- Load XTerm.js -->

View file

@ -31,6 +31,7 @@ export class Terminal extends LitElement {
private scrollAccumulator = 0; private scrollAccumulator = 0;
private touchScrollAccumulator = 0; private touchScrollAccumulator = 0;
private isTouchActive = false; private isTouchActive = false;
private momentumAnimationId: number | null = null;
// Operation queue for batching buffer modifications // Operation queue for batching buffer modifications
private operationQueue: (() => void)[] = []; private operationQueue: (() => void)[] = [];
@ -60,9 +61,6 @@ export class Terminal extends LitElement {
} }
const queueEnd = performance.now(); const queueEnd = performance.now();
console.log(
`Processed ${operationCount} operations in ${(queueEnd - queueStart).toFixed(2)}ms`
);
// Render once after all operations are complete // Render once after all operations are complete
this.renderBuffer(); this.renderBuffer();
@ -305,6 +303,12 @@ export class Terminal extends LitElement {
// Only handle touch pointers, not mouse // Only handle touch pointers, not mouse
if (e.pointerType !== 'touch' || !e.isPrimary) return; if (e.pointerType !== 'touch' || !e.isPrimary) return;
// Cancel any existing momentum scroll when new touch starts
if (this.momentumAnimationId) {
cancelAnimationFrame(this.momentumAnimationId);
this.momentumAnimationId = null;
}
this.isTouchActive = true; this.isTouchActive = true;
isScrolling = false; isScrolling = false;
pointerStartY = e.clientY; pointerStartY = e.clientY;
@ -365,6 +369,11 @@ export class Terminal extends LitElement {
// Add momentum scrolling if needed (only after touch scrolling) // Add momentum scrolling if needed (only after touch scrolling)
if (isScrolling && Math.abs(velocity) > 0.5) { if (isScrolling && Math.abs(velocity) > 0.5) {
// Cancel any existing momentum scroll before starting new one
if (this.momentumAnimationId) {
cancelAnimationFrame(this.momentumAnimationId);
this.momentumAnimationId = null;
}
this.startMomentumScroll(velocity); this.startMomentumScroll(velocity);
} }
}; };
@ -387,18 +396,21 @@ export class Terminal extends LitElement {
} }
private startMomentumScroll(initialVelocity: number) { private startMomentumScroll(initialVelocity: number) {
let velocity = initialVelocity * 0.8; // Scale down initial velocity for smoother feel let velocity = initialVelocity * 1.2; // Amplify initial velocity for better flick response
let accumulatedScroll = 0; let accumulatedScroll = 0;
let frameCount = 0; let frameCount = 0;
const animate = () => { const animate = () => {
// Stop when velocity becomes very small // Stop when velocity becomes very small
if (Math.abs(velocity) < 0.001) return; if (Math.abs(velocity) < 0.001) {
this.momentumAnimationId = null;
return;
}
frameCount++; frameCount++;
// macOS-like deceleration curve - more natural feel // More responsive deceleration curve for better flick feel
const friction = frameCount < 10 ? 0.98 : frameCount < 30 ? 0.96 : 0.92; const friction = frameCount < 15 ? 0.985 : frameCount < 45 ? 0.97 : 0.94;
// Convert velocity (pixels/ms) to pixels per frame // Convert velocity (pixels/ms) to pixels per frame
const pixelsPerFrame = velocity * 16; // 16ms frame time const pixelsPerFrame = velocity * 16; // 16ms frame time
@ -416,10 +428,10 @@ export class Terminal extends LitElement {
// Apply friction // Apply friction
velocity *= friction; velocity *= friction;
requestAnimationFrame(animate); this.momentumAnimationId = requestAnimationFrame(animate);
}; };
requestAnimationFrame(animate); this.momentumAnimationId = requestAnimationFrame(animate);
} }
private scrollViewport(deltaLines: number) { private scrollViewport(deltaLines: number) {
@ -507,9 +519,6 @@ export class Terminal extends LitElement {
const domUpdateTime = domUpdateEnd - domUpdateStart; const domUpdateTime = domUpdateEnd - domUpdateStart;
const linkProcessTime = linkProcessEnd - linkProcessStart; const linkProcessTime = linkProcessEnd - linkProcessStart;
console.log(
`Render performance: ${totalTime.toFixed(2)}ms total (buffer: ${bufferPrepTime.toFixed(2)}ms, DOM: ${domUpdateTime.toFixed(2)}ms, links: ${linkProcessTime.toFixed(2)}ms) - ${this.actualRows} rows`
);
} }
private renderLine(line: IBufferLine, cell: IBufferCell, cursorCol: number = -1): string { private renderLine(line: IBufferLine, cell: IBufferCell, cursorCol: number = -1): string {
@ -616,9 +625,6 @@ export class Terminal extends LitElement {
this.terminal.write(data, () => { this.terminal.write(data, () => {
const writeEnd = performance.now(); const writeEnd = performance.now();
console.log(
`XTerm write took: ${(writeEnd - writeStart).toFixed(2)}ms for ${data.length} chars`
);
}); });
}); });
} }