diffuse-facet
Create an interface or feature facet for Diffuse (diffuse.sh)
Informations de source
- Dépôt
- icidasset/diffuse
- Dernière activité de la source
- 31 août 2026 à 22:10
- Langue détectée de SKILL.md
- anglais
- Étoiles
- 874
- Forks
- 70
Options d'installation
Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.
Vérifiez les fichiers source
Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.
Explorateur de fichiers
2 fichiersAffichage de SKILL.md
SKILL.md
Instructions source · Aperçu en lecture seule- name
- diffuse-facet
- description
- Create an interface or feature facet for Diffuse (diffuse.sh)
- user-invocable
- true
- version
- 0.3.0
Create a [Diffuse](https://diffuse.sh) facet and produce the HTML ready to paste into the `create/` page.
## Step 1 — Read the docs
Use the read tool to read these files:
- `docs/architecture.txt` — system overview, facet rules, foundation API
- `docs/elements.txt` — all available custom elements with code examples
- `docs/foundation.js` — the foundation code mentioned throughout this document
- `example/index.html` — a representative interface facet to use as a reference
- Any specific definition you need (e.g. `docs/definitions/output/track.json` for the track schema)
- `docs/definitions/index.ts` — TypeScript types for all data structures
## Step 2 — Clarify intent
If the user hasn't described what the facet should do, ask one plain-language question before proceeding.
## Step 3 — Write the facet
Facets are HTML fragments (no `<!doctype>`, `<html>`, or `<head>`). The loader injects them into `<div id="container">` and sets a `<base>` pointing at the Diffuse build root, so all relative URLs resolve from there. The import map exposes `~/` as the root alias.
### Mandatory rules
- **`foundation.ready()`** must be called on every interface facet — it removes the loading spinner. Omitting it leaves the screen stuck on loading.
- **`foundation.setup({ title })`** should be called to set the document title.
- Always check the definitions fetched in Step 1 for the exact shape of any data you access — never assume top-level fields exist. For example, track metadata lives under `track.tags.*`, not at the top level.
- Signal reader functions (`queue.now`, `queue.past`, `queue.future`, …) must be **called inside `effect()`** to be reactive.
- Do **not** import modules with top-level `await` from Worker scripts — it causes RPC messages to be dropped.
- Use **`@param` annotations above functions**, not inline `@type` in parameter lists.
### Skeleton
```html
<style>
@import "./styles/base.css";
@import "./styles/diffuse/facet.css";
@import "./vendor/@phosphor-icons/web/fill/style.css"; /* or /bold/ */
@layer base, diffuse;
/* facet-specific styles */
</style>
<main>
<!-- markup -->
</main>
<script type="module">
import foundation from "~/common/foundation.js";
import { effect } from "~/common/signal.js";
foundation.setup({ title: "My Facet | Diffuse" });
// wire up elements …
foundation.ready();
</script>
```
### Standard two-column layout
```html
<main>
<div class="facet__left">
<a href="./dashboard/" class="diffuse-logo-container">
<svg viewBox="0 0 902 134" width="160">
<title>Diffuse</title>
<use href="images/diffuse-current.svg#diffuse"></use>
</svg>
</a>
<h1>Title</h1>
<p>Description.</p>
</div>
<div class="facet__right">
<!-- main content -->
</div>
</main>
```
For a centered or full-screen layout (player, dialog, etc.) override `body` and `main` in the facet's `<style>` block directly.
### Example foundation usage
```js
await foundation.orchestrator.queueAudio();
await foundation.orchestrator.mediaSession();
const [audio, ctl, queue] = await Promise.all([
foundation.engine.audio(),
foundation.orchestrator.controller(),
foundation.engine.queue(),
]);
await customElements.whenDefined(ctl.localName);
```
### Reactivity
Signals are used for reactivity, see the `~/common/signal.js` javascript file for the code. It's based on the alien-signals library.
```js
effect(() => {
const track = ctl.currentTrack(); // computed — call like a fn
const isPlaying = ctl.isPlaying();
const audioState = ctl.audio(); // AudioStateReadOnly | undefined
if (audioState) {
const progress = audioState.progress(); // 0–1
const current = audioState.currentTime();
const duration = audioState.duration();
}
const now = queue.now(); // SignalReader — call like a fn
const past = queue.past();
const future = queue.future();
});
```
### Audio control
```js
audio.play({ audioId: queue.now().id });
audio.pause({ audioId: queue.now().id });
audio.seek({ audioId: queue.now().id, percentage: 0.5 }); // 0–1
queue.shift(); // next track
queue.unshift(); // previous track
```
### Additional requirements and notes
- When working with track lists, realise that there could be a huge number of tracks that you need to work with (eg. 20000 tracks). Implement a custom virtual scroll (see the winamp or blur browser elements for examples).
- Prefer the lit-html library as the templating/rendering engine. It is available from `~/vendor/lit-html/index.js` (among some other libraries such as: `idb-keyval`, `throttle-debounce`, several `@atcute` libraries, and `kmenu-core`). Always make sure to use the `~/vendor/` prefix for libraries, you're not working in an enviroment that bundles code.
- Prefer to fetch the tracks from the `scoped-tracks` orchestrator element.
- Always prefer to use an orchestrator or another component instead of reimplementing logic yourself.
- Be mindful of performance.
## Step 4 — Deliver
Output the complete facet HTML in a code block.
If the page currently running in the browser exposes WebMCP tools, call the
`create-facet` tool with this HTML (plus the name, kind and description) instead
of asking the user to paste it in — the tool saves it directly to the user's
collection.
Otherwise, tell the user to open the `create/` page in Diffuse, paste it in, and
load it.
Voir sur GitHub