Introduction

Adding a Live2D widget to your blog can significantly enhance user interaction and give your site a unique personality. However, integrating it into a modern framework like Astro—especially when using Swup (PJAX) for transition animations—can be tricky.

This guide will walk you through the entire process, from asset preparation to solving persistence issues during page navigation.

Step 1: Asset Preparation

First, download the dist folder from the live2d-widget GitHub repository.

In your Astro project, create a directory for these assets. We recommend placing them in src/live2d/dist for development and syncing them to public/live2d/dist for static serving.

# Recommended structure
/public/live2d/
  └── dist/
      ├── autoload.js
      ├── waifu-tips.js
      ├── waifu.css
      └── ...

Step 2: Configuring the Autoloader

The autoload.js file is the entry point. You need to modify it to point to your local assets and enable features like dragging.

Modify src/live2d/dist/autoload.js:

// Set the local path
const live2d_path = '/live2d/dist/';

// Helper to load resources with Swup persistence
function loadExternalResource(url, type) {
  return new Promise((resolve, reject) => {
    let tag;
    if (type === 'css') {
      tag = document.createElement('link');
      tag.rel = 'stylesheet';
      tag.href = url;
    } else if (type === 'js') {
      tag = document.createElement('script');
      tag.type = 'module';
      tag.src = url;
    }
    if (tag) {
      // CRITICAL: Prevent Swup from removing these assets on navigation
      tag.setAttribute('data-swup-ignore-script', 'true');
      tag.setAttribute('data-swup-persist-asset', 'true');
      tag.onload = () => resolve(url);
      tag.onerror = () => reject(url);
      document.head.appendChild(tag);
    }
  });
}

(async () => {
  // Load waifu-tips.js only (CSS is handled statically in Step 3)
  await loadExternalResource(live2d_path + 'waifu-tips.js', 'js');
  
  initWidget({
    waifuPath: live2d_path + 'waifu-tips.json',
    cubism2Path: live2d_path + 'live2d.min.js',
    drag: true, // Enable dragging
    logLevel: 'warn',
  });
})();

Step 3: Integrating with Astro Layouts

To ensure the widget loads correctly across all pages without layout shifts, we split the integration into the Head and the Body.

1. Static CSS in BaseHead.astro

Including the CSS statically ensures that Swup recognizes it as a persistent asset across pages.

<!-- src/components/BaseHead.astro -->
<!-- Only load CSS for PC users (width >= 768px) -->
<link rel="stylesheet" href="/live2d/dist/waifu.css" media="(min-width: 768px)" />

2. Guarded Loader in BaseLayout.astro

We use a global variable guard to ensure the script only initializes once, preventing multiple widgets from appearing during Swup navigation.

<!-- src/layouts/BaseLayout.astro -->
<body>
  <slot />
  
  <script is:inline data-swup-ignore-script>
    (function () {
      if (window.__live2dLoaded) return;
      if (window.innerWidth >= 768) {
        window.__live2dLoaded = true;
        const script = document.createElement("script");
        script.src = "/live2d/dist/autoload.js";
        script.setAttribute("data-swup-ignore-script", "true");
        document.body.appendChild(script);
      }
    })();
  </script>
</body>

Step 4: Solving the Swup (PJAX) Disappearance

If you use @swup/astro, you might find the widget disappears when you navigate to a new page. This is because Swup clears the <head> or re-evaluates scripts incorrectly.

1. Update astro.config.mjs

Enable persistAssets to tell Swup to keep elements marked with data-swup-persist-asset.

// astro.config.mjs
export default defineConfig({
  integrations: [
    swup({
      // ... other options
      updateHead: true,
      persistAssets: true, // Essential for Live2D persistence
    }),
  ],
});

2. Use Data Attributes

As shown in Step 2 and 3, always add these attributes to your Live2D tags:

  • data-swup-ignore-script: Stops Swup from re-running the loader.
  • data-swup-persist-asset: Stops Swup from removing the asset from the DOM.

Conclusion

By following these steps, your Live2D widget will:

  1. Persist: Stay on the screen through animated page transitions.
  2. Efficient: Load only once and respect mobile device constraints.
  3. Interactive: Allow users to drag the character anywhere on the PC screen.

Happy coding!

Add a Live2D Widget to your Astro Blog

Author

Shayne Wong

Publish Date

02 - 08 - 2026

License

Shayne Wong

Avatar
Shayne Wong

All time is no time when it is past.