# System map — excalidraw/excalidraw

> Canonical page: https://codevetter.com/unpack/excalidraw/system-map

# System map — excalidraw/excalidraw

Scanned commit 31df3e6ef245c646b18a055ccf858cd6117c7768 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The runtime splits into a publishable editor (packages/excalidraw) and a Vite app (excalidraw-app) that mounts it. Geometry and the element model live in @excalidraw/element, @excalidraw/math, and @excalidraw/common; export helpers live in @excalidraw/utils. The app talks to three external systems configured only by Vite env vars: a Socket.IO collab server, Firebase (Firestore scenes plus Storage blobs), and an HTTP share backend. Production is a static Vite build deployed to Vercel or an nginx image; package publishes go through scripts/release.js on the release branch.
- Root package excalidraw-monorepo is a private Yarn 1.22.22 workspace (node >=18) covering excalidraw-app, packages/*, and examples/*. Scripts delegate: yarn start runs the Vite app, yarn build:packages builds common, fractional-indexing, laser-pointer, math, element, then excalidraw, and yarn test:all chains typecheck, eslint, prettier, and vitest. — [package.json#L1-96](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/package.json#L1-L96)
- The hosted app boots from excalidraw-app/index.tsx: it imports sentry, sets window.__EXCALIDRAW_SHA__ from VITE_APP_GIT_SHA, calls registerSW() from vite-plugin-pwa, and createRoot-renders <ExcalidrawApp /> in StrictMode. — [excalidraw-app/index.tsx#L1-17](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/index.tsx#L1-L17) [excalidraw-app/package.json#L43-52](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/package.json#L43-L52)
- The npm component entry is packages/excalidraw/index.tsx. ExcalidrawBase normalizes UIOptions and imageOptions, blocks iOS pinch-zoom unless interaction.enabled.browserZoom is set, and renders EditorJotaiProvider > InitializeApp > App. Excalidraw is React.memo(ExcalidrawBase, areEqual). Package exports point at dist/prod/index.js with peer react 17, 18, or 19. — [packages/excalidraw/index.tsx#L67-266](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L67-L266) [packages/excalidraw/index.tsx#L401-402](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L401-L402) [packages/excalidraw/package.json#L1-78](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/package.json#L1-L78)
- Supporting packages are @excalidraw/common (constants, emitter, editorInterface, feature flags), @excalidraw/element (Scene, Store, element types, fractional index), @excalidraw/math, @excalidraw/utils (exportToCanvas/Svg wrappers), @excalidraw/fractional-indexing, and @excalidraw/laser-pointer. Vitest and the app Vite config alias every @excalidraw/* import at the TypeScript source, not dist. — [packages/common/src/index.ts#L1-17](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/common/src/index.ts#L1-L17) [vitest.config.mts#L6-73](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/vitest.config.mts#L6-L73) [excalidraw-app/vite.config.mts#L24-92](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/vite.config.mts#L24-L92) [tsconfig.json#L21-38](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/tsconfig.json#L21-L38)
- App-only env surface is declared in excalidraw-app/vite-env.d.ts: VITE_APP_WS_SERVER_URL, VITE_APP_FIREBASE_CONFIG, VITE_APP_BACKEND_V2_GET_URL, VITE_APP_BACKEND_V2_POST_URL, VITE_APP_AI_BACKEND, VITE_APP_PLUS_APP, VITE_APP_PLUS_LP, VITE_APP_PORTAL_URL, VITE_APP_ENABLE_PWA, VITE_APP_DISABLE_SENTRY, VITE_APP_GIT_SHA. Vite loads env from the repo root (envDir: '../') and serves on VITE_APP_PORT or 3000, writing the production bundle to excalidraw-app/build. — [excalidraw-app/vite-env.d.ts#L4-45](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/vite-env.d.ts#L4-L45) [excalidraw-app/vite.config.mts#L11-23](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/vite.config.mts#L11-L23) [excalidraw-app/vite.config.mts#L94-118](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/vite.config.mts#L94-L118)
- Vercel config sets outputDirectory to excalidraw-app/build, installCommand yarn install, CORS Access-Control-Allow-Origin https://excalidraw.com, and redirects /webex/* to for-webex.excalidraw.com plus vscode.excalidraw.com to the VS Code marketplace item. — [vercel.json#L1-68](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/vercel.json#L1-L68)
- Docker image is a multi-stage build: node:24 runs yarn --frozen-lockfile then yarn build:app:docker (VITE_APP_DISABLE_SENTRY=true), and nginx:stable-alpine-slim serves excalidraw-app/build. docker-compose publishes host 3000 to container 80 and bind-mounts the repo. Publish workflow on branch release pushes excalidraw/excalidraw:latest for linux/amd64, arm64, and arm/v7. — [Dockerfile#L1-20](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/Dockerfile#L1-L20) [docker-compose.yml#L1-24](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/docker-compose.yml#L1-L24) [excalidraw-app/package.json#L45](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/package.json#L45) [ .github/workflows/publish-docker.yml#L1-30](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/%20.github/workflows/publish-docker.yml#L1-L30)
- GitHub Actions: test.yml runs yarn test:app on push to master (Node 20); lint.yml on pull_request runs yarn test:other, yarn test:code, and yarn test:typecheck; test-coverage-pr.yml runs yarn test:coverage and posts a coverage comment. release-branch workflows run yarn release --tag=next and upload Sentry sourcemaps. — [.github/workflows/test.yml#L1-19](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/.github/workflows/test.yml#L1-L19) [.github/workflows/lint.yml#L1-22](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/.github/workflows/lint.yml#L1-L22) [.github/workflows/test-coverage-pr.yml#L1-25](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/.github/workflows/test-coverage-pr.yml#L1-L25) [.github/workflows/autorelease-excalidraw.yml#L1-27](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/.github/workflows/autorelease-excalidraw.yml#L1-L27) [.github/workflows/sentry-production.yml#L1-37](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/.github/workflows/sentry-production.yml#L1-L37)
- Firebase is initialized lazily in excalidraw-app/data/firebase.ts from JSON.parse(import.meta.env.VITE_APP_FIREBASE_CONFIG). Scenes are Firestore documents at scenes/{roomId}; image bytes go to Storage via uploadBytes. There is no collaboration server implementation in this repo — the client only opens socket.io-client against VITE_APP_WS_SERVER_URL. — [excalidraw-app/data/firebase.ts#L44-79](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/data/firebase.ts#L44-L79) [excalidraw-app/data/firebase.ts#L145-171](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/data/firebase.ts#L145-L171) [excalidraw-app/collab/Collab.tsx#L518-539](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/collab/Collab.tsx#L518-L539)
- Editor state is a React class component (packages/excalidraw/components/App.tsx) owning Scene, Renderer, Store, History, ActionManager, Library, and binary files. Two Jotai stores exist (editor-jotai inside the package, app-jotai in the host). ESLint forbids importing jotai directly. — [packages/excalidraw/components/App.tsx#L638-949](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L638-L949) [.eslintrc.json#L29-34](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/.eslintrc.json#L29-L34) [excalidraw-app/App.tsx#L83-89](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/App.tsx#L83-L89)
- Font subsetting runs off the main thread through WorkerPool in packages/excalidraw/workers.ts, which refuses to construct a worker whose URL equals import.meta.url (WorkerInTheMainChunkError). WASM assets for harfbuzz and woff2 live under scripts/wasm. — [packages/excalidraw/workers.ts#L23-59](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/workers.ts#L23-L59) [packages/excalidraw/subset/subset-main.ts](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/subset/subset-main.ts)
- scripts/release.js publishes packages common, fractional-indexing, math, element, and excalidraw (utils is explicitly skipped). Tags are test (default), next, or latest; latest requires --version and updates the changelog via child_process execSync. — [scripts/release.js#L1-49](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/scripts/release.js#L1-L49)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
