Metadata-Version: 2.4
Name: puikit
Version: 1.0.0
Summary: Capability-based Python UI framework with TUI and GUI backends
Author: craftware
License-Expression: MIT
Project-URL: Homepage, https://github.com/crftwr/puikit
Project-URL: Repository, https://github.com/crftwr/puikit
Project-URL: Issues, https://github.com/crftwr/puikit/issues
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Terminals
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Requires-Dist: windows-curses>=2.4; sys_platform == "win32"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-timeout>=2; extra == "dev"
Requires-Dist: pillow>=9; extra == "dev"
Provides-Extra: macos
Requires-Dist: pyobjc-framework-Cocoa>=10; extra == "macos"
Requires-Dist: pyobjc-framework-Quartz>=10; extra == "macos"
Provides-Extra: images
Requires-Dist: pillow>=9; extra == "images"
Dynamic: license-file

# PuiKit

PuiKit is a capability-based Python UI framework that supports both TUI
(terminal) and GUI (desktop, web) backends. Build apps and widgets once, run
them on multiple backends without splitting implementations.

- Apps and widgets specify **what to draw (intent)**
- **How to draw (implementation)** is decided by the backend
- Backends declare their capabilities; the Panel layer resolves fallbacks
- Widget code never branches on TUI/GUI

See the [documentation](https://github.com/crftwr/puikit/tree/main/docs) for
design notes and per-system guides (layout, rendering, color, animation, fonts,
widgets, and more).

## Status

Stable release (1.0). Implemented:

- Core framework: `Panel`, `Backend` interface, capability profiles, event model
- Layout system: `HSplit` / `VSplit` / `Item` with weights and `min_px` / `min`
  hints — snapped to whole base units on TUI, resolved at pixel granularity on GUI
- Animation: `panel.animate(widget, hints={"transition": "fade", "duration_ms": 200})`
  — transitions `fade` (opacity), `slide` (position), `scale` (visual zoom),
  `size` (layout reflow), and `highlight` (color) rendered on the macOS
  backend; immediate switch on TUI
- Widgets: `Label`, `ListView`, `ScrollBar`, `Container`
- Widget tree: containers nest widgets with hierarchical clipping; animations
  on a parent cascade to all descendants, while children stay individually
  animatable
- Backends:
  - `CursesBackend` — TUI, all platforms
  - `MacOSBackend` — macOS native GUI (PyObjC; install with `pip install -e ".[macos]"`)
  - `WindowsBackend` — Windows native GUI (raw ctypes; Direct2D/DirectWrite)
  - `WebBackend` — runs in a web browser, launched with `webbrowser` over a
    local WebSocket (`--backend web`; see `docs/web_backend.md`)
  - `MemoryBackend` — headless, for tests
- Planned next: C++ CoreText render extension

## Quick start

```bash
python3.14 -m venv .venv
.venv/bin/pip install -e ".[dev]"

# Run the examples (in a terminal)
.venv/bin/python examples/hello_world/main.py
.venv/bin/python examples/demo_catalog/main.py

# On macOS, the same examples in a native window
.venv/bin/python examples/hello_world/main.py --backend gui
.venv/bin/python examples/demo_catalog/main.py --backend gui

# Or in a web browser (opens a tab; works on any platform)
.venv/bin/python examples/demo_catalog/main.py --backend web

# Run the tests
.venv/bin/python -m pytest
```

## Minimal app

```python
from puikit import EventType, Panel
from puikit.backends import create_backend
from puikit.widgets import Label

backend = create_backend("tui")
with backend:
    panel = Panel(backend)
    panel.add(Label("Hello, PuiKit!"), x=2, y=1, w=30, h=1)
    panel.render()

    def on_event(event):
        if event.type is EventType.KEY and event.key == "q":
            backend.quit()
            return
        panel.dispatch_event(event)
        panel.render()

    backend.run_event_loop(on_event)
```

## License

See [LICENSE](https://github.com/crftwr/puikit/blob/main/LICENSE).
