Plugins run inside a strictly sandboxed <iframe> with only two permissions granted:
| Permission | Meaning |
|---|---|
allow-scripts | JavaScript execution is allowed |
allow-forms | Form submission is allowed |
The following are not permitted:
| Restriction | Effect |
|---|---|
No allow-same-origin | The plugin runs from an opaque origin — it cannot access the parent page's DOM, cookies, localStorage, or sessionStorage |
No allow-top-navigation | The plugin cannot navigate the parent page or open new tabs |
No allow-popups | window.open() calls are blocked |
No allow-downloads | File downloads from within the plugin are blocked |
<script src="https://..."> will fail with a CORS error. All external libraries must be bundled inside the plugin directory. See Using Third-Party Libraries for details.Plugins are rendered at a fixed size of 400 × 400 pixels. This cannot be changed from the problem statement — the \plugin{} macro does not accept width or height arguments.
Design your plugin layout to fit within a 400 × 400 px viewport. If your visualizer needs more space, consider using scrollable containers or scaling your canvas/SVG to fit.
Plugin names must follow these rules:
plugins/ in the ZIP (case-sensitive)\plugin{name} — no nesting or compound expressions% ✅ Valid
\plugin{my-visualizer}
\plugin{graphView}
\plugin{graph_v2}
% ❌ Invalid — slashes not allowed
\plugin{tools/visualizer}
% ❌ Invalid — spaces not allowed
\plugin{my visualizer}
\plugin{} does not match a directory in the problem's plugins/ storage path, the iframe will render a blank or error page.Nesting \plugin{} calls inside other macros or environments is not supported. Each \plugin{name} must appear as a standalone macro in the document body.
The entire problem package ZIP (including all plugin files) must be 50 MB or less. This limit applies to the full upload, not just the plugin directory.
If your plugin uses large assets (images, fonts, data files), keep them as small as possible. Consider:
Because the iframe is recreated every time the selected input changes, plugins do not retain any state between input switches. Each load starts fresh from index.html.
If your plugin needs to preserve UI state (e.g. zoom level, selected node), you would need to encode that state in the URL hash — which is not currently supported by the platform's input passing mechanism.
Due to the opaque-origin sandbox, credentialed or cross-origin fetch/XHR requests to external APIs will be blocked or fail. Plugins are intended to be fully self-contained and work only with the input data passed via the URL hash.