Tie your thoughts, publish them quietly.
Musubi is Yunfei's opinionated personal website framework. Notion is the editing surface; a dedicated setup step records its data as local JSON, then Nuxt and Vue validate and typeset that snapshot into a static site.
You do not need to change source code or create a local website configuration file for the default site. An ordinary .env.local stores only the build secret and the two Notion source locators; optional private build inputs such as an alternate font-cache directory may also be set there.
- Fork this repository.
- Create or duplicate a Notion workspace that follows the Database and Config contract.
- Create a dedicated Notion internal integration with only
Read content, then share the workspace root with it. - Copy
.env.exampleto.env.localand fill the token plus both Notion page IDs. - Install, fetch the first Notion Data snapshot, and verify the site through Vite+:
vp install
vp run notion:setup
vp run readyvp run notion:setup is the only content command that contacts Notion. It writes the tracked snapshot as .musubi/notion-data-snapshot/config.json plus one .musubi/notion-data-snapshot/pages/<notion-page-id>.json file per Published page. Unchanged pages are reused on later refreshes. pnpm run dev, vp run site:build, and vp run ready consume those files locally and do not contact Notion. pnpm run build is notion:setup then site:build: refresh content first, then the offline static site pipeline.
package.json keeps only lifecycle hooks and entry scripts (dev, build, preview). Composable steps live as Vite+ tasks under vp run (site:build, notion:setup, font:setup, font:build, ready, and the rest).
The deployable artifact is .output/public. It does not need .output/server, a running Nitro process, Notion credentials, or a public content API.
Production deployment, publication, cache, and rollback procedures are documented in Production Operations.
Musubi works without proprietary font files: the open-licensed Musubi CJK Fallback is always available. Preferred Tsanger JinKai W04/W05 sources are never committed: font:setup downloads and verifies them into the ignored .musubi/font/tsanger/ cache (skips download when a verified cache already exists). Default download order is jsDelivr (cdn.jsdelivr.net/gh/tw93/Kami@main/assets/fonts/…), then the official tsanger.cn hosts; checksums must match the pinned pair.
The default pipeline runs vp run font:setup so install, dev, and site builds download a missing verified Tsanger cache (or reuse an existing one). Failure prints a clear error and stops the pipeline. MUSUBI_TSANGER_SETUP=0 skips the download attempt only; an existing cache or paired MUSUBI_TSANGER_*_PATH files still feed font:build. To force Fallback-only, clear the cache (vp run font:setup -- --clear) and keep setup skipped or leave no local sources.
postinstall—font:setupafternuxt preparepnpm run dev/vp run site:build—font:setupbeforefont:buildpnpm run build—notion:setupthensite:build
font:build only reads the on-disk Notion snapshot plus any Tsanger cache or path overrides; it does not call Notion itself. Review the official terms before using Tsanger. Full source files must never become public deployment artifacts.
Builder-only environment (do not commit secrets or private mirror URLs):
MUSUBI_TSANGER_W04_URL/MUSUBI_TSANGER_W05_URL— paired HTTPS mirrors; files must match the pinned size and SHA-256MUSUBI_TSANGER_W04_PATH/MUSUBI_TSANGER_W05_PATH— paired local source files forfont:buildMUSUBI_TSANGER_CACHE_DIR— alternate setup cache directoryMUSUBI_TSANGER_SETUP=0— skip setup download (does not clear an existing cache)
Manual: vp run font:setup, vp run font:setup -- --clear.
Start Nuxt against the tracked local Notion Data snapshot:
pnpm run devDevelopment reads only the tracked Notion Data snapshot. It also prepares the generated font files from local inputs; a private .musubi/font/build-state.json fingerprint makes unchanged starts reuse the existing output instead of rebuilding fonts.
Build from the same local snapshot and serve only the static artifact:
vp run site:build
pnpm run preview -- --port 4173The static preview mirrors the production cache contract: HTML and stable metadata URLs revalidate with ETag and Last-Modified, while content-addressed Nuxt assets, generated files, and font subsets use a one-year immutable policy. A deployment host should preserve the same distinction.
vp run lint runs Vite+'s code lint and Google's official designmd lint .agents/docs/DESIGN.md together. vp run ready includes that repository lint task alongside formatting, focused unit tests, Nuxt's Vue-aware type check, local snapshot validation, static generation, and artifact checks. User-facing changes additionally require the real-browser workflow in Visual Frontend Development and Acceptance.
- Published Posts become
/blog/:slug; Published Pages become/:slug. - A Published Page enters primary navigation only when its Notion row explicitly enables
Show in Navigation; a hidden Page remains directly routable. /shows the five newest Posts;/blogshows every published Post in one archive grouped by year.- Drafts, tag routes, paginated Blog routes, and a public content API are not generated.
- Notion Markdown is parsed into Musubi's allowlisted AST and rendered by Vue templates. Raw HTML and executable MDX are rejected.
- Notion images and file blocks retain their remote HTTPS URLs; Musubi does not download or rewrite them in the initial architecture. An X embed stores only its source URL and renders as a safe ordinary link without build-time oEmbed requests or browser widget loading.
- Tsanger JinKai W04 and W05 are accepted as optional local build inputs and are subset by body-versus-emphasis usage when supplied. Preferred subsets and the public LXGW WenKai GB Medium fallback use content-addressed WOFF2 URLs; the fallback preserves every mapped source code point across Unicode-range shards that also cover later runtime text.
- Light and warm dark themes follow the system by default; a persisted three-choice control selects Light, Dark, or System directly.
The durable product boundary is documented in Project Context Records, and the exact visual direction lives in DESIGN.md.