Experiment to rebuild Diffuse using web applets.
1import type { Output, Track } from "@applets/core/types.d.ts";
2import { applet, reactive } from "../../theme.ts";
3
4////////////////////////////////////////////
5// 🎨 Styles
6////////////////////////////////////////////
7import "@styles/themes/pilot/index.css";
8
9////////////////////////////////////////////
10// 🗂️ Applets
11////////////////////////////////////////////
12import type * as AudioEngine from "@applets/engine/audio/types.d.ts";
13import type * as QueueEngine from "@applets/engine/queue/types.d.ts";
14
15import type * as AudioUI from "@applets/themes/pilot/ui/audio/types.d.ts";
16
17const _configurator = {
18 output: await applet("../../configurator/output"),
19};
20
21const engine = {
22 audio: await applet<AudioEngine.State>("../../engine/audio"),
23 queue: await applet<QueueEngine.State>("../../engine/queue"),
24};
25
26const input = {
27 nativeFs: await applet("../../input/native-fs"),
28};
29
30const _orchestrator = {
31 input: await applet<Output>("../../orchestrator/input-cache"),
32 output: await applet<Output>("../../orchestrator/output-management"),
33 queue: await applet("../../orchestrator/single-queue"),
34};
35
36const ui = {
37 audio: await applet<AudioUI.State>("ui/audio", { setHeight: true }),
38};
39
40////////////////////////////////////////////
41// ⚙️ [Connections → Engines]
42// 🔉 AUDIO
43////////////////////////////////////////////
44
45// NOTE:
46// These could probably be optimised, but it works.
47
48reactive(
49 engine.audio,
50 (data) => data.items[engine.queue.data.now?.id ?? Infinity]?.isPlaying ?? false,
51 (isPlaying) => ui.audio.sendAction("modifyIsPlaying", isPlaying),
52);
53
54reactive(
55 engine.audio,
56 (data) => data.items[engine.queue.data.now?.id ?? Infinity]?.progress ?? 0,
57 (progress: number) => ui.audio.sendAction("modifyProgress", progress),
58);
59
60////////////////////////////////////////////
61// 🌅 [Connections → UI]
62// 🔉 AUDIO
63////////////////////////////////////////////
64
65reactive(
66 ui.audio,
67 (data) => data.isPlaying,
68 (isPlaying) => {
69 const trackId = engine.queue.data.now?.id;
70 const volume = 0.5; // TODO
71
72 // Automatically start playing something if nothing is playing yet.
73 if (!trackId) {
74 if (isPlaying) engine.queue.sendAction("shift");
75 return;
76 }
77
78 // Otherwise just control the audio
79 if (isPlaying) {
80 engine.audio.sendAction("play", { trackId, volume });
81 } else {
82 engine.audio.sendAction("pause", { trackId });
83 }
84 },
85);
86
87reactive(
88 ui.audio,
89 (data: AudioUI.State) => data.seekPosition,
90 (seekPosition) => {
91 if (seekPosition !== undefined && engine.queue.data.now?.id) {
92 engine.audio.sendAction("seek", {
93 percentage: seekPosition,
94 trackId: engine.queue.data.now.id,
95 });
96 }
97 },
98);