Skip to content

Build panels

Testing and debugging

Three ways to run a panel while you build it: a folder loaded in Deska, a dev server on localhost, and the preview tool from the examples repository. Plus the checks, the browser tools, and the failures people hit most.

Load a folder in Deska

Open the Panel Library (Cmd/CtrlShiftE), go to Community, then Build a panel, and choose Load a folder. Pick the folder that holds panel.json. This is the runtime your panel ships to, so every panel should pass here before it is published.

  • Deska checks the folder with the same rules deska.dev uses, and lists every problem on the folder’s page under What to fix.
  • It serves the folder with the same policy as an installed package and reloads the panel whenever a file changes, a moment after you save.
  • The panel holds exactly the permissions its panel.json asks for, as it will once people allow them. The folder’s page shows what they will be asked.
  • It keeps its own storage and files, apart from any installed version of the same panel, and init.panel.dev is true.
  • Load the folder panel.json is in. A folder of 5,000 files or more, like a project root with its node_modules, is refused and never watched.
  • A loaded folder is never pinned, synced to your account or published as it is.

A dev server on localhost

Running Vite or another dev server with hot reload? In Build a panel, under A page on localhost, enter its address, like http://localhost:5173. Only localhost and 127.0.0.1, over http or https, are accepted.

Heads upA page on localhost runs under looser rules than your panel will. Deska does not serve it, so its policy and page guard do not apply: it can reach any host and load remote scripts and styles. It also holds every permission, has no panel.json, and gets no Extras row. Something that works there can fail once packaged. Build the folder and load it with Load a folder before you publish.

The frame is still sandboxed: no localStorage, the same focus rules, links through deska.openUrl. Load /__deska/sdk.js from your own dev server: copy the preview tool’s tools/preview/sdk.js into your public folder: it is a copy of the SDK Deska serves.

The preview tool

The examples repository has a preview host that runs a panel in your own browser, next to your editor. It needs Node 20 or later.

sh
git clone https://github.com/0xPasho/deska-panels-examples.git
cd deska-panels-examples
npm install
npm run preview -- path/to/my-panel

Open the address it prints (http://127.0.0.1:5170/ by default). The preview:

  • serves each panel on an origin of its own with the same Content-Security-Policy and sandbox as Deska, and the SDK at /__deska/sdk.js;
  • plays Deska’s side of the bridge: theme, visibility, storage, files, notify, links, clipboard and the Extras row, with Deska’s limits, so a call Deska would refuse is refused here too;
  • lets you switch the theme (dark or light), the place (desk or Extras), visibility and idle, reload the panel and clear its storage;
  • logs every call and its answer in a bridge log beside the panel.
NoteThe preview is a stand-in to build fast. It does not run Deska’s page guard or its focus rules, and its theme values are its own. Load the folder in Deska before you publish.

Checks from the command line

sh
npm run preview -- panels/team-clocks   # one panel, several, or none for all
npm run preview -- panels/net-radio --port 5300
npm run validate                        # Deska's package checks on every folder in panels/
npm run check                           # the checks, then a headless load in dark and light
npm run check -- team-clocks            # one panel from panels/
  • validate runs Deska’s package checks on every folder in panels/, without a browser, prints each folder’s problems and fails when any folder is refused.
  • check runs the checks, then loads each panel headless in the preview, in dark and light (and in Extras when it has a row). It fails on a console error, a policy violation, a page that never calls deska.ready(), or a refused call, and writes screenshots to docs/screenshots/preview/.
  • Both look in panels/. To check your own panel with them, put its folder there in your clone; preview takes any path.

Console and browser tools

In the preview, open your browser’s developer tools. The panel is a normal frame there: pick it in the console’s context menu to run code in it, watch its requests in the network tab, and read policy violations, which name the directive that refused something (connect-src for a host you did not declare, script-src for a remote script or eval).

  • Log refusals by code: console.warn(err.code) in every catch turns a silent failure into a line you can read.
  • Keep SDK Playground loaded next to your panel to try a call by hand and see exactly what Deska answers.
  • Test the states people will meet: offline, a slow host, an empty first run, storage full, the panel hidden and shown again, reloaded mid task, both themes, and the Extras page if you have one.

Common failures

What you seeWhyFix
deska is not definedYour script ran before the SDK.Load /__deska/sdk.js as a classic script first, your code as a module or after it.
ready() never resolvesThe page is open outside Deska and the preview, or the SDK tag points elsewhere.Run it in Deska or the preview; the path is exactly /__deska/sdk.js.
Failed to fetchThe host is not in network, the address is http, or the API does not allow any origin.Declare the exact host, use https, and pick an API that answers Access-Control-Allow-Origin: *.
An image, font or video does not showIts host is not declared, or it is a remote stylesheet.Declare the host; ship fonts as woff2 in the package.
SecurityError on localStorageThe sandbox has an opaque origin.deska.storage
A library fails with a policy error about evalCode built from text at run time is refused.Use the library’s precompiled build.
The panel says it was disconnectedA link, a form or a location change navigated the frame.deska.openUrl for links, preventDefault() on submit, then Reload.
not_focused from openUrl or clipboard.writeCalled from a timer or after a slow await.Call it in the click handler, first.
A download link (<a download>) does nothingThe sandbox refuses downloads.Save the file with deska.files.save from the click.
The first click does nothingOn the canvas, the first click focuses the panel.Expected. The next click reaches the page.
invalid_args from setTitlenull, an empty string or more than 60 characters.Shorten it, or set init.panel.name to clear it.
permission_denied from extras.setpanel.json has no contributes.extras.Declare it, then reload the folder.
State is gone after moving the panelMoving, docking and updating reload the page.Keep state in deska.storage and rebuild from it.
Sound will not start after a reloadAudio needs a press in the panel first.Show a play button when play() is refused.
It works on localhost and fails as a folderLocalhost pages skip the policy.Fix what the folder’s policy errors name.
The folder is refused as too bigIt holds 5,000 files or more, like node_modules.Load the folder with panel.json, with only what the panel ships.

Next

When the folder passes in Deska and looks right in both themes, read Publishing.