Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0a2c181
feat(core): move the brand allowlist into core
hyamero Sep 28, 2026
09ef669
feat(core): measure text with generated Geist metrics
hyamero Sep 28, 2026
6ae8515
feat(core): derive per-slot text budgets for node cards
hyamero Sep 28, 2026
da80ad6
feat(schema): add the DiagramDraft schema and JSON Schema export
hyamero Sep 28, 2026
ef1ff93
feat(schema): validate diagrams with structured diagnostics
hyamero Sep 28, 2026
9891b34
fix(schema): address M1 review findings
hyamero Sep 28, 2026
362a051
feat(viewer): render the diagram embedded by deliver
hyamero Sep 28, 2026
adbc74d
feat(cli): add stackmap validate and deliver
hyamero Sep 28, 2026
3c3d981
fix(cli): address M2 review findings
hyamero Sep 28, 2026
0f4c427
feat(schema): add node evidence and a source URL for links
hyamero Sep 28, 2026
44acf9e
feat(viewer): expand the brand allowlist to 146 CC0 marks
hyamero Sep 28, 2026
00f0ea0
feat(viewer): add explorer state, graph and emphasis helpers
hyamero Sep 28, 2026
587fd4e
feat(viewer): add selection, inspector, search, lens, trace, views, d…
hyamero Sep 28, 2026
31cf0e8
fix(viewer): address M3 review findings
hyamero Sep 28, 2026
ee5f1c1
fix(viewer): fit views and focused cards clear of the chrome bands
hyamero Sep 28, 2026
62d5990
feat(cli): add stackmap serve with live reload
hyamero Sep 28, 2026
c071f6b
feat(viewer): add live reload status and PNG/SVG export
hyamero Sep 28, 2026
70525b3
fix: address M4 review findings
hyamero Sep 28, 2026
34a2144
feat(skill): add the stackmap agent skill, contract, schema reference…
hyamero Sep 28, 2026
9049d02
fix(schema): suggest moving a misplaced key into the object that acce…
hyamero Sep 28, 2026
35d5684
fix(skill): address M5 review findings
hyamero Sep 28, 2026
25abc6d
fix(viewer): centre revealed nodes between the chrome bands
hyamero Sep 28, 2026
4142c15
docs: add third-party notices and embed attribution in the viewer
hyamero Sep 28, 2026
9671a88
docs: add the README
hyamero Sep 28, 2026
5d1d84c
ci: add CI with e2e and visual regression
hyamero Sep 28, 2026
573134c
chore(cli): prepare @hyamero/stackmap for publishing
hyamero Sep 28, 2026
66b58fd
fix(core): measure text for Linux's whole-pixel glyph advances too
hyamero Sep 28, 2026
1b5186e
fix(core): allow a pixel of hinting in the Linux text model
hyamero Sep 28, 2026
5391ebc
test(viewer): add the Linux visual baselines
hyamero Sep 28, 2026
bf40938
docs(skill): update card text budgets for the Linux-aware measure
hyamero Sep 28, 2026
1f6b2a1
test(schema): pin edge-label limits to characters, not UTF-16 units
hyamero Sep 28, 2026
95a9d09
fix(viewer): keep PNG exports within WebKit's canvas area limit
hyamero Sep 28, 2026
1d8e37e
fix(viewer): smooth held-key pans, minimap drag, zero-size mounts
hyamero Sep 28, 2026
c1200ae
fix(viewer): show a card CTA as a link only when it has an href
hyamero Sep 28, 2026
3945019
fix(core): give an unlinked CTA label the arrow's width back
hyamero Sep 28, 2026
63f5a7e
Merge pull request #10 from hyamero/feat/polish
hyamero Sep 29, 2026
3e683b8
feat(viewer): set section and group labels in sentence case
hyamero Sep 29, 2026
7cca1e4
feat(viewer): animate the intro, popovers, inspector and view tabs wi…
hyamero Sep 29, 2026
62909c5
test(viewer): update visual baselines for sentence-case labels
hyamero Sep 29, 2026
5b22127
test(viewer): check the reduced-motion camera jump frame by frame
hyamero Sep 29, 2026
73e600c
fix(viewer): settle motion per element, animate only new nodes on liv…
hyamero Sep 29, 2026
bf9f8e0
refactor(viewer): replace anime.js with the Web Animations API
hyamero Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
update-visual:
description: Regenerate the visual baselines and upload them as an artifact
type: boolean
default: false

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
name: test · typecheck · build
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- uses: actions/setup-node@v4
with:
node-version: 24
- run: bun install --frozen-lockfile
- run: bun run test
- run: bun run typecheck
- run: bun run build
- name: CLI smoke (deliver is deterministic)
run: node packages/cli/scripts/smoke.mjs

