hono-decks 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.ja.md +289 -0
  2. package/README.md +86 -78
  3. package/package.json +6 -5
package/README.ja.md ADDED
@@ -0,0 +1,289 @@
1
+ # hono-decks
2
+
3
+ [English](https://github.com/ts-76/hono-decks/blob/main/packages/decks/README.md) | 日本語
4
+
5
+ Hono と Cloudflare Workers 上で MDX のスライドを配信するためのライブラリです。ビルド時に MDX を TypeScript module へ変換し、Worker runtime ではファイルシステムや compiler を読み込みません。
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ bun add hono hono-decks
11
+ bunx hono-decks init
12
+ bunx hono-decks compile
13
+ ```
14
+
15
+ `init` は次の2ファイルを作ります。既存ファイルは上書きしません。
16
+
17
+ - `hono-decks.config.ts`: CLI と runtime が共有する唯一の設定
18
+ - `src/decks.ts`: generated module をアプリへ接続する編集可能な facade
19
+
20
+ ```ts
21
+ // hono-decks.config.ts
22
+ import { defineDecksConfig } from "hono-decks";
23
+
24
+ export default defineDecksConfig({
25
+ mountPath: "/decks",
26
+ build: {
27
+ root: "decks",
28
+ outDir: "src/generated",
29
+ },
30
+ });
31
+ ```
32
+
33
+ ```ts
34
+ // src/decks.ts
35
+ import config from "../hono-decks.config";
36
+ import { createDecks } from "./generated/decks";
37
+
38
+ export const decks = createDecks(config);
39
+ ```
40
+
41
+ ```ts
42
+ // src/index.ts
43
+ import { Hono } from "hono";
44
+ import { decks } from "./decks";
45
+
46
+ const app = new Hono();
47
+ app.get("/", (c) => c.redirect(decks.paths("welcome").viewer));
48
+ app.route(decks.mountPath, decks.router());
49
+ export default app;
50
+ ```
51
+
52
+ `decks/welcome/deck.mdx` を作り、`bunx hono-decks compile` を実行すると `src/generated/decks.ts` と slide modules が更新されます。generated directory は直接編集しません。
53
+
54
+ ## One config, one runtime kit
55
+
56
+ 以前のように compile option、`app.route()`、asset URL の mount path を別々に指定する必要はありません。`mountPath` は config に一度だけ書きます。generated module の `createDecks(config)` は次の configured kit を返します。
57
+
58
+ - `decks.mountPath`: `app.route()` に渡す正規化済みパス
59
+ - `decks.source`: config の `source()` が適用された `DeckSource`
60
+ - `decks.router(overrides?)`: config と呼び出し時 override を安全に深く合成した router
61
+ - `decks.context(overrides?)`: custom route 用 middleware
62
+ - `decks.paths(slug)`: viewer、render、print、presentation、presenter、embed、export、OGP image、assets の完全な route map
63
+
64
+ ```ts
65
+ const paths = decks.paths("product");
66
+ paths.viewer; // /decks/product
67
+ paths.render; // /decks/product/render
68
+ paths.print; // /decks/product/print
69
+ paths.presentation; // /decks/product/presentation
70
+ paths.presenter; // /decks/product/presenter
71
+ paths.embed; // /decks/product/embed
72
+ paths.exportPdf; // /decks/product/export.pdf
73
+ paths.exportPng; // /decks/product/export.png
74
+ paths.ogImage; // /decks/product/og.png
75
+ paths.assets; // /decks/product/assets
76
+ ```
77
+
78
+ Viewer callbacks では同じ map を `input.meta.paths` から参照できます。文字列連結で route を再構築しないでください。
79
+
80
+ ```ts
81
+ export default defineDecksConfig({
82
+ mountPath: "/decks",
83
+ router: {
84
+ viewer: {
85
+ controls: {
86
+ after: ({ meta }) => [
87
+ { type: "link", href: `${meta.paths.viewer}/about`, label: "Details" },
88
+ ],
89
+ },
90
+ },
91
+ },
92
+ });
93
+ ```
94
+
95
+ ## Development integration
96
+
97
+ Cloudflare Workersでは、deck compilerをWranglerのcustom buildへ登録します。
98
+
99
+ ```jsonc
100
+ // wrangler.jsonc
101
+ {
102
+ "build": {
103
+ "command": "hono-decks compile",
104
+ "watch_dir": ["decks"]
105
+ }
106
+ }
107
+ ```
108
+
109
+ `wrangler dev --live-reload`が初回compileとMDX、deck-local component、asset、theme CSSの変更監視、ブラウザ更新を担当します。deploy時にも同じbuild commandが実行されます。
110
+
111
+ HonoXまたはViteでは、既存のVite configへpluginを追加します。
112
+
113
+ ```ts
114
+ import { honoDecks } from "hono-decks/vite";
115
+ import { defineConfig } from "vite";
116
+
117
+ export default defineConfig({
118
+ plugins: [honoDecks()],
119
+ });
120
+ ```
121
+
122
+ pluginはVite起動前にcompileし、deck rootと`hono-decks.config.ts`をVite watcherへ登録します。再compileに成功するとfull reloadを通知するため、手動更新は不要です。どちらの構成でも通常の`bun run dev`だけでauthoringできます。
123
+
124
+ ## Runtime configuration
125
+
126
+ すべての resolver は1個の object argument を受け取ります。引数の順序を覚える必要がなく、将来 input が増えても callback の意味が崩れません。
127
+
128
+ ```ts
129
+ interface AppEnv {
130
+ Bindings: {
131
+ BROWSER?: DeckBrowserRunBinding;
132
+ DECK_EXPORT_TOKEN?: string;
133
+ };
134
+ }
135
+
136
+ export default defineDecksConfig<AppEnv>({
137
+ mountPath: "/decks",
138
+ build: { root: "decks", outDir: "src/generated" },
139
+ router: {
140
+ presenter: {
141
+ enabled: ({ dev }) => dev,
142
+ viewerControl: true,
143
+ },
144
+ export: {
145
+ authorize: ({ c }) =>
146
+ c.req.header("authorization") === `Bearer ${c.env.DECK_EXPORT_TOKEN}`,
147
+ browser: ({ c }) => c.env.BROWSER,
148
+ pdf: true,
149
+ png: true,
150
+ },
151
+ },
152
+ });
153
+ ```
154
+
155
+ `dev`を省略すると、ViteとWranglerが設定する`NODE_ENV`から判定します。標準設定では、`vite`と`wrangler dev`は開発モード、プロダクションビルドと`wrangler deploy`は本番モードになります。`dev: false`やresolverを指定した場合は明示値が優先され、判定できない環境では本番モードとして扱われます。
156
+
157
+ 呼び出し元で一部だけ変える場合は `decks.router({ viewer: ... })` を使います。viewer controls、document surfaces、presenter、embed、export などの nested option は config を失わずに合成されます。機能を止めるときは `presenter: false`、`embed: false`、`export: false` のように明示できます。
158
+
159
+ ## Custom application routes
160
+
161
+ ```ts
162
+ import type { DeckContextVariables } from "hono-decks";
163
+ import { decks } from "./decks";
164
+
165
+ const app = new Hono<{ Variables: DeckContextVariables }>();
166
+
167
+ app.get(
168
+ `${decks.mountPath}/:slug/about`,
169
+ decks.context(),
170
+ (c) => c.json({
171
+ title: c.var.deckMeta.title,
172
+ viewer: c.var.deckMeta.paths.viewer,
173
+ slides: c.var.deckToc,
174
+ }),
175
+ );
176
+ ```
177
+
178
+ `decks.context()` は configured source、mount path、dev policy、viewer controls を自動的に共有します。custom route と標準 viewer で draft 判定や URL がずれません。
179
+
180
+ 標準ページ全体を差し替える場合は config の `viewer.render` を使います。callback には `frame`、`controls`、`toc`、`meta.paths` が渡るため、標準部品を再利用しながら app-owned layout を構築できます。
181
+
182
+ ## Deck-local components and CSS
183
+
184
+ Directory deck は次の構造を使えます。
185
+
186
+ ```text
187
+ decks/product/
188
+ deck.mdx
189
+ theme.css
190
+ assets/
191
+ diagram.svg
192
+ components/
193
+ index.tsx
194
+ client/
195
+ index.tsx
196
+ ```
197
+
198
+ `components/index.tsx` は server-side JSX component、`components/client/index.tsx` は browser で hydrate する component です。`theme.css` はその deck だけに適用されます。画像は compile 時に検出され、`mountPath` と slug を使った public URL に書き換えられます。
199
+
200
+ ## Embedding
201
+
202
+ 同じdocumentへ複数配置する場合は `createDeckViewerEmbed()` を使えます。これは app が取得済みの `CompiledDeck` から iframe viewer、controls、TOC を組み立てる high-level helper です。
203
+
204
+ Embedding from an external blog では `router.embed` を有効にし、`frameAncestors` に許可する親 origin を明示してください。`iframe navigationにCORSは不要`ですが、CSP の `frame-ancestors` は必要です。
205
+
206
+ ```ts
207
+ router: {
208
+ embed: {
209
+ frameAncestors: ["https://blog.example.com"],
210
+ robots: false,
211
+ },
212
+ }
213
+ ```
214
+
215
+ ```html
216
+ <iframe
217
+ src="https://slides.example.com/decks/product/embed"
218
+ title="Product deck"
219
+ allow="fullscreen"
220
+ ></iframe>
221
+ ```
222
+
223
+ ## Browser export
224
+
225
+ PDF/PNG export は Cloudflare Browser Rendering binding を resolver から返すと有効になります。viewer に export control が表示されるのは、その request が `authorize` を通った場合だけです。token は `vars` ではなく Wrangler secret として管理してください。
226
+
227
+ `Cmd + P` / `Ctrl + P` は viewer から print route を開き、印刷用に全 slide を表示します。server-side export も同じ print route を Browser Rendering に渡します。
228
+
229
+ ## Build-time OGP recipe
230
+
231
+ viewer の share image をビルド時に生成する場合は、`router.viewer.openGraph` を有効にします。既定の画像パスは `decks.paths(slug).ogImage` です。viewer は request origin から Open Graph / Twitter Card の絶対URLを生成します。
232
+
233
+ ```ts
234
+ export default defineDecksConfig({
235
+ mountPath: "/decks",
236
+ router: {
237
+ viewer: { openGraph: true },
238
+ },
239
+ });
240
+ ```
241
+
242
+ 独自CDNを使う場合は `imagePath: ({ deck }) => \`https://cdn.example.com/${deck.slug}.png\`` のように resolver で上書きできます。`false` または未指定なら social metadata は出力しません。
243
+
244
+ 生成処理は core に含まれません。`examples/ogp` では `hono-decks/node` の `compileDecks()` が返す manifest を Satori + resvg へ渡し、1200×630 PNG を Workers Static Assets へ保存します。Satori / resvg は example だけの依存で、Browser Rendering binding は不要です。Satori は TTF / OTF / WOFF を読み込めますが WOFF2 は扱えないため、対象言語の font file を build script から明示的に渡してください。
245
+
246
+ `build.ogpCacheFile` は `@[card](...)` が参照する外部サイトのメタデータキャッシュです。viewer 自身の share image とは別機能です。
247
+
248
+ ## Public entries
249
+
250
+ - `hono-decks`: config、configured kit の型、deck authoring、viewer/embed customization、source decorator
251
+ - `hono-decks/advanced`: `defineDecks()`、`decksRouter()`、`deckContext()`、raw renderer など独自 pipeline 用
252
+ - `hono-decks/client`: browser hydration
253
+ - `hono-decks/node`: compiler と Node filesystem adapter
254
+ - `hono-decks/cli`: programmatic CLI runner
255
+
256
+ 通常の generated workflow では root entry だけを import します。`hono-decks/advanced` は custom `DeckSource` や router をゼロから組み立てる場合に限定してください。
257
+
258
+ ## Cloudflare Workers
259
+
260
+ Wrangler は JSONC config、current compatibility date、必要に応じた `nodejs_compat` を使います。binding types は `wrangler types` で生成し、hand-written binding interface と実際の config がずれないようにしてください。
261
+
262
+ ```jsonc
263
+ {
264
+ "$schema": "node_modules/wrangler/config-schema.json",
265
+ "name": "my-decks",
266
+ "main": "src/index.ts",
267
+ "compatibility_date": "2026-07-14",
268
+ "compatibility_flags": ["nodejs_compat"]
269
+ }
270
+ ```
271
+
272
+ ## Advanced API
273
+
274
+ 既存 manifest、database、remote object store から完全に独自の runtime を作る場合だけ advanced entry を使います。
275
+
276
+ ```ts
277
+ import { decksRouter, manifestDeckSource } from "hono-decks/advanced";
278
+
279
+ const source = manifestDeckSource(manifest);
280
+ app.route("/internal-slides", decksRouter({ source, dev: true }));
281
+ ```
282
+
283
+ このレベルでは mount path、source policy、option merge をアプリ側が管理します。通常の利用では generated `createDecks(config)` のほうが安全で短くなります。
284
+
285
+ ## Examples
286
+
287
+ - `examples/minimal`: standalone Worker の最小構成
288
+ - `examples/basic`: R2、Browser Rendering、custom routes、client components
289
+ - `examples/honox`: HonoX integration
package/README.md CHANGED
@@ -1,21 +1,25 @@
1
1
  # hono-decks
2
2
 
3
- Hono Cloudflare Workers 上で MDX のスライドを配信するためのライブラリです。ビルド時に MDX を TypeScript module へ変換し、Worker runtime ではファイルシステムや compiler を読み込みません。
3
+ English | [日本語](https://github.com/ts-76/hono-decks/blob/main/packages/decks/README.ja.md)
4
+
5
+ hono-decks serves MDX slide decks from Hono applications and Cloudflare Workers. It compiles MDX into TypeScript modules at build time, so the Worker runtime does not load the filesystem or the compiler.
4
6
 
5
7
  ## Quick start
6
8
 
7
- ```bash
9
+ The examples below use Bun. npm, pnpm, and Yarn are supported as well.
10
+
11
+ ~~~bash
8
12
  bun add hono hono-decks
9
13
  bunx hono-decks init
10
14
  bunx hono-decks compile
11
- ```
15
+ ~~~
12
16
 
13
- `init` は次の2ファイルを作ります。既存ファイルは上書きしません。
17
+ <code>init</code> creates two files without overwriting existing files:
14
18
 
15
- - `hono-decks.config.ts`: CLI runtime が共有する唯一の設定
16
- - `src/decks.ts`: generated module をアプリへ接続する編集可能な facade
19
+ - <code>hono-decks.config.ts</code>: the shared configuration for the CLI and runtime
20
+ - <code>src/decks.ts</code>: an editable facade that connects the generated modules to your application
17
21
 
18
- ```ts
22
+ ~~~ts
19
23
  // hono-decks.config.ts
20
24
  import { defineDecksConfig } from "hono-decks";
21
25
 
@@ -26,17 +30,17 @@ export default defineDecksConfig({
26
30
  outDir: "src/generated",
27
31
  },
28
32
  });
29
- ```
33
+ ~~~
30
34
 
31
- ```ts
35
+ ~~~ts
32
36
  // src/decks.ts
33
37
  import config from "../hono-decks.config";
34
38
  import { createDecks } from "./generated/decks";
35
39
 
36
40
  export const decks = createDecks(config);
37
- ```
41
+ ~~~
38
42
 
39
- ```ts
43
+ ~~~ts
40
44
  // src/index.ts
41
45
  import { Hono } from "hono";
42
46
  import { decks } from "./decks";
@@ -45,21 +49,21 @@ const app = new Hono();
45
49
  app.get("/", (c) => c.redirect(decks.paths("welcome").viewer));
46
50
  app.route(decks.mountPath, decks.router());
47
51
  export default app;
48
- ```
52
+ ~~~
49
53
 
50
- `decks/welcome/deck.mdx` を作り、`bunx hono-decks compile` を実行すると `src/generated/decks.ts` slide modules が更新されます。generated directory は直接編集しません。
54
+ Create <code>decks/welcome/deck.mdx</code>, then run <code>bunx hono-decks compile</code>. The command updates <code>src/generated/decks.ts</code> and the generated slide modules. Do not edit the generated directory directly.
51
55
 
52
56
  ## One config, one runtime kit
53
57
 
54
- 以前のように compile option、`app.route()`、asset URL mount path を別々に指定する必要はありません。`mountPath` config に一度だけ書きます。generated module の `createDecks(config)` は次の configured kit を返します。
58
+ You do not need to repeat the mount path across compiler options, <code>app.route()</code>, and asset URLs. Define <code>mountPath</code> once in the config. The generated <code>createDecks(config)</code> function returns a configured kit:
55
59
 
56
- - `decks.mountPath`: `app.route()` に渡す正規化済みパス
57
- - `decks.source`: config の `source()` が適用された `DeckSource`
58
- - `decks.router(overrides?)`: config と呼び出し時 override を安全に深く合成した router
59
- - `decks.context(overrides?)`: custom route middleware
60
- - `decks.paths(slug)`: viewer、render、printpresentation、presenter、embed、export、OGP image、assets の完全な route map
60
+ - <code>decks.mountPath</code>: the normalized path to pass to <code>app.route()</code>
61
+ - <code>decks.source</code>: the <code>DeckSource</code> after applying the config's <code>source()</code> decorator
62
+ - <code>decks.router(overrides?)</code>: a router that safely deep-merges config and call-site overrides
63
+ - <code>decks.context(overrides?)</code>: middleware for application-owned routes
64
+ - <code>decks.paths(slug)</code>: the complete route map for the viewer, renderer, print view, presentation views, embeds, exports, OGP image, and assets
61
65
 
62
- ```ts
66
+ ~~~ts
63
67
  const paths = decks.paths("product");
64
68
  paths.viewer; // /decks/product
65
69
  paths.render; // /decks/product/render
@@ -71,30 +75,34 @@ paths.exportPdf; // /decks/product/export.pdf
71
75
  paths.exportPng; // /decks/product/export.png
72
76
  paths.ogImage; // /decks/product/og.png
73
77
  paths.assets; // /decks/product/assets
74
- ```
78
+ ~~~
75
79
 
76
- Viewer callbacks では同じ map `input.meta.paths` から参照できます。文字列連結で route を再構築しないでください。
80
+ Viewer callbacks receive the same map as <code>input.meta.paths</code>. Use it instead of rebuilding routes with string concatenation.
77
81
 
78
- ```ts
82
+ ~~~ts
79
83
  export default defineDecksConfig({
80
84
  mountPath: "/decks",
81
85
  router: {
82
86
  viewer: {
83
87
  controls: {
84
88
  after: ({ meta }) => [
85
- { type: "link", href: `${meta.paths.viewer}/about`, label: "Details" },
89
+ {
90
+ type: "link",
91
+ href: meta.paths.viewer + "/about",
92
+ label: "Details",
93
+ },
86
94
  ],
87
95
  },
88
96
  },
89
97
  },
90
98
  });
91
- ```
99
+ ~~~
92
100
 
93
101
  ## Development integration
94
102
 
95
- Cloudflare Workersでは、deck compilerWranglercustom buildへ登録します。
103
+ For Cloudflare Workers, register the deck compiler as a Wrangler custom build.
96
104
 
97
- ```jsonc
105
+ ~~~jsonc
98
106
  // wrangler.jsonc
99
107
  {
100
108
  "build": {
@@ -102,28 +110,28 @@ Cloudflare Workersでは、deck compilerをWranglerのcustom buildへ登録し
102
110
  "watch_dir": ["decks"]
103
111
  }
104
112
  }
105
- ```
113
+ ~~~
106
114
 
107
- `wrangler dev --live-reload`が初回compileMDXdeck-local component、asset、theme CSSの変更監視、ブラウザ更新を担当します。deploy時にも同じbuild commandが実行されます。
115
+ <code>wrangler dev --live-reload</code> performs the initial compile, watches MDX, deck-local components, assets, and theme CSS, and reloads the browser. Wrangler runs the same build command during deployment.
108
116
 
109
- HonoXまたはViteでは、既存のVite configへpluginを追加します。
117
+ For HonoX or another Vite application, add the plugin to the existing Vite config.
110
118
 
111
- ```ts
119
+ ~~~ts
112
120
  import { honoDecks } from "hono-decks/vite";
113
121
  import { defineConfig } from "vite";
114
122
 
115
123
  export default defineConfig({
116
124
  plugins: [honoDecks()],
117
125
  });
118
- ```
126
+ ~~~
119
127
 
120
- pluginVite起動前にcompileし、deck rootと`hono-decks.config.ts`をVite watcherへ登録します。再compileに成功するとfull reloadを通知するため、手動更新は不要です。どちらの構成でも通常の`bun run dev`だけでauthoringできます。
128
+ The plugin compiles before Vite starts and adds the deck root and <code>hono-decks.config.ts</code> to the Vite watcher. After a successful recompile, it requests a full browser reload. In both setups, the application's normal <code>dev</code> command is enough for authoring.
121
129
 
122
130
  ## Runtime configuration
123
131
 
124
- すべての resolver は1個の object argument を受け取ります。引数の順序を覚える必要がなく、将来 input が増えても callback の意味が崩れません。
132
+ Every resolver receives one object argument. Callbacks remain readable as inputs are added because their meaning does not depend on positional parameters.
125
133
 
126
- ```ts
134
+ ~~~ts
127
135
  interface AppEnv {
128
136
  Bindings: {
129
137
  BROWSER?: DeckBrowserRunBinding;
@@ -141,29 +149,29 @@ export default defineDecksConfig<AppEnv>({
141
149
  },
142
150
  export: {
143
151
  authorize: ({ c }) =>
144
- c.req.header("authorization") === `Bearer ${c.env.DECK_EXPORT_TOKEN}`,
152
+ c.req.header("authorization") === "Bearer " + c.env.DECK_EXPORT_TOKEN,
145
153
  browser: ({ c }) => c.env.BROWSER,
146
154
  pdf: true,
147
155
  png: true,
148
156
  },
149
157
  },
150
158
  });
151
- ```
159
+ ~~~
152
160
 
153
- `dev`を省略すると、ViteWranglerが設定する`NODE_ENV`から判定します。標準設定では、`vite`と`wrangler dev`は開発モード、プロダクションビルドと`wrangler deploy`は本番モードになります。`dev: false`やresolverを指定した場合は明示値が優先され、判定できない環境では本番モードとして扱われます。
161
+ When <code>dev</code> is omitted, hono-decks uses the <code>NODE_ENV</code> value supplied by Vite or Wrangler. The standard Vite and <code>wrangler dev</code> commands are treated as development, while production builds and <code>wrangler deploy</code> are treated as production. An explicit <code>dev: false</code> value or resolver takes precedence. Unknown environments fail closed as production.
154
162
 
155
- 呼び出し元で一部だけ変える場合は `decks.router({ viewer: ... })` を使います。viewer controlsdocument surfacespresenter、embed、export などの nested option config を失わずに合成されます。機能を止めるときは `presenter: false`、`embed: false`、`export: false` のように明示できます。
163
+ Use <code>decks.router({ viewer: ... })</code> for call-site overrides. Nested options for viewer controls, document surfaces, the presenter, embeds, and exports are merged without discarding the config. Disable a feature explicitly with values such as <code>presenter: false</code>, <code>embed: false</code>, or <code>export: false</code>.
156
164
 
157
165
  ## Custom application routes
158
166
 
159
- ```ts
167
+ ~~~ts
160
168
  import type { DeckContextVariables } from "hono-decks";
161
169
  import { decks } from "./decks";
162
170
 
163
171
  const app = new Hono<{ Variables: DeckContextVariables }>();
164
172
 
165
173
  app.get(
166
- `${decks.mountPath}/:slug/about`,
174
+ decks.mountPath + "/:slug/about",
167
175
  decks.context(),
168
176
  (c) => c.json({
169
177
  title: c.var.deckMeta.title,
@@ -171,17 +179,17 @@ app.get(
171
179
  slides: c.var.deckToc,
172
180
  }),
173
181
  );
174
- ```
182
+ ~~~
175
183
 
176
- `decks.context()` configured sourcemount path、dev policyviewer controls を自動的に共有します。custom route と標準 viewer draft 判定や URL がずれません。
184
+ <code>decks.context()</code> shares the configured source, mount path, development policy, and viewer controls. Application routes and the built-in viewer therefore use the same draft policy and URLs.
177
185
 
178
- 標準ページ全体を差し替える場合は config `viewer.render` を使います。callback には `frame`、`controls`、`toc`、`meta.paths` が渡るため、標準部品を再利用しながら app-owned layout を構築できます。
186
+ To replace a built-in page, configure <code>viewer.render</code>. The callback receives <code>frame</code>, <code>controls</code>, <code>toc</code>, and <code>meta.paths</code>, allowing an application-owned layout to reuse the standard parts.
179
187
 
180
188
  ## Deck-local components and CSS
181
189
 
182
- Directory deck は次の構造を使えます。
190
+ A directory deck can use this structure:
183
191
 
184
- ```text
192
+ ~~~text
185
193
  decks/product/
186
194
  deck.mdx
187
195
  theme.css
@@ -191,73 +199,73 @@ decks/product/
191
199
  index.tsx
192
200
  client/
193
201
  index.tsx
194
- ```
202
+ ~~~
195
203
 
196
- `components/index.tsx` server-side JSX component、`components/client/index.tsx` browser hydrate する component です。`theme.css` はその deck だけに適用されます。画像は compile 時に検出され、`mountPath` slug を使った public URL に書き換えられます。
204
+ <code>components/index.tsx</code> contains server-side JSX components. <code>components/client/index.tsx</code> contains components hydrated in the browser. <code>theme.css</code> applies only to that deck. Local images are detected during compilation and rewritten to public URLs based on the mount path and deck slug.
197
205
 
198
206
  ## Embedding
199
207
 
200
- 同じdocumentへ複数配置する場合は `createDeckViewerEmbed()` を使えます。これは app が取得済みの `CompiledDeck` から iframe viewer、controls、TOC を組み立てる high-level helper です。
208
+ Use <code>createDeckViewerEmbed()</code> to embed multiple decks into the same document. This high-level helper builds an iframe viewer, controls, and a table of contents from a <code>CompiledDeck</code> already loaded by the application.
201
209
 
202
- Embedding from an external blog では `router.embed` を有効にし、`frameAncestors` に許可する親 origin を明示してください。`iframe navigationにCORSは不要`ですが、CSP の `frame-ancestors` は必要です。
210
+ When embedding from an external blog, enable <code>router.embed</code> and list the allowed parent origins in <code>frameAncestors</code>. Iframe navigation does not require CORS, but it does require an appropriate CSP <code>frame-ancestors</code> directive.
203
211
 
204
- ```ts
212
+ ~~~ts
205
213
  router: {
206
214
  embed: {
207
215
  frameAncestors: ["https://blog.example.com"],
208
216
  robots: false,
209
217
  },
210
218
  }
211
- ```
219
+ ~~~
212
220
 
213
- ```html
221
+ ~~~html
214
222
  <iframe
215
223
  src="https://slides.example.com/decks/product/embed"
216
224
  title="Product deck"
217
225
  allow="fullscreen"
218
226
  ></iframe>
219
- ```
227
+ ~~~
220
228
 
221
229
  ## Browser export
222
230
 
223
- PDF/PNG export Cloudflare Browser Rendering binding resolver から返すと有効になります。viewer export control が表示されるのは、その request `authorize` を通った場合だけです。token `vars` ではなく Wrangler secret として管理してください。
231
+ Enable PDF and PNG exports by returning a Cloudflare Browser Rendering binding from the resolver. The viewer displays export controls only for requests accepted by <code>authorize</code>. Store export tokens as Wrangler secrets rather than in <code>vars</code>.
224
232
 
225
- `Cmd + P` / `Ctrl + P` viewer から print route を開き、印刷用に全 slide を表示します。server-side export も同じ print route Browser Rendering に渡します。
233
+ <code>Cmd + P</code> and <code>Ctrl + P</code> open the viewer's print route, which renders every slide for printing. Server-side export sends the same print route to Browser Rendering.
226
234
 
227
235
  ## Build-time OGP recipe
228
236
 
229
- viewer share image をビルド時に生成する場合は、`router.viewer.openGraph` を有効にします。既定の画像パスは `decks.paths(slug).ogImage` です。viewer request origin から Open Graph / Twitter Card の絶対URLを生成します。
237
+ Enable <code>router.viewer.openGraph</code> when generating share images at build time. The default image path is <code>decks.paths(slug).ogImage</code>. The viewer derives absolute Open Graph and Twitter Card URLs from the request origin.
230
238
 
231
- ```ts
239
+ ~~~ts
232
240
  export default defineDecksConfig({
233
241
  mountPath: "/decks",
234
242
  router: {
235
243
  viewer: { openGraph: true },
236
244
  },
237
245
  });
238
- ```
246
+ ~~~
239
247
 
240
- 独自CDNを使う場合は `imagePath: ({ deck }) => \`https://cdn.example.com/${deck.slug}.png\`` のように resolver で上書きできます。`false` または未指定なら social metadata は出力しません。
248
+ Override <code>imagePath</code> with a resolver when images are served from a separate CDN. Set Open Graph configuration to <code>false</code>, or omit it, to suppress social metadata.
241
249
 
242
- 生成処理は core に含まれません。`examples/ogp` では `hono-decks/node` `compileDecks()` が返す manifest Satori + resvg へ渡し、1200×630 PNG Workers Static Assets へ保存します。Satori / resvg example だけの依存で、Browser Rendering binding は不要です。Satori TTF / OTF / WOFF を読み込めますが WOFF2 は扱えないため、対象言語の font file build script から明示的に渡してください。
250
+ Image generation is intentionally not part of the core package. The <code>examples/ogp</code> recipe passes the manifest returned by <code>compileDecks()</code> from <code>hono-decks/node</code> to Satori and resvg, then stores 1200 by 630 PNG files in Workers Static Assets. Satori and resvg are example-only dependencies, and the recipe does not require Browser Rendering. Satori accepts TTF, OTF, and WOFF fonts but not WOFF2, so the build script must receive a font file that covers the target language.
243
251
 
244
- `build.ogpCacheFile` `@[card](...)` が参照する外部サイトのメタデータキャッシュです。viewer 自身の share image とは別機能です。
252
+ <code>build.ogpCacheFile</code> stores external site metadata used by <code>@[card](...)</code>. It is separate from the viewer's share image.
245
253
 
246
254
  ## Public entries
247
255
 
248
- - `hono-decks`: config、configured kit の型、deck authoringviewer/embed customizationsource decorator
249
- - `hono-decks/advanced`: `defineDecks()`、`decksRouter()`、`deckContext()`、raw renderer など独自 pipeline
250
- - `hono-decks/client`: browser hydration
251
- - `hono-decks/node`: compiler Node filesystem adapter
252
- - `hono-decks/cli`: programmatic CLI runner
256
+ - <code>hono-decks</code>: configuration, configured-kit types, deck authoring, viewer and embed customization, and source decorators
257
+ - <code>hono-decks/advanced</code>: <code>defineDecks()</code>, <code>decksRouter()</code>, <code>deckContext()</code>, raw renderers, and other low-level pipeline APIs
258
+ - <code>hono-decks/client</code>: browser hydration
259
+ - <code>hono-decks/node</code>: the compiler and Node filesystem adapter
260
+ - <code>hono-decks/cli</code>: the programmatic CLI runner
253
261
 
254
- 通常の generated workflow では root entry だけを import します。`hono-decks/advanced` custom `DeckSource` router をゼロから組み立てる場合に限定してください。
262
+ The generated workflow normally imports only the root entry. Use <code>hono-decks/advanced</code> only when assembling a custom <code>DeckSource</code> or router from the lower-level primitives.
255
263
 
256
264
  ## Cloudflare Workers
257
265
 
258
- Wrangler JSONC configcurrent compatibility date、必要に応じた `nodejs_compat` を使います。binding types `wrangler types` で生成し、hand-written binding interface と実際の config がずれないようにしてください。
266
+ Use a JSONC Wrangler config, a current compatibility date, and <code>nodejs_compat</code> when required. Generate binding types with <code>wrangler types</code> so handwritten environment types cannot drift from the deployed configuration.
259
267
 
260
- ```jsonc
268
+ ~~~jsonc
261
269
  {
262
270
  "$schema": "node_modules/wrangler/config-schema.json",
263
271
  "name": "my-decks",
@@ -265,23 +273,23 @@ Wrangler は JSONC config、current compatibility date、必要に応じた `nod
265
273
  "compatibility_date": "2026-07-14",
266
274
  "compatibility_flags": ["nodejs_compat"]
267
275
  }
268
- ```
276
+ ~~~
269
277
 
270
278
  ## Advanced API
271
279
 
272
- 既存 manifest、database、remote object store から完全に独自の runtime を作る場合だけ advanced entry を使います。
280
+ Use the advanced entry only when building a custom runtime from an existing manifest, database, or remote object store.
273
281
 
274
- ```ts
282
+ ~~~ts
275
283
  import { decksRouter, manifestDeckSource } from "hono-decks/advanced";
276
284
 
277
285
  const source = manifestDeckSource(manifest);
278
286
  app.route("/internal-slides", decksRouter({ source, dev: true }));
279
- ```
287
+ ~~~
280
288
 
281
- このレベルでは mount pathsource policyoption merge をアプリ側が管理します。通常の利用では generated `createDecks(config)` のほうが安全で短くなります。
289
+ At this level, the application owns the mount path, source policy, and option merging. For normal use, the generated <code>createDecks(config)</code> API is shorter and safer.
282
290
 
283
291
  ## Examples
284
292
 
285
- - `examples/minimal`: standalone Worker の最小構成
286
- - `examples/basic`: R2Browser Renderingcustom routesclient components
287
- - `examples/honox`: HonoX integration
293
+ - <code>examples/minimal</code>: the smallest standalone Worker setup
294
+ - <code>examples/basic</code>: R2, Browser Rendering, custom routes, and client components
295
+ - <code>examples/honox</code>: HonoX integration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-decks",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Slide decks for Hono and Cloudflare Workers",
5
5
  "keywords": [
6
6
  "cloudflare-workers",
@@ -8,15 +8,15 @@
8
8
  "mdx",
9
9
  "slides"
10
10
  ],
11
- "homepage": "https://github.com/ts-76/hono-slides#readme",
11
+ "homepage": "https://github.com/ts-76/hono-decks#readme",
12
12
  "bugs": {
13
- "url": "https://github.com/ts-76/hono-slides/issues"
13
+ "url": "https://github.com/ts-76/hono-decks/issues"
14
14
  },
15
15
  "license": "MIT",
16
16
  "author": "ts-76",
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "git+https://github.com/ts-76/hono-slides.git",
19
+ "url": "git+https://github.com/ts-76/hono-decks.git",
20
20
  "directory": "packages/decks"
21
21
  },
22
22
  "bin": {
@@ -24,7 +24,8 @@
24
24
  },
25
25
  "files": [
26
26
  "dist",
27
- "README.md"
27
+ "README.md",
28
+ "README.ja.md"
28
29
  ],
29
30
  "type": "module",
30
31
  "sideEffects": false,