# pixel-bit

A pixel-art CSS framework for game interfaces. It styles semantic HTML — no
classes on every element, no JavaScript, no dependencies.

[![npm](https://img.shields.io/npm/v/pixel-bit)](https://www.npmjs.com/package/pixel-bit)
[![license](https://img.shields.io/npm/l/pixel-bit)](https://github.com/luisnavarrete12/pixel-bit/blob/main/LICENSE)

**2.83 KB gzipped. Zero dependencies. Works with any framework, or none.**

## Install

```html
<link rel="stylesheet" href="https://unpkg.com/pixel-bit" />
```

Or via npm:

```bash
npm install pixel-bit
```

```js
import "pixel-bit";
```

## Use

Add `class="pb"` to a container. Everything inside is styled — plain HTML, no
extra classes:

```html
<body class="pb">
  <button>Continue</button>
  <input type="text" placeholder="Name" />
  <select>
    <option>Warrior</option>
  </select>

  <label><input type="checkbox" checked /> Sound</label>
</body>
```

Only the subtree you mark is affected. The rest of your app is untouched.

### Semantic modifiers

```html
<button class="pb-accent">Save</button>
<button class="pb-danger">Delete</button>
<button class="pb-success">Confirm</button>
<button class="pb-warning">Careful</button>
```

### Validation

Style follows the ARIA attribute, so the error state is announced to screen
readers, not just colored:

```html
<input type="text" aria-invalid="true" />
```

## Every rule has zero specificity

Selectors are wrapped in `:where()`, so **any** rule you write overrides the
framework — no `!important`, no specificity fights:

```css
button { background: rebeccapurple; }  /* just works */
```

## Theming

Everything configurable is a CSS custom property. Redefine what you need:

```css
:root {
  --pb-accent: #c0392b;
  --pb-unit: 6px;      /* rescales the whole pixel grid */
  --pb-bg: #1b2b1b;
}
```

| Token | Purpose |
| --- | --- |
| `--pb-unit` | Base pixel grid. All sizes derive from it. |
| `--pb-edge-width` | Thickness of the notched outline |
| `--pb-bevel-width` | Depth of the inner bevel |
| `--pb-drop-depth` | Offset of the solid drop shadow |
| `--pb-font-family` `--pb-font-size` `--pb-line-height` `--pb-letter-spacing` | Typography |
| `--pb-bg` `--pb-surface` `--pb-surface-raised` | Surfaces |
| `--pb-ink` `--pb-ink-muted` `--pb-edge` | Text and edges |
| `--pb-accent` `--pb-danger` `--pb-success` `--pb-warning` | Semantic colors |
| `--pb-accent-ink` `--pb-danger-ink` `--pb-success-ink` `--pb-warning-ink` | Text on top of each semantic color |
| `--pb-tint-light` `--pb-tint-dark` | What every bevel mixes toward. Keep them close to white and black or colored controls go muddy. |
| `--pb-hover-veil` | Overlay that darkens a control on hover |
| `--pb-fill` | Fill of a single control. Set it and the bevel re-derives itself. |
| `--pb-transition` | Animation duration. Set to `0ms` to disable. |

Variables starting with `--_pb-` are internal. They hold composed shadow
recipes that the components depend on, and redefining one breaks every
component at once.

### Themes

Four themes ship with the framework. Set `data-pb-theme` on any element and
everything inside it changes:

```html
<body class="pb" data-pb-theme="dark">
```

| Theme | Look |
| --- | --- |
| *(none)* | Light ground, white controls, saturated accents |
| `dark` | Dark slate |
| `mono` | Four-tone green, like an early handheld screen |
| `amber` | Amber phosphor terminal |

A theme only redefines the surface and semantic colors. The pixel grid, the
bevels and the shadow recipes are shared, so a theme is about twenty lines.

### Fonts

pixel-bit ships **no font files and makes no network requests** — it will not
block your render or break under a strict CSP. To use a pixel typeface, load it
yourself and point the token at it:

```html
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P" rel="stylesheet" />
<style>
  :root {
    --pb-font-family: "Press Start 2P", monospace;
    --pb-font-size: 10px;
  }
</style>
```

## Components

**Forms** — `button` `input` `select` `textarea` `checkbox` `radio`
`fieldset` `legend` `label`

**Layout** — panel with notched title, table, badge, modal dialog on
`<dialog>`

**Text** — links, lists, horizontal rules and semantic text colors

**Game** — dialogue balloon, HP/MP/XP bars, key prompts for keyboard and
gamepad, heart icons

Buttons, fields and bars need no classes at all: write plain HTML inside a
`.pb` container and it is styled.

## Roadmap

Shipped:

- [x] Buttons, fields, checkboxes and radios
- [x] Panels, badges and tables
- [x] Dialogue balloons
- [x] Stat bars for HP, MP and XP
- [x] Key prompts for keyboard and gamepad
- [x] Full theming through CSS variables
- [x] Links, lists and horizontal rules
- [x] Modal dialogs built on `<dialog>`
- [x] Four swappable themes

Coming next:

- [ ] A wider icon set
- [ ] `pixel-bit/react`, an optional typed component layer

Releases ship every one to two weeks. Open an issue if you want something
moved up the list.

## Accessibility

- Focus is always visible; the outline is never removed without a replacement.
- Error states pair color with `aria-invalid`, never color alone.
- Animation respects `prefers-reduced-motion`.
- Disabled controls keep readable contrast.

## Browser support

Chrome, Edge, Firefox and Safari — current versions. Uses `:where()`,
`color-mix()` and custom properties.

## Contributing

Issues and pull requests are welcome. `npm test` runs the linter and the
build.

## License

MIT © Luis Navarrete
