Skip to content

Modding Guide

Multiverse Echoes supports three modding systems: theme overrides, export templates, and extension slots. All are available through the client's JavaScript API.

Theme Overrides

Override any CSS design token to create custom visual themes.

import { useThemeStore } from 'multiverse-echoes-client/stores';

// Register a custom theme
useThemeStore.getState().registerOverride({
  id: 'synthwave',
  name: 'Synthwave',
  variables: {
    '--canvas': '#1a0a2e',
    '--surface': '#2d1b4e',
    '--accent': '#ff6ec7',
    '--accent-hover': '#ff8fd4',
    '--text-primary': '#e0d4ff',
  },
});

// Apply it
useThemeStore.getState().applyOverride('synthwave');

// Remove it
useThemeStore.getState().unregisterOverride('synthwave');

Registered themes appear in Settings > Appearance alongside the built-in dark and light modes.

Export Templates

Add custom formats for Echo story exports.

import { registerExportTemplate, unregisterExportTemplate } from 'multiverse-echoes-client/lib/exportTemplates';

registerExportTemplate({
  id: 'screenplay',
  name: 'Screenplay',
  description: 'Formatted as a film screenplay',
  render(echo, feed) {
    let output = `FADE IN:\n\nINT. ${echo.name}'s WORLD - DAY\n\n`;
    for (const item of feed) {
      if (item.item_type === 'diary_entry') {
        output += `${echo.name.toUpperCase()}\n(${item.title})\n${item.body}\n\n`;
      }
    }
    output += 'FADE OUT.\n';
    return output;
  },
});

Extension Slots

Inject custom UI components into predefined slots in the application.

Available Slots

Slot Name Location
dashboard-panel Bottom of the Dashboard main area
echo-detail-panel Bottom of the Echo Detail page
shard-view-panel Bottom of the Shard View page
settings-tab Additional tab in Settings
sidebar-footer Bottom of the sidebar

Registering an Extension

import { registerExtension, unregisterExtension } from 'multiverse-echoes-client/lib/extensions';

registerExtension({
  id: 'weather-widget',
  slot: 'dashboard-panel',
  render() {
    const div = document.createElement('div');
    div.textContent = 'Custom weather widget for the Shard';
    div.style.padding = '1rem';
    return div;
  },
});

React Extensions

For React-based extensions, return a React element from the render function:

registerExtension({
  id: 'analytics',
  slot: 'echo-detail-panel',
  render() {
    return <AnalyticsDashboard />;
  },
});

Best Practices

  1. Use unique IDs — prefix with your mod name to avoid conflicts (e.g. mymod-theme)
  2. Clean up — call unregister* when your mod is disabled
  3. Respect design tokens — override tokens, don't use hardcoded colours
  4. Test both themes — verify your overrides look good in both dark and light mode
  5. Keep it accessible — maintain contrast ratios (4.5:1 AA minimum for text)

Further Reading

  • Full modding API documentation: MODDING.md
  • Design system tokens: client/src/styles/tokens.css
  • Extension slot component: client/src/lib/extensions.ts