尚未偵測到更新。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.