# Embed on a website

| Requirement | Use |
| --- | --- |
| Display a finished score on any static site | Exported SVG, with optional PDF/source downloads |
| Let visitors change source and redraw | Self-hosted browser WASM and a small component |
| Publish a copy of the documentation | [Self-host this wiki](self-hosting.md) |

Neither notation approach needs a ScoreScript account or a rendering server
at page-view time. Browser rendering is an engine interface, not a prebuilt
drop-in Studio application or a sound player.

## Static notation

With the [CLI installed](integration.md), render during your site build:

```sh
scorescript check piece.scorescript
scorescript render piece.scorescript -o piece.svg
scorescript pdf piece.scorescript -o piece.pdf
```

Put the generated files and the source in your site's `music/` directory.
In an HTML page:

```html
<figure>
  <img src="./music/piece.svg" alt="Flute melody in C major" style="max-width:100%;height:auto">
  <figcaption>
    <a href="./music/piece.pdf">PDF</a>
    <a href="./music/piece.scorescript" download>ScoreScript source</a>
  </figcaption>
</figure>
```

The SVG contains the notation glyphs; no music-font download is needed.
Use a meaningful description for the actual piece. Editing the source does
not change an already uploaded SVG: rerun the build and redeploy the outputs.
An ordinary Markdown image link to the SVG works when the host permits SVG.

## Interactive browser rendering

This path requires authorized repository access and permission to redistribute
the engine. Build the web package from the repository root with Rust/Cargo and
`wasm-pack` installed:

```sh
bash crates/scorescript_wasm/build.sh web
```

Copy the generated `crates/scorescript_wasm/pkg/` directory into your website
as `vendor/scorescript/`. Copy the package, including its JavaScript, WASM,
and notices; do not mix files from different builds.

```text
site/
  index.html
  score.js
  piece.scorescript
  vendor/scorescript/
    scorescript.js
    scorescript_bg.wasm
    ...generated package files
```

`index.html`:

```html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ScoreScript notation</title>
<label for="source">ScoreScript source</label>
<textarea id="source" rows="12" cols="60"></textarea>
<button id="render" disabled>Render</button>
<pre id="status" role="status"></pre>
<img id="notation" alt="Notation generated from the source above" style="max-width:100%;height:auto">
<script type="module" src="./score.js"></script>
</html>
```

`score.js`:

```js
import init, { CompiledDocument } from "./vendor/scorescript/scorescript.js";

const source = document.querySelector("#source");
const status = document.querySelector("#status");
const notation = document.querySelector("#notation");
const button = document.querySelector("#render");
let score;
let imageUrl;

function clearImage() {
  notation.removeAttribute("src");
  if (imageUrl) URL.revokeObjectURL(imageUrl);
  imageUrl = undefined;
}

function render() {
  try {
    score.update(source.value);
    const diagnostics = JSON.parse(score.diagnostics_json());
    status.textContent = diagnostics.map(d => `${d.severity}: ${d.message}`).join("\n");
    clearImage();
    if (diagnostics.some(d => d.severity === "error")) return;
    const svg = score.render_svg(JSON.stringify({ width_px: 800, foreground: "#111" }));
    imageUrl = URL.createObjectURL(new Blob([svg], { type: "image/svg+xml" }));
    notation.src = imageUrl;
    if (!diagnostics.length) status.textContent = "Rendered.";
  } catch (error) {
    clearImage();
    status.textContent = String(error);
  }
}

try {
  await init();
  const response = await fetch("./piece.scorescript");
  if (!response.ok) throw new Error(`Source download failed: ${response.status}`);
  source.value = await response.text();
  score = new CompiledDocument(source.value);
  button.addEventListener("click", render);
  button.disabled = false;
  render();
} catch (error) {
  status.textContent = String(error);
}

window.addEventListener("pagehide", event => {
  if (event.persisted) return;
  clearImage();
  score?.free();
}, { once: false });
```

Supply a valid `piece.scorescript`, for example the complete [file syntax](first-score.md)
example. Serve the directory over HTTP(S), not by opening `index.html` as a
`file:` URL. The initial page loads the local JS, WASM, and score; subsequent
render clicks compile in the visitor's browser without uploading their text.
This example does not save edits; add explicit save/download controls if needed.

## Hosting requirements and boundaries

- Serve `.wasm` as `application/wasm` and JavaScript with a JavaScript MIME type.
- If your site sets Content Security Policy, allow its own modules and fetches,
  WebAssembly compilation (`'wasm-unsafe-eval'` in `script-src` where required),
  and `blob:` in `img-src` for this example. Do not disable the site's policy.
- Render generated SVG as an image, as above. Do not insert user source or
  arbitrary uploaded SVG into the page with `innerHTML`.
- For large or untrusted input, impose size/time limits and move compilation to
  a terminable Web Worker. The minimal example is for bounded scores, not an
  unrestricted public compilation service.
- Keep the editable source; SVG and PDF are outputs. Do not edit SVG to change
  the musical document.

Browser requirements are documented in MDN's [WebAssembly streaming reference](https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/JavaScript_interface/instantiateStreaming_static)
and [script-src policy reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src).

`render_svg` produces flowing notation. `render_pages_json` provides paginated
SVG and a report. `performance_json` provides note/timing data; your application
must supply its own audio engine. It does not start playback by itself.

## Updates and distribution

Pin a tested engine revision and replace the generated package as one unit
when upgrading. Rerun representative scores and inspect their diagnostics and
output. Hosting this wiki does not install the browser engine, and publishing
the wiki does not publish an npm package.

The renderer embeds font assets. The current package build does not copy all
font license files automatically: include the applicable notices from
`crates/scorescript_render/assets/*/OFL.txt` with any distribution.
Repository access alone does not establish permission to redistribute private
source or engine artifacts. Confirm the applicable distribution terms before
uploading those artifacts publicly.
