From 1ddaab325e916fde1cd6156858f18cdda06b46f8 Mon Sep 17 00:00:00 2001 From: CodeDevMLH <145071728+CodeDevMLH@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:10:19 +0100 Subject: [PATCH] Update CONTRIBUTING.md for clarity and consistency in theme development guidelines --- CONTRIBUTING.md | 63 ++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c000aa8..4b5954a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ The orchestrator file `seasonals.js` manages theme loading at runtime. It reads ## Standard Theme File Structure -Here is the complete file layout for a theme called `mytheme`: +Here is a complete file layout for a theme called `mytheme`: ``` Jellyfin.Plugin.Seasonals/ @@ -65,7 +65,7 @@ Jellyfin.Plugin.Seasonals/ Every theme JS file follows a **consistent skeleton**. Use this as your starting template: ```javascript -// ── 1. Read Configuration ────────────────────────────────────────── +// 1. Read Configuration const config = window.SeasonalsPluginConfig?.MyTheme || {}; const enabled = config.EnableMyTheme !== undefined ? config.EnableMyTheme : true; @@ -74,8 +74,8 @@ const elementCount = config.ElementCount || 25; let msgPrinted = false; -// ── 2. Toggle Function ──────────────────────────────────────────── -// Hides the effect when a video player, trailer, dashboard, or user menu is active. +// 2. Toggle Function +// Hides the effect when a video player, trailer (in full width mode), dashboard, or user menu is active. function toggleMyTheme() { const container = document.querySelector('.mytheme-container'); if (!container) return; @@ -100,7 +100,7 @@ function toggleMyTheme() { } } -// ── 3. MutationObserver ──────────────────────────────────────────── +// 3. MutationObserver // Watches the DOM for changes so the effect can auto-hide/show. const observer = new MutationObserver(toggleMyTheme); observer.observe(document.body, { @@ -109,7 +109,7 @@ observer.observe(document.body, { attributes: true }); -// ── 4. Element Creation ──────────────────────────────────────────── +// 4. Element Creation // Create and append your animated elements to the container. function createElements() { const container = document.querySelector('.mytheme-container') || document.createElement('div'); @@ -140,7 +140,7 @@ function createElements() { } } -// ── 5. Initialization ───────────────────────────────────────────── +// 5. Initialization function initializeMyTheme() { if (!enabled) return; createElements(); @@ -153,9 +153,9 @@ initializeMyTheme(); ### Key Rules - **Always** read config from `window.SeasonalsPluginConfig?.{ThemeName}`. -- **Always** implement the toggle function with the same selectors (`.videoPlayerContainer`, `.youtubePlayerContainer`, `.dashboardDocument`, `#app-user-menu`). +- **Always** implement the toggle function with the same selectors (`.videoPlayerContainer`, `.youtubePlayerContainer`, `.dashboardDocument`, `#app-user-menu`, just use the above template). - **Always** use `aria-hidden="true"` on the container for accessibility. -- **Always** call your `initialize` function at the end of the file. +- Call your `initialize` function at the end of the file. - For **canvas-based** themes (like `snowfall.js`), use a `` element with `requestAnimationFrame` instead of CSS animations. Make sure to clean up with `cancelAnimationFrame` when hidden. --- @@ -165,7 +165,7 @@ initializeMyTheme(); Every theme CSS file follows this structure: ```css -/* ── Container ──────────────────────────────────────────────────── */ +/* Container */ /* Full-screen overlay, transparent, non-interactive */ .mytheme-container { display: block; @@ -179,7 +179,7 @@ Every theme CSS file follows this structure: z-index: 10; } -/* ── Animated Element ───────────────────────────────────────────── */ +/* Animated Element */ .mytheme-element { position: fixed; z-index: 15; @@ -193,7 +193,7 @@ Every theme CSS file follows this structure: animation-iteration-count: infinite, infinite; } -/* ── Keyframes ──────────────────────────────────────────────────── */ +/* Keyframes */ @keyframes mytheme-fall { 0% { top: -10%; } 100% { top: 100%; } @@ -204,7 +204,7 @@ Every theme CSS file follows this structure: 50% { transform: translateX(80px); } } -/* ── Staggered Delays for Base Elements ─────────────────────────── */ +/* Staggered Delays for Base Elements */ /* Spread the initial 12 elements across the screen */ .mytheme-element:nth-of-type(1) { left: 10%; animation-delay: 1s, 1s; } .mytheme-element:nth-of-type(2) { left: 20%; animation-delay: 6s, 0.5s; } @@ -214,9 +214,9 @@ Every theme CSS file follows this structure: ### Key Rules -- **Container** must be `position: fixed`, full-screen, with `pointer-events: none` and `z-index: 10`. -- **Elements** should use `position: fixed` with `z-index: 15`. -- Use **two animations** (primary movement + secondary effect) for natural-looking motion. +- **Container** must be `position: fixed`, full-screen, with `pointer-events: none` and at least `z-index: 10`. +- **Elements** should use `position: fixed` with at least `z-index: 15`. +- Use **animations** (eg. primary movement + secondary effect for natural-looking motion). - Include **`nth-of-type` rules** for the initial set of base elements to stagger them. - Include **webkit prefixes** (`-webkit-animation-*`, `@-webkit-keyframes`) for broader compatibility (see existing themes for examples). @@ -224,7 +224,7 @@ Every theme CSS file follows this structure: ## Image Assets (Optional) -If your theme uses image sprites (e.g., leaves, ghosts, eggs): +If your theme uses images (e.g., leaves, ghosts, eggs): 1. Create a folder: `Jellyfin.Plugin.Seasonals/Web/{themeName}_images/` 2. Place your assets inside (PNG recommended, keep files small) @@ -232,11 +232,6 @@ If your theme uses image sprites (e.g., leaves, ghosts, eggs): ```javascript img.src = '../Seasonals/Resources/mytheme_images/sprite1.png'; ``` -4. For local testing, you can reference them directly: - ```javascript - img.src = './mytheme_images/sprite1.png'; - ``` - --- ## Registering Your Theme @@ -264,7 +259,7 @@ const ThemeConfigs = { > [!NOTE] > The backend registration is handled by the plugin maintainers. You do **not** need to modify C# files for your theme submission. Just focus on the JS/CSS/images. > -> However, if you'd like to include full backend integration, add your theme to the enum/configuration in `Configuration/PluginConfiguration.cs`. +> However, if you'd like to include full backend integration, add your theme to the enum/configuration in `Configuration/PluginConfiguration.cs` and the selectors in `configPage.html`. --- @@ -275,19 +270,18 @@ You can test your theme without a Jellyfin server by using the included test sit ### Steps 1. Navigate to the `Jellyfin.Plugin.Seasonals/Web/` directory -2. Open `test-site-new.html` in your browser (just double-click the file) +2. Open `test-site.html` in your browser (just double-click the file) or vscode or what ever you use... 3. Use the **theme selector dropdown** to pick an existing theme or select **"Custom (Local Files)"** to test your own -4. When "Custom" is selected, enter your theme's JS and CSS filenames (e.g., `mytheme.js` and `mytheme.css`) +4. When "Custom" is selected, enter your theme's JS and CSS filenames (e.g., `mytheme.js` and `mytheme.css` (must be in the same folder as `test-site.html` for this to work)) 5. Click **"Load Theme"** to apply. Click **"Clear & Reload"** to reset and try again ### What to Verify -- ✅ The effect is visible on the dark background -- ✅ The animation runs smoothly without jank +- ✅ The effect is visible on the background +- ✅ The animation runs smoothly - ✅ Elements are spread across the full viewport - ✅ The mock header is **not blocked** by the effect (thanks to `pointer-events: none`) -- ✅ Performance is acceptable (check DevTools → Performance tab) -- ✅ No console errors appear (check DevTools → Console) +- ✅ No theme related console errors appear (check DevTools → Console) --- @@ -299,8 +293,8 @@ You can test your theme without a Jellyfin server by using the included test sit - [ ] Created `{themeName}.css` following the [CSS pattern](#css-file-pattern) - [ ] (If applicable) Created `{themeName}_images/` with optimized assets - [ ] Added theme to `ThemeConfigs` in `seasonals.js` -- [ ] Tested locally with `test-site-new.html` -- [ ] No console errors +- [ ] Tested locally with `test-site.html` +- [ ] No theme related console errors - [ ] Effect has `pointer-events: none` (doesn't block the UI) - [ ] Effect hides during video/trailer playback (toggle function implemented) - [ ] (Optional) Included a screenshot or short recording of the effect to the readme @@ -312,13 +306,8 @@ You can test your theme without a Jellyfin server by using the included test sit **Description:** Brief description of the theme and what occasion/season it's for. -**Files Added:** -- `{themeName}.js` -- `{themeName}.css` -- `{themeName}_images/` (if applicable) - **Screenshot / Recording:** -[Attach a screenshot or GIF here] +[Attach a screenshot or GIF showcasing the theme in action] **Testing:** - Tested locally with test-site-new.html ✅