@kanbun-skam/skam-html-renderer
v0.1.0
Published
SKAM to HTML renderer - SKAMドキュメントから静的HTMLを生成
Maintainers
Readme
@kanbun-skam/skam-html-renderer
SKAM ドキュメントから静的 HTML を生成するレンダラー。
縦書き・横書き・縦中横対応、返り点・送り仮名・ルビ等の訓点レンダリングを提供。
インストール
npm install @kanbun-skam/skam-html-renderer
# or
pnpm add @kanbun-skam/skam-html-renderer使い方
基本的なレンダリング
import { render } from '@kanbun-skam/skam-html-renderer';
import type { SKAMDocument } from '@kanbun-skam/skam';
const doc: SKAMDocument = {
format: '[email protected]',
tokens: [
{ id: 't1', text: '学' },
{ id: 't2', text: '而' },
],
marks: [{ type: 'okurigana', anchor: { from: 't1', to: 't1' }, value: 'びて' }],
readings: [],
};
const result = render(doc);
// result.html: レンダリングされた HTML
// result.css: 適用すべき CSS書字方向の指定
import { render } from '@kanbun-skam/skam-html-renderer';
// 縦書き(デフォルト)
const vertical = render(doc, { writingMode: 'vertical' });
// 横書き
const horizontal = render(doc, { writingMode: 'horizontal' });表示プロファイル
import { render, PROFILES } from '@kanbun-skam/skam-html-renderer';
// フルプロファイル(すべての要素を表示、デフォルト)
const full = render(doc, { profile: PROFILES.full });
// 学習用基本プロファイル(返り点のみ)
const basic = render(doc, { profile: PROFILES.learningBasic });
// 学習用ヒント付きプロファイル(返り点+送り仮名)
const hint = render(doc, { profile: PROFILES.learningHint });スタイルのカスタマイズ
import { render, getDefaultStyles, generateCSS } from '@kanbun-skam/skam-html-renderer';
// CSS 生成オプション
const css = generateCSS({
writingMode: 'vertical', // 'vertical' | 'horizontal' | 'both'
inline: false, // インラインモード
useLayer: true, // @layer でラップ(デフォルト: true)
layerName: 'skam-kanbun', // レイヤー名(デフォルト: 'skam-kanbun')
});
// レンダリングも同様のオプションに対応
const result = render(doc, { writingMode: 'vertical' });CSS Variables によるカスタマイズ
生成される CSS は CSS Variables を公開しており、ユーザー側で簡単にカスタマイズできます。
/* ユーザー側でカスタマイズ */
.skam-document {
--skam-color-fg: #333;
--skam-color-kaeriten: #c00;
--skam-color-ruby: #666;
--skam-font-family: '游明朝', serif;
}公開 CSS Variables 一覧
| カテゴリ | 変数名 | デフォルト値 | 用途 |
| -------------- | ------------------------- | -------------- | -------------------------- |
| 色 | --skam-color-fg | currentColor | 前景色(テキスト、傍線等) |
| | --skam-color-kaeriten | currentColor | 返り点の色 |
| | --skam-color-ruby | currentColor | ルビ・送り仮名の色 |
| | --skam-color-emphasis | currentColor | 傍点の色 |
| フォント | --skam-font-family | inherit | 本文フォント |
| | --skam-font-family-ruby | inherit | ルビ・送り仮名フォント |
| サイズ | --skam-glyph-size | 1em | 基準グリフサイズ |
| | --skam-ruby-font-size | 0.5em | ルビ・送り仮名サイズ |
| 余白・間隔 | --skam-line-height | 2 | 行間 |
| | --skam-letter-spacing | 0 | 字間 |
コピー可能範囲の制御
デフォルトでは、テキスト選択・コピー時に本文のみがコピーされ、返り点・送り仮名・ルビなどの注記はコピーされません。
API での指定
import { render, renderHTML } from '@kanbun-skam/skam-html-renderer';
// デフォルト: 本文のみコピー可能
const result = render(doc);
// 読み仮名もコピー可能
const result = render(doc, { copyable: ['ruby'] });
// 複数指定
const result = render(doc, { copyable: ['ruby', 'okurigana'] });
// 全てコピー可能
const result = render(doc, { copyable: 'all' });生成される HTML
<!-- デフォルト: 本文のみコピー可能 -->
<div class="skam-document">...</div>
<!-- 読み仮名もコピー可能 -->
<div class="skam-document" data-copyable="ruby">...</div>
<!-- 複数指定(スペース区切り) -->
<div class="skam-document" data-copyable="ruby okurigana">...</div>
<!-- 全てコピー可能 -->
<div class="skam-document" data-copyable="all">...</div>指定可能な値
| 値 | 対象 |
| ----------- | ---------------- |
| ruby | 読み仮名(ルビ) |
| okurigana | 送り仮名 |
| soegana | 添え仮名 |
| kaeriten | 返り点 |
| okototen | ヲコト点 |
| all | 全ての注記要素 |
Note: data-copyable 属性は CSS で制御されるため、HTML を直接編集して属性を変更することで、ビルド後でも動的に切り替えられます。
CSS @layer との統合
生成される CSS はデフォルトで @layer skam-kanbun でラップされます。
これにより、ユーザー側でカスケード順序を制御できます。
/* ユーザー側でレイヤー順序を定義 */
@layer reset, base, skam-kanbun, app;
/* skam-kanbun レイヤーより後のレイヤーで上書き可能 */
@layer app {
.skam-document {
--skam-color-kaeriten: red;
}
}@layer を無効にする
const css = generateCSS({ useLayer: false });リセット CSS との共存
本ライブラリは :where() セレクタで specificity を 0 に抑えているため、
一般的なリセット CSS と競合しにくい設計です。
sanitize.css との組み合わせ
<link rel="stylesheet" href="sanitize.css" />
<style>
@layer reset, skam-kanbun;
</style>Tailwind CSS preflight との組み合わせ
@layer base, skam-kanbun, components, utilities;レンダリング対応
| Mark Type | 対応状況 |
| ----------- | -------- |
| kaeri | ✅ |
| okurigana | ✅ |
| yomigana | ✅ |
| soegana | ✅ |
| okimoji | ✅ |
| joji | ✅ |
| kutoten | ✅ |
| emphasis | ✅ |
| saidoku | ✅ |
| tateten | ✅ |
| highlight | ✅ |
| ref | ✅ |
| okototen | 🚧 |
出力形式
interface RenderResult {
/** レンダリングされた HTML 文字列 */
html: string;
/** 適用すべき CSS 文字列 */
css: string;
}内部アーキテクチャ
モジュール構成と依存方向
依存方向は shared → display → API の一方向に固定されています。
API層 (renderer.ts)
├── 公開 API (render, renderHTML, generateCSS)
├── option 正規化
└── CSS 生成呼び出し (styles.ts)
│
▼
display オーケストレータ層 (render-display-layer.ts)
├── group 解決 (tateten/highlight/range marks)
├── Pass 1/Pass 2 呼び出し
└── block 単位合成
│
▼
display 実装層
├── Pass 1: build-render-tree.ts (tokens+marks → BlockRenderTree)
├── Pass 2: render-tree.ts (BlockRenderTree → HTML string)
└── token-renderer.ts (個別トークンの HTML 生成)
│
▼
共通基盤層
├── render-config.ts (RenderProfile, RubyMethod, PROFILES)
├── html-utils.ts (escapeHtml, shouldApplyTateChuYoko 等)
├── mark-utils.ts (getBlockStartMarks 等)
└── render-tree-types.ts (IR 型定義)CSS Grid 命名規約
styles.ts のグリッドコンテナは grid-template-areas で名前付き配置を使用しています。
| 領域名 | 用途 |
| ------------ | ----------------------------- |
| ruby | ルビ注記(読み仮名) |
| ruby-over | 再読文字の上側ルビ |
| ruby-under | 再読文字の下側ルビ |
| base | 本文文字 |
| suffix | suffix-row(改行排除用) |
| emphasis | 傍点行 |
| okuri | 送り仮名(suffix-row 内) |
| kutoten | 句読点(suffix-row 内) |
| kaeri | 返り点(suffix-row 内) |
| saidoku | 再読送り仮名(suffix-row 内) |
baseline 補正契約
calibrate.ts が Chromium の inline-grid baseline バグを実測検出し、
--{prefix}-grid-baseline-fix: 1 を設定します。
各グリッドコンテナの vertical-align がこの変数を参照して補正値を算出します。
関連パッケージ
- @kanbun-skam/skam - 型定義・バリデーター
- @kanbun-skam/skam-xml-parser - SKAM-ML/XML パーサー
Playground
インタラクティブなデモ: https://berlysia.github.io/kanbun-annotation/
ライセンス
MIT
