@achorde/tab-renderer
v0.8.1
Published
**Live demo:** [tab-renderer-react.vercel.app](https://tab-renderer-react.vercel.app/)
Readme
@achorde/tab-renderer
Live demo: tab-renderer-react.vercel.app
Open-source chord sheet rendering library with:
- a headless core for parsing, transposition, and interleaved bar preparation
- a React adapter with a styled
Tabviewer and composable primitives for custom layouts - Vite as the build tool
- Storybook for isolated UI development
- Vitest for TDD
Architecture
The package exposes two public entrypoints:
| Entrypoint | Role |
| -------------------- | ------------- |
| tab-renderer | Headless core |
| tab-renderer/react | React adapter |
Rendering model
Tab (public viewer) — interleaved chord-over-lyric layout (RFC 0002 CSS trick):
parseTab()→ optionaltransposeParsedTab()→prepareSongFromParsedTab()→generateBarList()→ React nodes- Chord and decoration markers (
DecorationToken) sit above lyrics viaposition: relative,bottom, and negativemarginRight(chordHeight,blockMarginRight) insidewhite-space: pre-wrap Tabacceptsstyle?: Partial<TabStyleConfig>(typography, colors,displayMode,viewMode, transpose, margins)
Legacy styled pipeline — prepareSong() still runs the Achordex pairer (splitSections → pairLines → extractChords → transpose). Prefer the ParsedTab bridge above for strict grammar and column positions.
Headless AST — for custom UI or inspection:
parseTab()→ParsedTab→ParsedTabSection→ParsedTabLine→ParsedTabToken(ChordToken,LyricToken,DecorationToken,SpaceToken)- Compose with
Tab.Root,Tab.Section,Tab.Line,Tab.Chord,Tab.Lyric,TabDecoration
Repository guidance: AGENTS.md, docs/AGENTS.md, src/AGENTS.md.
Install
Not published to npm yet. From the achorde monorepo:
pnpm add tab-renderer@git+https://github.com/achorde/achorde.git#main:packages/tab-rendererOr clone and use the workspace:
git clone https://github.com/achorde/achorde.git
cd achorde && pnpm installAfter the first npm release:
npm install tab-rendererPeer dependencies: react and react-dom (^18 or ^19).
Core usage
Styled pipeline (used by Tab)
import {
parseTab,
prepareSongFromParsedTab,
transposeParsedTab,
} from "tab-renderer";
const parsed = parseTab(body);
const transposed = transposeParsedTab(parsed, 0);
const prepared = prepareSongFromParsedTab(transposed, {
viewMode: "e", // "o" = compact newline suffix, "e" = ". . "
});
// prepared.sections[].barList — lyric fragments, chords, decoration markersLegacy styled pipeline (pairer-based)
import { prepareSong } from "tab-renderer";
const prepared = prepareSong({
body,
transposeNumber: 0,
viewMode: "e",
beat: 4,
});Headless AST (per-line tokens)
import { parseTab } from "tab-renderer";
const song = parseTab(body);
// song.sections[].lines[].tokens — ChordToken | LyricToken | DecorationToken | SpaceTokenExported: ParsedTab, PreparedSong, TabStyleConfig, ChordLineMarker, BarsListItem, prepareSongFromParsedTab, transposeParsedTab. Contracts from achorde-musical-domain 0.3.1+ (DecorationToken). See CONTEXT.md.
React usage
Styled Tab (default)
import { Tab, DEFAULT_TAB_STYLE } from "tab-renderer/react";
export function Example() {
return (
<Tab
body={body}
style={{
...DEFAULT_TAB_STYLE,
fontSize: 21,
displayMode: "both",
viewMode: "e",
transposeNumber: 0,
}}
/>
);
}Composable primitives (headless AST)
import { parseTab } from "tab-renderer";
import { Tab } from "tab-renderer/react";
const song = parseTab(body);
<Tab.Root song={song}>
{song.sections.map((section, i) => (
<Tab.Section key={i} section={section} index={i} />
))}
</Tab.Root>;Also exported: Tab.Line, Tab.Chord, Tab.Lyric, TabDecoration.
TabStyleConfig
| Field | Purpose |
| --------------------------------------------- | -------------------------------------------- |
| transposeNumber | Semitone shift (core transposer) |
| fontSize, lineHeight | Container typography |
| chordHeight, blockMarginRight | Chord and decoration offset above lyrics |
| contentMarginRightPx | Container margin-right (200–1000 when set) |
| viewMode | "o" original | "e" extended bar spacing |
| displayMode | "chords" | "lyrics" | "both" |
| chordColor, lyricColor, backgroundColor | Colors |
scrollSpeed is intentionally not part of this package (app-level fullscreen viewer).
Storybook
npm run storybookTeaching trail (sidebar):
| Group | Content |
| -------------------- | ------------------------------------------------------------------------------------- |
| 01 Core … 06 Tab | tua-flor fixture — raw body → AST → tokens → lines → sections → composition → Tab |
| 07 Styling | Full TabStyleConfig controls on tua-flor |
Use the Theme toolbar (Light / Dark) for readable preview frames.
Local development
npm install
npm run dev
npm run storybook
npm test
npm run lint
npm run build
npm run build-storybook
npm run build:site
npm run preview:siteThe demo site is published at tab-renderer-react.vercel.app.
Documentation
- docs/README.md — index
v0.1 bootstrap:
v0.2 styled viewer (shipped):
Repository layout
src/core/— headless parser, transposer,prepareSongsrc/react/— styledTab, primitives, Storybook storiessrc/test/stubs/tua-flor.txt— shared fixture for tests and storiessrc/stories/— stock Vite Storybook template (not library API)
