Skip to content

Repository files navigation

Simulant

Simulant is a small simulator toolkit for research on mobile entities and distributed algorithms.

For a quick presentation, public project links, and a short explanation of the simulator internals, start with the project page:

https://bramas.github.io/simulant/

This repository contains the reusable simulator core, the reusable web interface, and public paper artifacts.

Repository Layout

apps/public-site/        public landing page and documentation site
packages/core/           reusable simulator core package
packages/simulator-ui/   reusable SolidJS simulator interface
projects/                public project and paper packages
projects/private/        local private projects, not published by the public site

Only projects listed in apps/public-site/src/public-projects.mjs are published on the website.

Install

pnpm install

Common Commands

pnpm dev      # run the starter ring project locally
pnpm build    # generate the full public static site in dist/

Creating A Project With Published Packages

For a separate project, depend on the published simulator packages. With GitHub Packages, add this .npmrc:

@bramas:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

Then use the released packages:

{
  "dependencies": {
    "@bramas/simulant-core": "0.1.0",
    "@bramas/simulant-ui": "0.1.0",
    "solid-js": "^1.9.3"
  }
}

During local development, you can point a private project to a local simulator checkout instead of publishing temporary versions:

{
  "dependencies": {
    "@bramas/simulant-core": "link:../simulant/packages/core",
    "@bramas/simulant-ui": "link:../simulant/packages/simulator-ui",
    "solid-js": "^1.9.3"
  }
}

Switch back to exact published versions when a paper artifact must be frozen.

Minimal Project Example

This example uses the ring model from @bramas/simulant-core@0.1.0. A project exports a projects map; each entry exposes a setup function that returns a model instance.

// projects.ts
import { Config } from '@bramas/simulant-core/lib/system';
import Ring, {
  Actions,
  AbstractGraphAgent,
  type RingConfigType,
} from '@bramas/simulant-core/models/ring';
import type { ProjectType } from '@bramas/simulant-core/types/project';

type Memory = {
  moving: boolean;
};

class Walker extends AbstractGraphAgent<Memory> {
  moving = true;

  constructor(id: number, position: number) {
    super(id, position);
  }

  visibleMemory(): Memory {
    return { moving: this.moving };
  }

  action_simpl(view: Memory[]): Actions {
    return view.length > 0 ? Actions.IDLE : Actions.CLOCKWISE;
  }

  clone(): Walker {
    const clone = new Walker(this._id, this._pos);
    clone.moving = this.moving;
    return clone;
  }
}

type MyConfig = RingConfigType<Walker, Memory, null>;

export const projects = {
  'basic-ring-walk': {
    setup: (settings: { N?: number }) => {
      const N = settings.N ?? 8;
      const agents = [new Walker(0, 0), new Walker(1, 3)];
      const initialConfig = new Config() as MyConfig;

      for (const agent of agents) {
        initialConfig.addAgent(agent._pos, agent);
      }

      return Ring(N, agents, initialConfig);
    },
    editorSchema: {
      fields: [{ key: 'N', label: 'Ring size', type: 'number', defaultValue: 8, min: 3 }],
    },
  },
} satisfies Record<string, ProjectType<MyConfig>>;

For a web page using the default simulator UI:

// web/src/App.tsx
import { SimulatorApp } from '@bramas/simulant-ui/SimulatorApp';
import { projects } from '../../projects';

export default function App() {
  return (
    <SimulatorApp
      title="Basic Ring Walk"
      projects={projects}
      createGraphWorker={() =>
        new Worker(new URL('./workers/graph-worker.ts', import.meta.url), { type: 'module' })
      }
      storageKey="basic-ring-walk-settings-v1"
    />
  );
}
// web/src/workers/graph-worker.ts
import { execute } from '@bramas/simulant-core/lib/system';
import { projects } from '../../../projects';

self.onmessage = (event) => {
  const { project, settings, path } = event.data;
  const model = projects[project].setup(settings);
  const graph = execute(model);

  self.postMessage({
    config: graph.get(path),
    childCount: graph.getChildrenCount(path),
    siblingCount: graph.getSiblingCount(path),
  });
};

In practice, most papers also add drawConfig, getAgentsRenderInfo, executionStatusChecker, and presets, but the core contract is the same: define agents, choose a model, return a SystemInfo.

Publishing Public Pages

The public site is generated by scripts/build-public-site.mjs. It builds every public project listed in apps/public-site/src/public-projects.mjs, then builds apps/public-site/ into dist/.

GitHub Pages deployment is configured in .github/workflows/pages.yml. In the GitHub repository settings, set Pages source to GitHub Actions.

Package Releases

.github/workflows/release-packages.yml publishes:

  • @bramas/simulant-core
  • @bramas/simulant-ui

It runs manually from GitHub Actions or when pushing a tag matching simulator-v*. Before tagging a release, bump the package versions in packages/core/package.json and packages/simulator-ui/package.json.

Author

Simulant is developed by Quentin Bramas.

License

This software is distributed under the CeCILL-B free software license. See LICENCE.txt.

If you use this simulator or the black-hole-search artifact, please cite:

François Bonnet, Quentin Bramas, and Anissa Lamani. Searching for an Eventually-Emerging Black Hole in Rings. In 5th Symposium on Algorithmic Foundations of Dynamic Networks (SAND 2026).

See PUBLICATION.md for the versioning strategy used when publishing paper code.

About

A simulator for mobile entities computations, mobile agents and autonomous robots

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages