Skip to content

[Proposal]: migrate documentation to VitePress with TypeDoc integration #81

Closed

Description

@soimy

Proposal

Migrate the documentation to VitePress, retaining TypeDoc as the API extraction layer. TypeDoc will generate Markdown from src/index.ts and JSDoc; VitePress will build the user guides, contributor documentation, and generated API reference into one searchable site.

Use the documentation organization and agent-development conventions of OpenClaw DingTalk Channel Plugin as a reference, adapted to this library's English-only policy, npm toolchain, master branch, and compatibility requirements.

This issue is a design proposal, not a report of an implemented migration. Hosting remains an open decision; GitHub Pages is the proposed default.

Problem and current state

  • README.md mixes the project entry point, installation, examples, API reference, and feature explanations.
  • CONTRIBUTING.md provides useful rules but contains inconsistent test descriptions and outdated baseline figures.
  • AGENTS.md records essential invariants, but also contains extensive implementation details and historical findings that need clearer ownership.
  • typedoc.json already uses src/index.ts, but produces a separate HTML site with typedoc-unhoax-theme.
  • The entire docs/ directory is gitignored and currently contains generated HTML.
  • doc:clean deletes the entire docs/ directory. Introducing tracked documentation without changing this command would expose that source to deletion.
  • doc:publish uploads the entire docs/ tree, which would also publish internal plans unless the output boundary changes.
  • Code CI checks lint, formatting, types, coverage, and package consumption, but does not build the documentation.
  • DEFERRED_WORK.md already identifies the documentation-directory problem; its proposed mixed source/output layout should be superseded by this design.

Audit evidence

The existing TypeDoc configuration successfully generated HTML and JSON into a temporary directory. The reflection output contained the six runtime exports (Rectangle, MaxRectsPacker, PACKING_LOGIC, Bin, MaxRectsBin, and OversizedElementBin) and three type exports (IRectangle, IOption, and IBin).

No complete test or coverage run was performed during this documentation audit. The recorded repository baseline must not be presented as a fresh measurement. The new TypeDoc/VitePress plugin combination has not yet been build-tested.

Goals

  1. Keep README concise and provide durable, topic-focused documentation.
  2. Separate user documentation, contributor documentation, and internal agent work records.
  3. Preserve source-generated API signatures, overloads, generics, and JSDoc.
  4. Provide consistent navigation, appearance, and local search across guides and API pages.
  5. Make clean builds, safe cleanup, and documentation validation reproducible in CI.
  6. Preserve existing documentation URLs where practical through explicit compatibility pages.
  7. Keep the published library's API, packing behavior, ES5 output, and zero runtime dependencies intact.

Non-goals

  • Algorithm changes or fixes to deferred behavior questions.
  • A custom documentation frontend, custom JSON renderer, or hand-maintained API signatures.
  • Switching package managers or changing the TypeScript 6/7 setup.
  • Multilingual documentation, a multi-version site, or a custom theme in the first migration.
  • Hand-editing CHANGELOG.md or changing the package version.

Proposed architecture

src/index.ts + JSDoc
        |
        v
TypeDoc + Markdown/VitePress plugins
        |
        v
