vccs
Vue 3용 차트 컴포넌트 모음, Recharts에서 포팅
표 하나를 시각 그리드·Markdown·CSV·TSV·HTML·Jira·JSON 형태로 편집하고 모든 뷰를 동기화하며 브라우저에서만 작업합니다
Edit one table as a visual grid or as Markdown, CSV, TSV, HTML, Jira or JSON, every view kept in sync, entirely in your browser
데이터TypeScript · CSSGitHub @martonpaulo온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Edit one table as a grid, Markdown, CSV, TSV, HTML, Jira, JSON or records, with every view synchronized and everything running in your browser
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Edit one table as a grid, Markdown, CSV, TSV, HTML, Jira, JSON or records, with every view
synchronized and everything running in your browser.
Tabelo is a table editor for the moments when a spreadsheet is too much, but hand-editing pipes
and commas is no fun either. Change a cell in the visual table and the Markdown updates. Fix the CSV
and the table updates. Open up to four views at once and they all stay in sync. Everything runs
in your browser: no account, no server, no upload.README 전문 보기 ↗Edit one table as a grid, Markdown, CSV, TSV, HTML, Jira, JSON or records, with every view synchronized and everything running in your browser.
Tabelo is a table editor for the moments when a spreadsheet is too much, but hand-editing pipes and commas is no fun either. Change a cell in the visual table and the Markdown updates. Fix the CSV and the table updates. Open up to four views at once and they all stay in sync. Everything runs in your browser: no account, no server, no upload.
Tabelo is the word for table in the language Esperanto. It exists because moving a table between a wiki, a ticket, a spreadsheet and a code review usually means retyping it, and every retype is a chance to lose a line break, an alignment marker or a leading zero. Here one canonical document backs every format, so a round trip through CSV or Jira and back leaves the table exactly as it was.
Requires Node.js 24+ and pnpm 11+.
pnpm install
pnpm dev
Then open the URL it prints, which on a plain checkout and in CI is http://localhost:3001.
Every other worktree gets its own port derived from its path, so several checkouts can run side by side without serving each other's build.
An optional local MCP connection lets an agent edit the open table while you keep working. See setup and command conventions. No hosted backend or store registration is needed; the editor works without it.
| Command | What it does |
|---|---|
pnpm validate | The full gate before a commit |
pnpm dev | Dev server |
pnpm build | Production build |
pnpm test | Unit and property tests |
pnpm test:watch | Unit tests, re-running on change |
pnpm test:unit | Unit tests only |
pnpm test:property | Property tests only |
pnpm bench | Benchmarks |
pnpm test:e2e:install | Install Chromium for browser tests |
pnpm test:e2e | Browser tests in Chromium |
pnpm test:e2e:failed | Only the tests that failed last time |
pnpm test:e2e:changed | Only the specs affected by uncommitted changes |
pnpm test:e2e:ui | Playwright's watch and time-travel interface |
pnpm test:e2e:serve | Build once and keep the preview server warm |
pnpm check-types | TypeScript |
pnpm lint | Biome check |
pnpm check | Biome check, writing fixes |
pnpm check:dead-code | Knip, for unused files, exports and dependencies |
pnpm test:e2e builds and serves the app itself. test:e2e:serve is worth starting first when a fix
needs several test:e2e:failed rounds: the suite reuses that server and skips its boot. Each round
rebuilds first when a product file changed since the last build, and skips the build when only the
browser specs changed, so the warm server never tests an old build.
Property tests run 100 generated cases per invariant. A failure reports its seed, path, and
minimal counterexample. Replay it by temporarily passing the reported { seed, path } beside
numRuns in that test.prop call, then run the focused spec. Keep the property after the fix. Add
the shrunk example as an ordinary regression test only when it communicates a distinct contract more
clearly than the property itself.
Chromium is the only browser the suite runs, locally and in CI, because it is the only browser Tabelo supports. There is no second project to opt into and no cross-browser command to remember before opening a pull request.
[!TIP] Before you commit:
pnpm validate, that ispnpm check,pnpm check:dead-code,pnpm check-typesandpnpm test. Addpnpm test:e2ewhen the change crosses a UI boundary, which is the coverage CI selects for you anyway.
There is no application secret to configure: Tabelo has no backend, no API key and no account. Both
workflows use only the GITHUB_TOKEN that GitHub Actions provides on its own.
| Variable | Where | What it does |
|---|---|---|
BASE_PATH | Build | Public base path of the built site. Defaults to /; the deploy workflow sets it explicitly |
SITE_ORIGIN | Build | Absolute origin used in the page metadata and social card tags |
TABELO_DEV_PORT | Local dev | Overrides the path-derived dev server port |
TABELO_PREVIEW_PORT | Local dev | Overrides the path-derived preview server port |
TABELO_PWA_DEV | Local dev | Enables the service worker in dev, for working on the worker itself |
CI | CI | Set by GitHub Actions; pins the canonical ports and the Playwright retry policy |
These are not separate files. They are the same table:
Grid
| Name | Role | Active |
|---|---|---|
| Ingrid | Designer | Yes |
| Paulo | Developer | No |
Markdown: alignment and all
| Name | Role | Active |
| :----- | :-------: | -----: |
| Ingrid | Designer | Yes |
| Paulo | Developer | No |
CSV
Name,Role,Active
Ingrid,Designer,Yes
Paulo,Developer,No
Jira
||Name||Role||Active||
|Ingrid|Designer|Yes|
|Paulo|Developer|No|
JSON
[
{"Name": "Ingrid", "Role": "Designer", "Active": "Yes"},
{"Name": "Paulo", "Role": "Developer", "Active": "No"}
]
Records: each row as a titled block of bullets
Name: Ingrid
- Role: Designer
- Active: Yes
Name: Paulo
- Role: Developer
- Active: No
Go through CSV or Jira and back and those :---: alignment markers are still
there. Those formats cannot express alignment, so Tabelo quietly remembers it.
No formulas, extra sheets, charts, macros, pivot tables, accounts, cloud sync, collaboration, or analytics. Tabelo is happiest staying small.
Both hands stay where they are.
| Keys | What happens |
|---|---|
| Arrows | Move between cells |
Shift + arrows | Extend the selection |
Enter / F2 | Edit the focused cell |
| Any character | Replace the cell and start typing |
Enter while editing | Commit, move down |
Shift Enter while editing | Line break inside the cell |
Tab / Shift Tab | Next / previous cell |
Alt + arrows | Move the row or column itself |
Backspace | Clear the selected cells |
⌘ Backspace | Delete the selected rows or columns |
⌘ Enter | Add a row below |
⌘ A | Select everything |
⌘ Z / ⌘ ⇧ Z | Undo / redo |
Undo is layered: inside a source view it undoes your keystrokes, and once that history runs out it keeps going through the table's own history. One timeline underneath, native behaviour on top.
Every shortcut also has a menu entry, so nothing is reachable only by keyboard.
React 19, Vite, Tailwind v4, shadcn/ui on Base UI, CodeMirror 6 for source views (lazily loaded), Papa Parse for delimited formats. Scaffolded with Better-T-Stack. The grid is hand-built, with no grid library, and there is no router: the one page is mounted directly.
One idea holds the whole thing up: there is a single canonical table document, and every format is a parser and serializer around it. No text format is ever the source of truth. That is what makes round trips safe.
Formats and views live in two small registries. Adding a format is one file plus one registry line, and it becomes editable, downloadable, importable, and pasteable everywhere at once.
The decisions worth reading before you change anything:
docs/design-system.md is binding for anything visual,
CONTEXT.md defines the vocabulary, and AGENTS.md
holds the working agreements.
Editing never sends your data anywhere. There is no backend, no account, and no
telemetry of any kind. Your tables live in localStorage on your machine.
Clear your browser storage and they are gone: there is no copy anywhere else,
including with us.
The one exception is the optional external agent, and only after you pair it yourself. A paired agent on your computer reaches that tab's tables, to read, create, open, rename and edit them but never delete one, and it may send what it reads to its own model provider. Disconnect it from the app menu at any time; until you pair one, nothing is shared.
. That is the price
of not losing it: a table row is one line. Renderers read it as whitespace
rather than as a visible break. Settings has Use <br> for line breaks in
cells for renderers that draw <br> as a break, such as GitHub's; strict
CommonMark renderers show <br> literally.MIT © 2026 Marton Paulo.