Skip to content

Commit 244e5d9

Browse files
committed
refac
1 parent 99e2fbe commit 244e5d9

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

docs/tutorials/theming.mdx

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,17 @@ This theme adds a subtle, animated gradient to the background.
166166
}
167167
```
168168

169-
### Example 3: tsParticles Theme
169+
### Animations
170170

171-
This theme uses `tsParticles` to create an interactive particle background. Paste a valid `tsParticles` JSON config into the `tsparticlesConfig` property.
171+
Open WebUI supports two powerful methods for creating dynamic, animated backgrounds for your themes: **tsParticles** for easy-to-configure particle effects, and **Custom Animation Scripts** for full control over a canvas element.
172+
173+
#### Using tsParticles
174+
175+
[tsParticles](https://particles.js.org/) is a lightweight library for creating particle animations. You can create a wide variety of effects, from falling snow to interactive starfields.
176+
177+
To use tsParticles, you need to provide a valid configuration object in the `tsparticlesConfig` property of your `theme.json`. The easiest way to get started is to use the [official tsParticles editor](https://particles.js.org/samples/#twinkle) to create your desired effect and then export the JSON configuration.
178+
179+
Let's break down the `starfield` example:
172180

173181
```json
174182
{
@@ -190,20 +198,68 @@ This theme uses `tsParticles` to create an interactive particle background. Past
190198
}
191199
```
192200

193-
### Example 4: Custom Animation Theme
201+
- **`particles.number`**: Controls the number of particles. `density` makes the number of particles responsive to the screen size.
202+
- **`particles.color`**: Sets the color of the particles.
203+
- **`particles.shape`**: Defines the shape of the particles (e.g., `circle`, `square`, `triangle`).
204+
- **`particles.opacity`**: Controls the transparency of the particles.
205+
- **`particles.size`**: Controls the size of the particles.
206+
- **`particles.move`**: Defines the movement of the particles, including their `speed` and `direction`.
207+
208+
#### Using a Custom Animation Script
209+
210+
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.
211+
212+
**The Web Worker Environment**
213+
214+
Because the script runs in a Web Worker, it has a few unique characteristics:
215+
- It does not have access to the `window` or `document` objects.
216+
- The global scope is `self`.
217+
- It communicates with the main application via messages.
218+
219+
**Receiving Messages**
220+
221+
Your script should include an `onmessage` handler to receive data and events from the main application.
222+
223+
```javascript
224+
self.onmessage = (e) => {
225+
if (e.data.type === 'init') {
226+
// Initialization logic
227+
} else if (e.data.type === 'resize') {
228+
// Resize logic
229+
} else if (e.data.type === 'mousemove') {
230+
// Mouse move logic
231+
}
232+
};
233+
```
234+
235+
- **`init` message**: This is the first message your script will receive. The `e.data` object will contain:
236+
- `canvas`: An `OffscreenCanvas` object that you can draw on.
237+
- `width`: The initial width of the canvas.
238+
- `height`: The initial height of the canvas.
239+
- **`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.
240+
- **`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.
194241

195-
For complete control, you can provide JavaScript for a custom canvas animation. This script runs in a separate worker thread for performance.
242+
### Example 4: The `Matrix Rain` theme
243+
244+
The following is an example of a `Matrix Rain` theme.
196245

197246
```json
198247
{
199248
"id": "matrix-rain",
200249
"name": "Matrix Rain",
201250
"base": "oled-dark",
202251
"emoji": "🔢",
203-
"animationScript": "const canvas = self.canvas; const ctx = canvas.getContext('2d'); let columns; let drops; function setup() { const width = self.width; const height = self.height; canvas.width = width; canvas.height = height; columns = Math.floor(width / 20); drops = []; for (let i = 0; i < columns; i++) { drops[i] = 1; } } function draw() { ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#0F0'; ctx.font = '15px monospace'; for (let i = 0; i < drops.length; i++) { const text = String.fromCharCode(0x30A0 + Math.random() * 96); ctx.fillText(text, i * 20, drops[i] * 20); if (drops[i] * 20 > canvas.height && Math.random() > 0.975) { drops[i] = 0; } drops[i]++; } } self.onmessage = (e) => { if (e.data.type === 'init') { self.canvas = e.data.canvas; setup(); setInterval(draw, 33); } else if (e.data.type === 'resize') { self.width = e.data.width; self.height = e.data.height; setup(); } };"
252+
"css": "#main-container.matrix-rain-bg { background-color: transparent !important; isolation: isolate; position: relative; } #matrix-rain-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; }",
253+
"animationScript": "let animationFrameId;let canvas;let ctx;let columns;let rainDrops=[];const alphabet='アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッンABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';const fontSize=16;const setup=(width,height)=>{if(!canvas)return;canvas.width=width;canvas.height=height;columns=canvas.width/fontSize;rainDrops=[];for(let x=0;x<columns;x++){rainDrops[x]=1}};const draw=()=>{if(!ctx)return;ctx.fillStyle='rgba(0, 0, 0, 0.05)';ctx.fillRect(0,0,canvas.width,canvas.height);ctx.fillStyle='#06F0BF';ctx.font=`${fontSize}px monospace`;for(let i=0;i<rainDrops.length;i++){const text=alphabet.charAt(Math.floor(Math.random()*alphabet.length));ctx.fillText(text,i*fontSize,rainDrops[i]*fontSize);if(rainDrops[i]*fontSize>canvas.height&&Math.random()>0.975){rainDrops[i]=0}rainDrops[i]++}};let lastTime=0;const fps=15;const interval=1000/fps;const animate=(timestamp)=>{if(timestamp-lastTime>interval){draw();lastTime=timestamp}animationFrameId=requestAnimationFrame(animate)};self.onmessage=(event)=>{if(event.data.type==='init'){canvas=event.data.canvas;ctx=canvas.getContext('2d');setup(event.data.width,event.data.height);animate(0)}else if(event.data.type==='resize'){setup(event.data.width,event.data.height)}};"
204254
}
205255
```
206256

257+
- In the `init` handler, the script gets the `canvas` object, calls a `setup()` function, and then kicks off a performant animation loop using `requestAnimationFrame`.
258+
- The `animate` function is throttled to run at a specific FPS (15 frames per second) for efficiency.
259+
- The `draw()` function is where the actual drawing happens, filling the canvas with random characters from a large alphabet to create the Matrix effect.
260+
- The `resize` handler updates the canvas dimensions and re-runs the `setup()` function to adapt the animation to the new size.
261+
- The theme also includes a `css` property to make the main container transparent and correctly position the animation canvas behind all other content.
262+
207263
### Example 5: Background Image Theme
208264

209265
This theme adds a background image to the chat and the overall system.
@@ -223,4 +279,4 @@ This theme adds a background image to the chat and the overall system.
223279

224280
### Sharing Your Theme
225281

226-
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.
282+
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

Comments
 (0)