e2e:
name: e2e · visual
runs-on: ubuntu-latest
timeout-minutes: 20
# The same image the visual baselines were generated in, so fonts rasterise identically.
container: mcr.microsoft.com/playwright:v1.63.0-noble
env:
HOME: /root
steps:
- uses: actions/checkout@v4
- run: npm install -g bun@1.3.14
- run: bun install --frozen-lockfile
- run: bun run build
- name: Viewer e2e and visual regression
working-directory: packages/viewer
run: bunx playwright test ${{ inputs.update-visual && '--update-snapshots=all' || '' }}
- name: Delivered-file and live-serve e2e
if: success() || failure()
working-directory: packages/cli
run: bunx playwright test
# Always: a missing baseline is written by Playwright, and this is how it gets back into the repo.
- name: Upload visual snapshots
if: always()
uses: actions/upload-artifact@v4
with:
name: visual-baselines
path: packages/viewer/e2e/visual.spec.ts-snapshots/
- name: Upload Playwright results on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-results
path: |
packages/viewer/test-results/
packages/cli/test-results/
50 changes: 50 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
MIT License

Copyright (c) 2026 hyamero

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

---------------------------------------------------------------------------

stackmap is a successor to archify (https://github.com/tt-a1i/archify). Parts
of the agent skill (skill/references/authoring-contract.md) are adapted from
archify's documentation, used under the following license:

MIT License

Copyright (c) 2026 tt-a1i (Archify)
Copyright (c) 2025 Cocoon AI

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
97 changes: 97 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# stackmap

**Architecture and data-flow diagrams that your coding agent writes, delivered as one offline HTML file.**

You ask your agent to diagram a codebase or a system. It writes a small typed JSON, `stackmap` validates it with repair hints the agent acts on, lays it out, and hands you a single self-contained viewer — pan and zoom, search, trace upstream and downstream, guided views, dark and light themes, PNG/SVG export. No server, no account, nothing to install to open it.

<p align="center">
<img src="assets/readme/viewer-light.png" alt="stackmap viewer in light mode: a Commerce API topology with the Orders database selected and its upstream traced; the inspector shows its details, connections and source evidence" width="49%" />
<img src="assets/readme/viewer-dark.png" alt="The same diagram in dark mode" width="49%" />
</p>

## Quick start

Install the skill into your agent (Claude Code, Cursor, Codex and [others](https://github.com/vercel-labs/skills)):

```bash
npx skills add hyamero/stackmap
```

Then ask:

> Make an architecture diagram of this repository, backed by evidence from the code.

The agent writes `.stackmap/<name>/diagram.json`, validates and repairs it, and delivers `.stackmap/<name>/diagram.html`. Open that file in any browser. To change the diagram, just ask again — the agent edits the JSON and re-delivers; the viewer itself is read-only.

## The CLI

The skill drives the CLI for you, but it works on its own too (Node ≥ 22.12):

```bash
npx @hyamero/stackmap validate diagram.json [--json] # diagnostics with fixes; exit 1 on errors
npx @hyamero/stackmap deliver diagram.json [-o out.html] # validate → layout → one offline HTML file
npx @hyamero/stackmap serve diagram.json [--port 4400] # live viewer that reloads on every save
```

- **validate** reports every problem as `{ code, severity, subject, message, evidence, allowedFixes }` — schema errors, dangling references, group cycles, duplicate ids, orphans, and card text that wouldn't fit (measured with the real font). Exit codes: `0` ok, `1` the diagram has errors, `2` usage/IO/internal.
- **deliver** writes atomically and prints `delivered <path> · sha256 <hash> · <bytes> bytes`. The same input always gives byte-identical output.
- **serve** binds `127.0.0.1` only, keeps the last good version on screen when a save is invalid (the errors appear in a toast), and preserves the camera, selection and theme across reloads.

## The diagram

```json
{
"$schema": "https://unpkg.com/@hyamero/stackmap@0.1.0/dist/stackmap.schema.json",
"kind": "architecture",
"title": "Bookshop",
"direction": "DOWN",
"groups": [{ "id": "data", "label": "Data tier" }],
"nodes": [
{ "id": "api", "type": "service", "card": { "title": "shop-api", "subtitle": "REST API" },
"evidence": [{ "file": "services/api/src/server.ts", "line": 12 }] },
{ "id": "db", "type": "database", "group": "data", "card": { "title": "Orders DB", "subtitle": "PostgreSQL", "brand": "postgresql" } }
],
"edges": [{ "id": "api-db", "from": "api", "to": "db" }],
"views": [{ "id": "state", "label": "State", "nodes": ["db"] }]
}
```

Nine node types set the colour (`client`, `gateway`, `service`, `database`, `cache`, `queue`, `storage`, `external`, `security`); cards can carry rows, stats, a footer and a link; `brand` adds one of 146 [Simple Icons](https://simpleicons.org) logos. There are no coordinates — [ELK](https://eclipse.dev/elk/) lays everything out. Full reference: [skill/references/schema.md](skill/references/schema.md); modelling guidance: [authoring contract](skill/references/authoring-contract.md).

## The viewer

- **Explore:** click a card for its details, connections and source evidence (linked to your repo when `source.url` is set). **Trace** keeps a node's upstream and downstream and dims the rest.
- **Find:** `/` searches titles, subtitles, ids and types; the **lens** dims node types you don't care about.
- **Guided views:** tabs the agent defines (“Checkout path”, “Data tier”) that dim everything else and fit the camera.
- **Share:** state lives in the URL hash (`#view=…&node=…&lens=…`); export PNG (1×/2×), copy PNG, or an SVG snapshot.
- **Keyboard:** Tab reaches the toolbar, then the canvas; arrows move between cards, Enter selects, Esc clears; with the canvas focused, arrows pan and `+`/`-`/`0` zoom. Honours reduced motion.

## Development

Bun workspaces monorepo; tests run on Node via Vitest and Playwright.

```bash
bun install
bun run test && bun run typecheck && bun run build # unit tests, types, viewer template + CLI bundle
cd packages/viewer && bunx playwright test # viewer e2e (dev server)
cd packages/cli && bunx playwright test # delivered-file + live-serve e2e
```

| Package | What it does |
|---|---|
| `packages/core` | types, theme tokens, card metrics, headless text measurement (generated Geist metrics), samples |
| `packages/schema` | Zod schema → `stackmap.schema.json`, the validator and its diagnostics |
| `packages/layout` | ELK wrapper: diagram → absolute node/group/edge geometry |
| `packages/viewer` | React viewer, built into one self-contained HTML template |
| `packages/cli` | `@hyamero/stackmap`: validate · deliver · serve |
| `skill/` | the agent skill that `npx skills add` installs |

Visual regression baselines are Linux-only and are checked in CI. Regenerate them with the CI workflow's *update-visual* run (it uploads them as an artifact), or locally with `bun run --filter @stackmap/viewer visual:update` (Playwright's Linux image in Docker). `bun run --filter @stackmap/viewer metrics:gen` regenerates the font metrics after a font change.

## Credits

stackmap is a successor to [archify](https://github.com/tt-a1i/archify) by tt-a1i, itself based on [Cocoon AI's architecture-diagram-generator](https://github.com/Cocoon-AI/architecture-diagram-generator) — it keeps archify's agent → JSON → validate → single-HTML model and repair-loop contract, with a new renderer and visual language. Layout by [Eclipse ELK](https://eclipse.dev/elk/) (elkjs, EPL-2.0), fonts [Geist](https://vercel.com/font) (OFL-1.1), logos [Simple Icons](https://simpleicons.org) (CC0).

## License

[MIT](LICENSE). Third-party components and their licenses: [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
147 changes: 147 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Third-party notices

stackmap is MIT-licensed (see [LICENSE](LICENSE)). It builds on the work below.

## Shipped inside the viewer (every delivered HTML file, and `dist/viewer.html` in the npm package)

| Component | Version | License | Copyright |
|---|---|---|---|
| React, React DOM, scheduler | 19.3.0 / 0.28.0 | MIT | Meta Platforms, Inc. and affiliates |
| d3-zoom, d3-selection, d3-transition, d3-dispatch, d3-drag, d3-interpolate, d3-color, d3-timer | 3.x | ISC | 2010–2022 Mike Bostock |
| d3-ease | 3.0.1 | BSD-3-Clause | 2010–2021 Mike Bostock; 2001 Robert Penner |
| lucide-react | 1.48.0 | ISC | 2026 Lucide Icons and Contributors |
| html-to-image | 1.11.13 | MIT | 2017–2025 W.Y. |
| Simple Icons (146 marks) | 16.x | CC0-1.0 | public domain dedication; marks remain trademarks of their owners |
| Geist, Geist Mono (Latin subset, via @fontsource-variable) | 5.3.0 | SIL OFL 1.1 | 2024 The Geist Project Authors — full license below |

## Shipped inside the CLI bundle (`dist/cli.js`)

| Component | Version | License | Copyright |
|---|---|---|---|
| zod | 4.6.5 | MIT | 2025 Colin McDonnell |

## Runtime dependency (installed by npm, not bundled)

| Component | Version | License |
|---|---|---|
| elkjs (Eclipse Layout Kernel) | 0.12.x | EPL-2.0 OR GPL-3.0-or-later — used unmodified as a separate package; source at https://github.com/kieler/elkjs |

## Adapted documentation

Parts of `skill/references/authoring-contract.md` are adapted from [archify](https://github.com/tt-a1i/archify), MIT, Copyright (c) 2026 tt-a1i (Archify), Copyright (c) 2025 Cocoon AI. The full notice is included in [LICENSE](LICENSE) and [skill/LICENSE](skill/LICENSE).

## MIT license text (React, html-to-image, zod)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

## ISC license text (d3 modules, lucide)

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

## BSD-3-Clause (d3-ease)

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: (1) redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer; (2) redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution; (3) neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED.

## SIL Open Font License 1.1 (Geist, Geist Mono)

```
Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) Geist-Italic[wght].ttf: Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
```
Binary file added assets/readme/viewer-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readme/viewer-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading