Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ The full index lives in [`docs/README.md`](docs/README.md). Quick reference:
| `docs/plugin-compat-layer.md` | A chromeless-CSS shim, offset neutralizer, or dock-builder adaptation for a third-party plugin shape is added/changed. |
| `docs/dock-customization.md` | Dock rendering, ordering, or decoration hooks change. |
| `docs/desktop-themes.md` | The desktop-theme manifest format, icon/texture slot lists, value grammar, or fallback semantics change. **Slot names must stay equal on both sides** (`desktop_mode_desktop_theme_icon_slots()` ↔ `src/desktop-themes/slots.ts`). |
| `docs/screen-effects.md` | The canvas stage, the `ScreenEffectDef` contract, shader conventions, or the HTML-in-Canvas browser requirement changes. **`src/stage/` is the implementation; the built-in shaders live in `src/stage/effects/`.** |
| `docs/files-on-desktop.md` | Desktop file/folder behavior, tile metadata, or placement changes. |
| `docs/folder-sharing.md` | Folder-sharing API, ACL model, or REST routes change. |
| `docs/migration-*.md` | A breaking change ships, write a migration note here in the same PR. |
Expand Down
36 changes: 36 additions & 0 deletions assets/css/os-settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -1417,3 +1417,39 @@
font-size: 22px;
line-height: 1;
}

/*
* Experimental tab β€” canvas stage + screen effects.
*
* Each effect is a checkbox with an optional description and, when
* ticked, a stack of parameter sliders. The sliders are indented under
* their checkbox so a chain of several effects still reads as a list of
* effects rather than a wall of controls.
*/
.desktop-mode-experimental__effect {
display: flex;
flex-direction: column;
gap: 6px;
padding-block: 10px;
border-block-start: 1px solid var( --wpd-border-subtle, rgba( 0, 0, 0, 0.08 ) );
}

.desktop-mode-experimental__effect:first-child {
border-block-start: 0;
padding-block-start: 0;
}

