Gea UI Engineering
Mission
Use Gea as a compiler-first, browser UI framework, not as a general backend runtime. Prefer ordinary JavaScript/TypeScript, compile-time JSX, proxy-based stores, direct DOM ownership, and surgical updates. Keep the shipped code proportional to the features actually used.
Gea is especially appropriate for interactive websites, dashboards, product interfaces, animation-heavy UI, embedded widgets, mobile-style web interfaces, and applications where bundle size and update cost matter. It does not replace a Node/Python/Go backend, database, job worker, or API layer. The backend may serve data and SSR HTML; Gea runs the interactive client layer.
Workflow
- Inspect before coding. Identify the existing stack, package manager, entry point, Vite configuration, TypeScript settings, rendering mode, browser support, and current bundle/performance symptoms. Do not convert an entire app to Gea merely because Gea is small.
- Choose the rendering path.
- New Vite app: use
npm create gea@latest and the official Vite plugin.
- Existing Vite app: add the Gea plugin only after checking JSX ownership and coexistence constraints.
- No-build page or small widget: use the browser runtime; use Babel only when runtime JSX is genuinely necessary.
- SEO/first-paint/server-rendered app: use
@geajs/ssr, then hydrate on the client.
- Backend-only request: do not introduce Gea; return an API/server solution instead.
- Model state deliberately. Put shared mutable state in a small
Store class. Keep presentational pieces as pure function components; use class components for state and lifecycle. Use getters for computed values. Avoid duplicating derived state.
- Build the smallest correct UI. Use Gea JSX (
class, lowercase event attributes such as click/input/change), semantic HTML, stable keys/identifiers, and the least expensive DOM structure. Import optional router/UI/mobile/SSR features only when needed.
- Design motion separately from state. Prefer CSS transitions/keyframes for declarative motion. Use
requestAnimationFrame for continuous imperative motion, and keep animation state local or outside high-frequency global stores. Never cause layout thrashing by alternating reads and writes in a loop.
- Verify behavior and delivery. Run typecheck, lint, tests, production build, and bundle-size inspection. Check hydration, keyboard operation, reduced-motion behavior, responsive layout, and cleanup after component disposal.
- Report trade-offs. State what Gea improves, what remains backend-owned, which optional packages were added, and the measured before/after bundle or interaction result. Treat README benchmark numbers as indicative, not as a guarantee for every app.
Non-negotiable Gea rules
- Use
@geajs/vite-plugin for compiled JSX/reactivity. Do not assume ordinary Babel JSX alone provides Gea’s compile-time reactivity.
- In Vite JSX, use
class, not React’s className; use lowercase native event attributes such as click, input, change, and keydown, not onClick.
- In a class component, keep the root structure compatible with Gea’s ownership model; the browser/manual-template path requires the root
id="${this.id}".
- Do not add React hooks, signals, dependency arrays,
setState, emit, or v-model patterns unless integrating an external library that explicitly requires them.
- Do not manually attach one listener per element when delegated
events or JSX event attributes can express the behavior.
- Do not perform side effects in function components. Put effects in lifecycle methods or explicit store/service methods.
- Unsubscribe every manual
store.observe() subscription; store its remover in GEA_OBSERVER_REMOVERS or use the documented lifecycle cleanup mechanism.
- Never put secrets, database credentials, privileged operations, or backend-only code in a client bundle.
- Do not claim that Gea automatically optimizes arbitrary third-party animation libraries. Measure the library, import only required modules, and wrap it behind a cleanup-aware component boundary.
Component and state selection
| Need |
Preferred Gea design |
| Static/presentational markup |
Pure function component |
| Local interactive behavior/lifecycle |
Class component |
| Shared mutable state |
One focused Store instance |
| Derived state |
Getter on the store or component |
| Server data |
API client/service + store; handle loading/error/empty states |
| Modal/menu/tooltip/accordion |
@geajs/ui when its accessibility behavior is useful |
| Mobile navigation/gestures |
@geajs/mobile only when needed |
| URL navigation |
Tree-shakeable router APIs from @geajs/core |
| Server HTML/hydration |
@geajs/ssr with per-request store isolation |
| Backend logic |
Separate server framework/service |
Performance and animation playbook
- Measure first: production build, compressed JS/CSS, long tasks, layout/paint, interaction latency, and animation frame rate.
- Keep hot state local. Do not update a global store at pointer/touch/scroll frequency unless multiple views truly need it.
- Animate
transform and opacity where possible. Avoid repeatedly changing layout properties such as top, left, width, and height during a frame loop.
- Batch reads before writes, use
requestAnimationFrame, cancel handles on dispose, and respect prefers-reduced-motion: reduce.
- For large lists, minimize reactive dependencies, paginate/virtualize where appropriate, and avoid recreating large arrays or markup for unrelated changes.
- Use
store.silent() only when intentionally managing the corresponding DOM update yourself; document the invariant so the UI cannot silently become stale.
- Lazy-load routes and heavy animation/editor/chart libraries. Confirm tree-shaking in the final bundle rather than trusting import syntax.
Validation checklist
npm run build succeeds in production mode.
npm run typecheck/tsc --noEmit and lint pass when configured.
- No hydration mismatch or cross-request store leakage exists in SSR.
- Keyboard navigation, focus restoration, labels, semantics, and reduced motion work.
- Components dispose observers, timers, animation frames, and third-party instances.
- Network/API failures have visible loading, empty, retry, and error states.
- Bundle output is inspected in compressed form; benchmark claims are not copied without measurement.
- If converting from another framework, behavior and accessibility are tested before comparing size.
Progressive references
Read only the reference needed for the task:
- API and syntax: stores, components, JSX, browser runtime, router, SSR, package boundaries, and migration traps.
- Performance and animation: measurement, CSS/WAAPI/rAF decisions, high-frequency input, cleanup, and third-party libraries.
- Recipes and diagnostics: complete patterns for app setup, stores, SSR, widgets, conversion, and failure diagnosis.
- Templates: ready-to-use production scaffolds:
templates/minimal-starter/: Official Vite + TypeScript starter with Store, Component, and Vite plugin.
templates/router-starter/: Declarative client-side routing with @geajs/core/router.
templates/zag-ui-dialog/: Accessible modal dialog pattern with @geajs/ui.
templates/mobile-starter/: Hybrid mobile views and transitions with @geajs/mobile.
When Gea’s current repository/API differs from these references, inspect the installed package and official repository docs before changing code. Prefer source and type definitions over assumptions.
Response contract for agents using this skill
When producing or modifying Gea code, explain briefly: (1) rendering mode, (2) state ownership, (3) animation strategy if relevant, (4) optional packages added and why, (5) verification performed, and (6) any backend boundary. Return runnable code rather than framework-agnostic pseudocode unless the user explicitly asks for a design only.
Source of truth used to design this skill: https://github.com/dashersw/gea and its docs/ directory. Gea is MIT-licensed; verify the installed version before relying on version-specific APIs.
1---2name: gea-ui-engineering3description: Build, refactor, debug, optimize, and review ultra-light reactive web UIs with Gea (the @geajs/core ecosystem). Use for Gea/Vite/JSX projects, browser UI, SSR and hydration, routing, accessible headless UI, mobile UI, DOM animations, converting React/Vue/vanilla interactions to Gea, bundle-size work, and performance diagnosis. Do not use Gea as a backend framework; use it only for browser-facing UI, with @geajs/ssr when server-rendered HTML is needed.4---56# Gea UI Engineering78## Mission910Use Gea as a **compiler-first, browser UI framework**, not as a general backend runtime. Prefer ordinary JavaScript/TypeScript, compile-time JSX, proxy-based stores, direct DOM ownership, and surgical updates. Keep the shipped code proportional to the features actually used.1112Gea is especially appropriate for interactive websites, dashboards, product interfaces, animation-heavy UI, embedded widgets, mobile-style web interfaces, and applications where bundle size and update cost matter. It does not replace a Node/Python/Go backend, database, job worker, or API layer. The backend may serve data and SSR HTML; Gea runs the interactive client layer.1314## Workflow15161. **Inspect before coding.** Identify the existing stack, package manager, entry point, Vite configuration, TypeScript settings, rendering mode, browser support, and current bundle/performance symptoms. Do not convert an entire app to Gea merely because Gea is small.172. **Choose the rendering path.**18 - New Vite app: use `npm create gea@latest` and the official Vite plugin.19 - Existing Vite app: add the Gea plugin only after checking JSX ownership and coexistence constraints.20 - No-build page or small widget: use the browser runtime; use Babel only when runtime JSX is genuinely necessary.21 - SEO/first-paint/server-rendered app: use `@geajs/ssr`, then hydrate on the client.22 - Backend-only request: do not introduce Gea; return an API/server solution instead.233. **Model state deliberately.** Put shared mutable state in a small `Store` class. Keep presentational pieces as pure function components; use class components for state and lifecycle. Use getters for computed values. Avoid duplicating derived state.244. **Build the smallest correct UI.** Use Gea JSX (`class`, lowercase event attributes such as `click`/`input`/`change`), semantic HTML, stable keys/identifiers, and the least expensive DOM structure. Import optional router/UI/mobile/SSR features only when needed.255. **Design motion separately from state.** Prefer CSS transitions/keyframes for declarative motion. Use `requestAnimationFrame` for continuous imperative motion, and keep animation state local or outside high-frequency global stores. Never cause layout thrashing by alternating reads and writes in a loop.266. **Verify behavior and delivery.** Run typecheck, lint, tests, production build, and bundle-size inspection. Check hydration, keyboard operation, reduced-motion behavior, responsive layout, and cleanup after component disposal.277. **Report trade-offs.** State what Gea improves, what remains backend-owned, which optional packages were added, and the measured before/after bundle or interaction result. Treat README benchmark numbers as indicative, not as a guarantee for every app.2829## Non-negotiable Gea rules3031- Use `@geajs/vite-plugin` for compiled JSX/reactivity. Do not assume ordinary Babel JSX alone provides Gea’s compile-time reactivity.32- In Vite JSX, use `class`, not React’s `className`; use lowercase native event attributes such as `click`, `input`, `change`, and `keydown`, not `onClick`.33- In a class component, keep the root structure compatible with Gea’s ownership model; the browser/manual-template path requires the root `id="${this.id}"`.34- Do not add React hooks, signals, dependency arrays, `setState`, `emit`, or `v-model` patterns unless integrating an external library that explicitly requires them.35- Do not manually attach one listener per element when delegated `events` or JSX event attributes can express the behavior.36- Do not perform side effects in function components. Put effects in lifecycle methods or explicit store/service methods.37- Unsubscribe every manual `store.observe()` subscription; store its remover in `GEA_OBSERVER_REMOVERS` or use the documented lifecycle cleanup mechanism.38- Never put secrets, database credentials, privileged operations, or backend-only code in a client bundle.39- Do not claim that Gea automatically optimizes arbitrary third-party animation libraries. Measure the library, import only required modules, and wrap it behind a cleanup-aware component boundary.4041## Component and state selection4243| Need | Preferred Gea design |44| --- | --- |45| Static/presentational markup | Pure function component |46| Local interactive behavior/lifecycle | Class component |47| Shared mutable state | One focused `Store` instance |48| Derived state | Getter on the store or component |49| Server data | API client/service + store; handle loading/error/empty states |50| Modal/menu/tooltip/accordion | `@geajs/ui` when its accessibility behavior is useful |51| Mobile navigation/gestures | `@geajs/mobile` only when needed |52| URL navigation | Tree-shakeable router APIs from `@geajs/core` |53| Server HTML/hydration | `@geajs/ssr` with per-request store isolation |54| Backend logic | Separate server framework/service |5556## Performance and animation playbook57581. Measure first: production build, compressed JS/CSS, long tasks, layout/paint, interaction latency, and animation frame rate.592. Keep hot state local. Do not update a global store at pointer/touch/scroll frequency unless multiple views truly need it.603. Animate `transform` and `opacity` where possible. Avoid repeatedly changing layout properties such as `top`, `left`, `width`, and `height` during a frame loop.614. Batch reads before writes, use `requestAnimationFrame`, cancel handles on dispose, and respect `prefers-reduced-motion: reduce`.625. For large lists, minimize reactive dependencies, paginate/virtualize where appropriate, and avoid recreating large arrays or markup for unrelated changes.636. Use `store.silent()` only when intentionally managing the corresponding DOM update yourself; document the invariant so the UI cannot silently become stale.647. Lazy-load routes and heavy animation/editor/chart libraries. Confirm tree-shaking in the final bundle rather than trusting import syntax.6566## Validation checklist6768- `npm run build` succeeds in production mode.69- `npm run typecheck`/`tsc --noEmit` and lint pass when configured.70- No hydration mismatch or cross-request store leakage exists in SSR.71- Keyboard navigation, focus restoration, labels, semantics, and reduced motion work.72- Components dispose observers, timers, animation frames, and third-party instances.73- Network/API failures have visible loading, empty, retry, and error states.74- Bundle output is inspected in compressed form; benchmark claims are not copied without measurement.75- If converting from another framework, behavior and accessibility are tested before comparing size.7677## Progressive references7879Read only the reference needed for the task:8081- [API and syntax](references/api-reference.md): stores, components, JSX, browser runtime, router, SSR, package boundaries, and migration traps.82- [Performance and animation](references/performance-and-animation.md): measurement, CSS/WAAPI/rAF decisions, high-frequency input, cleanup, and third-party libraries.83- [Recipes and diagnostics](references/recipes-and-diagnostics.md): complete patterns for app setup, stores, SSR, widgets, conversion, and failure diagnosis.84- [Templates](templates/): ready-to-use production scaffolds:85 - `templates/minimal-starter/`: Official Vite + TypeScript starter with Store, Component, and Vite plugin.86 - `templates/router-starter/`: Declarative client-side routing with `@geajs/core/router`.87 - `templates/zag-ui-dialog/`: Accessible modal dialog pattern with `@geajs/ui`.88 - `templates/mobile-starter/`: Hybrid mobile views and transitions with `@geajs/mobile`.8990When Gea’s current repository/API differs from these references, inspect the installed package and official repository docs before changing code. Prefer source and type definitions over assumptions.9192## Response contract for agents using this skill9394When producing or modifying Gea code, explain briefly: (1) rendering mode, (2) state ownership, (3) animation strategy if relevant, (4) optional packages added and why, (5) verification performed, and (6) any backend boundary. Return runnable code rather than framework-agnostic pseudocode unless the user explicitly asks for a design only.9596Source of truth used to design this skill: https://github.com/dashersw/gea and its `docs/` directory. Gea is MIT-licensed; verify the installed version before relying on version-specific APIs.9798---