Skip to content

Add asset cache system for IC message rendering#291

Draft
OmniTroid wants to merge 3 commits intoAttorneyOnline:masterfrom
OmniTroid:sequencing-rework
Draft

Add asset cache system for IC message rendering#291
OmniTroid wants to merge 3 commits intoAttorneyOnline:masterfrom
OmniTroid:sequencing-rework

Conversation

@OmniTroid
Copy link
Contributor

Summary

  • Implements preloading of all assets before IC message rendering begins, eliminating visual glitches from sprites popping in late
  • Adds caching to avoid repeated HEAD requests for previously loaded assets
  • Uses Cache API with in-memory metadata (LRU, bounded to 1000 entries)

Changes

New cache system (webAO/cache/):

  • AssetCache: Cache API wrapper with browser-managed storage and in-memory metadata
  • UrlResolver: Extension probing with request deduplication via pending resolutions Map
  • AssetPreloader: Parallel resolution of all URLs needed for a ChatMsg, returns PreloadManifest

Modified render flow:

  • handleMS now preloads all assets before calling handle_ic_speaking
  • handleICSpeaking and chat_tick use pre-resolved manifest URLs directly
  • Graceful fallback to original setEmote() behavior when manifest unavailable

Test plan

  • Basic IC message - sprites should appear immediately without pop-in
  • Test with pairing enabled - both characters should appear simultaneously
  • Test with preanimation - preanim should play correctly timed
  • Test rapid messages - no visual glitches, latest message renders
  • Check DevTools Network tab - repeated emotes should show cached (no new HEAD requests)
  • Check DevTools Application > Cache Storage - assets should be stored

🤖 Generated with Claude Code

Implements preloading of all assets before IC message rendering begins,
eliminating visual glitches from sprites popping in late. Adds caching
to avoid repeated HEAD requests for previously loaded assets.

New cache system (webAO/cache/):
- AssetCache: Cache API wrapper with in-memory metadata (LRU, 1000 entries)
- UrlResolver: Extension probing with request deduplication
- AssetPreloader: Parallel resolution of all URLs for a ChatMsg

Modified render flow:
- handleMS now preloads all assets before calling handle_ic_speaking
- handleICSpeaking and chat_tick use pre-resolved manifest URLs
- Graceful fallback to original setEmote() when manifest unavailable

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@OmniTroid
Copy link
Contributor Author

OmniTroid and others added 2 commits February 1, 2026 23:43
Only set image src if the URL has changed, preventing the idle
animation from restarting when paired characters receive new messages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move appendICLog and checkCallword to handleMS before preloading
  to ensure messages are logged in arrival order
- Add message sequence counter to track current message
- Skip rendering if a newer message arrived during preload
- Prevents out-of-order IC log entries when messages arrive rapidly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
if (result) {
manifest.pairCharIdleUrl = result.resolvedUrl;
} else {
manifest.failedAssets.push(`pair-idle:${pairName}/${pairEmote}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are pair sprites treated seperately


export const getAssetPreloader = (
emoteExtensions: string[],
animationExtensions: string[] = [".gif", ".webp", ".apng"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file extension priority can be set by the server using extensions.json


if (extension === ".png") {
url = `${characterFolder}${encodedChar}/${encodedEmote}${extension}`;
} else if (extension === ".webp.static") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is duplicate code, either use it from setEmote.ts, remove it there or put it in a seperate file.

@stonedDiscord stonedDiscord mentioned this pull request Feb 7, 2026
@OmniTroid OmniTroid marked this pull request as draft February 11, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants