aurora-ui 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. aurora_ui-0.2.0/.editorconfig +15 -0
  2. aurora_ui-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +47 -0
  3. aurora_ui-0.2.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. aurora_ui-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +26 -0
  5. aurora_ui-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  6. aurora_ui-0.2.0/.github/workflows/ci.yml +76 -0
  7. aurora_ui-0.2.0/.github/workflows/release.yml +74 -0
  8. aurora_ui-0.2.0/.gitignore +6 -0
  9. aurora_ui-0.2.0/CHANGELOG.md +94 -0
  10. aurora_ui-0.2.0/CLAUDE.md +96 -0
  11. aurora_ui-0.2.0/CODE_OF_CONDUCT.md +32 -0
  12. aurora_ui-0.2.0/CONTRIBUTING.md +85 -0
  13. aurora_ui-0.2.0/Cargo.lock +2465 -0
  14. aurora_ui-0.2.0/Cargo.toml +32 -0
  15. aurora_ui-0.2.0/LICENSE +21 -0
  16. aurora_ui-0.2.0/PKG-INFO +233 -0
  17. aurora_ui-0.2.0/README.md +205 -0
  18. aurora_ui-0.2.0/ROADMAP.md +75 -0
  19. aurora_ui-0.2.0/SECURITY.md +19 -0
  20. aurora_ui-0.2.0/VISION.md +99 -0
  21. aurora_ui-0.2.0/docs/architecture.md +238 -0
  22. aurora_ui-0.2.0/docs/assets/banner.png +0 -0
  23. aurora_ui-0.2.0/docs/assets/logo.png +0 -0
  24. aurora_ui-0.2.0/docs/assets/logo.svg +10 -0
  25. aurora_ui-0.2.0/docs/guide.md +483 -0
  26. aurora_ui-0.2.0/docs/reference.md +504 -0
  27. aurora_ui-0.2.0/docs/studio/1-resumen.png +0 -0
  28. aurora_ui-0.2.0/docs/studio/2-tablero.png +0 -0
  29. aurora_ui-0.2.0/docs/studio/3-modal.png +0 -0
  30. aurora_ui-0.2.0/docs/studio/4-equipo-claro.png +0 -0
  31. aurora_ui-0.2.0/examples/README.md +19 -0
  32. aurora_ui-0.2.0/examples/brand.py +125 -0
  33. aurora_ui-0.2.0/examples/hello.py +61 -0
  34. aurora_ui-0.2.0/examples/studio.py +912 -0
  35. aurora_ui-0.2.0/pyproject.toml +70 -0
  36. aurora_ui-0.2.0/python/aurora/__init__.py +129 -0
  37. aurora_ui-0.2.0/python/aurora/_core.pyi +95 -0
  38. aurora_ui-0.2.0/python/aurora/components.py +430 -0
  39. aurora_ui-0.2.0/python/aurora/elements.py +144 -0
  40. aurora_ui-0.2.0/python/aurora/py.typed +0 -0
  41. aurora_ui-0.2.0/python/aurora/signal.py +52 -0
  42. aurora_ui-0.2.0/python/aurora/theme.py +69 -0
  43. aurora_ui-0.2.0/src/color.rs +41 -0
  44. aurora_ui-0.2.0/src/edit.rs +389 -0
  45. aurora_ui-0.2.0/src/image.rs +263 -0
  46. aurora_ui-0.2.0/src/input.rs +144 -0
  47. aurora_ui-0.2.0/src/keys.rs +218 -0
  48. aurora_ui-0.2.0/src/lib.rs +55 -0
  49. aurora_ui-0.2.0/src/pilot.rs +266 -0
  50. aurora_ui-0.2.0/src/render.rs +1263 -0
  51. aurora_ui-0.2.0/src/runtime.rs +993 -0
  52. aurora_ui-0.2.0/src/scroll.rs +273 -0
  53. aurora_ui-0.2.0/src/spec.rs +472 -0
  54. aurora_ui-0.2.0/src/window.rs +393 -0
  55. aurora_ui-0.2.0/tests/test_components.py +238 -0
  56. aurora_ui-0.2.0/tests/test_elements.py +55 -0
  57. aurora_ui-0.2.0/tests/test_image.py +133 -0
  58. aurora_ui-0.2.0/tests/test_input.py +277 -0
  59. aurora_ui-0.2.0/tests/test_keyboard.py +258 -0
  60. aurora_ui-0.2.0/tests/test_pilot.py +256 -0
  61. aurora_ui-0.2.0/tests/test_render.py +115 -0
  62. aurora_ui-0.2.0/tests/test_scroll.py +162 -0
  63. aurora_ui-0.2.0/tests/test_signal.py +20 -0
  64. aurora_ui-0.2.0/tests/test_studio.py +62 -0
  65. aurora_ui-0.2.0/uv.lock +229 -0