.desktop-mode-experimental__hint {
margin: 0;
font-size: 12px;
color: var( --wpd-fg-muted, #50575e );
line-height: 1.5;
}

.desktop-mode-experimental__params {
display: flex;
flex-direction: column;
gap: 10px;
margin-block-start: 4px;
padding-inline-start: 24px;
}
114 changes: 114 additions & 0 deletions assets/css/stage.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Desktop Mode β€” canvas stage.
*
* Styles the `<canvas id="desktop-mode-stage" layoutsubtree>` that
* `src/stage/stage.ts` wraps `#desktop-mode-shell` in when the user
* turns on OS Settings β†’ Experimental β†’ "Render the desktop in a
* canvas".
*
* **Most of the stage's geometry is NOT here.** The canvas's fixed
* placement, its insets, and the shell's `position: absolute; inset: 0`
* are set inline by `_wrap()` in `stage.ts`. That is deliberate: the
* renderer sizes its backing store from `canvas.clientWidth`, so a
* stylesheet that failed to reach the page β€” not enqueued, blocked,
* stale in cache β€” would leave the canvas at its intrinsic size and
* render the entire desktop into a corner at the wrong scale. Layout
* the element cannot function without belongs with the code that
* creates it.
*
* What remains here is the one rule that is genuinely stateful and
* belongs in the cascade: the fullscreen-window override. It needs
* `!important` to beat the inline value.
*/

/*
* Mirrors `body.desktop-mode-has-fullscreen-window .desktop-mode-shell`
* in desktop.css. A fullscreen window hides the admin bar, so the
* canvas has to reclaim those 32px or the desktop would sit below a
* band of the classic admin page.
*
* `!important` because `_wrap()` sets `inset-block-start` inline.
*/
body.desktop-mode-has-fullscreen-window .desktop-mode-stage {
inset-block-start: 0 !important;
}

/*
* Marker class for the shell while it lives inside the canvas.
*
* Carries no geometry of its own β€” `_wrap()` sets `position: absolute`
* and `inset: 0` inline for the reason above. It exists so plugin CSS
* and DevTools can tell a staged shell from a normal one.
*/
.desktop-mode-shell--staged {
z-index: auto;

/*
* NO DROP SHADOWS WHILE THE DESKTOP IS IN THE CANVAS.
*
* A window effect animates a frozen COPY of a window, captured from
* `getBoundingClientRect()` β€” the border box. `box-shadow` paints
* outside that box, so the copy never carries one, and the shadow
* snapped back into existence the moment the real window returned.
*
* Reproducing it in PixiJS is possible (`src/stage/window-fx/shadow.ts`
* still does, if a shadow survives this) but it is an approximation of
* a browser's own blur, and matching it exactly is a losing game. A
* desktop with no drop shadows at all is consistent, which a desktop
* with almost-right ones is not.
*
* Set on the shell rather than `:root` so it is the nearest ancestor
* declaring these tokens: a theme setting them globally is overridden
* for staged windows, while one styling `.desktop-mode-window`
* directly still wins, which is the precedence a theme author would
* expect.
*
* A transparent zero-size shadow rather than `none`, because these
* tokens get COMPOSED into longer shadow lists β€” the linked-window
* halo in `window-links.css` is `0 0 18px 4px <glow>,
* var(--desktop-mode-window-shadow)`. `none` is only valid on its own,
* so substituting it there would invalidate the whole declaration and
* take the halo with it.
*
* Only the tokens, deliberately. `outline` focus rings and the `inset`
* highlights that draw borders and pressed states are untouched β€” they
* are not drop shadows, several are accessibility affordances, and
* none of them extend past the box an effect captures.
*/
--desktop-mode-window-shadow: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-window-shadow-focused: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-dock-floating-shadow: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-tile-shortcut-shadow: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-tile-label-shadow: 0 0 0 rgba(0, 0, 0, 0);
--wpd-ribbon-shadow: 0 0 0 rgba(0, 0, 0, 0);
}

/*
* Inheritance for PROMOTED windows.
*
* While a window effect with a live texture plays, `acquireLiveWindow()`
* moves the window element out of the shell and directly under the
* canvas (the HTML-in-Canvas API only draws direct children). Two
* things the window used to inherit from the shell have to be restated
* on the canvas or the window's recorded image changes mid-effect:
*
* - The shell typeface (`desktop.css` sets it on `.desktop-mode-shell`);
* without it a promoted window's title bar falls back to the admin
* default font for the duration of a drag.
* - The no-drop-shadows tokens declared on `.desktop-mode-shell--staged`
* above β€” the canvas becomes the nearest declaring ancestor for a
* promoted window, so it needs the same values.
*
* The scheme variables get the same treatment in `variables.css`, keyed
* off the `data-desktop-mode-scheme` attribute the stage mirrors from
* the shell.
*/
.desktop-mode-stage {
font-family: var(--desktop-mode-font, inherit);
--desktop-mode-window-shadow: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-window-shadow-focused: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-dock-floating-shadow: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-tile-shortcut-shadow: 0 0 0 rgba(0, 0, 0, 0);
--desktop-mode-tile-label-shadow: 0 0 0 rgba(0, 0, 0, 0);
--wpd-ribbon-shadow: 0 0 0 rgba(0, 0, 0, 0);
}
37 changes: 28 additions & 9 deletions assets/css/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -380,72 +380,91 @@
* from inlining the resulting hex value.
*/

/*
* Each scheme matches the stage canvas too. While a window effect
* plays, `stage.ts` promotes the window to a direct child of
* `<canvas class="desktop-mode-stage">` (its live-texture path), which
* takes it OUT of the shell subtree these variables are scoped to. The
* stage mirrors the shell's `data-desktop-mode-scheme` attribute, so
* listing it here keeps a promoted window's recorded image in the
* user's scheme instead of flashing the defaults mid-effect.
*/

/* Fresh β€” default WP blue. */
.desktop-mode-shell[data-desktop-mode-scheme="fresh"] {
.desktop-mode-shell[data-desktop-mode-scheme="fresh"],
.desktop-mode-stage[data-desktop-mode-scheme="fresh"] {
--wp-admin-theme-color: #2271b1;
/* color-mix(in srgb, #1d2327 80%, #fff 20%) */
--desktop-mode-titlebar-bg-focused: #4a4f52;
--desktop-mode-titlebar-color-focused: #fff;
}

/* Light β€” pale sidebar, teal accent. */
.desktop-mode-shell[data-desktop-mode-scheme="light"] {
.desktop-mode-shell[data-desktop-mode-scheme="light"],
.desktop-mode-stage[data-desktop-mode-scheme="light"] {
--wp-admin-theme-color: #04a4cc;
/* color-mix(in srgb, #e5e5e5 85%, #000 15%) */
--desktop-mode-titlebar-bg-focused: #c3c3c3;
--desktop-mode-titlebar-color-focused: #333;
}

/* Modern β€” vivid indigo accent, near-black sidebar. */
.desktop-mode-shell[data-desktop-mode-scheme="modern"] {
.desktop-mode-shell[data-desktop-mode-scheme="modern"],
.desktop-mode-stage[data-desktop-mode-scheme="modern"] {
--wp-admin-theme-color: #3858e9;
/* color-mix(in srgb, #1e1e1e 78%, #fff 22%) */
--desktop-mode-titlebar-bg-focused: #505050;
--desktop-mode-titlebar-color-focused: #f3f1f1;
}

/* Blue. */
.desktop-mode-shell[data-desktop-mode-scheme="blue"] {
.desktop-mode-shell[data-desktop-mode-scheme="blue"],
.desktop-mode-stage[data-desktop-mode-scheme="blue"] {
--wp-admin-theme-color: #096484;
/* color-mix(in srgb, #096484 82%, #fff 18%) */
--desktop-mode-titlebar-bg-focused: #35809a;
--desktop-mode-titlebar-color-focused: #e5f8ff;
}

/* Coffee. */
.desktop-mode-shell[data-desktop-mode-scheme="coffee"] {
.desktop-mode-shell[data-desktop-mode-scheme="coffee"],
.desktop-mode-stage[data-desktop-mode-scheme="coffee"] {
--wp-admin-theme-color: #c7a589;
/* color-mix(in srgb, #46403c 80%, #fff 20%) */
--desktop-mode-titlebar-bg-focused: #6b6663;
--desktop-mode-titlebar-color-focused: #ece6f6;
}

/* Ectoplasm. */
.desktop-mode-shell[data-desktop-mode-scheme="ectoplasm"] {
.desktop-mode-shell[data-desktop-mode-scheme="ectoplasm"],
.desktop-mode-stage[data-desktop-mode-scheme="ectoplasm"] {
--wp-admin-theme-color: #a3b745;
/* color-mix(in srgb, #413256 80%, #fff 20%) */
--desktop-mode-titlebar-bg-focused: #675b78;
--desktop-mode-titlebar-color-focused: #ece6f6;
}

/* Midnight. */
.desktop-mode-shell[data-desktop-mode-scheme="midnight"] {
.desktop-mode-shell[data-desktop-mode-scheme="midnight"],
.desktop-mode-stage[data-desktop-mode-scheme="midnight"] {
--wp-admin-theme-color: #e14d43;
/* color-mix(in srgb, #25282b 80%, #fff 20%) */
--desktop-mode-titlebar-bg-focused: #515355;
--desktop-mode-titlebar-color-focused: #f1f2f3;
}

/* Ocean. */
.desktop-mode-shell[data-desktop-mode-scheme="ocean"] {
.desktop-mode-shell[data-desktop-mode-scheme="ocean"],
.desktop-mode-stage[data-desktop-mode-scheme="ocean"] {
--wp-admin-theme-color: #9ebaa0;
/* color-mix(in srgb, #627c83 80%, #fff 20%) */
--desktop-mode-titlebar-bg-focused: #81969c;
--desktop-mode-titlebar-color-focused: #f2fcff;
}

/* Sunrise. */
.desktop-mode-shell[data-desktop-mode-scheme="sunrise"] {
.desktop-mode-shell[data-desktop-mode-scheme="sunrise"],
.desktop-mode-stage[data-desktop-mode-scheme="sunrise"] {
--wp-admin-theme-color: #dd823b;
/* color-mix(in srgb, #b43c38 80%, #fff 20%) */
--desktop-mode-titlebar-bg-focused: #c36360;
Expand Down
8 changes: 8 additions & 0 deletions assets/vendor/pixi-html-source.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

192 changes: 96 additions & 96 deletions assets/vendor/pixi.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions desktop-mode.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ function desktop_mode_request_needs_admin_modules() {
require_once DESKTOP_MODE_DIR . 'includes/dock-rail-renderer.php';
require_once DESKTOP_MODE_DIR . 'includes/title-bar-buttons.php';
require_once DESKTOP_MODE_DIR . 'includes/unfocus-effects.php';
require_once DESKTOP_MODE_DIR . 'includes/screen-effects.php';
require_once DESKTOP_MODE_DIR . 'includes/window-links.php';
require_once DESKTOP_MODE_DIR . 'includes/window-chrome.php';
require_once DESKTOP_MODE_DIR . 'includes/window-notices.php';
Expand Down
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ If you are **building a plugin** that interacts with the desktop shell β€” opens
11. **[Plugin Compatibility Layer](./plugin-compat-layer.md)** β€” *internals doc.* How Desktop Mode adapts third-party plugins (WooCommerce, Yoast, etc.) whose CSS or menu-registration assumes classic admin chrome. The three-tier mental model β€” CSS variables β†’ runtime offset scanner β†’ targeted overrides β€” and the decision tree for adding a new fix. Read before touching `chromeless.css` or the dock builder for plugin-specific work.
12. **[Files on the Desktop](./files-on-desktop.md)** β€” *Experimental (since 0.9.0).* `Desktop_Mode_File` base class, `desktop_mode_register_file_type()`, and `wp.desktop.files.*`. Phase-0 registry only today; folders, opener associations, sharing, and drag-from-Recycle-Bin land in subsequent phases.
13. **[Desktop Themes](./desktop-themes.md)** β€” *Experimental (since 0.9.7).* Whole-OS reskins uploaded as a ZIP of `theme.json` plus images and fonts: every design token, the typeface, a texture on any of 22 surfaces (chrome, dock, desk, menus, dialogs, tables, buttons) plus a documented way to add your own, and a complete iconset down to the window control glyphs. No author CSS or JS ever executes β€” PHP validates the manifest and compiles the stylesheet, `@font-face` rules included. Read before authoring a theme, or before touching the texture and typography tokens in `variables.css`. See also [examples/register-desktop-theme.md](./examples/register-desktop-theme.md).

13. **[Screen Effects & the Canvas Stage](./screen-effects.md)** β€” *Experimental (since 0.9.8).* The whole desktop rendered inside a `<canvas layoutsubtree>` through the WICG HTML-in-Canvas API, with PixiJS fragment shaders over it β€” scanlines, a CRT tube, pixel art, and a registry for your own. The DOM underneath stays live, hit-tested and accessible; only the pixels take a detour through the GPU. Chrome 148+ behind a flag, no fallback. Read before writing a shader or touching `src/stage/`. See also [examples/register-screen-effect.md](./examples/register-screen-effect.md).
13. **[Folder Sharing](./folder-sharing.md)** β€” *Experimental (since 0.18.0).* Per-principal read / write grants on desktop folders with first-sight opt-in, polymorphic `target_type` schema, If-Match conflict detection, and a `<wpd-modal>`-based Share Settings UI.
13. **[Progressive Web App (PWA)](./pwa.md)** β€” *Stable (since 0.8.0).* Web app manifest, service worker (root-scope, narrow fetch handler), install affordance, and `wp.desktop.notify()` for local notifications. Phase-4 Web Push wiring lands later without breaking the v1 call surface.
14. **[Migration 0.7 β†’ 0.8.1](./migration-0.7-to-0.8.1.md)** β€” what landed in the architecture-0.8.1 refactor: the `@core` / `@api` / `@protocol` / `@layout` / `@ui` path aliases, the registry / server-sync / api-client primitives, the public-API facade home, and the PHP slicing of `helpers.php` / `components.php` / `render.php`. Read once before adopting any of the new modules in your plugin.
Expand Down
Loading