Back to blockfall
SOURCE / PINNED RELEASE

Made of little things.

blockfall

Release
a6bb863994d9…
Author-recorded commit
e6ab5899ddac…
License
LICENSE
Author’s source reference
nostr://npub1dmmh0futyszl4445mv4xrygkgsgj8vpu79yx3qyy9qxmz4pemtzqlqmc87/wss%3A%2F%2Fgit.napplet.soy%2F/n-afafae55ef1

Archive hash verified: ba8de5cbee33e11e…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/napplet-settings.ts
import { config } from '@napplet/sdk';
import { runtimeHasDomain } from './domain-availability.js';
import settingsSchema from '../config.schema.json';

export interface GameSettings {
  effects: boolean;
  trajectoryGuide: boolean;
}

export const gameSettings: GameSettings = {
  effects: true,
  trajectoryGuide: true,
};

type SettingsListener = (settings: GameSettings) => void;
const listeners = new Set<SettingsListener>();

export function onGameSettings(listener: SettingsListener): () => void {
  listeners.add(listener);
  listener({ ...gameSettings });
  return () => {
    listeners.delete(listener);
  };
}

function notify(): void {
  const snapshot = { ...gameSettings };
  for (const listener of listeners) listener(snapshot);
}

// The upstream Vite plugin embeds config.schema.json into the signed build.
// Config stays optional: the game supplies sensible defaults above.
if (runtimeHasDomain('config')) {
  void (async () => {
    if (!config.schema) {
      await config.registerSchema(
        settingsSchema as Parameters<typeof config.registerSchema>[0],
      );
    }
    const subscription = config.subscribe((values) => {
      if (typeof values.effects === 'boolean') gameSettings.effects = values.effects;
      if (typeof values.trajectoryGuide === 'boolean') {
        gameSettings.trajectoryGuide = values.trajectoryGuide;
      }
      notify();
    });
    window.addEventListener('pagehide', () => subscription.close(), { once: true });
  })().catch(() => {
    // Optional settings: keep local defaults when the host does not support them.
  });
}