docs/api/*.md + typedoc-sidebar.json  (generated, ignored)
        |
        +---- tracked user/contributor/release pages
        |
        v
VitePress
        |
        v
docs/.vitepress/dist/                (generated, ignored)
        |
        v
Static hosting

Tooling

Candidate versions checked against npm metadata on 2026-09-30:

  • vitepress@1.6.4 (stable; also used by the reference repository)
  • existing typedoc@0.28.20
  • typedoc-plugin-markdown@4.13.1
  • typedoc-vitepress-theme@1.1.4

The plugins' declared peer ranges match TypeDoc 0.28. These are candidates for an integration spike, not a claim that the complete combination already works. Lock the validated combination in package-lock.json. All documentation tooling belongs in devDependencies.

Retain TypeDoc's TypeScript 6 JS API path and the existing native TypeScript 7 type-checking gate. Do not copy instructions for VitePress 2.x alpha into the 1.6.4 setup or change the library's Node 20/22/24 CI matrix as a side effect.

Target documentation structure

README.md                         concise entry and runnable minimal example
CONTRIBUTING.md                   contribution entry and essential rules
AGENTS.md                         mandatory agent constraints and reading map
CHANGELOG.md                      existing release-generated history
docs/
  index.md
  .vitepress/
    config.mts
  user/
    index.md
    getting-started.md
    options.md
    packing.md
    rotation-and-tags.md
    repacking.md
    persistence.md
    troubleshooting.md
  api/                            generated; never edit or commit
  contributor/
    index.md
    development.md
    testing.md
    architecture.md
    behavior-contracts.md
    compatibility.md
    documentation.md
    releasing.md
  releases/
    index.md
  spec/                           tracked designs; excluded from site
  plans/                          tracked plans; excluded from site
    deferred-work.md

Create pages when migrating real content; do not scaffold empty archives, translation trees, or per-version release pages.

Content ownership and migration

Content Canonical source Migration rule
Public signatures and member documentation Source types and JSDoc Generate API pages; do not duplicate signatures manually
Usage, examples, options, and limitations docs/user/ Move detailed README content here
Module responsibilities and data flow contributor/architecture.md AGENTS links to the detailed explanation
Stable packing and cloning contracts contributor/behavior-contracts.md AGENTS retains concise mandatory invariants
ES5, TS 6/7, declarations, and package entry points contributor/compatibility.md Preserve current compatibility decisions
Development, testing, and release procedures Contributor pages and package scripts CONTRIBUTING retains entry points and essential contribution rules
Release history Root CHANGELOG.md Include at build time or link; do not maintain a second copy
Designs and execution plans docs/spec/, docs/plans/ Track in Git but exclude from HTML and search
Deferred findings docs/plans/deferred-work.md Move existing records and update all references

The initial editorial pass must fix or clarify:

  • The syntactically invalid oversized background object in the README example.
  • References to MaxRectsPacker.IRectangle; show the actual package-level type import.
  • next() returning an index and affecting subsequent additions rather than immediately returning a new bin.
  • save/load preserving free space, not restoring already-placed rectangles.
  • Packing being a heuristic, with no guarantee of a minimum bin count.
  • Per-item rotation limitations, plain-object rotation footprints, tag grouping, oversized rectangles, dirty repacking, and shallow clone boundaries.
  • CONTRIBUTING's Jest/CommonJS description versus the actual Vitest/ESM source tests, and stale test/coverage figures.

Use existing source and tests to establish behavior. Do not turn a documentation correction into an unrequested algorithm change. Compile/run the principal JavaScript and TypeScript examples; reuse existing verification tooling where possible.

Agent-development constraints

Keep AGENTS as an actionable entry point rather than reducing it to links. It must still state the English policy, commit/release rules, zero runtime dependencies, API compatibility obligations, required checks, and concise versions of the critical packing and cloning invariants.

Add explicit routing rules:

  1. User-facing details belong in docs/user/; contributor/process details belong in docs/contributor/.
  2. Agent-authored designs go to docs/spec/YYYY-MM-DD-<topic>.md.
  3. Execution plans go to docs/plans/YYYY-MM-DD-<topic>.md.
  4. Do not create tool-specific roots such as docs/superpowers/.
  5. Never edit generated API Markdown or built site files.
  6. Behavior changes update relevant tests, JSDoc, and guides together.
  7. Keep ongoing findings in the deferred-work ledger rather than growing AGENTS as a log.

The reference repository requests attribution for substantial reuse of documentation and agent conventions. If text is substantially adapted, acknowledge OpenClaw DingTalk Channel Plugin — YM Shen and contributors, with its repository URL. Retain this project's English-only communication policy rather than importing the reference project's language rules.

Build and cleanup contract

TypeDoc should continue reading src/index.ts, generate to docs/api/, set docsRoot to docs, and use the Markdown and VitePress plugins instead of the Unhoax HTML theme.

Initial configuration intent:

  • readme: "none" to avoid embedding README again in the API landing page.
  • Hide private implementation members; explain internal algorithm flow in the architecture guide.
  • Keep undocumented public members visible so missing JSDoc cannot silently hide API.
  • Initially retain skipErrorChecking; keep the separate type-checking gate mandatory.
  • Generate API sidebar data and use it directly in the VitePress configuration.
Command Proposed behavior
docs:api Clean and regenerate only docs/api/
docs:dev Generate API, then start the VitePress development server
docs:build Generate API, then build the complete site
docs:preview Serve the production build locally
docs:clean Remove only generated API, cache, and site output
doc Compatibility alias for docs:build
doc:clean Compatibility alias for docs:clean

Generate API on development-server startup initially; rerun generation after JSDoc changes. Add watching only if that workflow proves insufficient.

Required coordinated changes:

  • Stop ignoring all of docs/; ignore docs/api/, docs/.vitepress/cache/, and docs/.vitepress/dist/ explicitly.
  • Remove old generated HTML before adding tracked Markdown sources.
  • Never clean the documentation source root.
  • Move doc:json output into a generated temporary location.
  • Publish only docs/.vitepress/dist/.
  • Update CONTRIBUTING, AGENTS, and the PR template so tracked documentation is allowed and generated output is prohibited.
  • Cover documentation configuration in formatting checks.
  • Review the npm files allowlist and obsolete theme assets. Keep docs, plans, and site output out of the published package; inspect tarball changes before removing currently published assets/configuration.
  • Keep lockfile tarball URLs on registry.npmjs.org and account for the documented npm peer-resolution/alias pitfalls.

Site behavior

  • English-only site, default VitePress theme, and local search.
  • Navigation: User Guide, API, Contributing, Releases, and GitHub.
  • Curated guide/contributor sidebars; generated API sidebar.
  • Exclude spec/** and plans/** from page generation and search. Navigation omission alone is not sufficient.
  • Keep dead-link checks enabled.
  • Provide edit links for handwritten pages, not nonexistent generated API source files.
  • Use explicit base configuration: /maxrects-packer/ for the existing Pages URL; / for a root-domain deployment.
  • State that the initial site is built from master, with its source revision. Do not label unreleased source behavior as published npm behavior solely because package.json still says 2.7.4.

Hosting decision

Proposed default: retain GitHub Pages at https://soimy.github.io/maxrects-packer/. VitePress and TypeDoc integration does not require changing hosting.

Alternative: Vercel when online PR preview is a desired review requirement. The reference repository chose Actions-controlled Vercel previews and production deployment to resolve overlapping deployment paths. That is not evidence of a performance, regional-access, or cost advantage.

If Vercel is selected, use one explicit deployment owner, define preview/production triggers, and configure project credentials. Specify fork-PR behavior; the reference workflow skips fork deployments and should not be described as providing previews for every external PR.

For GitHub Pages:

  • Build docs on PRs and changes to master; deploy only the intended production branch or explicit production dispatch.
  • Include src/**, docs, README/CONTRIBUTING/AGENTS, TypeDoc/config changes, lockfile/package changes, CHANGELOG, relevant scripts, and the workflow in trigger coverage.
  • Use one documentation job, proposed Node 24, with npm ci --include=dev.
  • Run the existing type check before docs generation; upload the site artifact for PR review.
  • Deploy the built artifact via the Pages Actions mechanism and update repository Pages settings when switching from branch publishing.
  • Keep existing library CI gates and the Node matrix.

URL compatibility and rollback

Inventory the current live page URLs and important member anchors before switching. Examples include:

classes/MaxRectsPacker.html -> api/classes/MaxRectsPacker.html
interfaces/IOption.html    -> api/interfaces/IOption.html
enums/PACKING_LOGIC.html   -> api/enums/PACKING_LOGIC.html

Confirm destinations against actual plugin output. Generate small static redirect pages at legacy paths, and explicitly check common member-anchor mappings. Do not assume old TypeDoc anchors match VitePress anchors or rely on server redirects on Pages.

Retain the previous site artifact and deployment configuration until the new production site passes URL, content, search, and subpath checks. Roll back deployment if needed without discarding the tracked documentation source.

Implementation phases

  • A — Integration spike: use an isolated .worktrees/ checkout, install dev dependencies, verify the candidate plugin combination and a minimal site; inspect all nine exports, generics, overloads, cross-references, and anchors.
  • B — Safe source structure: change ignore/cleanup/output boundaries together, remove old generated HTML, establish tracked docs/config, and prove a fresh checkout builds.
  • C — Content and agent migration: split README/CONTRIBUTING, correct examples and descriptions, add architecture/contracts/compatibility pages, update AGENTS and move the deferred ledger.
  • D — Deployment and compatibility: add docs CI, implement the selected hosting path, preserve legacy URLs, and validate the production base path.
  • E — Retire old tooling: remove unused theme/customization/publishing dependencies after successful validation; inspect npm package content and rerun the existing gates.

Acceptance criteria

  • A clean checkout builds the complete documentation without preexisting API Markdown or sidebar JSON.
  • Repeated generation leaves no stale API pages after a symbol is removed.
  • Cleanup preserves every tracked handwritten document and configuration file.
  • API reference includes all six runtime and three type exports, with correct overloads and generics.
  • Generated/private/internal content boundaries are verified in the actual build and search index.
  • Principal ESM, CommonJS, and TypeScript examples run or compile successfully.
  • Usage guidance accurately explains mutation, rotation, tags, dirty repacking, free-space persistence, oversized handling, cloning, and heuristic limits.
  • Search, assets, deep-link refreshes, navigation, and legacy links work at the deployed base path.
  • Lint, formatting, type checking, tests, coverage artifacts/thresholds, and package-consumption verification pass after implementation.
  • Tarball review confirms no documentation site/internal plans or runtime dependencies were added and package entry points remain valid.
  • The old deployment can be restored if production validation fails.

Open decisions

  1. Confirm hosting: retain Pages, or use Vercel for online PR previews.
  2. Confirm the old URL/member-anchor inventory during the integration spike.
  3. Finalize exact plugin versions after a successful build, and decide which existing TypeDoc warnings can immediately become blocking without unrelated JSDoc churn.

References

Prepared with AI assistance from the repository audit and migration discussion. No implementation changes are included in this proposal.

Activity

  1. soimy commented on Sep 30, 2026

    @soimy
    OwnerAuthor

    Phase A (integration spike) — done, and the combination works

    Run in a throwaway worktree from 202a9f6, branch docs/vitepress-spike. The full evidence, including the URL inventory, is in docs/spec/2026-09-30-docs-migration-spike.md.

    Toolchain (all four at the proposed versions, no workarounds): vitepress@1.6.4, existing typedoc@0.28.20, typedoc-plugin-markdown@4.13.1, typedoc-vitepress-theme@1.1.4. Installed with --no-save; package.json and package-lock.json are byte-identical afterwards and no mirror host reached the lockfile.

    Emitted: docs/api/ with 10 markdown files — index.md plus classes/ (5), interfaces/ (3), enumerations/ (1), covering all six runtime and three type exports — plus typedoc-sidebar.json; and a 13-page site at base /maxrects-packer/ with the local search index. TypeDoc printed 0 warnings.

    Acceptance checks measured, not assumed:

    Check Result
    Clean generation + build (no preexisting API markdown) 10 md, 13 pages, exit 0
    Stale API page after a symbol disappears removed by TypeDoc's cleanOutputDir default
    Generics, overloads, cross-references MaxRectsPacker\<T\> + type parameters; two call signatures under add(); links rewritten to ../interfaces/IRectangle.html; dead-link check green
    spec/**, plans/** out of pages and search verified with markers in the page source, the built HTML and the search index chunk
    Tarball untouched npm pack --dry-run: 0 docs/ entries, only typedoc.json from the docs tooling

    URL and anchor inventory (member anchors preserved / checked): interfaces 8/8, 9/9, 5/5; classes 21/23, 22/33, 21/24, 21/24, 18/28; enums/PACKING_LOGIC.html → api/enumerations/PACKING_LOGIC.html 1/4; modules.html → api/index.html 3/12; index.html 0/21; hierarchy.html has no successor.

    Every miss falls into four buckets, and only the first is a real loss:

    1. Private members — _dirty, _currentBinIndex, _width/_height/_x/_y/_rot/_data/_allowRotation, stage, border, verticalExpand, findNode, place, splitNode, updateBinSize, pruneFreeList, expandFreeRects, sort. They have anchors today only because typedoc.json sets excludePrivate: false; hiding them is what this proposal asks for, and it is the largest bucket.
    2. Unhoax composite anchors — constructorMaxRectsPackerT, collide-2, contain-2: theme artifacts with no heading equivalent.
    3. Separator/case renames — enum members #max_area → #max-area.
    4. Pages that change shape — modules.html's list becomes api/index.html's; README headings become docs/user/ pages; hierarchy.html redirects to api/index.html.

    Phase B scope proposed (first PR): the .gitignore swap to docs/api/ + .vitepress/{cache,dist}/; removing the old generated HTML; splitting typedoc.json for the markdown output (out: "docs/api", docsRoot: "docs"); the docs:* scripts with doc/doc:clean kept as aliases and doc:publish narrowed to docs/.vitepress/dist/; moving the deferred ledger to docs/plans/deferred-work.md and updating its three references; and a check that fails if docs:clean is ever changed back to deleting the source root.

    Decisions I need before Phase B:

    1. Hosting: keep GitHub Pages at base /maxrects-packer/ (the spike built at that base) or go to Vercel for PR previews?
    2. Confirm excludePrivate: true — that is exactly what drops bucket 1.
    3. The spike branch is pushed for review; say the word and I delete it once Phase B carries the real files.
  2. soimy commented on Sep 30, 2026

    @soimy
    OwnerAuthor

    Phase A–E implemented — acceptance criteria, with where each one is verified

    All five phases are written and pushed. #82 (B) is ready and green; #83 (C), #84 (D) and #85 (E) are stacked drafts on top of it, so their CI and review start when B lands.

    Acceptance criterion Evidence State
    A clean checkout builds the documentation without preexisting API markdown Measured in the phase A spike and in every local run since: docs:api starts with rimraf docs/api verified
    Repeated generation leaves no stale API pages The explicit rimraf above, plus the spike's Ghost.md test against TypeDoc's cleanOutputDir verified
    Cleanup preserves every tracked handwritten document and configuration file npm run verify:docs runs docs:clean in a throwaway fixture and compares a sha256 inventory of every source file before/after; it also fingerprints the checkout itself, so the check cannot touch the working tree verified, in CI
    API reference includes all six runtime and three type exports, with correct overloads and generics Built pages for all nine exports; MaxRectsPacker<T> with Type Parameters; both add() call signatures; cross-page links rewritten to ../interfaces/IRectangle.html verified
    Generated/private/internal content boundaries verified in the actual build and search index excludePrivate: true (private members out), and the new output check fails if dist/spec/dist/plans exists or the search index carries no site text. Both directions measured by breaking the config verified, in CI
    Principal ESM, CommonJS and TypeScript examples run or compile verify:package runs require, import, compiles the type fixture under bundler/node16/nodenext, and executes every block marked <!-- docs-example: name --> against the installed tarball verified, in CI
    Usage guidance explains mutation, rotation, tags, dirty repacking, free-space persistence, oversized handling, cloning, heuristic limits The user guide covers each; four claims were corrected against measurements while writing it (rotation of a rect that already fits, next()'s return value, addArray() returning nothing, bin.repack()) verified
    Search, assets, deep-link refreshes, navigation and legacy links work at the deployed base path Served the built tree under /maxrects-packer/: home, API, both guide sections, releases and all legacy class/interface/enum paths return 200, and every asset the home page references returns 200 verified locally — real deployment is phase D's remaining step
    Lint, formatting, type checking, tests, coverage, package verification pass Every gate exits 0 on the chain head: lint 0/0, format:check, typecheck (TS 7), 126 passed / 2 skipped, coverage 100%, verify:package verified, in CI for B
    Tarball review: no documentation site, internal plans or runtime dependencies added; entry points still valid npm pack --dry-run: 28 files, zero docs/ entries; files unchanged for the library verified
    Old deployment can be restored if production validation fails doc:publish (gh-pages) is kept as the fallback until the Pages source is switched to GitHub Actions mechanism in place

    Two things stand between this and a finished migration, and both are yours:

    1. Merge #82 — C, D and E rebase onto master one at a time after that, each then running CI and review for the first time.
    2. Switch Settings → Pages → Build and deployment to "GitHub Actions" before the first deployment from .github/workflows/docs.yml. Until then the gh-pages path stays and the two must not run together.

    Hosting is implemented as the proposed default (GitHub Pages, base /maxrects-packer/). The legacy URL inventory, including the anchors that cannot be preserved, is in docs/spec/2026-09-30-docs-migration-spike.md.

  3. 41 remaining items

  4. soimy commented on Oct 9, 2026

    @soimy
    OwnerAuthor

    Close via #88

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions