# How to Troubleshoot Filmstrip Cache Misses and Memory Pressure Issues in Clypra

> Troubleshoot Clypra filmstrip cache misses and memory pressure. Learn to monitor memory, velocity states, and LRU eviction using Clypra's debugging APIs for efficient video thumbnail rendering.

- Repository: [Abdulkabir Musa/Clypra](https://github.com/AIEraDev/Clypra)
- Tags: how-to-guide
- Published: 2026-07-16

---

**Clypra employs a multi-layered caching system combining a viewport-bounded `FilmstripCache` with a tile-addressable `FilmstripTileCache` to render video thumbnails efficiently; diagnosing issues requires monitoring memory budgets, velocity states, and LRU eviction cycles through the exposed debugging APIs.**

Clypra's filmstrip rendering pipeline relies on a sophisticated interplay between a **filmstrip cache**, a **tile-addressable tile cache**, and a **viewport-bounded request scheduler** to deliver smooth thumbnail scrolling. When thumbnails flicker, disappear, or consume excessive memory, developers must understand how these layers interact to troubleshoot filmstrip cache misses and memory pressure issues in Clypra effectively.

## Understanding the Filmstrip Cache Architecture

### Core Components

The rendering stack spans several modules:

- **`FilmstripCache`** ([`src/lib/renderEngine/FilmstripCache.ts`](https://github.com/AIEraDev/Clypra/blob/main/src/lib/renderEngine/FilmstripCache.ts)): Manages viewport-bounded thumbnail requests, groups updates per animation frame, and owns all `ImageBitmap` instances.
- **`FilmstripTileCache`** ([`src/lib/filmstrip/FilmstripTileCache.ts`](https://github.com/AIEraDev/Clypra/blob/main/src/lib/filmstrip/FilmstripTileCache.ts)): Stores individual thumbnails keyed by tile addresses for reuse across zoom levels and rapid scrolling.
- **[`filmstripTiers.ts`](https://github.com/AIEraDev/Clypra/blob/main/filmstripTiers.ts)** ([`src/lib/filmstrip/filmstripTiers.ts`](https://github.com/AIEraDev/Clypra/blob/main/src/lib/filmstrip/filmstripTiers.ts)): Generates deterministic grid addresses for viewport and zoom tier calculations.
- **[`useFilmstrip.ts`](https://github.com/AIEraDev/Clypra/blob/main/useFilmstrip.ts)** ([`src/lib/filmstrip/useFilmstrip.ts`](https://github.com/AIEraDev/Clypra/blob/main/src/lib/filmstrip/useFilmstrip.ts)): React hook subscribing to cache updates and triggering UI re-renders.

### Memory Management Strategy

Clypra implements strict memory controls:

- **Hard budget**: Default 100 MiB configured via `new FilmstripCache(100)`.
- **LRU eviction**: When memory exceeds the budget, the oldest clip entry (by `lastViewportUpdate`) is purged via `_evictLRU`.
- **Tile cache isolation**: `FilmstripTileCache` maintains a separate budget contributing to overall utilization reported by `getStats`.

### Cache-Miss Handling Mechanisms

The system optimizes for perceived performance:

- **Viewport-bounded generation**: Only tiles intersecting the visible area (plus overscan) are requested via `generateViewportFilmstripTimestamps` and `generateViewportTileAddresses`.
- **Aggressive cheating**: During fast scrolling (`velocityState >= VelocityState.Fast`), the cache falls back to the nearest cached tile through `_buildArtifactsFromTiles` to prevent blank UI states.
- **Debounced requests**: Duplicate tile addresses requested within ~100 ms reuse cached entries without triggering new transport requests.

## Common Symptoms and Diagnostic Patterns

| Symptom | Likely Root Cause |
|---------|-------------------|
| **Blank or flickering filmstrip** during scrolling | Tile cache miss under high velocity, or incorrect `velocityState` triggering frequent re-requests. |
| **Out-of-memory warnings** | Memory budget too low, excessive clips retained, or `FilmstripTileCache` failing to evict via `tileCache.dispose`. |
| **UI stutter or rerender storms** | Missing RAF batching in `scheduleArtifactUpdate` or excessive pending artifacts. |
| **Stale thumbnails after clip removal** | Missing `invalidateClip` call when the store deletes a clip without notifying the cache. |
| **Artifacts never appearing** | Silent failure in `requestProgressiveTiers` due to `epochId` mismatches. |

## Step-by-Step Troubleshooting Guide

1. **Verify Cache Budget Utilization**

   Check if the cache is nearing its limit:

   ```typescript
   const stats = renderEngine.filmstripCache.getStats();
   console.log('Filmstrip cache stats', stats);
   ```

   If `memoryMB` approaches `budgetMB` (above 90%) with high `utilizationPercent`, increase the budget in the `RenderEngine` constructor: `new RenderEngine({ filmstripMemoryMB: 200 })`.

2. **Validate Velocity State Propagation**

   Ensure `RenderEngine` updates `filmstripCache.setVelocityState` on every scroll or zoom event. A stale state prevents the "aggressive cheating" fallback during fast scrolling. Verify this in [`src/lib/renderEngine/RenderEngine.ts`](https://github.com/AIEraDev/Clypra/blob/main/src/lib/renderEngine/RenderEngine.ts) around line 80.

3. **Detect Cache Misses**

   Enable debug logging in `FilmstripCache._buildArtifactsFromTiles`:

   ```typescript
   console.debug('[FilmstripCache] cache miss for tile', addr);
   ```

   Alternatively, monitor the temporary logger output while reproducing the issue to identify specific tile addresses failing to resolve.

4. **Inspect Tile Address Generation**

   Validate that `generateViewportTileAddresses` returns non-empty arrays for visible clips. If it returns `[]` (lines 92-94 in the source), the viewport parameters (`viewportScrollLeft`, `viewportWidth`, `pixelsPerSecond`) may diverge from the actual UI layout.

5. **Force LRU Eviction Testing**

   Manually trigger eviction to verify stale tile cleanup:

   ```typescript
   renderEngine.filmstripCache._evictLRU(); // private method for debugging only
   ```

   Observe whether fresh tiles are requested and displayed correctly after eviction.

6. **Confirm Clip Invalidation**

   When clips are removed or epochs change, verify that `invalidateClip` is called. Search for `invalidateClip(` in `timelineStore` or `recordingStore` to ensure proper lifecycle integration.

7. **Monitor RAF Batching**

   Excessive `scheduleArtifactUpdate` calls without `flushPendingArtifacts` indicate a lost `rafId`. Ensure `requestAnimationFrame` is not being throttled by polyfills that limit frame rates.

8. **Analyze Tile Cache Statistics**

   Inspect tile-level metrics:

   ```typescript
   const tileStats = renderEngine.filmstripCache.tileCache.getStats();
   console.log('Tile cache', tileStats);
   ```

   Low `tileUtilizationPercent` suggests premature eviction causing frequent cache misses.

9. **Isolate with Minimal Reproduction**

   Create a timeline with a single short clip, set the viewport to cover it fully, and observe the filmstrip. Gradually add clips or increase zoom to identify the threshold where issues manifest.

10. **Run Unit Test Coverage**

    Execute the repository's test suite to surface regressions:

    ```bash
    npm run test -- src/lib/__tests__/useFilmstrip.test.ts
    npm run test -- src/lib/filmstrip/__tests__/FilmstripTileCache.test.ts
    ```

## Practical Debugging Code Examples

### Adjusting the Memory Budget

Increase the filmstrip cache capacity when deploying to high-memory devices:

```typescript
import { RenderEngine } from './core/renderEngine/renderEngine';

const engine = new RenderEngine({
  filmstripMemoryMB: 200, // default is 100 MiB
});

```

### Inspecting Runtime Statistics

Monitor cache health in your debug UI:

```typescript
const stats = engine.filmstripCache.getStats();
console.table({
  ClipCount: stats.clipCount,
  MemoryUsed: `${stats.memoryMB} MiB`,
  Budget: `${stats.budgetMB} MiB`,
  Utilisation: `${stats.utilizationPercent}%`,
  TileCount: stats.tileCount,
});

```

### Logging Cache Misses

Patch the prototype for development debugging:

```typescript
const originalBuild = FilmstripCache.prototype._buildArtifactsFromTiles;
FilmstripCache.prototype._buildArtifactsFromTiles = function (addresses, clipId, tier, videoPath) {
  const artifacts = originalBuild.call(this, addresses, clipId, tier, videoPath);
  if (artifacts.length < addresses.length) {
    console.warn('[Debug] Filmstrip cache miss:', {
      clipId,
      missing: addresses.length - artifacts.length,
    });
  }
  return artifacts;
};

```

### Forcing Complete Cache Clearance

Dispose the entire cache when suspecting memory leaks:

```typescript
engine.filmstripCache.dispose();
// Re-initialize if continued rendering is required
engine.filmstripCache = new FilmstripCache(200);

```

## Summary

- Clypra's filmstrip rendering relies on `FilmstripCache` and `FilmstripTileCache` working in tandem with a viewport-bounded request scheduler.
- **Memory pressure** arises when the 100 MiB default budget is exceeded or when LRU eviction fails to trigger via `_evictLRU`.
- **Cache misses** typically indicate incorrect `velocityState` propagation, mismatched viewport parameters, or missing tile addresses in `generateViewportTileAddresses`.
- Use `getStats()` to monitor utilization and `invalidateClip()` to prevent stale data when clips are removed.
- The React hook [`useFilmstrip.ts`](https://github.com/AIEraDev/Clypra/blob/main/useFilmstrip.ts) provides the UI subscription layer, while [`renderEngine.ts`](https://github.com/AIEraDev/Clypra/blob/main/renderEngine.ts) manages the velocity state updates critical for fallback rendering during fast scrolling.

## Frequently Asked Questions

### Why do thumbnails disappear when I scroll quickly?

Rapid scrolling triggers `velocityState` checks in [`FilmstripCache.ts`](https://github.com/AIEraDev/Clypra/blob/main/FilmstripCache.ts). If the state is not set to `VelocityState.Fast` or the fallback mechanism `_buildArtifactsFromTiles` cannot locate nearest cached tiles, the UI renders blank spaces. Verify that your scroll handler calls `setVelocityState` with the correct enum value from [`RenderEngine.ts`](https://github.com/AIEraDev/Clypra/blob/main/RenderEngine.ts).

### How do I know if memory pressure is causing performance issues?

Call `renderEngine.filmstripCache.getStats()` and check if `memoryMB` exceeds 90% of `budgetMB`. High utilization forces aggressive LRU eviction in `_evictLRU`, which can cause stuttering as the system purges and rebuilds the cache. Consider increasing `filmstripMemoryMB` in the constructor or investigating `tileCache.dispose` calls that might not be releasing memory.

### What causes the "rerender storm" in the filmstrip component?

This occurs when `scheduleArtifactUpdate` is invoked repeatedly without proper RAF batching. Ensure that `flushPendingArtifacts` is being called within the animation frame loop. Check that `requestAnimationFrame` is not being intercepted by polyfills that limit the frame rate, as this can cause the `rafId` tracking to fail.

### Why do deleted clips still show thumbnails in the filmstrip?

The cache retains tiles until `invalidateClip` is called with the specific clip ID. If your `timelineStore` or `recordingStore` removes clips without notifying the cache, zombie thumbnails persist. Audit your data layer to ensure `invalidateClip(clipId)` is invoked whenever clip epochs change or deletions occur.