Login Register
Back to Help Center

Plugin File Structure & Paths

Reference for how plugin files are organised inside the problem package and how assets are resolved at runtime

Plugin Structure Inside the ZIP

Plugins live under the plugins/ directory in your problem package ZIP. Each plugin is a named subdirectory containing at minimum an index.html file.

my-problem.zip
├── problem_statement/
│   └── problem.en.tex
└── plugins/
    └── my-visualizer/
        ├── index.html        ← Required entry point
        ├── script.js         ← Your plugin logic
        ├── style.css         ← Your plugin styles
        └── assets/
            └── icon.svg      ← Any additional assets

The plugin name is the directory name (my-visualizer in the example above). This name must match exactly what you pass to \plugin{my-visualizer} in the problem statement.

How Files Are Served

After the problem package is imported, all plugin files are stored and served via the platform API:

GET /api/v1/problems/{problemId}/plugin/{pluginName}/{...filePath}

For example, script.js inside my-visualizer is served at:

/api/v1/problems/42/plugin/my-visualizer/script.js

The entry point index.html is always loaded first by the iframe.

Referencing Assets with Relative Paths

Inside index.html, always use relative paths to reference other files in the same plugin directory. The platform resolves them correctly regardless of the problem ID or environment.

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!-- Relative paths work correctly -->
  <script src="./monkeyCodeInput.js"></script>
  <script src="./script.js"></script>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <img src="./assets/icon.svg" alt="icon">
</body>
</html>
Do not use absolute paths (e.g. /script.js) or paths that include the problem ID. These will break when the problem is viewed. Always use ./filename relative paths.

Auto-Injected Files

The platform automatically injects monkeyCodeInput.js into every plugin's storage directory at import time. You do not need to include it in your ZIP — it will always be available at ./monkeyCodeInput.js relative to your index.html.

plugins/
  my-visualizer/
    index.html
    script.js
    monkeyCodeInput.js   ← Injected automatically, not from your ZIP

Multiple Files in a Single Plugin

You can organise a plugin with as many files as needed. Subdirectories are supported:

plugins/
  my-visualizer/
    index.html
    script.js
    style.css
    lib/
      d3.min.js          ← Bundled third-party library
      helpers.js
    assets/
      background.png
      font.woff2

Reference subdirectory files with relative paths from index.html:

index.html
<script src="./lib/d3.min.js"></script>
<script src="./lib/helpers.js"></script>
<link rel="stylesheet" href="./style.css">

Multiple Plugins in One Problem

A problem can contain multiple plugins, each in its own subdirectory:

plugins/
  visualizer/
    index.html
    script.js
  debug-view/
    index.html
    style.css

Each plugin is completely independent — they have separate storage paths, separate iframes, and do not share files or state. Reference them individually in the problem statement:

problem.en.tex
\plugin{visualizer}

\plugin{debug-view}

Storage Layout After Import

After uploading the problem package, the platform stores plugin files at:

{problemId}/
  plugins/
    {pluginName}/
      index.html
      script.js
      style.css
      monkeyCodeInput.js    ← Auto-injected

This maps directly to the API route used by the iframe src, so the directory structure you define in the ZIP is preserved exactly as-is in storage.