npx agentspec-cli install 08afcbb0-e5fe-4ead-800a-13d280ec248e --file-type cursorrules→ .cursor/rules/
# dash-openlayers — AI Agent Rules
`dash-openlayers` bridges a declarative Python/Dash API with an imperative
OpenLayers (Canvas/WebGL) runtime through React. Violating the invariants
below produces code that looks correct but leaks memory, breaks the Python
wrapper generator, or silently mis-projects coordinates. Follow them exactly.
## 1. React & OpenLayers Lifecycle Rules
- Every OpenLayers object (`ol/Map`, `ol/layer/*`, `ol/source/*`,
`ol/interaction/*`, event listeners via `.on(...)`) MUST be instantiated
inside a `useEffect`/`useLayoutEffect` hook — never at module scope or
directly in the render body.
- Every `useEffect` that creates an OpenLayers object MUST return a cleanup
function that disposes it: `map.removeLayer(layer)`,
`map.removeInteraction(interaction)`, `map.setTarget(null)`,
`source.clear()`, `unByKey(listenerKey)`. Do not rely on garbage collection.
- Do not hold OpenLayers instances (`Map`, `layer`, `source`) in React state
unless the component render output depends on them. Prefer `useRef` for
imperative handles; use `useState` only for the value(s) consumed by JSX
(e.g. `OLContext.Provider value={map}` needs state so children re-render
once the map exists).
- Never mutate an OpenLayers instance stored in a ref during render. All
mutation happens in effects or event handlers.
- New components consume the map via `useMap()` from
`src/lib/context/OLContext.js` — never re-implement context lookup or pass
the map instance through props.
## 2. Dash State Bridge Rules
- Outward event propagation to Python is **only** done via
`setProps({ propName: value })`. Never invent a new callback mechanism.
- `setProps` is optional at runtime (Dash omits it outside a live app); always
guard with `if (setProps) { ... }` before calling it.
- Props that Dash can set from Python and that the component also updates
itself (e.g. `center`, `zoom`) must be documented as bidirectional in their
JSDoc (see Docstring Invariant below).
- Do not hallucinate React state for data that Python owns. If a prop comes
from Dash, treat it as the source of truth and call the matching OpenLayers
setter (`view.setCenter()`, `view.setZoom()`) — do not shadow it in local
`useState` unless reconciling controlled/uncontrolled updates.
## 3. Docstring Invariant (mandatory)
`dash_openlayers/metadata.json` is the maintained source for generated Python
wrapper types/docstrings and the API reference. Keep each metadata description
aligned with the component's `propTypes` and JSDoc.
- Every single key in `propTypes` MUST have a JSDoc block comment (`/** ... */`)
immediately above it describing the prop, its units/coordinate order where
relevant, and whether it is bidirectional.
- Banned: inline `//` comments on `propTypes` entries — they are not parsed
by `react-docgen` and do not satisfy the invariant.
```javascript
// DO
PropTypes.shape({
/** Component ID, used for Dash callback matching. */
id: PropTypes.string,
/** [lon, lat] in EPSG:4326, converted internally per `projection`. */
center: PropTypes.arrayOf(PropTypes.number),
});
// DO NOT
PropTypes.shape({
id: PropTypes.string, // component id
});
```
## 4. Styling & Bundle Rules
- Import `ol/ol.css` only at component boundaries that render a map
(currently `Map.react.js`). Do not re-import it from every component —
Webpack/Rollup's `css-loader`/`style-loader` will otherwise emit duplicate
CSS into the bundle.
- Keep OpenLayers/proj4 imports scoped to the file that needs them
(tree-shaking friendly); do not add a barrel file that re-exports all of
`ol/*`.
## 5. Coordinate & Projection Rules
- OpenLayers coordinates are always `[x, y]` — i.e. `[lon, lat]` in
EPSG:4326/EPSG:3857, not `[lat, lon]`. Never pass `[lat, lon]` to
`fromLonLat`, `View.center`, or a geometry constructor.
- Use `ol/proj` helpers (`fromLonLat`, `toLonLat`, `transform`) for all
conversions; do not hand-roll trigonometric projection math.
- Custom EPSG definitions arrive from Python as `proj4Defs` (`{code, def}`)
and must be registered with `proj4.defs(code, def)` followed by
`register(proj4)` from `ol/proj/proj4` **before** a `View` using that
projection is constructed.
## 6. Repository File Map
| Path | Purpose |
| --- | --- |
| `src/lib/components/*.react.js` | React components (OpenLayers wrappers) |
| `src/lib/context/OLContext.js` | Map instance context (`useMap()`) |
| `src/index.js` | Public JS export surface — update when adding a component |
| `dash_openlayers/*.esm.js`, `*.umd.js` | Generated JS bundles — never hand-edit, regenerated by `npm run build` (Rollup) |
| `dash_openlayers/metadata.json` | Maintained source metadata; update alongside React `propTypes` and JSDoc |
| `dash_openlayers/<Component>.py`, `_imports_.py`, `docs/api.md` | Generated from metadata by `npm run build`; do not hand-edit |
| `tests/` | Python tests (`pytest`) |
| `usage*.py` | Manual/demo Dash apps exercising components |
## 7. Build, Test & Verification Commands
```bash
npm install # JS deps
npm run build # JS bundles + Python wrappers/imports + API reference — see §8
npm run lint # ESLint over src/
npm run format # Prettier over src/ and root JS/JSON
uv sync # Python dev deps (pytest, ruff, pre-commit)
uv run pytest -q # Python tests
uv run ruff check . # Python lint
uv run ruff format . # Python format
uv run coverage xml # coverage CLI lives in the uv venv — always prefix with `uv run`, never call `coverage` bare (breaks in CI)
```
Run `npm run build` after any component or prop change. Update its entry in
`dash_openlayers/metadata.json`; the build generates Python wrappers/imports
and `docs/api.md`. Verify those generated diffs before committing.
## 8. Python Wrapper & Bundle Generation Reality Check
- `npm run build` runs Rollup, then `scripts/generate_components.py` and
`scripts/generate_api_docs.py`. The checked-in metadata is the source for
generated Python classes, imports, package-info, and `docs/api.md`. Update
the metadata alongside React `propTypes`/JSDoc, then run the full build.
The generator verifies that every React component has a metadata entry.
Do not hand-edit generated Python wrappers or API docs.
- `dash_openlayers/__init__.py`'s `_js_dist` must list **only** the UMD
bundle (`dash_openlayers.umd.js`). Dash serves `relative_package_path`
assets as plain `<script src=...>` tags — it only adds `type="module"`
for `asset_path` files ending in `.mjs`. Listing the ESM build
(`dash_openlayers.esm.js`) in `_js_dist` makes the browser throw
`Uncaught SyntaxError: Unexpected token 'export'`. The ESM bundle can
still be built and referenced via `package-info.json`'s `module` field
for npm/bundler consumers — just keep it out of `_js_dist`.
- `rollup.config.js` must mark `react`, `react-dom`, and `prop-types` as
`external` (with `output.globals` for the UMD build). Without this the
UMD bundle embeds a second copy of React, and once it runs alongside
Dash's own React instance, hooks like `useRef` fail at runtime
(`Cannot read properties of null (reading 'useRef')`) and nothing renders.
## 9. Agent Skills
Executable skill recipes live under `.agent/skills/`. Prefer using them over
hand-writing boilerplate:
| Skill | When to use |
| --- | --- |
| `scaffold-dash-ol-component` ([SKILL.md](.agent/skills/scaffold-dash-ol-component/SKILL.md)) | Adding a new component — produces the React file, `src/index.js` export, Python test draft, and usage demo in one pass |
| `gis-projection-validator` ([SKILL.md](.agent/skills/gis-projection-validator/SKILL.md)) | Auditing or adding coordinate/projection code (`fromLonLat`, `proj4Defs`, custom EPSG) |
| `dash-duo-test-generator` ([SKILL.md](.agent/skills/dash-duo-test-generator/SKILL.md)) | Adding Selenium-based `dash_duo` integration tests for interactive map behavior |
| `dash-ol-test-runner` ([SKILL.md](.agent/skills/dash-ol-test-runner/SKILL.md)) | Writing and running tests across all layers (unit, integration, demos), coverage commands, CI alignment, and debugging failing browser tests |
=====================
Cursor IDE rules and conventions for AI-assisted development.
by AgentHub Crawler
Cursor AI Rules for Interact Platform
import { useQuery } from '@tanstack/react-query'; export const useActivities = () => { queryKey: ['activities'], queryFn: () => api.get('/activities'),
by AgentHub Crawler
🤖 OpenClaw JS — Manual for AI Agents
**Welcome!** If you are an AI Coding Agent tasked to modify, review, or debug this project, read this document first. It contains essential architectural constraints, coding conventions, and project-specific knowledge.
by AgentHub Crawler
Sign in to leave a comment.
nano-binary-search — AI Agent Rules
nano-binary-search is a single-function binary search (lower bound) for JavaScript. Zero dependencies, single file. Equivalent to C++ `std::lower_bound` / Python `bisect.bisect_left`.
by AgentHub Crawler