···4455Diffuse provides a range of custom elements: audio input, data output, metadata & artwork processing, audio playback, a queue system, and much more.
6677-It is also aimed at consumers, providing themes and constituents, preconfigured component compositions; while simultaneously trying to be [malleable software](https://www.inkandswitch.com/essay/malleable-software/).
77+It is also aimed at consumers, providing themes and facets, preconfigured component compositions; while simultaneously trying to be [malleable software](https://www.inkandswitch.com/essay/malleable-software/).
8899More information on the [website](https://elements.diffuse.sh/latest/).
1010···2525import QueueEngine from "@toko/diffuse/components/engine/queue/element.js"
26262727const queue = new QueueEngine()
2828-queue.setAttribute("group", "constituents")
2828+queue.setAttribute("group", "facets")
29293030document.body.append(queue)
3131````
···3333## Other directories
34343535- `src/common`: Common Javascript code shared by various components and/or themes.
3636-- `src/styles`: Common CSS shared by themes, the index page or constituents (part of themes).
3636+- `src/styles`: Common CSS shared by themes, the index page or facets.
3737- `src/favicons`, `src/fonts`, `src/images` are binary assets for themes and the index page (`src/index.vto`)
3838- `src/_components` and `src/_includes` are templates used in `.vto` templates, again themes and index page.
···1010</style>
11111212<script type="module">
1313- import foundation from "./common/constituents/foundation.js";
1313+ import foundation from "./common/facets/foundation.js";
14141515 const queue = foundation.engine.queue();
1616
···99</style>
10101111<script type="module">
1212- import foundation from "./common/constituents/foundation.js";
1212+ import foundation from "./common/facets/foundation.js";
1313 import { computed, effect } from "./common/signal.js";
14141515 foundation.features.processInputs();
+25-25
src/constituents/index.js
src/facets/index.js
···77import { javascript as langJs } from "@codemirror/lang-javascript";
88import { autocompletion } from "@codemirror/autocomplete";
991010-import foundation from "@common/constituents/foundation.js";
1010+import foundation from "@common/facets/foundation.js";
1111import { effect } from "@common/signal.js";
12121313/**
1414- * @import {Constituent} from "@definitions/types.d.ts"
1414+ * @import {Facet} from "@definitions/types.d.ts"
1515 */
16161717////////////////////////////////////////////
···2525const output = foundation.orchestrator.output();
26262727effect(() => {
2828- const col = output.constituents.collection().sort((a, b) => {
2828+ const col = output.facets.collection().sort((a, b) => {
2929 return a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase());
3030 });
3131···3838 <span>${c.name}</span>
3939 <div class="list-description">
4040 <div class="button-row">
4141- <a href="constituents/l/?cid=${c.cid}" class="button">Open</a>
4141+ <a href="facets/l/?cid=${c.cid}" class="button">Open</a>
4242 <button
4343 style="background-color: var(--accent-twist-2);"
4444- @click="${deleteConstituent({
4444+ @click="${deleteFacet({
4545 cid: c.cid,
4646 name: c.name,
4747 })}"
···5757 )}
5858 </ul>
5959 `
6060- : output.constituents.state() === "loaded"
6161- ? emptyConstituentsList
6060+ : output.facets.state() === "loaded"
6161+ ? emptyFacetsList
6262 : html`
6363 <i class="ph-bold ph-spinner-gap"></i>
6464 `;
···6666 render(h, listEl);
6767});
68686969-const emptyConstituentsList = html`
6969+const emptyFacetsList = html`
7070 <p style="margin-bottom: 0;">
7171- <i class="ph-fill ph-info"></i> You have not saved any constituents yet.
7171+ <i class="ph-fill ph-info"></i> You have not saved any facets yet.
7272 </p>
7373`;
74747575/**
7676 * @param {{ cid: string; name: string }} _
7777 */
7878-function deleteConstituent({ cid, name }) {
7878+function deleteFacet({ cid, name }) {
7979 return () => {
8080- const c = confirm("Are you sure you want to delete this constituent?");
8080+ const c = confirm("Are you sure you want to delete this facet?");
8181 if (!c) return;
82828383- output.constituents.save(
8484- output.constituents.collection().filter((c) =>
8383+ output.facets.save(
8484+ output.facets.collection().filter((c) =>
8585 !(c.name === name && c.cid === cid)
8686 ),
8787 );
···111111</style>
112112113113<script type="module">
114114- import foundation from "./common/constituents/foundation.js";
114114+ import foundation from "./common/facets/foundation.js";
115115 import { effect } from "./common/signal.js";
116116117117 const components = foundation.features.fillQueueAutomatically();
···154154 const cid = await CID.create(0x55, new TextEncoder().encode(html));
155155 const name = nameEl?.value ?? "nameless";
156156157157- /** @type {Constituent} */
158158- const constituent = {
159159- $type: "sh.diffuse.output.constituent",
157157+ /** @type {Facet} */
158158+ const facet = {
159159+ $type: "sh.diffuse.output.facet",
160160 cid: CID.toString(cid),
161161 html,
162162 name,
···177177 break;
178178 }
179179 case "save":
180180- await saveConstituent(constituent);
180180+ await saveFacet(facet);
181181 break;
182182 case "save+open":
183183- await saveConstituent(constituent);
184184- window.open(`./constituents/l/?cid=${constituent.cid}`, "blank");
183183+ await saveFacet(facet);
184184+ window.open(`./facets/l/?cid=${facet.cid}`, "blank");
185185 break;
186186 }
187187}
188188189189/**
190190- * @param {Constituent} constituent
190190+ * @param {Facet} facet
191191 */
192192-async function saveConstituent(constituent) {
193193- const col = output.constituents.collection();
194194- const colWithoutName = col.filter((c) => c.name !== constituent.name);
192192+async function saveFacet(facet) {
193193+ const col = output.facets.collection();
194194+ const colWithoutName = col.filter((c) => c.name !== facet.name);
195195196196- await output.constituents.save([...colWithoutName, constituent]);
196196+ await output.facets.save([...colWithoutName, facet]);
197197}
+22-22
src/constituents/index.vto
src/facets/index.vto
···11---
22-layout: layouts/constituent.vto
22+layout: layouts/facet.vto
33base: ../
4455styles:
···99 - styles/vendor/phosphor/fill/style.css
10101111scripts:
1212- - constituents/index.js
1212+ - facets/index.js
13131414-# CONSTITUENTS
1414+# FACETS
15151616-constituents:
1717- - url: "themes/blur/artwork-controller/constituent.html.txt"
1616+facets:
1717+ - url: "themes/blur/artwork-controller/facet.html.txt"
1818 title: "Blur / Artwork controller"
1919 desc: >
2020 Audio playback controller with an artwork display.
2121- - url: "themes/webamp/browser/constituent.html.txt"
2121+ - url: "themes/webamp/browser/facet.html.txt"
2222 title: "Webamp / Browser"
2323 desc: >
2424 Collection browser + search in a retro, win98, look.
2525- - url: "themes/webamp/configurators/input/constituent.html.txt"
2525+ - url: "themes/webamp/configurators/input/facet.html.txt"
2626 title: "Webamp / Input Configurator"
2727 desc: >
2828 Windows 98 styled input configurator where you can add music sources.
···3636 </a>
3737 </div>
3838 <p class="construct dither-mask" style="margin-top: 0; max-width: none;">
3939- Constituents
3939+ Facets
4040 </p>
4141 <p>
4242- Constituents are various interface components each loaded in their own web page. Every used component is configured so that it operates in broadcast mode, making all the pages communicate with each other.
4242+ Facets are various interface components each loaded in their own web page. Every used component is configured so that it operates in broadcast mode, making all the pages communicate with each other.
4343 </p>
44444545 <ul class="table-of-contents">
4646- <li><a href="constituents/#built-in">Built-in</a></li>
4747- <li><a href="constituents/#community">Community</a></li>
4848- <li><a href="constituents/#saved">Your collection</a></li>
4949- <li><a href="constituents/#examples">Examples</a></li>
5050- <li><a href="constituents/#build">Build</a></li>
5151- <li><a href="constituents/#foundation">Foundation</a></li>
4646+ <li><a href="facets/#built-in">Built-in</a></li>
4747+ <li><a href="facets/#community">Community</a></li>
4848+ <li><a href="facets/#saved">Your collection</a></li>
4949+ <li><a href="facets/#examples">Examples</a></li>
5050+ <li><a href="facets/#build">Build</a></li>
5151+ <li><a href="facets/#foundation">Foundation</a></li>
5252 </ul>
5353 </div>
5454 <div class="dither-mask filler"></div>
···6060 <h2 id="built-in">Built-in</h2>
61616262 <div style="margin-top: var(--space-lg);">
6363- {{ await comp.constituents({ items: constituents }) }}
6363+ {{ await comp.facets({ items: facets }) }}
6464 </div>
6565 </section>
66666767 <section class="flex">
6868 <h2 id="community">Community</h2>
6969 <p>
7070- Check out some constituents from the community and load them here.
7070+ Check out some facets from the community and load them here.
7171 </p>
7272 <p>
7373 <small><i class="ph-fill ph-info"></i> Nothing here yet, too early.</small>
···106106107107 <div class="flex">
108108 <p style="margin-top: 0">
109109- Your code here builds on the <a href="constituents/#foundation">foundation</a> listed below, it'll be injected into a <code><div id="container"></code> element in the body.
109109+ Your code here builds on the <a href="facets/#foundation">foundation</a> listed below, it'll be injected into a <code><div id="container"></code> element in the body.
110110 </p>
111111 <input id="name-input" type="text" placeholder="Unique name" name="name" value="Unique name" required />
112112 <p>
···124124 <selectedcontent></selectedcontent>
125125 </button>
126126127127- <option value="constituents/examples/now-playing.html.txt" selected>Now playing & next queue item</option>
128128- <option value="constituents/examples/generate-playlist.html.txt">Generate playlist from queue</option>
127127+ <option value="facets/examples/now-playing.html.txt" selected>Now playing & next queue item</option>
128128+ <option value="facets/examples/generate-playlist.html.txt">Generate playlist from queue</option>
129129 </select>
130130 </div>
131131 <p>
···151151 <div class="code-block">
152152 <code>
153153 {{- echo -}}
154154- import foundation from "common/constituents/foundation.js"
154154+ import foundation from "common/facets/foundation.js"
155155 {{ /echo }}
156156{{ echo -}}foundation.engine.audio(){{- /echo }}
157157{{ echo -}}foundation.engine.queue(){{- /echo }}
···203203 </ul>
204204 <h3>Notes</h3>
205205 <p>
206206- While you have the ability to do whatever you want in a custom constituent, the existing constituents are designed to work a certain way; so here's some things to keep in mind:
206206+ While you have the ability to do whatever you want in a custom facet, the existing facets are designed to work a certain way; so here's some things to keep in mind:
207207 </p>
208208 <ul>
209209 <li><span>In most cases you'll want to call <code>foundation.features.processInputs()</code> so that your audio files and streams actually show up.</span></li>
+16-16
src/constituents/l/index.js
src/facets/l/index.js
···11import * as CID from "@atcute/cid";
2233-import foundation from "@common/constituents/foundation.js";
33+import foundation from "@common/facets/foundation.js";
44import { effect } from "@common/signal.js";
5566/**
77- * @import {Constituent} from "@definitions/types.d.ts"
77+ * @import {Facet} from "@definitions/types.d.ts"
88 */
991010////////////////////////////////////////////
···3333const container = /** @type {HTMLDivElement} */ (containerNull);
34343535effect(async () => {
3636- const collection = output.constituents.collection();
3737- if (output.constituents.state() !== "loaded") return;
3636+ const collection = output.facets.collection();
3737+ if (output.facets.state() !== "loaded") return;
38383939- let constituent;
3939+ let facet;
40404141 if (cid) {
4242- constituent = collection.find((c) => c.cid === cid);
4242+ facet = collection.find((c) => c.cid === cid);
4343 } else if (name) {
4444- constituent = collection.find((c) => c.name === name);
4444+ facet = collection.find((c) => c.name === name);
4545 } else if (url) {
4646 const html = await fetch(url).then((res) => res.text());
4747 const cid = await CID.create(0x55, new TextEncoder().encode(html));
4848 const name = "tryout";
49495050- /** @type {Constituent} */
5050+ /** @type {Facet} */
5151 const c = {
5252- $type: "sh.diffuse.output.constituent",
5252+ $type: "sh.diffuse.output.facet",
5353 cid: CID.toString(cid),
5454 html,
5555 name,
5656 };
57575858- constituent = c;
5858+ facet = c;
5959 }
60606161- // TODO: Message that constituent was not found
6262- if (!constituent) return;
6161+ // TODO: Message that facet was not found
6262+ if (!facet) return;
63636464- loadIntoContainer(constituent);
6464+ loadIntoContainer(facet);
6565});
66666767/**
6868- * @param {Constituent} constituent
6868+ * @param {Facet} facet
6969 */
7070-function loadIntoContainer(constituent) {
7070+function loadIntoContainer(facet) {
7171 // TODO: Validate if CID matches HTML
72727373 const range = document.createRange();
7474 range.selectNode(container);
7575- const documentFragment = range.createContextualFragment(constituent.html);
7575+ const documentFragment = range.createContextualFragment(facet.html);
76767777 container.innerHTML = "";
7878 container.append(documentFragment);
···11-export * as ShDiffuseOutputConstituent from "./types/sh/diffuse/output/constituent.ts";
11+export * as ShDiffuseOutputFacet from "./types/sh/diffuse/output/facet.ts";
22export * as ShDiffuseOutputPlaylist from "./types/sh/diffuse/output/playlist.ts";
33export * as ShDiffuseOutputTheme from "./types/sh/diffuse/output/theme.ts";
44export * as ShDiffuseOutputTrack from "./types/sh/diffuse/output/track.ts";
···11{
22 "lexicon": 1,
33- "id": "sh.diffuse.output.constituent",
33+ "id": "sh.diffuse.output.facet",
44 "defs": {
55 "main": {
66 "type": "record",
···1515 "description": { "type": "string" },
1616 "html": {
1717 "type": "string",
1818- "description": "The UTF8 HTML string that makes up the constituent"
1818+ "description": "The UTF8 HTML string that makes up the facet"
1919 },
2020 "name": { "type": "string" },
2121 "url": {
2222 "type": "string",
2323- "description": "An optional URL that points at the constituent; can be used to update this artifact"
2323+ "description": "An optional URL that points at the facet; can be used to update this artifact"
2424 }
2525 }
2626 }
+1-3
src/definitions/types.d.ts
···11-export type {
22- Main as Constituent,
33-} from "./types/sh/diffuse/output/constituent.ts";
11+export type { Main as Facet } from "./types/sh/diffuse/output/facet.ts";
4253export type {
64 AutoGenerate as PlaylistAutoGeneration,
···11-import { GROUP } from "@common/constituents/foundation.js";
11+import { GROUP } from "@common/facets/foundation.js";
2233import InputConfigurator from "@components/configurator/input/element.js";
44import MetadataProcessor from "@components/processor/metadata/element.js";
+16-16
src/index.vto
···2121 - title: "Loader"
2222 todo: true
2323 desc: >
2424- **A theme that loads other themes!** _If you're taking the first steps to customize, checkout the [constituents loader](#constituents) first!_
2424+ **A theme that loads other themes!** _If you're taking the first steps to customize, checkout the [facets loader](#facets) first!_
2525 - url: "themes/webamp/"
2626 title: "Webamp"
2727 desc: >
···163163# DEFINITIONS
164164165165definitions:
166166- - title: "Output / Constituent"
166166+ - title: "Output / Facet"
167167 desc: >
168168- Constituent pointer or HTML snippet.
169169- url: "definitions/output/constituent.json"
168168+ Facet pointer or HTML snippet.
169169+ url: "definitions/output/facet.json"
170170 - title: "Output / Playlist"
171171 desc: >
172172 Represents a collection of tracks, which may be ordered or unordered. Tracks are matched based on the given criteria.
···212212 <ul class="table-of-contents">
213213 <li><a href="#usage">Usage</a></li>
214214 <li><a href="#themes">Themes</a></li>
215215- <li><a href="#constituents">Constituents</a></li>
215215+ <li><a href="#facets">Facets</a></li>
216216 <li><a href="#agency">Agency</a></li>
217217 <li><a href="#elements">Elements</a></li>
218218 <li><a href="#definitions">Definitions</a></li>
···235235 </p>
236236237237 <p>
238238- Alternatively, there's <a href="constituents/">constituents</a> which allows you to use any component from any theme interchange­ably, among pieces that are not in themes; each in a separate browser tab. Each tab talks to each other, so you can for example browse audio in one tab and play it in another.
238238+ Alternatively, there's <a href="facets/">facets</a> which allows you to use any component from any theme interchange­ably, among pieces that are not in themes; each in a separate browser tab. Each tab talks to each other, so you can for example browse audio in one tab and play it in another.
239239 </p>
240240 </div>
241241242242 <div class="element">
243243 <p>
244244- <strong style="color: var(--accent); font-weight: 700;">Diffuse is not your typical streaming service though, you have to add sources of audio.</strong> To start you can try out the demo by clicking the button below, or, go to a <a href="themes/">theme</a> or <a href="constituents/">constituent</a> that lets you add your audio input.
244244+ <strong style="color: var(--accent); font-weight: 700;">Diffuse is not your typical streaming service though, you have to add sources of audio.</strong> To start you can try out the demo by clicking the button below, or, go to a <a href="themes/">theme</a> or <a href="facets/">facet</a> that lets you add your audio input.
245245 </p>
246246247247 <p>
···253253 </div>
254254 </section>
255255256256- <!-- THEMES & CONSTITUENTS -->
256256+ <!-- THEMES & FACETS -->
257257 <div class="columns">
258258 <section>
259259 <h2 id="themes">Themes</h2>
···269269 </section>
270270271271 <section>
272272- <h2 id="constituents">Constituents</h2>
272272+ <h2 id="facets">Facets</h2>
273273274274 <p>
275275- Constituents are various interface components each loaded in their own web page. Every used component is configured so that it operates in broadcast mode, making all the pages communicate with each other.
275275+ Facets are various interface components each loaded in their own web page. Every used component is configured so that it operates in broadcast mode, making all the pages communicate with each other.
276276 </p>
277277278278 <p>
279279- <a class="button button--alt" href="constituents/">Explore</a>
279279+ <a class="button button--alt" href="facets/">Explore</a>
280280 </p>
281281 </section>
282282 </div>
···302302 <!-- 2 -->
303303 <li>
304304 <p>
305305- <i class="ph-fill ph-basket"></i> <strong>Level 2</strong>: Take out food from various places, eg. cheese shop + bakery. You choose how you combine the foods and from where you order them. That's <a href="constituents/">constituents</a>.
305305+ <i class="ph-fill ph-basket"></i> <strong>Level 2</strong>: Take out food from various places, eg. cheese shop + bakery. You choose how you combine the foods and from where you order them. That's <a href="facets/">facets</a>.
306306 </p>
307307 </li>
308308 <!-- 3 -->
···311311 <i class="ph-fill ph-pepper"></i> <strong>Level 3</strong>: Now that you know which food is good and how to make combinations, you might make a slight customization, add a little something of your own (eg. add some spice). However, you're not quite confident enough which spice to pick, so you hire some help.
312312 </p>
313313 <p>
314314- This can be done using the <a href="constituents/#builder">constituents builder</a> which allows you to build on top of a familiar preconfigured foundation and load custom constituents. People might share their own, or maybe you use an LLM to generate something for you (eg. an album art gallery).
314314+ This can be done using the <a href="facets/#builder">facets builder</a> which allows you to build on top of a familiar preconfigured foundation and load custom facets. People might share their own, or maybe you use an LLM to generate something for you (eg. an album art gallery).
315315 </p>
316316 </li>
317317 <!-- 4 -->
···320320 <i class="ph-fill ph-knife"></i> <strong>Level 4</strong>: You learned a bit from watching and talking to the help you hired, so you decide to take things in your own hands.
321321 </p>
322322 <p>
323323- You continue to use the <a href="constituents/#builder">constituents builder</a> but learn a bit of <a href="https://htmlforpeople.com">HTML</a>, <a href="https://javascript.info">Javascript</a> and <a href="https://htmlforpeople.com/css-basics/">CSS</a>; so you're able to write your own constituent.
323323+ You continue to use the <a href="facets/#builder">facets builder</a> but learn a bit of <a href="https://htmlforpeople.com">HTML</a>, <a href="https://javascript.info">Javascript</a> and <a href="https://htmlforpeople.com/css-basics/">CSS</a>; so you're able to write your own facet.
324324 </p>
325325 </li>
326326 </div>
···331331 <i class="ph-fill ph-cooking-pot"></i> <strong>Level 5</strong>: At this point you're confident enough to make a meal from scratch. You can start very simple, eg. just throwing a steak in the pan with some butter and some salt to it. Then later add some baked potatoes and go from there.
332332 </p>
333333 <p>
334334- A similar tool comes into play here, the <a href="themes/#builder">themes builder</a>. Same concept as the constituents builder, but now you need to specify the foundation yourself. You can use the <a href="#elements">elements</a> listed below to do so. The code for these is available from this website or through the <a href="https://jsr.io/@toko/diffuse">Javascript package</a>.
334334+ A similar tool comes into play here, the <a href="themes/#builder">themes builder</a>. Same concept as the facets builder, but now you need to specify the foundation yourself. You can use the <a href="#elements">elements</a> listed below to do so. The code for these is available from this website or through the <a href="https://jsr.io/@toko/diffuse">Javascript package</a>.
335335 </p>
336336 </li>
337337 <!-- 6 -->
···365365 </p>
366366367367 <p>
368368- Consume these using the constituents <a href="constituents/#builder">builder</a>, the Javascript <a href="https://jsr.io/@toko/diffuse">package</a>, or the linked Javascript files down below.
368368+ Consume these using the facets <a href="facets/#builder">builder</a>, the Javascript <a href="https://jsr.io/@toko/diffuse">package</a>, or the linked Javascript files down below.
369369 </p>
370370371371 <div class="columns">
···11-import foundation from "@common/constituents/foundation.js";
11+import foundation from "@common/facets/foundation.js";
22import ArtworkController from "@themes/blur/artwork-controller/element.js";
3344// Setup the prerequisite elements
···11-import foundation from "@common/constituents/foundation.js";
11+import foundation from "@common/facets/foundation.js";
22import BrowserElement from "@themes/webamp/browser/element.js";
3344foundation.features.fillQueueAutomatically();
···11-import foundation from "@common/constituents/foundation.js";
11+import foundation from "@common/facets/foundation.js";
22import InputConfigElement from "@themes/webamp/configurators/input/element.js";
33import { effect } from "@common/signal.js";
44