尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
🎸 Try it live on GitHub Pages
A lightweight, offline-capable web application for creating and editing ASCII-style guitar tablature. Works seamlessly on desktop browsers and iPad devices with full keyboard and touch support. The UI is built on Jelly UI — soft, tactile web components with a playful wobble.
This editor lets you create guitar tabs using ASCII characters, the standard format used across the internet for sharing guitar music. You can:查看完整 README ↗A lightweight, offline-capable web application for creating and editing ASCII-style guitar tablature. Works seamlessly on desktop browsers and iPad devices with full keyboard and touch support. The UI is built on Jelly UI — soft, tactile web components with a playful wobble.
This editor lets you create guitar tabs using ASCII characters, the standard format used across the internet for sharing guitar music. You can:
Place the cursor in a tab block and click Listen. Choose the browser audio input and one of two local analysis modes:
The session starts exactly at the current cursor. Use Left/Right to review detected events, Up/Down to choose another fretboard position, and Space to pause or resume. A selected position anchors later choices so phrases remain in the same area of the neck. Done keeps the phrase as one undoable edit; Cancel restores the pre-listen tab.
Microphone and line-input samples are processed in memory with Web Audio, TensorFlow.js, and the bundled model. Audio is never uploaded. Browser permission and HTTPS (or localhost during development) are required. The first version targets clean solo guitar in standard EADGBE tuning; mixed songs, alternate tunings, rhythm transcription, and playing techniques are not inferred.
The Text button opens a dialog that shows your entire tab as plain text. This is your hub for importing and exporting tabs:
.txt file
guitar-tab.txt.txt tab file from your deviceThe parser detects tab blocks (6 consecutive lines starting with string labels like e|, B|, etc.) and text blocks. Empty lines separate blocks. A single text line directly above a tab block becomes a "docked" chord/lyric line attached to that tab.
The Share button (in the Text dialog) generates a shareable URL that includes your entire tab:
Tab data is compressed with LZ-String into a ?tab=... URL parameter. URLs are validated to stay under 2,000 characters; if your tab is too large, use Export instead. The URL format is stable — old shared links keep working.
Connect to your Dropbox account to open and save tab files directly from the cloud — no server required.
.txt filesA fullscreen auto-scrolling view for playing along to your tabs. Click the amber Perform button; the tab is rendered read-only at the largest monospace font that fits the screen width.
Chord names typed in a docked text line (like C, Gmaj7, or F#m) become clickable. The popup shows a fret diagram (vexchords) with alternative fingerings from chords-db, and an Insert button that writes the fingering into the tab below.
The app is zero-build: plain ES modules served as static files — push to GitHub Pages to deploy. npm is used for dev tooling only.
npm install # dev dependencies (vitest)
npm run serve # python3 -m http.server 8000
npm test # unit tests (vitest)
Service worker note: all app files are precached by
sw.js. Whenever any cached file changes, bumpCACHE_NAMEinsw.js(tab-editor-vN) so clients pick up the new version. During local development you may need to unregister the service worker (DevTools → Application) to see changes.
Vanilla ES modules with a central mutable store and a tiny event bus. core/ is DOM-free (unit-testable); ui/ renders and subscribes to bus events. UI chrome uses Jelly UI web components (vendored bundle, no build step); the monospace tab grid is custom DOM kept deliberately lightweight.
guitartabs/
├── index.html # Markup: jelly-theme wrapper, toolbar, dialogs
├── styles.css # Custom styling (grid, blocks, popups) on Jelly's palette
├── sw.js # Service worker (precaches everything for offline)
├── manifest.json # PWA manifest
├── package.json # Dev tooling only (vitest)
└── js/
├── main.js # Bootstrap: init modules, load document, register SW
├── core/ # DOM-free logic (unit-tested)
│ ├── constants.js # Tunings, lengths, storage key
│ ├── bus.js # Event bus (cells-changed, structure-changed, dirty, …)
│ ├── model.js # Pure data-model helpers (docking, notes, frets)
│ ├── store.js # State + mutators (cursor, selection, undo, edit mode)
│ ├── editing.js # Tab operations (insert/delete/shift/paste/blocks)
│ ├── serialize.js # ASCII format parser/formatter, titles, filenames
│ ├── share.js # Share-URL encode/decode (stable format)
│ └── persistence.js# localStorage save/load (stable key + legacy migration)
├── audio/ # Web Audio capture + local lead/chord analysis
├── ui/ # DOM layer
│ ├── editor-view.js# Tiered rendering + event delegation (see below)
│ ├── selection.js # Drag/keyboard selection, highlight classes
│ ├── chords.js # Chord regex, popup, vexchords diagrams, insert
│ ├── keyboard.js # Global keydown router
│ ├── toolbar.js # Toolbar + jelly-segmented edit-mode control
│ ├── modals.js # Settings / Text / Legend dialogs
│ ├── dialogs.js # jelly-dialog helpers + confirmDialog()
│ ├── perform.js # Fullscreen auto-scroll mode
│ ├── toast.js # jellyToast wrapper (all notifications)
│ ├── listen.js # Listen popover + transactional phrase entry
│ ├── tooltip.js # Note-name tooltip
│ ├── theme.js # meta theme-color sync with OS scheme
│ ├── navigation.js # Arrow-key suppression when switching focus
│ └── dom.js # $, escapeHtml, focusKeyboard (iPad keyboard hook)
├── dropbox/
│ ├── api.js # OAuth2 PKCE + Dropbox HTTP API (DOM-free)
│ └── ui.js # Browse/save dialogs, shared entry-list renderer
└── vendor/
├── jelly.js # Jelly UI bundle (ESM, vendored for offline)
├── globals.js # ESM adapter over the classic vendor globals
├── vexchords.js # Chord diagram rendering (classic script)
├── chords-db.js # Guitar chord database (classic script)
└── lz-string.min.js # URL-safe compression (classic script)
Rendering is tiered so typing stays cheap — there is no full re-render per keystroke:
| Bus event | Handler | Cost |
|---|---|---|
cells-changed {block} | syncBlockCells(i) — update changed cell text only | no DOM creation |
cursor-changed / selection-changed | class toggles on cells | trivial |
structure-changed / document-replaced / linelength-changed | renderAll() full rebuild | rare |
All cell and block-button events are delegated from the #editor container, so rebuilds never re-attach per-cell listeners. Jelly components live only in DOM that never rebuilds on edit (toolbar, dialogs, perform overlay); per-block controls are plain buttons styled to match.
blocks = [
{ type: 'tab', data: [string1[], …, string6[]] }, // char grid, high e first
{ type: 'text', data: "string content" } // single-line + tab below = docked
];
cur = { block, stringIdx, col };
lineLength = 80; // 50–120, characters per tab line
editMode = 'replace' | 'shift' | 'insert';
State is persisted to localStorage["ascii_tab_editor_v1"] after every change (stable format, including migration from the legacy raw-array format).
| draws a full vertical bar; bars are cleared column-wisenpm test runs Vitest suites over the DOM-free core: the ASCII parser/formatter (round-trips), share-URL encoding (including a golden pre-refactor fixture that guards backward compatibility of shared links and saved documents), editing operations (cascade overflow, smart insert/delete, clipboard), the store (undo, selection normalization), and persistence (legacy format migration). Fixtures live in test/fixtures/golden.json — do not regenerate them; they encode the pre-refactor behavior.