@@ -0,0 +1,15 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{yml,yaml,toml,json,md}]
12
+ indent_size = 2
13
+
14
+ [*.md]
15
+ trim_trailing_whitespace = false
@@ -0,0 +1,47 @@
1
+ name: Reportar un bug
2
+ description: Algo no funciona como esperabas.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: Gracias por tomarte el tiempo de reportarlo. Cuanto más concreto, antes se arregla.
8
+ - type: textarea
9
+ id: what
10
+ attributes:
11
+ label: Qué pasa
12
+ description: Describe el problema. Si es visual, adjunta una captura (puedes usar `app.render_png()`).
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: expected
17
+ attributes:
18
+ label: Qué esperabas que pasara
19
+ validations:
20
+ required: true
21
+ - type: textarea
22
+ id: repro
23
+ attributes:
24
+ label: Ejemplo mínimo
25
+ description: El programa más corto posible que reproduzca el problema.
26
+ render: python
27
+ validations:
28
+ required: true
29
+ - type: input
30
+ id: version
31
+ attributes:
32
+ label: Versión de Aurora
33
+ placeholder: "0.1.0 (o el commit)"
34
+ validations:
35
+ required: true
36
+ - type: dropdown
37
+ id: os
38
+ attributes:
39
+ label: Sistema operativo
40
+ options: [Windows, macOS, Linux (X11), Linux (Wayland)]
41
+ validations:
42
+ required: true
43
+ - type: input
44
+ id: python
45
+ attributes:
46
+ label: Versión de Python
47
+ placeholder: "3.13"
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Preguntas y dudas de uso
4
+ url: https://github.com/<usuario>/aurora/discussions
5
+ about: Para preguntas generales, usa Discussions en lugar de issues.
@@ -0,0 +1,26 @@
1
+ name: Proponer una funcionalidad
2
+ description: Una idea para mejorar Aurora.
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Antes de proponer, echa un vistazo a [VISION.md](../blob/main/VISION.md) y al
9
+ [ROADMAP.md](../blob/main/ROADMAP.md): puede que ya esté planificada.
10
+ - type: textarea
11
+ id: problem
12
+ attributes:
13
+ label: Qué problema resuelve
14
+ description: Cuéntanos el caso de uso real. Es lo que más pesa al priorizar.
15
+ validations:
16
+ required: true
17
+ - type: textarea
18
+ id: proposal
19
+ attributes:
20
+ label: Cómo te gustaría usarlo
21
+ description: Un ejemplo de cómo se vería la API desde Python.
22
+ render: python
23
+ - type: textarea
24
+ id: alternatives
25
+ attributes:
26
+ label: Alternativas que consideraste
@@ -0,0 +1,14 @@
1
+ ## Qué cambia
2
+
3
+ <!-- Describe el cambio y por qué es necesario. Enlaza el issue si existe: "Cierra #123". -->
4
+
5
+ ## Cómo se probó
6
+
7
+ <!-- Tests añadidos, ejemplos ejecutados, capturas antes/después si es visual. -->
8
+
9
+ ## Checklist
10
+
11
+ - [ ] `uv run pytest` pasa
12
+ - [ ] `uv run ruff check .` y `cargo clippy --release -- -D warnings` sin avisos
13
+ - [ ] Si es visual: hay un test de render y adjunto capturas
14
+ - [ ] Si cambia la API pública: actualicé `docs/reference.md`, los stubs y el `CHANGELOG.md`
@@ -0,0 +1,76 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ env:
13
+ CARGO_TERM_COLOR: always
14
+
15
+ jobs:
16
+ lint:
17
+ name: Lint (Python + Rust)
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v6
22
+ - uses: dtolnay/rust-toolchain@stable
23
+ with:
24
+ components: rustfmt, clippy
25
+ - uses: Swatinem/rust-cache@v2
26
+ - name: Dependencias del sistema
27
+ run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype-dev
28
+ - name: Ruff
29
+ run: |
30
+ uvx ruff check .
31
+ uvx ruff format --check .
32
+ - name: rustfmt
33
+ run: cargo fmt --check
34
+ - name: Clippy
35
+ run: cargo clippy --release -- -D warnings
36
+
37
+ test:
38
+ name: Tests (${{ matrix.os }}, py${{ matrix.python }})
39
+ runs-on: ${{ matrix.os }}
40
+ strategy:
41
+ fail-fast: false
42
+ matrix:
43
+ os: [ubuntu-latest, macos-latest, windows-latest]
44
+ python: ["3.10", "3.13"]
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+ - uses: astral-sh/setup-uv@v6
48
+ with:
49
+ python-version: ${{ matrix.python }}
50
+ - uses: dtolnay/rust-toolchain@stable
51
+ - uses: Swatinem/rust-cache@v2
52
+ - name: Dependencias del sistema (Linux)
53
+ if: runner.os == 'Linux'
54
+ run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype-dev
55
+ - name: Compilar e instalar
56
+ run: uv sync
57
+ - name: Tests
58
+ run: uv run pytest -v
59
+ # Con `extension-module` el binario de tests de Rust no enlaza contra libpython en
60
+ # Linux/macOS; en Windows sí (python3.lib), así que los tests unitarios corren ahí.
61
+ - name: Tests de Rust (Windows)
62
+ if: runner.os == 'Windows'
63
+ run: uv run cargo test --release
64
+ - name: Renderizar los ejemplos (smoke test visual)
65
+ run: |
66
+ uv run examples/hello.py --png hello.png
67
+ uv run examples/studio.py --png studio-shots
68
+ - name: Subir capturas
69
+ if: always()
70
+ uses: actions/upload-artifact@v4
71
+ with:
72
+ name: capturas-${{ matrix.os }}-py${{ matrix.python }}
73
+ path: |
74
+ hello.png
75
+ studio-shots/
76
+ if-no-files-found: ignore
@@ -0,0 +1,74 @@
1
+ # Publica wheels en PyPI al crear un tag vX.Y.Z.
2
+ #
3
+ # Requisitos (una sola vez):
4
+ # 1. Crear el proyecto en PyPI y configurar "Trusted Publishing" para este repositorio
5
+ # y el workflow release.yml (sin tokens ni secretos).
6
+ # 2. Crear el environment "pypi" en la configuración del repositorio.
7
+ #
8
+ # Nota: el wheel es abi3, así que basta uno por plataforma y arquitectura para todas
9
+ # las versiones de Python >= 3.10.
10
+
11
+ name: Release
12
+
13
+ on:
14
+ push:
15
+ tags: ["v*"]
16
+ workflow_dispatch:
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ wheels:
23
+ name: Wheel ${{ matrix.platform.name }}
24
+ runs-on: ${{ matrix.platform.runner }}
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ platform:
29
+ - { name: linux-x86_64, runner: ubuntu-latest, target: x86_64 }
30
+ - { name: windows-x64, runner: windows-latest, target: x64 }
31
+ - { name: macos-arm64, runner: macos-latest, target: aarch64 }
32
+ # macos-13 ya no existe en GitHub Actions; macos-15-intel es la última imagen Intel.
33
+ - { name: macos-x86_64, runner: macos-15-intel, target: x86_64 }
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: PyO3/maturin-action@v1
37
+ with:
38
+ target: ${{ matrix.platform.target }}
39
+ args: --release --out dist
40
+ manylinux: 2_28
41
+ before-script-linux: dnf install -y fontconfig-devel freetype-devel
42
+ - uses: actions/upload-artifact@v4
43
+ with:
44
+ name: wheel-${{ matrix.platform.name }}
45
+ path: dist
46
+
47
+ sdist:
48
+ name: Source distribution
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ - uses: PyO3/maturin-action@v1
53
+ with:
54
+ command: sdist
55
+ args: --out dist
56
+ - uses: actions/upload-artifact@v4
57
+ with:
58
+ name: sdist
59
+ path: dist
60
+
61
+ publish:
62
+ name: Publicar en PyPI
63
+ needs: [wheels, sdist]
64
+ runs-on: ubuntu-latest
65
+ if: startsWith(github.ref, 'refs/tags/v')
66
+ environment: pypi
67
+ permissions:
68
+ id-token: write
69
+ steps:
70
+ - uses: actions/download-artifact@v4
71
+ with:
72
+ path: dist
73
+ merge-multiple: true
74
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,6 @@
1
+ target/
2
+ .venv/
3
+ __pycache__/
4
+ *.so
5
+ *.pyd
6
+ /*.png
@@ -0,0 +1,94 @@
1
+ # Changelog
2
+
3
+ Todos los cambios relevantes de Aurora se documentan aquí.
4
+
5
+ El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y el proyecto usa
6
+ [Versionado Semántico](https://semver.org/lang/es/). Mientras la versión sea `0.x`, cualquier
7
+ versión menor puede incluir cambios incompatibles, que siempre se señalarán aquí.
8
+
9
+ ## [Sin publicar]
10
+
11
+ ## [0.2.0] — 2026-10-15
12
+
13
+ Apps de verdad: scroll, teclado y foco, campos de texto, imágenes y más componentes.
14
+
15
+ ### Añadido
16
+
17
+ - Componentes `divider`, `avatar`, `checkbox`, `switch`, `tabs` (con ← →) y `select` (desplegable en
18
+ capa superior, con scroll, Esc y ↑ ↓), enlazados a `Signal` donde aplica.
19
+ - `tooltip(child, tip)` y la propiedad `tooltip`: burbuja tras medio segundo de hover, colocada
20
+ dentro de la ventana, con colores heredables `tooltip_bg` y `tooltip_color`; `Pilot.tooltip`.
21
+ - Primitiva `image(src, fit=...)`: PNG, JPEG, WebP, GIF, BMP, ICO y SVG (vectorial) desde una ruta
22
+ o desde `bytes`, con proporción automática, `fit` (`contain`, `cover`, `fill`, `none`), recorte a
23
+ las esquinas redondeadas, caché de decodificación que detecta cambios en disco y errores claros
24
+ (`FileNotFoundError`, `ValueError`).
25
+ - Campos de texto `text_input` y `textarea`, enlazados en los dos sentidos a un `Signal[str]`:
26
+ cursor que parpadea, selección con teclado y ratón (doble y triple clic), recorrido por grafemas y
27
+ palabras, portapapeles, deshacer/rehacer agrupando lo escrito, composición con IME, placeholder,
28
+ `on_submit`, desplazamiento horizontal en una línea y crecimiento con el contenido en varias.
29
+ - Propiedades `placeholder_color` y `selection_color`; cursor de texto del ratón sobre los campos.
30
+ - `Pilot.type()`, `ime_preedit()`, `ime_commit()`, `selection()` y `clipboard`.
31
+ - Teclado y foco: Tab / Shift+Tab en orden de pintura (atrapado dentro de barreras `capture`),
32
+ activación con Enter y Espacio, anillo de foco animado solo al navegar con teclado
33
+ (`focus_color`, heredable) y desplazamiento automático del `scroll` para mostrar el foco.
34
+ - `on_key` con `KeyEvent` (`key`, `text`, modificadores, `matches("mod+s")`), que burbujea desde el
35
+ foco hasta la raíz; `on_focus`, `on_blur`, `focusable` y `autofocus`.
36
+ - Desplazamiento con flechas, RePág/AvPág, Inicio/Fin y Espacio.
37
+ - `Pilot.press()`, `key_down()`, `key_up()`, `focus()` y `focused`.
38
+ - Contenedor `scroll(axis="y" | "x" | "both")`: recorte, rueda con desplazamiento suave, trackpad,
39
+ encadenado al `scroll` exterior en el límite y barra superpuesta que se oculta sola y se puede
40
+ arrastrar. La posición se conserva entre reconstrucciones.
41
+ - Propiedades `min_height`, `max_height` y `scrollbar_color`.
42
+ - `Pilot.wheel()`, `Pilot.scroll()` y `Pilot.scroll_offset()`.
43
+ - `app.pilot()`: piloto headless para tests de interacción (`click`, `move_to`, `hovered`, `rect`,
44
+ `settle`, `png`…) que usa el mismo runtime que la ventana.
45
+ - `Signal.set` es seguro desde cualquier hilo y despierta el bucle de eventos: la ventana se
46
+ actualiza sin esperar a un evento del usuario.
47
+ - `app.spawn(coro)`: ejecuta corrutinas en un bucle `asyncio` en segundo plano.
48
+ - Propiedad `layer="overlay"`: pinta un elemento y le da los eventos por encima de todo el árbol.
49
+ - Manejadores genéricos: cualquier argumento `on_<evento>` de un elemento es un manejador.
50
+
51
+ ### Cambiado
52
+
53
+ - `Element.to_spec()` serializa los manejadores en `"handlers": {"click": fn}` en lugar de
54
+ `"on_click"`. `Element.on_click` sigue disponible como propiedad de solo lectura.
55
+ - El núcleo separa el estado de la app (`Runtime`) del bucle de ventana.
56
+ - El hit-testing respeta el recorte de los contenedores `scroll`.
57
+ - La demo `studio.py` desplaza el contenido de cada página y estrena búsqueda en el tablero, un
58
+ formulario de nueva tarea (Ctrl+N y el botón lo abren en vez de añadir una tarea de ejemplo),
59
+ una página de Ajustes y tooltips.
60
+ - Nuevas dependencias del núcleo: `arboard` (portapapeles) y `unicode-segmentation`. Las features de
61
+ `skia-safe` cambian por sistema (`svg`, `webp` y, fuera de macOS, `ganesh` + `vulkan`) para
62
+ seguir usando binarios precompilados de Skia.
63
+
64
+ ### Corregido
65
+
66
+ - `examples/studio.py --png` ya no falla en consolas de Windows sin UTF-8.
67
+
68
+ ## [0.1.0] — 2026-10-15
69
+
70
+ Primera versión: la base del framework.
71
+
72
+ ### Añadido
73
+
74
+ - Núcleo nativo en Rust expuesto como `aurora._core` (PyO3 + maturin, wheel abi3 para Python ≥ 3.10).
75
+ - Layout flexbox con Taffy: `direction`, `gap`, `padding`, `align`, `justify`, `grow`, `shrink`,
76
+ `wrap`, tamaños en píxeles o porcentaje, `min_width`/`max_width` y `position="absolute"` con
77
+ `top`/`right`/`bottom`/`left`.
78
+ - Render con Skia: esquinas redondeadas, bordes, sombras difuminadas, gradientes lineales y opacidad.
79
+ - Texto con shaping real, fallback de fuentes, herencia de estilos de texto, alineación por baseline,
80
+ `max_lines` con elipsis y `text_align`.
81
+ - Ventana nativa con winit; el bucle de eventos corre sin el GIL.
82
+ - Estados hover y pressed animados en el núcleo (`bg_hover`, `bg_pressed`, `press_scale`).
83
+ - Hit-testing con burbujeo al ancestro interactivo y barreras de eventos (`capture`).
84
+ - API declarativa: `box`, `row`, `column`, `text`, `spacer`, hijos con `[...]`, `key` y `on_click`.
85
+ - `Signal` para el estado reactivo.
86
+ - Temas con tokens (`"$primary"`), temas `MIDNIGHT` y `DAYLIGHT`, y tema reactivo vía `Signal[Theme]`.
87
+ - Componentes: `button` (variantes `primary`, `soft`, `ghost`), `card`, `badge` y `stat`.
88
+ - `App.render_png()` para renderizar sin ventana.
89
+ - Ejemplos: `hello.py`, `studio.py` (demo completa) y `brand.py` (genera las imágenes del README).
90
+ - Documentación: guía, referencia, arquitectura, visión y roadmap.
91
+
92
+ [Sin publicar]: https://github.com/<usuario>/aurora/compare/v0.2.0...HEAD
93
+ [0.2.0]: https://github.com/<usuario>/aurora/compare/v0.1.0...v0.2.0
94
+ [0.1.0]: https://github.com/<usuario>/aurora/releases/tag/v0.1.0
@@ -0,0 +1,96 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ Aurora (`aurora-ui`, pre-alpha v0.2) is a declarative, reactive desktop UI library: the public API is
6
+ Python (`python/aurora/`), and layout/render/animation/events run in a native Rust core
7
+ (`src/`, built as the extension module `aurora._core` via PyO3 + maturin). Stack: Skia (`skia-safe`)
8
+ for painting and text, Taffy for flexbox layout, winit + softbuffer for the window (CPU raster).
9
+
10
+ ## Commands
11
+
12
+ ```bash
13
+ uv sync # builds the Rust core (release) and installs editable + dev deps
14
+ uv run pytest # all tests
15
+ uv run pytest tests/test_render.py::test_name # single test
16
+ uv run examples/studio.py # full demo app (opens a window)
17
+ uv run examples/studio.py --png studio-shots # headless render of the demo (CI smoke test)
18
+ uv run examples/hello.py --png hello.png
19
+ ```
20
+
21
+ Full lint, same as CI:
22
+
23
+ ```bash
24
+ uv run ruff check . && uv run ruff format --check .
25
+ cargo fmt --check && cargo clippy --release -- -D warnings
26
+ ```
27
+
28
+ - Python edits in `python/aurora/` apply immediately (editable install). Rust edits in `src/**/*.rs`
29
+ trigger an automatic rebuild on the next `uv run` (configured via `tool.uv.cache-keys`).
30
+ - Rust unit tests (`uv run cargo test --release`) only link on Windows: with `extension-module`,
31
+ the test binary doesn't link libpython on Linux/macOS.
32
+ - First build downloads prebuilt Skia binaries and takes minutes. The `skia-safe` features in
33
+ `Cargo.toml` (per OS) must match a combination published in rust-skia/skia-binaries; any other
34
+ combination silently falls back to building Skia from source (needs LLVM, very slow). Check the
35
+ release assets before adding a Skia feature. Linux needs
36
+ `libfontconfig-dev` and `libfreetype-dev`.
37
+
38
+ ## Architecture
39
+
40
+ Core principle: **Python describes, Rust executes; the boundary is crossed once per update with a
41
+ complete tree.** Never expose low-level operations (draw rect, measure text) to Python.
42
+
43
+ Frame lifecycle:
44
+
45
+ 1. `App._build()` (`python/aurora/__init__.py`) calls the user's `view()`, applies root defaults,
46
+ and serializes the `Element` tree to nested dicts via `Element.to_spec(theme)` — this is where
47
+ `"$token"` theme values and text lambdas are resolved.
48
+ 2. `spec::parse` (`src/spec.rs`) is the **only** place in Rust that knows the shape of the Python
49
+ data: dicts → typed `Node`. Text style inheritance (`color`, `font_size`, `font_weight`,
50
+ `font_family`, `line_height`, `letter_spacing`) is resolved here once, CSS-style.
51
+ 3. `render.rs` `Engine`: builds a parallel Taffy tree (text nodes carry a shaped Skia `Paragraph`,
52
+ reused for both measuring and painting), ticks hover/pressed transitions (exponential smoothing,
53
+ τ = 70 ms, real `dt`), and `Painter` paints shadow → bg → border → text → children while
54
+ recording `HitRegion`s in paint order.
55
+ 4. `runtime.rs` `Runtime`: window-independent app state (tree, hit regions, pointer, event
56
+ dispatch by handler name via `dispatch(key, event, arg)`). Two drivers share it: `window.rs`
57
+ (winit loop, runs with the GIL released via `py.detach`; the GIL is taken only to run a handler or
58
+ rebuild the view; hover never touches Python) and `pilot.rs` (`Pilot`, headless, for interaction
59
+ tests via `app.pilot()`).
60
+
61
+ `Signal.set` calls `_core.wake()` (any thread): an atomic flag that `Runtime::sync` consumes, plus an
62
+ `EventLoopProxy` user event to request a frame. Nodes with `layer="overlay"` are deferred by `Painter`
63
+ and painted (and hit-tested) after the whole tree.
64
+
65
+ Hit-testing: take the last-painted region containing the point, bubble up through parents to the
66
+ first node with a `click` handler; a node with `capture=True` stops the bubbling (e.g. modals).
67
+
68
+ Node identity is stable (explicit `key` or tree path) and is used to keep animation state across
69
+ full rebuilds — every event currently rebuilds the whole view.
70
+
71
+ `App.render_png()` → `_core.render_png` renders without a window; this powers `tests/test_render.py`
72
+ (which decodes PNG pixels without Pillow), CI smoke tests, and the README images (`examples/brand.py`).
73
+
74
+ ## Extending
75
+
76
+ - **New component:** compose primitives in `components.py` in pure Python whenever possible. Only
77
+ push to Rust what can't be expressed otherwise (new node kinds, render effects, layout).
78
+ - **New style property:** add the field to `spec::Style` and its parsing, its effect in
79
+ `taffy_style` (layout) or `Painter::paint` (paint), and document it in `docs/reference.md`.
80
+ - **New node type:** new `spec::Kind` variant + its layout measurement + its painting.
81
+ - Visual changes need a render test in `tests/test_render.py`; interaction changes need a `Pilot`
82
+ test in `tests/test_pilot.py`. Public API changes must update
83
+ `docs/reference.md`, `python/aurora/_core.pyi` stubs (if the native API changes), and the
84
+ "Sin publicar" section of `CHANGELOG.md`.
85
+
86
+ ## Conventions
87
+
88
+ - Code identifiers in English (`bg`, `radius`, `on_click`, CSS-like); docs, comments and commit
89
+ messages in **Spanish**. Commits in imperative mood (`Añade contenedor scroll con clipping`).
90
+ - Components must look good with default values. Optional parameters are keyword-only; positional
91
+ args only for essentials (`text(content)`, `button(label, on_click)`).
92
+ - Children are attached with `[...]` (`column(gap=8)[a, b]`); theme colors use `"$token"` strings.
93
+ - Rust: no `unwrap()` on paths that depend on user data — input errors must surface in Python as
94
+ clear exceptions.
95
+ - Ruff line length is 110; Spanish typography rules (RUF001–003) and lambda assignment (E731) are
96
+ ignored on purpose.
@@ -0,0 +1,32 @@
1
+ # Código de conducta
2
+
3
+ Aurora quiere ser un proyecto donde cualquier persona pueda participar con comodidad,
4
+ independientemente de su experiencia, origen o identidad.
5
+
6
+ ## Lo que esperamos
7
+
8
+ - Trato respetuoso y empático, también cuando no estamos de acuerdo.
9
+ - Críticas dirigidas a las ideas y al código, nunca a las personas.
10
+ - Paciencia con quien está aprendiendo: todos empezamos en algún momento.
11
+ - Asumir buena fe, y pedir aclaraciones antes de sacar conclusiones.
12
+ - Reconocer los errores propios y aprender de ellos.
13
+
14
+ ## Lo que no aceptamos
15
+
16
+ - Insultos, burlas, comentarios despectivos o ataques personales.
17
+ - Acoso, público o privado, de cualquier tipo.
18
+ - Lenguaje o imágenes sexualizadas, y atención no deseada.
19
+ - Publicar información privada de otras personas sin su permiso.
20
+ - Cualquier conducta que sería inapropiada en un entorno profesional.
21
+
22
+ ## Ámbito y aplicación
23
+
24
+ Este código se aplica en todos los espacios del proyecto (issues, pull requests, discusiones y
25
+ canales de chat) y cuando alguien representa al proyecto en público.
26
+
27
+ Para reportar un problema, escribe a las personas que mantienen el proyecto
28
+ (**TODO: añadir un email de contacto**). Los reportes se tratarán con confidencialidad. Quienes
29
+ mantienen el proyecto pueden editar o eliminar contribuciones que no respeten este código y, en
30
+ casos graves o reiterados, excluir temporal o permanentemente a quien lo incumpla.
31
+
32
+ Este código está inspirado en el [Contributor Covenant](https://www.contributor-covenant.org).
@@ -0,0 +1,85 @@
1
+ # Contribuir a Aurora
2
+
3
+ ¡Gracias por tu interés! Toda contribución suma: reportar un bug, mejorar la documentación,
4
+ proponer una idea o implementar una funcionalidad.
5
+
6
+ ## Antes de empezar
7
+
8
+ - **Bugs:** abre un issue con la plantilla de bug. Un ejemplo mínimo reproducible (y una captura
9
+ si es visual) ahorra mucho tiempo.
10
+ - **Funcionalidades:** abre primero un issue para discutirla. Revisa [VISION.md](VISION.md) y el
11
+ [ROADMAP.md](ROADMAP.md): las propuestas alineadas con ellos tienen más recorrido.
12
+ - **Cambios pequeños** (erratas, docs, tests): envía el PR directamente.
13
+
14
+ ## Entorno de desarrollo
15
+
16
+ Necesitas Python ≥ 3.10, [uv](https://docs.astral.sh/uv/) y Rust estable
17
+ ([rustup](https://rustup.rs)). En Linux, además, `libfontconfig-dev` y `libfreetype-dev`.
18
+
19
+ ```bash
20
+ git clone https://github.com/<usuario>/aurora.git
21
+ cd aurora
22
+ uv sync # compila el núcleo e instala todo (incluye pytest y ruff)
23
+ uv run pytest # tests
24
+ uv run examples/studio.py # demo completa
25
+ ```
26
+
27
+ - Los cambios en `python/aurora/` se aplican al instante (instalación editable).
28
+ - Los cambios en `src/*.rs` disparan la recompilación en el siguiente `uv run`.
29
+
30
+ ## Antes de enviar un PR
31
+
32
+ Ejecuta lo mismo que la CI:
33
+
34
+ ```bash
35
+ uv run ruff check . && uv run ruff format --check .
36
+ cargo fmt --check && cargo clippy --release -- -D warnings
37
+ uv run pytest
38
+ ```
39
+
40
+ Y verifica a mano:
41
+
42
+ - [ ] Si el cambio es **visual**, hay un test en `tests/test_render.py` que lo renderiza, y
43
+ `uv run examples/studio.py` sigue viéndose bien.
44
+ - [ ] Si cambia la **API pública**, están actualizados `docs/reference.md`, la guía si aplica,
45
+ los stubs (`_core.pyi`) y el `CHANGELOG.md` (sección *Sin publicar*).
46
+ - [ ] Si añades una **propiedad de estilo**, sigue los pasos de
47
+ [Extender Aurora](docs/architecture.md#extender-aurora).
48
+
49
+ ## Convenciones
50
+
51
+ ### Diseño de la API
52
+
53
+ - **Bonito por defecto:** los valores por defecto de un componente nuevo deben verse bien sin
54
+ configurar nada.
55
+ - **Componentes en Python** siempre que se puedan componer con primitivas. Al núcleo Rust solo
56
+ bajan capacidades que no se puedan expresar de otra forma (nuevos tipos de nodo, efectos de
57
+ render, layout).
58
+ - **Nombres en inglés en el código** (`bg`, `radius`, `on_click`), siguiendo las convenciones
59
+ habituales de CSS y de otros frameworks de UI. Documentación y comentarios, en español.
60
+ - **Keyword arguments** para todo lo opcional; los posicionales, solo para lo esencial
61
+ (`text(contenido)`, `button(label, on_click)`).
62
+
63
+ ### Código
64
+
65
+ - **Python:** formateado con `ruff format` y con type hints en la API pública.
66
+ - **Rust:** `cargo fmt` y `clippy` sin warnings. Nada de `unwrap()` en rutas que dependan de datos
67
+ del usuario: los errores de entrada deben llegar a Python como excepciones claras.
68
+ - **Commits:** mensajes en imperativo y descriptivos (`Añade contenedor scroll con clipping`).
69
+ Un commit por cambio lógico.
70
+
71
+ ## Estructura del proyecto
72
+
73
+ ```
74
+ python/aurora/ API pública en Python
75
+ src/ Núcleo nativo en Rust (módulo aurora._core)
76
+ tests/ Tests (pytest), incluidos tests de render headless
77
+ examples/ Apps de ejemplo; brand.py genera las imágenes del README
78
+ docs/ Guía, referencia, arquitectura y recursos gráficos
79
+ ```
80
+
81
+ El recorrido completo por el núcleo está en [docs/architecture.md](docs/architecture.md).
82
+
83
+ ## Licencia
84
+
85
+ Al contribuir aceptas que tu aportación se publique bajo la [licencia MIT](LICENSE) del proyecto.