@dixy-ui/themes 0.0.0-stage → 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +104 -2
- package/dist/ansi/ornament.d.ts +3 -0
- package/dist/ansi/ornament.js +8 -0
- package/dist/ansi-panes.css +929 -0
- package/dist/art-deco.css +850 -0
- package/dist/atelier/ornament.d.ts +4 -0
- package/dist/atelier/ornament.js +9 -0
- package/dist/atomic/ornament.d.ts +3 -0
- package/dist/atomic/ornament.js +8 -0
- package/dist/atomic-lounge.css +946 -0
- package/dist/authoring.d.ts +142 -0
- package/dist/authoring.js +83 -0
- package/dist/azulejo/ornament.d.ts +3 -0
- package/dist/azulejo/ornament.js +8 -0
- package/dist/azulejo-tile.css +962 -0
- package/dist/blueprint/ornament.d.ts +3 -0
- package/dist/blueprint/ornament.js +8 -0
- package/dist/blueprint.css +897 -0
- package/dist/brutalist/ornament.d.ts +3 -0
- package/dist/brutalist/ornament.js +8 -0
- package/dist/brutalist-concrete.css +936 -0
- package/dist/bytes.json +162 -0
- package/dist/candy-clay.css +778 -0
- package/dist/catalog.d.ts +1346 -0
- package/dist/catalog.js +1379 -0
- package/dist/character.d.ts +103 -0
- package/dist/character.js +477 -0
- package/dist/chrome.d.ts +114 -0
- package/dist/chrome.js +247 -0
- package/dist/clay/ornament.d.ts +3 -0
- package/dist/clay/ornament.js +8 -0
- package/dist/compile-css.d.ts +3 -0
- package/dist/compile-css.js +133 -0
- package/dist/deco/ornament.d.ts +3 -0
- package/dist/deco/ornament.js +8 -0
- package/dist/diwali/ornament.d.ts +3 -0
- package/dist/diwali/ornament.js +8 -0
- package/dist/diwali-lights.css +894 -0
- package/dist/documents.d.ts +104 -0
- package/dist/documents.js +1411 -0
- package/dist/forest/ornament.d.ts +3 -0
- package/dist/forest/ornament.js +12 -0
- package/dist/foundations.d.ts +105 -0
- package/dist/foundations.js +140 -0
- package/dist/frame-corners.d.ts +5 -0
- package/dist/frame-corners.js +5 -0
- package/dist/frame-styles.d.ts +36 -0
- package/dist/frame-styles.js +146 -0
- package/dist/freeze.d.ts +2 -0
- package/dist/freeze.js +9 -0
- package/dist/freighter/ornament.d.ts +3 -0
- package/dist/freighter/ornament.js +8 -0
- package/dist/freighter.css +942 -0
- package/dist/glass/ornament.d.ts +3 -0
- package/dist/glass/ornament.js +8 -0
- package/dist/glass-ui.css +923 -0
- package/dist/hardware/ornament.d.ts +4 -0
- package/dist/hardware/ornament.js +10 -0
- package/dist/holi/ornament.d.ts +3 -0
- package/dist/holi/ornament.js +8 -0
- package/dist/holi-colours.css +887 -0
- package/dist/hud/ornament.d.ts +3 -0
- package/dist/hud/ornament.js +8 -0
- package/dist/light/ornament.d.ts +3 -0
- package/dist/light/ornament.js +10 -0
- package/dist/living-forest.css +917 -0
- package/dist/lunar/ornament.d.ts +3 -0
- package/dist/lunar/ornament.js +8 -0
- package/dist/lunar-new-year.css +811 -0
- package/dist/manifests.d.ts +2485 -0
- package/dist/manifests.js +264 -0
- package/dist/material-light.css +880 -0
- package/dist/neon/ornament.d.ts +3 -0
- package/dist/neon/ornament.js +8 -0
- package/dist/neon-night-market.css +944 -0
- package/dist/ocean/ornament.d.ts +3 -0
- package/dist/ocean/ornament.js +8 -0
- package/dist/ocean-depths.css +825 -0
- package/dist/orbital-hud.css +973 -0
- package/dist/organic-css.d.ts +3 -0
- package/dist/organic-css.js +23 -0
- package/dist/organic-geometry.d.ts +20 -0
- package/dist/organic-geometry.js +74 -0
- package/dist/organic-ornament.d.ts +9 -0
- package/dist/organic-ornament.js +28 -0
- package/dist/organic-paint-launch.d.ts +43 -0
- package/dist/organic-paint-launch.js +1156 -0
- package/dist/organic-paint-world.d.ts +24 -0
- package/dist/organic-paint-world.js +676 -0
- package/dist/organic-paint.d.ts +50 -0
- package/dist/organic-paint.js +695 -0
- package/dist/organic-runtime.d.ts +4 -0
- package/dist/organic-runtime.js +231 -0
- package/dist/organic-settings.d.ts +680 -0
- package/dist/organic-settings.js +433 -0
- package/dist/ornament-parts.d.ts +20 -0
- package/dist/ornament-parts.js +15 -0
- package/dist/papel-picado.css +904 -0
- package/dist/phosphor/ornament.d.ts +3 -0
- package/dist/phosphor/ornament.js +8 -0
- package/dist/phosphor-terminal.css +1011 -0
- package/dist/picado/ornament.d.ts +3 -0
- package/dist/picado/ornament.js +8 -0
- package/dist/prism/ornament.d.ts +4 -0
- package/dist/prism/ornament.js +9 -0
- package/dist/prism-glass.css +970 -0
- package/dist/recipes.d.ts +938 -0
- package/dist/recipes.js +939 -0
- package/dist/resolve.d.ts +40 -0
- package/dist/resolve.js +24 -0
- package/dist/retro/ornament.d.ts +5 -0
- package/dist/retro/ornament.js +10 -0
- package/dist/retro-os.css +867 -0
- package/dist/riso/ornament.d.ts +3 -0
- package/dist/riso/ornament.js +8 -0
- package/dist/riso-zine.css +786 -0
- package/dist/sail/ornament.d.ts +3 -0
- package/dist/sail/ornament.js +8 -0
- package/dist/scrapbook.css +685 -0
- package/dist/signal/ornament.d.ts +4 -0
- package/dist/signal/ornament.js +11 -0
- package/dist/skins/ansi-panes.d.ts +68 -0
- package/dist/skins/ansi-panes.js +68 -0
- package/dist/skins/art-deco.d.ts +68 -0
- package/dist/skins/art-deco.js +68 -0
- package/dist/skins/atomic-lounge.d.ts +68 -0
- package/dist/skins/atomic-lounge.js +68 -0
- package/dist/skins/azulejo-tile.d.ts +68 -0
- package/dist/skins/azulejo-tile.js +68 -0
- package/dist/skins/blueprint.d.ts +68 -0
- package/dist/skins/blueprint.js +68 -0
- package/dist/skins/brutalist-concrete.d.ts +68 -0
- package/dist/skins/brutalist-concrete.js +68 -0
- package/dist/skins/candy-clay.d.ts +57 -0
- package/dist/skins/candy-clay.js +57 -0
- package/dist/skins/diwali-lights.d.ts +68 -0
- package/dist/skins/diwali-lights.js +68 -0
- package/dist/skins/freighter.d.ts +68 -0
- package/dist/skins/freighter.js +68 -0
- package/dist/skins/glass-ui.d.ts +68 -0
- package/dist/skins/glass-ui.js +68 -0
- package/dist/skins/holi-colours.d.ts +68 -0
- package/dist/skins/holi-colours.js +68 -0
- package/dist/skins/living-forest.d.ts +68 -0
- package/dist/skins/living-forest.js +68 -0
- package/dist/skins/lunar-new-year.d.ts +68 -0
- package/dist/skins/lunar-new-year.js +68 -0
- package/dist/skins/material-light.d.ts +57 -0
- package/dist/skins/material-light.js +57 -0
- package/dist/skins/neon-night-market.d.ts +68 -0
- package/dist/skins/neon-night-market.js +68 -0
- package/dist/skins/ocean-depths.d.ts +57 -0
- package/dist/skins/ocean-depths.js +57 -0
- package/dist/skins/orbital-hud.d.ts +68 -0
- package/dist/skins/orbital-hud.js +68 -0
- package/dist/skins/papel-picado.d.ts +68 -0
- package/dist/skins/papel-picado.js +68 -0
- package/dist/skins/phosphor-terminal.d.ts +68 -0
- package/dist/skins/phosphor-terminal.js +68 -0
- package/dist/skins/prism-glass.d.ts +57 -0
- package/dist/skins/prism-glass.js +57 -0
- package/dist/skins/retro-os.d.ts +57 -0
- package/dist/skins/retro-os.js +57 -0
- package/dist/skins/riso-zine.d.ts +68 -0
- package/dist/skins/riso-zine.js +68 -0
- package/dist/skins/scrapbook.d.ts +57 -0
- package/dist/skins/scrapbook.js +57 -0
- package/dist/skins/solar-sail.d.ts +68 -0
- package/dist/skins/solar-sail.js +68 -0
- package/dist/skins/studio-hardware.d.ts +57 -0
- package/dist/skins/studio-hardware.js +57 -0
- package/dist/skins/sumi-ink.d.ts +68 -0
- package/dist/skins/sumi-ink.js +68 -0
- package/dist/skins/swiss-poster.d.ts +68 -0
- package/dist/skins/swiss-poster.js +68 -0
- package/dist/skins/tactile-atelier.d.ts +57 -0
- package/dist/skins/tactile-atelier.js +57 -0
- package/dist/skins/tokyo-transit.d.ts +68 -0
- package/dist/skins/tokyo-transit.js +68 -0
- package/dist/skins/winamp-signal.d.ts +57 -0
- package/dist/skins/winamp-signal.js +57 -0
- package/dist/skins/y2k-titanium.d.ts +57 -0
- package/dist/skins/y2k-titanium.js +57 -0
- package/dist/skins/yule-knit.d.ts +68 -0
- package/dist/skins/yule-knit.js +68 -0
- package/dist/solar-sail.css +901 -0
- package/dist/starters-launch.d.ts +361 -0
- package/dist/starters-launch.js +808 -0
- package/dist/studio-hardware.css +867 -0
- package/dist/sumi/ornament.d.ts +3 -0
- package/dist/sumi/ornament.js +8 -0
- package/dist/sumi-ink.css +733 -0
- package/dist/swiss/ornament.d.ts +3 -0
- package/dist/swiss/ornament.js +8 -0
- package/dist/swiss-poster.css +727 -0
- package/dist/tactile-atelier.css +922 -0
- package/dist/theme-document.schema.json +790 -0
- package/dist/theme-schema.d.ts +453 -0
- package/dist/theme-schema.js +416 -0
- package/dist/titanium/ornament.d.ts +3 -0
- package/dist/titanium/ornament.js +11 -0
- package/dist/tokyo-transit.css +756 -0
- package/dist/transit/ornament.d.ts +3 -0
- package/dist/transit/ornament.js +8 -0
- package/dist/winamp-signal.css +1048 -0
- package/dist/y2k-titanium.css +979 -0
- package/dist/yule/ornament.d.ts +3 -0
- package/dist/yule/ornament.js +8 -0
- package/dist/yule-knit.css +850 -0
- package/package.json +351 -3
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { cssCornerRadius, roundedBorder } from "./organic-geometry.js";
|
|
2
|
+
import { defaultOrganicOrnament, organicFrameRecipes, canopyShapes, stemCharacters, } from "./organic-settings.js";
|
|
3
|
+
const jobs = new Set();
|
|
4
|
+
let frame = 0;
|
|
5
|
+
function tick(now) {
|
|
6
|
+
frame = 0;
|
|
7
|
+
for (const job of [...jobs])
|
|
8
|
+
if (!job(now))
|
|
9
|
+
jobs.delete(job);
|
|
10
|
+
if (jobs.size)
|
|
11
|
+
frame = requestAnimationFrame(tick);
|
|
12
|
+
}
|
|
13
|
+
function schedule(job) {
|
|
14
|
+
jobs.add(job);
|
|
15
|
+
if (!frame)
|
|
16
|
+
frame = requestAnimationFrame(tick);
|
|
17
|
+
}
|
|
18
|
+
function cancel(job) {
|
|
19
|
+
jobs.delete(job);
|
|
20
|
+
if (!jobs.size && frame) {
|
|
21
|
+
cancelAnimationFrame(frame);
|
|
22
|
+
frame = 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// A single stylesheet observer invalidates all mounted frames, including exported CSS changes.
|
|
26
|
+
const styleListeners = new Set();
|
|
27
|
+
let stylesheetObserver;
|
|
28
|
+
function watchStyles(listener) {
|
|
29
|
+
styleListeners.add(listener);
|
|
30
|
+
if (!stylesheetObserver) {
|
|
31
|
+
stylesheetObserver = new MutationObserver(() => styleListeners.forEach((notify) => notify()));
|
|
32
|
+
stylesheetObserver.observe(document.head, {
|
|
33
|
+
childList: true,
|
|
34
|
+
subtree: true,
|
|
35
|
+
characterData: true,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return () => {
|
|
39
|
+
styleListeners.delete(listener);
|
|
40
|
+
if (!styleListeners.size) {
|
|
41
|
+
stylesheetObserver?.disconnect();
|
|
42
|
+
stylesheetObserver = undefined;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Mount only after hydration. Every observer, listener and queued paint is released on disposal. */
|
|
47
|
+
export function mountOrganicCanvas(canvas, kind, painter, instance, animate, motion) {
|
|
48
|
+
const host = canvas.parentElement, surface = host?.parentElement;
|
|
49
|
+
const ctx = canvas.getContext("2d");
|
|
50
|
+
if (!host || !surface || !ctx)
|
|
51
|
+
return () => { };
|
|
52
|
+
const defaults = defaultOrganicOrnament(kind);
|
|
53
|
+
let settings = defaults;
|
|
54
|
+
let colors;
|
|
55
|
+
let width = 0, height = 0, dpr = 1;
|
|
56
|
+
let path = roundedBorder(1, 1, Array.from({ length: 4 }, () => ({ x: 0, y: 0 })));
|
|
57
|
+
let limits = { top: 24, inline: 24, bottom: 24 };
|
|
58
|
+
let shown = defaults.density;
|
|
59
|
+
let initialized = false, visible = true, dirty = true, disposed = false;
|
|
60
|
+
let clock = 0, lastPaint = 0;
|
|
61
|
+
const deadline = performance.now() + 20000;
|
|
62
|
+
const preferences = [
|
|
63
|
+
"(prefers-reduced-motion: reduce)",
|
|
64
|
+
"(prefers-reduced-transparency: reduce)",
|
|
65
|
+
"(prefers-contrast: more)",
|
|
66
|
+
"(forced-colors: active)",
|
|
67
|
+
].map((query) => matchMedia(query));
|
|
68
|
+
const numeric = (style, key, fallback, min, max) => {
|
|
69
|
+
const value = Number.parseFloat(style.getPropertyValue(`--dixy-organic-${key}`));
|
|
70
|
+
return Number.isFinite(value)
|
|
71
|
+
? Math.max(min, Math.min(max, value))
|
|
72
|
+
: fallback;
|
|
73
|
+
};
|
|
74
|
+
function measure() {
|
|
75
|
+
const elementStyle = getComputedStyle(surface), style = getComputedStyle(host);
|
|
76
|
+
width = host.getBoundingClientRect().width;
|
|
77
|
+
height = host.getBoundingClientRect().height;
|
|
78
|
+
path = roundedBorder(width, height, [
|
|
79
|
+
elementStyle.borderTopLeftRadius,
|
|
80
|
+
elementStyle.borderTopRightRadius,
|
|
81
|
+
elementStyle.borderBottomRightRadius,
|
|
82
|
+
elementStyle.borderBottomLeftRadius,
|
|
83
|
+
].map((value) => cssCornerRadius(value, width, height)));
|
|
84
|
+
const px = (value) => Number.parseFloat(value) || 0;
|
|
85
|
+
// Keep the actual authored content insets clear, rather than cutting the leaves with a mask.
|
|
86
|
+
const safe = (key, fallback) => {
|
|
87
|
+
const authored = Number.parseFloat(style.getPropertyValue(`--dixy-skin-frame-safe-${key}`));
|
|
88
|
+
return Number.isFinite(authored)
|
|
89
|
+
? Math.max(6, authored)
|
|
90
|
+
: Math.max(8, fallback - 5);
|
|
91
|
+
};
|
|
92
|
+
limits = {
|
|
93
|
+
top: safe("top", px(elementStyle.paddingTop)),
|
|
94
|
+
inline: safe("inline", Math.min(px(elementStyle.paddingLeft), px(elementStyle.paddingRight))),
|
|
95
|
+
bottom: safe("bottom", px(elementStyle.paddingBottom)),
|
|
96
|
+
};
|
|
97
|
+
const recipe = organicFrameRecipes[kind];
|
|
98
|
+
settings = {
|
|
99
|
+
density: numeric(style, "density", defaults.density, 0, 100),
|
|
100
|
+
cornerDensity: numeric(style, "cornerDensity", defaults.cornerDensity, 0, 100),
|
|
101
|
+
canopyDepth: numeric(style, "canopyDepth", defaults.canopyDepth, 0, 100),
|
|
102
|
+
variation: numeric(style, "variation", defaults.variation, 0, 100),
|
|
103
|
+
scale: numeric(style, "scale", defaults.scale, 10, 32),
|
|
104
|
+
stemWeight: numeric(style, "stemWeight", defaults.stemWeight, 0, 100),
|
|
105
|
+
motion: numeric(style, "motion", defaults.motion, 0, 100),
|
|
106
|
+
seed: Math.round(numeric(style, "seed", defaults.seed, 1, 9999)),
|
|
107
|
+
style: recipe.styles[Math.round(numeric(style, "style", 0, 0, recipe.styles.length - 1))],
|
|
108
|
+
canopy: canopyShapes[Math.round(numeric(style, "canopy", 0, 0, canopyShapes.length - 1))],
|
|
109
|
+
stem: stemCharacters[Math.round(numeric(style, "stem", 0, 0, stemCharacters.length - 1))],
|
|
110
|
+
};
|
|
111
|
+
const ink = (key, fallback) => style.getPropertyValue(`--dixy-organic-${key}`).trim() || fallback;
|
|
112
|
+
colors = {
|
|
113
|
+
a: ink("a", recipe.light[0]),
|
|
114
|
+
b: ink("b", recipe.light[1]),
|
|
115
|
+
c: ink("c", recipe.light[2]),
|
|
116
|
+
d: ink("d", recipe.light[3]),
|
|
117
|
+
paper: elementStyle.backgroundColor,
|
|
118
|
+
line: elementStyle.borderTopColor,
|
|
119
|
+
};
|
|
120
|
+
// Bound backing memory to two million pixels per visible surface; keep CSS geometry exact.
|
|
121
|
+
dpr = Math.min(devicePixelRatio || 1, 2, Math.sqrt(2_000_000 / ((width + 64) * (height + 64))));
|
|
122
|
+
const cw = Math.max(1, Math.round((width + 64) * dpr)), ch = Math.max(1, Math.round((height + 64) * dpr));
|
|
123
|
+
if (canvas.width !== cw)
|
|
124
|
+
canvas.width = cw;
|
|
125
|
+
if (canvas.height !== ch)
|
|
126
|
+
canvas.height = ch;
|
|
127
|
+
if (!initialized) {
|
|
128
|
+
shown = settings.density;
|
|
129
|
+
initialized = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const job = (now) => {
|
|
133
|
+
if (disposed)
|
|
134
|
+
return false;
|
|
135
|
+
const update = dirty;
|
|
136
|
+
if (dirty) {
|
|
137
|
+
measure();
|
|
138
|
+
dirty = false;
|
|
139
|
+
}
|
|
140
|
+
if (!visible || document.hidden || width <= 0 || height <= 0) {
|
|
141
|
+
canvas.removeAttribute("data-running");
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const reduce = motion === "reduced" || preferences.some((query) => query.matches);
|
|
145
|
+
const running = animate &&
|
|
146
|
+
!reduce &&
|
|
147
|
+
settings.motion > 0 &&
|
|
148
|
+
now < deadline &&
|
|
149
|
+
getComputedStyle(canvas).display !== "none";
|
|
150
|
+
if (reduce)
|
|
151
|
+
shown = settings.density;
|
|
152
|
+
const changing = Math.abs(shown - settings.density) > 0.015;
|
|
153
|
+
const elapsed = Math.min(0.05, Math.max(0, (now - lastPaint) / 1000));
|
|
154
|
+
if (!update && (running || changing) && now - lastPaint < 1000 / 30)
|
|
155
|
+
return true;
|
|
156
|
+
if (changing)
|
|
157
|
+
shown += (settings.density - shown) * Math.min(1, elapsed * 9);
|
|
158
|
+
else
|
|
159
|
+
shown = settings.density;
|
|
160
|
+
if (running)
|
|
161
|
+
clock += elapsed;
|
|
162
|
+
lastPaint = now;
|
|
163
|
+
canvas.toggleAttribute("data-running", running);
|
|
164
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
165
|
+
ctx.clearRect(0, 0, width + 64, height + 64);
|
|
166
|
+
ctx.translate(32, 32);
|
|
167
|
+
painter(ctx, path, width, height, settings, colors, clock, running, instance, limits, shown);
|
|
168
|
+
return running || Math.abs(shown - settings.density) > 0.015;
|
|
169
|
+
};
|
|
170
|
+
const refresh = () => {
|
|
171
|
+
if (disposed)
|
|
172
|
+
return;
|
|
173
|
+
dirty = true;
|
|
174
|
+
schedule(job);
|
|
175
|
+
};
|
|
176
|
+
const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(refresh);
|
|
177
|
+
resize?.observe(host);
|
|
178
|
+
const intersection = typeof IntersectionObserver === "undefined"
|
|
179
|
+
? null
|
|
180
|
+
: new IntersectionObserver((entries) => {
|
|
181
|
+
visible = entries.some((entry) => entry.isIntersecting);
|
|
182
|
+
if (visible)
|
|
183
|
+
refresh();
|
|
184
|
+
else {
|
|
185
|
+
cancel(job);
|
|
186
|
+
canvas.removeAttribute("data-running");
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
intersection?.observe(surface);
|
|
190
|
+
const attributes = new MutationObserver(refresh);
|
|
191
|
+
// Every enclosing Theme can contribute appearance or custom CSS variables.
|
|
192
|
+
for (let ancestor = surface; ancestor; ancestor = ancestor.parentElement)
|
|
193
|
+
attributes.observe(ancestor, {
|
|
194
|
+
attributes: true,
|
|
195
|
+
attributeFilter: [
|
|
196
|
+
"style",
|
|
197
|
+
"class",
|
|
198
|
+
"data-appearance",
|
|
199
|
+
"data-motion",
|
|
200
|
+
"data-effects",
|
|
201
|
+
"data-ornament",
|
|
202
|
+
],
|
|
203
|
+
});
|
|
204
|
+
const stopWatching = watchStyles(refresh);
|
|
205
|
+
const visibility = () => {
|
|
206
|
+
if (document.hidden) {
|
|
207
|
+
cancel(job);
|
|
208
|
+
canvas.removeAttribute("data-running");
|
|
209
|
+
}
|
|
210
|
+
else
|
|
211
|
+
refresh();
|
|
212
|
+
};
|
|
213
|
+
document.addEventListener("visibilitychange", visibility);
|
|
214
|
+
window.addEventListener("resize", refresh);
|
|
215
|
+
canvas.addEventListener("contextrestored", refresh);
|
|
216
|
+
preferences.forEach((query) => query.addEventListener("change", refresh));
|
|
217
|
+
refresh();
|
|
218
|
+
return () => {
|
|
219
|
+
disposed = true;
|
|
220
|
+
cancel(job);
|
|
221
|
+
resize?.disconnect();
|
|
222
|
+
intersection?.disconnect();
|
|
223
|
+
attributes.disconnect();
|
|
224
|
+
stopWatching();
|
|
225
|
+
document.removeEventListener("visibilitychange", visibility);
|
|
226
|
+
window.removeEventListener("resize", refresh);
|
|
227
|
+
canvas.removeEventListener("contextrestored", refresh);
|
|
228
|
+
preferences.forEach((query) => query.removeEventListener("change", refresh));
|
|
229
|
+
canvas.removeAttribute("data-running");
|
|
230
|
+
};
|
|
231
|
+
}
|