This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
npm run dev # Start development server (Vite)
npm run build # Type-check + build for production
npm run build-only # Build without type checking
npm run type-check # Type-check Vue + TS files (vue-tsc)
npm run lint # Lint and auto-fix (ESLint)
npm run preview # Preview production buildThere are no automated tests; verification is manual.
Map Explorer is a fully browser-based geographic data visualization tool. It renders GeoJSON maps and colors regions by joining them with external CSV/Parquet data. All data querying happens client-side via DuckDB-WASM — there is no backend.
Configuration system (src/map-config/)
- Map configs are JSON files in
src/map-config/map-configs/. Files prefixed with_are ignored. - Loaded via
import.meta.globat build time and validated at runtime against a Zod schema (map-config/types.ts). - Config shape:
kind,geojsonFileName,dataFileName,idColumnGeojson,idColumnDataFile,categoryColumns,valueColumn,mapColorConfig, and optionalfilterdefaults.
Data processing (src/data-processing/)
ProcessorFactorycreates aCsvProcessororParquetProcessordepending on file extension.- Both extend the abstract
Processorclass. SQL query builders live inprocessors/helpers.ts. - DuckDB initialization and file registration is in
src/data-processing/duckdb.ts.
State management (src/map-manager.ts)
MapManagercaches loaded map states (GeoJSON + processor + region data) across map switches.ValidFilterLookupis an optimized index that prevents users from selecting invalid filter combinations.
Presentation (src/components/)
App.vueis the central orchestrator: it owns all reactive state and handles events bubbled up from children.map.vuerenders the SVG map using D3 (zoom/pan + region coloring).control-panel.vuedrives the filter/color controls.- Data flows unidirectionally: child components emit events →
App.vueupdates state → components re-render.
Color mapping (src/map-color.ts)
MapColorwraps D3 color interpolators. Supports 10+ schemes (viridis, plasma, etc.) with dynamic or fixed min/max scaling.
@/* resolves to ./src/* (configured in vite.config.ts and tsconfig.app.json).
- TypeScript: Use
type(notinterface) for object shapes. Derive types from Zod schemas withz.infer<typeof Schema>rather than duplicating them manually. Preferimport typefor type-only imports. - Naming: PascalCase for classes and Zod schemas (e.g.
MapColorConfigSchema), camelCase for functions and variables, kebab-case for Vue component filenames (e.g.control-panel.vue), UPPER_SNAKE_CASE for module-level constants. - Vue components: Use
<script setup>with the Composition API. Props are typed inline. Child components emit typed events;App.vuehandles them — keep business logic out of leaf components. - Async: Use
async/awaitthroughout. Fire independent async operations in parallel withPromise.all. - Comments: Inline comments explain why, not what. Use block comments (with
/** */) only for non-obvious classes or algorithms (seeValidFilterLookupinmap-manager.ts). - Zod: Define schemas first, derive TypeScript types from them. Apply
.refine()for cross-field validation on the schema itself.