Skip to content

JollyPixel

💡 About ​

Lit components for building editor interfaces: fields, panels, docks, dialogs, trees and more. The JollyPixel editors are built with it, with light and dark themes and live collaboration included.

💃 Getting Started ​

This package is available in the Node Package Repository and can be easily installed with npm or yarn.

bash
$ npm i @jolly-pixel/ui
# or
$ yarn add @jolly-pixel/ui

IMPORTANT

lit is a peer dependency. Use one compatible copy in the application.

📖 Guides ​

Start with Getting started, then pick the task at hand.

Fields:

Panels and shell:

Collaboration and debugging:

📚 API ​

Each element registers when its own entry point is imported: @jolly-pixel/ui/elements/<name>, where <name> is the tag without jolly-. That entry also exports the element class, and the elements it renders register with it. The root entry point registers no element: it exports the element types, the theme, the controllers and the helpers. The facade and its types live in @jolly-pixel/ui/facade, and the network adapters in @jolly-pixel/ui/network.

ts
import "@jolly-pixel/ui/elements/tree";
import { Dialog } from "@jolly-pixel/ui/elements/dialog";
import type { TreeNode } from "@jolly-pixel/ui";

Import the element in the module whose template renders it, not once at the application entry: a lazily loaded panel then brings its own elements, and nothing else loads them. In this repository the @jolly-pixel/import-rendered-elements lint rule enforces it.

Each element page lists its properties, events and slots. A property marked property only has no HTML attribute.

Components ​

Each entry gives the HTML tag, then the class name.

Controls ​

Field controls share the field API. Building an inspector maps values to controls.

Math fields ​

The vector, quaternion and transform fields take structural values and do not depend on Three.js.

Containers ​

Editor layout and Dialogs cover how they fit together.

The root entry point also exports DockAlign, DockSide, DockSlot, RailOrientation, TabsOrientation and ToolbarOrientation.

Data ​

Feedback ​

Icons ​

The registry comes from the root entry point. The built-in glyphs register with jolly-icon.

ts
import { Icon } from "@jolly-pixel/ui/elements/icon";
import {
  getIcon,
  hasIcon,
  registerIcon
} from "@jolly-pixel/ui";
  • jolly-icon (Icon)
  • Icon registry: registers application glyphs and exposes them to Lit templates. BuiltinIconName, IconName and IconGlyph describe the accepted names and glyphs.

Monitors ​

Stats ​

Peer presence ​

Theme ​

Theming and density covers scope setup.

Facade ​

The facade builds the components from JavaScript and binds them to object properties. Debug panels walks through a panel.

ts
import {
  DockFacade,
  Pane
} from "@jolly-pixel/ui/facade";

The facade registers every element it can create, and exports its own types.

Headless APIs ​

Classes, ports and functions that register no element.

Storage ​

  • StorageAdapter: the port stateful components persist through, with LocalStorageAdapter and MemoryStorageAdapter.

Interaction ​

Stats recording ​

Recording is separate from rendering, and @jolly-pixel/ui/stats loads no element:

ts
import {
  StatsRecorder,
  resolveMetricFormat,
  resolveMetricRange,
  type MetricDefinition,
  type MetricSource
} from "@jolly-pixel/ui/stats";
  • StatsRecorder: a DOM-free frame and metric recorder.
  • Metric definitions: aggregation, formatting and graph bounds. MetricSource lets another package describe metrics without depending on this one.

Color picker preferences ​

@jolly-pixel/ui/color-picker loads no element either. It exports the preference types, the values with their labels, and the defaults, so a settings page can edit the picker preferences from code that runs without a DOM:

ts
import {
  COLOR_PICKER_DEFAULTS,
  COLOR_PICKER_OPTIONS,
  type ColorPickerPreferences
} from "@jolly-pixel/ui/color-picker";

Presence ​

Lit helpers ​

  • FieldBinding: binds a field in a Lit template to one value.
  • SubscriptionController: keeps a host subscribed to one source while connected.
  • LazyTemplate: renders part of a template once the module that defines its elements is loaded.

Utilities ​

  • Colour: parseColor and formatHex.
  • Search queries: SearchQuery and the Searchable hook.
  • Geometry: Rect and anchored placement.
  • DOM: DOM guards and field event helpers.

Every component has a gallery entry, which is also its end to end fixture.

bash
pnpm run dev

Open one example with /?example=controls/number, and add &chrome=off to hide the shell.

To add an example, put its module in examples/scripts/examples/<group>/ and register it in that folder's index.ts. Declare variants as options on the same page; the shell keeps them in the URL.

Contributors Guide ​

Read the contributing guide, and add tests with every feature or bug fix.

bash
pnpm run test      # unit (node:test) and type tests
pnpm run test:e2e  # Playwright against the gallery
pnpm run lint

End to end specs in test/e2e/ sit with the component they cover. Cross-component workflows go in scenarios/, shared helpers in support/.

IMPORTANT

node --test cannot import decorated components, so keep unit-test assertions in plain modules.

License ​

MIT

This package embeds Roboto Mono (weight 400, latin subset), licensed under the Apache License 2.0. See NOTICE for the full attribution.