You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An updated and more comprehensive section on using custom animation scripts, including a guide for converting standard JavaScript animations to be compatible with the Open WebUI theme engine.
@@ -125,7 +125,7 @@ Here are the available toggles:
125
125
126
126
### CodeMirror Themes
127
127
128
-
You can customize the appearance of the code editor in Open WebUI by specifying a CodeMirror theme in the `codeMirrorTheme` property of your `theme.json`. A wide variety of themes are available to choose from.
128
+
You can customize the appearance of the code editor in Open WebUI by specifying a `codeMirrorTheme` property of your `theme.json`. A wide variety of themes are available to choose from.
129
129
130
130
Here is a list of the available CodeMirror themes:
131
131
@@ -288,37 +288,152 @@ Let's break down the `starfield` example:
288
288
289
289
#### Using a Custom Animation Script
290
290
291
-
For complete control over your theme's animation, you can provide a JavaScript script in the `animationScript` property. This script runs in a separate Web Worker to ensure the main application remains responsive.
291
+
This section provides a step-by-step guide on how to convert a standard JavaScript canvas animation into a format that is compatible with the Open WebUI theme system.
292
292
293
-
**The Web Worker Environment**
293
+
##### Understanding the Open WebUI Theme Engine
294
294
295
-
Because the script runs in a Web Worker, it has a few unique characteristics:
296
-
- It does not have access to the `window` or `document` objects.
297
-
- The global scope is `self`.
298
-
- It communicates with the main application via messages.
295
+
The Open WebUI theme engine runs custom animation scripts in a **Web Worker**. This is a crucial point to understand, as it imposes several restrictions on the code you can write.
299
296
300
-
**Receiving Messages**
297
+
**Key characteristics of the Web Worker environment:**
301
298
302
-
Your script should include an `onmessage` handler to receive data and events from the main application.
299
+
***No DOM Access:** You do not have access to the `document` or `window` objects. This means you cannot create or manipulate DOM elements (like `<canvas>`) directly from the animation script.
300
+
***Communication via Messaging:** The only way to communicate between the main application and the animation script (the worker) is through the `self.onmessage` and `postMessage` APIs.
301
+
***Canvas is an `OffscreenCanvas`:** The main application will create a `<canvas>` element and transfer it to the worker as an `OffscreenCanvas`. You will receive this canvas object in the `init` message.
302
+
303
+
##### The Conversion Process
304
+
305
+
Here is a step-by-step guide to converting a typical JavaScript canvas animation.
306
+
307
+
###### 1. Identify and Isolate the Core Animation Logic
308
+
309
+
Most canvas animations have the following components:
310
+
311
+
***Setup/Initialization Code:** This code runs once at the beginning to set up the canvas, create initial objects, etc. In a typical script, this might be at the top level of the script.
312
+
***Animation Loop:** This is a function that is called repeatedly to draw each frame of the animation. It usually uses `requestAnimationFrame` or `setTimeout`.
313
+
***Helper Functions:** These are utility functions for things like math, color manipulation, etc.
314
+
***Object Definitions:** These are classes or constructor functions for the objects in the animation (e.g., `Particle`).
315
+
***Event Listeners:** These are functions that respond to user input, like `mousemove` or `resize`.
316
+
317
+
Your goal is to separate these components and adapt them to the worker environment.
318
+
319
+
###### 2. Adapt the Code for the Worker Environment
320
+
321
+
Here is a template for a converted animation script. You will need to move the code from the original script into the appropriate sections of this template.
303
322
304
323
```javascript
305
-
self.onmessage= (e) => {
324
+
// 1. Paste all helper functions and object definitions here.
325
+
// (e.g., randomIntFromRange, Particle, etc.)
326
+
327
+
// 2. Define global variables for the worker script.
328
+
let canvas;
329
+
let ctx;
330
+
let w, h;
331
+
// ... any other global variables your animation needs
332
+
333
+
// 3. The main message handler for the worker.
334
+
self.onmessage=function(e) {
306
335
if (e.data.type==='init') {
307
-
// Initialization logic
336
+
// This is where the setup/initialization code goes.
337
+
canvas =e.data.canvas;
338
+
ctx =canvas.getContext('2d');
339
+
w =canvas.width=e.data.width;
340
+
h =canvas.height=e.data.height;
341
+
342
+
// Call your initialization function here.
343
+
init();
344
+
// Start the animation loop.
345
+
animate();
346
+
308
347
} elseif (e.data.type==='resize') {
309
-
// Resize logic
348
+
// This is where the resize handling code goes.
349
+
w =canvas.width=e.data.width;
350
+
h =canvas.height=e.data.height;
351
+
// You might need to re-initialize your animation on resize.
352
+
init();
353
+
310
354
} elseif (e.data.type==='mousemove') {
311
-
// Mouse move logic
355
+
// This is where the mouse move handling code goes.
356
+
// Update your mouse coordinates object here.
357
+
mouse.x=e.data.x;
358
+
mouse.y=e.data.y;
312
359
}
313
360
};
361
+
362
+
// 4. Your initialization function.
363
+
functioninit() {
364
+
// ... your init code here ...
365
+
}
366
+
367
+
// 5. Your animation loop.
368
+
functionanimate() {
369
+
// ... your drawing code here ...
370
+
requestAnimationFrame(animate);
371
+
}
372
+
```
373
+
374
+
###### 3. Conversion Checklist
375
+
376
+
Here is a checklist of common things to look for and change in the original script:
377
+
378
+
***`document.querySelector('canvas')` or `document.getElementById('canvas')`:** Remove these lines. The canvas is provided to you.
379
+
***`canvas.getContext('2d')`:** Move this line inside the `init` message handler.
380
+
***`canvas.width = window.innerWidth` and `canvas.height = window.innerHeight`:** Remove these lines from the top level of the script. The canvas dimensions are provided in the `init` and `resize` messages.
381
+
***`addEventListener('mousemove', ...)` and `addEventListener('resize', ...)`:** Remove these event listeners. This functionality is now handled by the `self.onmessage` handler.
382
+
***`requestAnimationFrame(animate)` or `setTimeout(animate, ...)`:** Make sure the animation loop is started by calling `animate()` once from within the `init` message handler. The loop itself should use `requestAnimationFrame(animate)`.
383
+
***Global variables:** Make sure any global variables from the original script are defined at the top level of your worker script (outside the `self.onmessage` handler).
384
+
385
+
###### Example: Before and After
386
+
387
+
Here is an example of a simple animation before and after conversion.
388
+
389
+
**Before:**
390
+
```javascript
391
+
constcanvas=document.querySelector('canvas');
392
+
constctx=canvas.getContext('2d');
393
+
canvas.width=window.innerWidth;
394
+
canvas.height=window.innerHeight;
395
+
396
+
let x =0;
397
+
398
+
functionanimate() {
399
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
400
+
ctx.fillRect(x, 100, 50, 50);
401
+
x +=1;
402
+
requestAnimationFrame(animate);
403
+
}
404
+
405
+
animate();
406
+
```
407
+
408
+
**After:**
409
+
```javascript
410
+
let canvas;
411
+
let ctx;
412
+
let w, h;
413
+
let x =0;
414
+
415
+
self.onmessage=function(e) {
416
+
if (e.data.type==='init') {
417
+
canvas =e.data.canvas;
418
+
ctx =canvas.getContext('2d');
419
+
w =canvas.width=e.data.width;
420
+
h =canvas.height=e.data.height;
421
+
animate();
422
+
}
423
+
};
424
+
425
+
functionanimate() {
426
+
ctx.clearRect(0, 0, w, h);
427
+
ctx.fillRect(x, 100, 50, 50);
428
+
x +=1;
429
+
if (x > w) {
430
+
x =0;
431
+
}
432
+
requestAnimationFrame(animate);
433
+
}
314
434
```
315
435
316
-
-**`init` message**: This is the first message your script will receive. The `e.data` object will contain:
317
-
-`canvas`: An `OffscreenCanvas` object that you can draw on.
318
-
-`width`: The initial width of the canvas.
319
-
-`height`: The initial height of the canvas.
320
-
-**`resize` message**: This message is sent whenever the application window is resized. The `e.data` object will contain the new `width` and `height`. You should use this to update your animation's dimensions.
321
-
-**`mousemove` message**: This message is sent when the user moves their mouse over the application. The `e.data` object will contain the `x` and `y` coordinates of the mouse relative to the canvas.
436
+
By following these instructions, you should be able to convert most JavaScript canvas animations to work with the Open WebUI theme system.
322
437
323
438
### Example 4: The `Matrix Rain` theme
324
439
@@ -360,4 +475,4 @@ This theme adds a background image to the chat and the overall system.
360
475
361
476
### Sharing Your Theme
362
477
363
-
To make your theme easily shareable and updatable, host the `theme.json` file somewhere with a raw file link (like GitHub Gist or a public repository) and set the `sourceUrl` property to that link. This allows others to install your theme with one click and receive updates automatically.
478
+
To make your theme easily shareable and updatable, host the `theme.json` file somewhere with a raw file link (like GitHub Gist or a public repository) and set the `sourceUrl` property to that link. This allows others to install your theme with one click and receive updates automatically.
0 commit comments