factcircuit
FactCircuit는 불변 출처와 단계별 검증, 제한된 검색, 재현 가능한 평가를 제공하는 감사 가능한 주장·증거 검증 루프입니다
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Free, open-source browser GIS: interactive web maps, map briefings, guided tours, field tasks and LiDAR/3D from one link. AI-agent ready (llms.txt, agent skill, JSON link forms). No account or server. MapLibre, three.js, ArcGIS.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗GISMap.online makes interactive web maps and map briefings from one link. It's free and open source and runs in the browser: no account, API key or server. People build in the app; AI assistants write the link.
| Make | From | Example |
|---|---|---|
| Styled, filtered web map | ArcGIS REST, GeoJSON, WMS, KML, GeoParquet, PMTiles, local files | California grape production |
| Map briefing (slides on a live map) | The same layers, one slide per area or time | Philadelphia police divisions |
| Guided map tour | Places in order, with camera and captions | San Francisco landmarks |
| Field task with check-in and report | A location and a checklist | Park inspection |
| 3D: extrusions, LiDAR, CAD models | Polygons; LAS/LAZ; glTF, OBJ, PLY | LiDAR and 3D models |
Every result is one link with readable JSON after json:. A chatbot can write it without running code:
https://gismap.online/#map=json:{"version":1,"layers":[{"url":"<layer URL>","renderer":{"type":"choropleth","field":"<FIELD>"}}]}
https://gismap.online/?tourOnly=1#tour=json:{"title":"…","stops":[{"name":"…","lat":37.8,"lon":-122.4}]}
https://gismap.online/?workflow=tasks#fieldTask=json:{"title":"…","lat":37.76,"lon":-122.43,"steps":["…"]}
Briefings go inside the map JSON ("briefing": {...}). Start with llms.txt, the agent skill (Claude Code, Codex), the agent recipes (JSON) and the map-v1 schema. In an open page, globalThis.gisMapOnline is the in-page API.
GISMap supports MapLibre (the default, with three.js for point clouds and models) and the ArcGIS Maps SDK. It uses native ES modules, local browser project storage and portable project packages; no application login or database is required. The interface uses a layered globe-and-analysis mark with an editable HTML wordmark and the descriptor “Spatial intelligence studio.”
The examples index and featured dataset pages are generated from js/catalog.js:
node scripts/build-examples.mjs
CI runs the same script with --check to keep the committed pages and sitemap in
sync with the application catalog.
Choose Project > Copy share link to copy a URL that reopens the current public
remote layers and basemap. Local files and credentials are never included. Shared
URLs use repeatable layer and layerType parameters; curated catalog entries may
also be opened with ?example=<slug>. Only HTTPS resources are accepted in
production (HTTP is permitted for localhost development).
The SDK and browser module security require HTTP; do not open index.html directly from the filesystem.
python3 -m http.server 8080
Then open http://localhost:8080.
Tools → Map assistant is a chat with the AI model the user connects in Project → Configure AI (local Ollama, OpenAI, Anthropic or any OpenAI-compatible endpoint). It builds interactive maps, briefings, guided tours and field-task drafts through 17 tools (js/map-assistant.js): get_map_state, inspect_source, search_datasets, query_features, add_layer, update_layer, remove_layer, suggest_styles, set_view, set_basemap, load_map, create_briefing, generate_briefing, present_briefing, create_tour, draft_field_task and get_share_link. The app writes the model's instructions (how to work from data, the formats, the live map state) and sends them as the system message with every turn; nothing is registered with the provider. Models with tool calling use it natively (Ollama /api/chat, Chat Completions, Anthropic Messages); others fall back to fenced JSON tool calls. Everything runs in the browser.
Language models and agents start at /llms.txt (the whole reference is in /llms-full.txt) and the guide Making maps with an AI agent, with recipes for a chat-only model, a code-running agent and a browser-driving agent. Worked examples show chatbots and agents making real maps and briefings, with their prompts, code, links and QR codes. /api/url-parameters.json and /api/catalog.json list every link parameter and the curated datasets. These files are generated by node scripts/build-examples.mjs and readable from any origin.
Everything an agent needs is on globalThis.gisMapOnline once await gisMapOnline.ready resolves (also a gismap:ready event and <html data-gismap-state="ready">):
const api = globalThis.gisMapOnline;
await api.ready;
const corn = await api.layers.add("https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/Corn/FeatureServer/0", {
renderer: { type: "choropleth", field: "CORN_SALES_IN_DOLLARS", ramp: "greens" }, // -1 "Not Disclosed" goes to "No data"
});
await api.camera.fitTo(corn.id);
api.describe(); // capabilities + live layers, basemap, camera, skin, mode
await api.application.runTool("layer.filter", { layer: corn.id, where: "CORN_SALES_IN_DOLLARS >= 0" });
A chat-only model can make a map by writing a map-v1 spec and URI-encoding it into a link:
https://gismap.online/#map=json:{"version":1,"basemap":"gray-vector","layers":[{"url":"https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/Corn/FeatureServer/0","renderer":{"type":"choropleth","field":"CORN_SALES_IN_DOLLARS","method":"auto","ramp":"greens","exclude":[-1]}}]}
URI-encode the JSON (encodeURIComponent) when you can; the readable form holds up to 8,192 characters. gisMapOnline.mapSpec.createLink(spec) (or mapSpec.createLink from js/gismap-core.js) gives the compressed #map= form, and ?spec=<https URL> opens a hosted spec. For one layer and one field there is no JSON at all: ?layer=<URL>&style=choropleth&field=<FIELD>&method=auto&ramp=greens&exclude=-1&basemap=gray-vector. Invalid parts are skipped and listed in describe().state.issues.
"method": "auto" lets the app choose the class breaks from the data (quantile for skewed values, natural breaks for clusters, equal interval for even spreads), and { "type": "auto", "field": "…" } (style=auto) lets it choose the whole style. breaks: [1000, 50000, …] fixes the classes. When the app resolves an auto style it records the result with its breaks, so saved projects and shared links look the same for everyone. gisMapOnline.layers.suggestStyles(id, { field }) (and the Style options list in the style panel) ranks the styles that suit a field, each with a reason, its breaks and a pinnedSpec to apply; renderers.suggest in js/gismap-core.js does the same from values you pass in.
Errors are GisMapError with a code and a hint written for agents. The contracts are api/capabilities.json (namespaces, stability, tools with input schemas, error codes, ramps, basemaps, URL parameters), schemas/renderer-v1.schema.json and js/gismap-core.d.ts (InPageApi). A ?layer= link zooms to its data unless it says zoom=none or gives center=lon,lat&level= / &scale=.
GISMap exposes the same versioned Briefing functions to in-page agents and to ES-module callers. No GISMap server or account is required.
const api = globalThis.gisMapOnline;
const slide = api.briefing.createSlide("map-narrative", {
title: "Where improvements are planned",
});
const document = api.briefing.addSlide(api.briefing.create(), slide);
api.briefing.load(document); // opens the document in Briefing
// The same link the app shares: it opens the slides with the map's layers,
// styles, filters, skin and view. { documentOnly: true } gives a slides-only
// link (#briefing=b1.…) that applies to whatever layers the URL loads (?layer=…).
const link = await api.briefing.createLink(document, { qrSafe: true });
const project = api.briefing.exportGmo(document); // { fileName, mimeType, text, blob }
// Build slides from the map as it looks (style, filter, chosen features), and render the PDF handout.
await api.briefing.generate({ layerId: "https://…/FeatureServer/0", ai: true });
const pdf = await api.briefing.exportPdf(); // File
const qrCard = await api.briefing.exportQrCard(); // branded PNG File
The experimental in-page briefing.generateTemplate API previews or appends Filter Series, Timeline, Grid Atlas, and 3D Spatial Chart slides from an already loaded layer. It queries at most 500 features and reports coverage as unknown; its statistics are not guaranteed complete. Set previewOnly: true to avoid saving. It is not a standalone core or HTTP API. See data-driven briefing API for options, geometry limits, and verification guidance.
A briefing document can say which data it is about: layerId is best given as the layer's service URL, which GISMap loads if it is not already on the map, and selection.ids lists the chosen features. Host a document as JSON (CORS-enabled) and link to it as https://gismap.online/?briefing=<file URL>; GISMap opens it on that layer and starts presenting. The file may be a briefing document, a project that contains one, or the briefing file the share dialog downloads.
Headless agents can import the pure core without opening the app:
import { briefing, sources } from "./js/gismap-core.js";
const metadata = await sources.inspect("https://example.org/arcgis/rest/services/Projects/FeatureServer/0");
const result = briefing.validate(document);
The machine-readable contracts are api/capabilities.json, schemas/briefing-v1.schema.json, and the gismap-core TypeScript declarations. Filters, slides, blocks, cameras and styles are declarative data; credentials and temporary viewer state do not belong in a briefing. Browser source inspection remains subject to CORS. The library does not provide hosted links, access control, or background jobs.
Project → Download project can create a Smart map image: a polished, standards-compliant PNG containing the complete editable project configuration in GISMap's private giMp ancillary chunk. The visible image opens normally anywhere; importing the original PNG through Project → Import restores its camera, basemap, public layer references, styling, bookmarks, workflows, and Briefing slides.
const output = await gisMapOnline.smartImages.createCurrent();
const manifest = await gisMapOnline.smartImages.read(output.blob);
console.log(output.file.name, output.share?.url, output.share?.qr);
await gisMapOnline.smartImages.downloadCurrent();
createCurrent() gives an agent the PNG without forcing a browser download and also returns share, the equivalent live-map link with public layers, styles, filters, camera, basemap, and skin. createShareLink() returns that link directly. Its qr flag says whether it fits safely in GISMap's separate branded QR image. Keeping the QR as a separate artifact leaves the Smart Image clean while providing a reliable route back to the live map; GISMap can also reopen QR screenshots and photos.
The embedded payload is versioned, deflate-compressed when supported, protected by PNG CRC and SHA-256 integrity checks, and bounded by explicit input limits. Remote URLs containing credentials are rejected. Smart Images reference public services and do not make those services offline; use .gisx when local datasets must travel with the project. Keep the original PNG—social networks and image editors may resize it or remove ancillary metadata. When another service strips the private PNG chunk, share the companion live link or QR image alongside it.
Feature branches under codex/** run .github/workflows/development-preview.yml. Every run produces a 14-day static preview artifact after the complete test suite and JavaScript syntax checks pass. An isolated Cloudflare Pages development deployment is enabled only when the development GitHub environment defines CLOUDFLARE_PAGES_PROJECT_DEV, CLOUDFLARE_API_TOKEN_DEV, and CLOUDFLARE_ACCOUNT_ID_DEV. These names deliberately do not reuse production credentials or destinations, and the workflow has no production trigger.
The production site remains unchanged until its separate release process is explicitly invoked.
The current application version is recorded in VERSION. Releases use
Semantic Versioning and vX.Y.Z Git tags. See the
CHANGELOG.md for feature-level history and the
GitHub Releases page for
published builds and generated release notes.
Keep VERSION, js/version.js, and api/capabilities.json in sync; tests check
their agreement. Asset cache-busting revisions and portable document schema
versions are independent and need not match the application version.
js/map-controller.js — the provider-neutral application facade: selects an engine and owns workflows that can be composed from common map primitivesjs/engines/engine-registry.js — lazy engine registration and factory; MapLibre is the default and additional renderers can register without changing application consumersjs/engines/engine-interface.js — the small renderer contract plus the larger application facade, capabilities, events and plain-data types (layer handles, features, view targets)js/engines/maplibre/maplibre-engine.js — the MapLibre preview renderer (?engine=maplibre or Map → Map engine): OpenFreeMap basemaps and open raster-DEM 3D terrain; GeoJSON and ArcGIS feature layers held in the browser (filtered, queried and identified here, spatial relationships asked of the service); ArcGIS map image and imagery services and WMS as images; camera and capture. Beside it: terrain.js, arcgis-service.js (describing and paging ArcGIS services), arcgis-renderer.js (ArcGIS renderers as MapLibre paint), where.js, geojson.js and basemaps.jsjs/basemap-themes.js — basemap themes derived from a skin's design tokens (the "skin" basemap); js/engines/maplibre/basemap-theme.js applies one to an OpenMapTiles style by layer rolejs/engine-preference.js — which engine draws the map: the link's ?engine=, then the saved Display settings choice, else MapLibrejs/engines/arcgis/arcgis-loader.js — loads ArcGIS runtime CSS and JavaScript only when the ArcGIS renderer is selectedjs/engines/arcgis/arcgis-engine.js — the ArcGIS renderer adapter: 3D scene/camera lifecycle, elevation ground, layer adapters, queries, identify, drawing, refresh, rendering, navigation, capture and geocodingjs/identify.js — popup-free identify results from the engine, de-duplicated across layer typesjs/ui.js — sidebar, menus, tabbed workspace tools, layer controls, places, and insight renderingjs/project.js — local projects plus .gis project and .gisx package import/export (legacy JSON/ZIP files remain supported)js/attribute-table.js — searchable, paginated queryable layer table in a non-modal map drawerjs/ai.js — optional Ollama, OpenAI, Anthropic, and OpenAI-compatible adapters; online tokens stay in memory onlyjs/tool-manager.js — opt-in local JavaScript tool registrationSELECT, WITH, DESCRIBE, EXPLAIN, SHOW, or SUMMARIZE statement at a time. Data-changing statements, extension loading, arbitrary attachment, imports, and exports are rejected before execution. AI-assisted requests always produce a visible plan for review and use the same validator./rest/info and associated with their owning Portal. Standalone Servers can use either a discovered token endpoint or explicitly configured browser-managed web-tier authentication (IWA, PKI, or reverse proxy).GeoJSONLayer instances and retain refresh, styling, and table settings in project files.MapImageLayer./query URLs are accepted and normalized to their layer endpoint; and are applied to the native feature layer. Layer zoom uses a live, filter-aware feature extent when supported, avoiding stale or malformed service extents.js/events.js — pub/sub event busjs/application-state.js — authoritative selections, filters, active layer, time, styling, navigation, bookmarks, and chaptersjs/application-registry.js — validated panel and tool extension contracts with lifecycle cleanupjs/application-config.js — versioned application configuration, presets, and legacy presentation migrationjs/layout-manager.js — constrained dock placement and reversible previews around one map instancejs/application-runtime.js — registered workspace/data/presentation panels and approved builder operationsjs/data-catalog.js — portable catalog schema, read-only SQL validation, and deterministic natural-language query planningjs/gismap-core.js — pure client-side API for briefing documents, filters, statistics, source inspection, and share encodingjs/briefing-api.js — binds the pure API to the active GISMap project and camera as globalThis.gisMapOnline.briefingjs/smart-image.js — renders portable map PNGs and safely embeds or restores versioned GISMap project manifestsjs/duckdb-client.js — optional, lazily loaded DuckDB-Wasm execution for browser feature records and HTTPS analytical sourcesjs/catalog.js — public data services plus categories, stable slugs, source
metadata, reuse guidance, tags, and featured-example controlsscripts/build-examples.mjs — generates the searchable examples index,
featured dataset pages, viewer guides, and sitemapjs/share.js — safe parsing and creation of shareable remote-layer URLsjs/markdown.js — sanitized Markdown rendering for intelligence responsesjs/enterprise-catalog.js — live ArcGIS Enterprise service-directory browserjs/engines/arcgis/arcgis-auth.js — ArcGIS Online/Enterprise OAuth, standalone Server token/web-tier registration, federation discovery, and connection diagnosticsjs/export/ — paginated vector retrieval and background-worker GeoJSON/KML/KMZ/Shapefile conversionwhereoutFieldslaunchctl setenv OLLAMA_ORIGINS "https://gismap.online", fully quit Ollama, and reopen it..shp, .shx, and .dbf components.