Motion

Foundation
@wabbit/tome-motionv0.3.1

Client-side motion adapter layer — React bindings over GSAP, @gsap/react, and Lenis, plus a prefers-reduced-motion contract every hook honors; binds tome-chrome scroll behavior and tome-blocks-extras block animation.

Installnpm install @wabbit/tome-motion

Overview

@wabbit/tome-motion

The client-side motion adapter layer: React bindings over GSAP + @gsap/react + Lenis, plus a prefers-reduced-motion contract every declarative hook honors. ui layer per root ARCHITECTURE.md — depends on @wabbit/tome-core and (via a documented @deprecated back-compat shim only) @wabbit/tome-blocks-core. Adapter modules bind motion's hooks to two downstream consumers' adapter contracts: @wabbit/tome-chrome (header/footer scroll behavior) and @wabbit/tome-blocks-extras (block-level scroll animation).

Install

pnpm add @wabbit/tome-motion gsap @gsap/react

| Peer | Range | Notes | |---|---|---| | gsap | >=3.13 | | | @gsap/react | >=2.1 | | | react / react-dom | >=19.0.0 | | | lenis | >=1.1 | optional — only needed if you mount LenisProvider/useLenis |

60-second quickstart

// app root
import { MotionProvider } from '@wabbit/tome-motion'

<MotionProvider>{children}</MotionProvider>
// any client component under the provider
'use client'
import { useRef } from 'react'
import { useTween, useReducedMotion } from '@wabbit/tome-motion'

const ref = useRef<HTMLDivElement>(null)
useTween(ref, { x: 100, opacity: 1, duration: 0.4 })

Public API

| Export | Description | |---|---| | MotionProvider | Root provider — registers GSAP plugins, parses --tome-motion-* tokens, subscribes to prefers-reduced-motion, seeds gsap.defaults | | LenisProvider, useLenis, useLenisRefresh | Optional smooth-scroll integration | | useTween | Declarative gsap.to/from/fromTo/set wrapper with automatic reduced-motion collapse | | useTimeline | gsap.core.Timeline ref, React-lifecycle-managed via useGSAP | | useScrollTrigger | ScrollTrigger-driven tween wrapper | | useTicker | gsap.ticker-driven per-frame callback | | useGSAPContext | Escape hatch — raw useGSAP context + contextSafe, for patterns the declarative hooks can't express | | useReducedMotion | Thin accessor over MotionContext.prefersReducedMotion — the provider owns the single matchMedia subscription | | useParallaxScope, ParallaxScope | Parallax scroll utility hook + wrapper component | | usePerfMonitor, MotionDebugHUD | Dev-time FPS/reduced-motion telemetry overlay | | RouteTransition | View-transition wrapper for route changes | | killTweensInScope | Cleanup utility | | useDebouncedResize | `@deprecated` — re-exports from @wabbit/tome-blocks-core/utilities/useDebouncedResize; removed from this package's own implementation in v0.2.0 | | gsap (default), ScrollTrigger | Raw GSAP re-export — see escape hatch note below | | ./adapters/chrome → chromeMotionAdapters | Binds useScrollDirection/useReducedMotion/useFooterParallax to @wabbit/tome-chrome's ChromeMotionAdapters contract | | ./adapters/blocks-extras | Binds motion hooks to @wabbit/tome-blocks-extras' adapter contract | | ./test → MockMotionProvider | Test-only MotionProvider stand-in for component tests that don't need real GSAP |

Server / client posture

There is no server subpath — this entire package is browser-only. 18 of its ~19 source modules declare 'use client' (every hook, provider, and component); the barrel index.ts itself carries no directive but re-exports exclusively client-only modules plus the raw gsap/ScrollTrigger values, so importing anything from @wabbit/tome-motion other than pure types forces the importing tree client.

The reduced-motion contract — and the raw-GSAP escape hatch (documented honestly)

MotionProvider owns the single matchMedia('(prefers-reduced-motion: reduce)') subscription and exposes prefersReducedMotion through context; every hook reads it from there — none subscribes independently. The declarative hooks auto-gate, with a per-call opt-out:

  • useTween — when reduced-motion is active (and respectReducedMotion !== false), kind: 'to'/'fromTo'/'set' collapse to gsap.set() (instant end state) and kind: 'from' becomes a no-op. Pass { respectReducedMotion: false } for an animation that IS the content.
  • useTimeline — still builds the timeline (so the ref is populated and consumer .to() calls don't throw), then calls .progress(1).pause() when reduced-motion is active. The caller is responsible for re-calling .progress(1) after appending children if they want an instant end state visible — useTimeline only provides a best-effort default.
  • MotionProvider itself, on a live OS-level toggle to reduced-motion, walks gsap.globalTimeline.getChildren() and force-progresses every active tween to 1 (end-state jump).

The escape hatch does NOT auto-gate. gsap and ScrollTrigger are re-exported raw from the package root (export { default as gsap } from 'gsap') — a consumer reaching for raw gsap instead of the hooks gets zero reduced-motion protection; nothing in this package intercepts calls made directly on the raw instance. Likewise useGSAPContext (the hook-level escape hatch for patterns the declarative hooks can't express — mobile-state branching, getBoundingClientRect() mid-setup, cross-element contextSafe orchestration) does not auto-collapse: its own source comment states the contract plainly — "Callers MUST read `useReducedMotion()` and branch manually," typically via an early if (prefersReduced) return inside the setup callback. Any new consumer code that reaches for raw gsap or useGSAPContext carries the reduced-motion obligation itself; there is no ambient enforcement.

Extending

New declarative hooks follow the useTween/useTimeline pattern: read useMotionContext() for gsap/prefersReducedMotion, wrap the GSAP call in useGSAP() for automatic cleanup, and decide the reduced-motion collapse behavior explicitly in the hook body (don't leave it to the consumer unless the hook is itself an escape hatch). New adapter bindings (a third downstream consumer beyond chrome/blocks-extras) follow adapters/chrome.ts's pattern: a type-only compile-time import of the consumer's adapter contract, a thin object of hook references, no wrapping.

Design history

  • docs/superpowers/specs/2026-04-16-tome-motion-layer-design.md, 2026-04-16-tome-motion-layer-orchestrate-prompt.md — original design
  • docs/superpowers/specs/2026-04-17-tome-motion-hardening-plan.md, 2026-04-17-tome-block-motion-author-guide.md — hardening + block-author guidance
  • docs/superpowers/specs/2026-04-18-tome-motion-optional-enhancement-plan.md, 2026-04-18-tome-motion-optional-enhancement-refactor.md — the motion-optional pattern behind NOOP_CHROME_ADAPTERS/isMotionActive and the useDebouncedResize deprecation
  • docs/claude-gotchas.md → Payload / Typing / Layer Design section — "Duplicate installed copies of an adapter-bearing pack break React context" applies directly to this package's adapter modules

Exports

  • @wabbit/tome-motion
  • @wabbit/tome-motion/test
  • @wabbit/tome-motion/adapters/blocks-extras
  • @wabbit/tome-motion/adapters/chrome

Changelog

v0.3.1patch

Updated dependencies [404d325] - @wabbit/tome-blocks-core@0.17.0

  • Updated dependencies [404d325] - @wabbit/tome-blocks-core@0.17.0
v0.3.0minor

b01ca1f: Raise the `react` / `react-dom` peer floor to `>=19.0.0` (ruled 2026-09-01). The platform declared React peers in five different shapes — `>=18.0.0`, `>=18`, `^18 || ^19`, `^18.3.0 || ^19.0.0`, `^19.0.0` — while its kernel (`@wabbit/tome-core`) and five app-layer packages already required `>=19`. Any package advertising React 18 was advertising a configuration that could not be installed alongside the kernel, so the split was never a supported matrix; it was drift. One shape now, and it is the honest one. These nine version independently of the `linked` blocks family (which gets its own coordinated bump), so they are listed here: - `@wabbit/tome-admin`, `@wabbit/tome-admin-pro` — from `^18.3.0 || ^19.0.0` - `@wabbit/tome-blocks-gallery` — from `^18 || ^19`; devDeps `react`/`@types/react` `^18.0.0` → `^19.0.0` - `@wabbit/tome-blocks-org-pack` — from `>=18.0.0`; same devDep correction - `@wabbit/tome-engine`, `@wabbit/tome-motion`, `@wabbit/tome-rpg`, `@wabbit/tome-webgl` — from `>=18` - `@wabbit/tome-ui` — from `>=18.0.0` The `^18` devDependency pins on the two block-shaped packages were already fiction: the root `pnpm.overrides` pins `@types/react` to `19.2.14`, so both have been building against React 19 types regardless. Correcting them changes the manifest, not the resolved tree. Consumer impact: a React 18 consumer can no longer install these. That install was already impossible with the kernel in the graph.

  • b01ca1f: Raise the `react` / `react-dom` peer floor to `>=19.0.0` (ruled 2026-09-01). The platform declared React peers in five different shapes — `>=18.0.0`, `>=18`, `^18 || ^19`, `^18.3.0 || ^19.0.0`, `^19.0.0` — while its kernel (`@wabbit/tome-core`) and five app-layer packages already required `>=19`. Any package advertising React 18 was advertising a configuration that could not be installed alongside the kernel, so the split was never a supported matrix; it was drift. One shape now, and it is the honest one. These nine version independently of the `linked` blocks family (which gets its own coordinated bump), so they are listed here: - `@wabbit/tome-admin`, `@wabbit/tome-admin-pro` — from `^18.3.0 || ^19.0.0` - `@wabbit/tome-blocks-gallery` — from `^18 || ^19`; devDeps `react`/`@types/react` `^18.0.0` → `^19.0.0` - `@wabbit/tome-blocks-org-pack` — from `>=18.0.0`; same devDep correction - `@wabbit/tome-engine`, `@wabbit/tome-motion`, `@wabbit/tome-rpg`, `@wabbit/tome-webgl` — from `>=18` - `@wabbit/tome-ui` — from `>=18.0.0` The `^18` devDependency pins on the two block-shaped packages were already fiction: the root `pnpm.overrides` pins `@types/react` to `19.2.14`, so both have been building against React 19 types regardless. Correcting them changes the manifest, not the resolved tree. Consumer impact: a React 18 consumer can no longer install these. That install was already impossible with the kernel in the graph.
  • 0836ef5: dist now raw-Node loadable: relative specifiers get explicit extensions post-build. `build` gains `&& node ../../scripts/fix-dist-extensions.mjs --strict` as its last step, joining the 13 packages that already ran it. tsup builds `bundle: false` and emits relative specifiers exactly as the TypeScript source wrote them — extensionless — which bundlers resolve and raw Node does not (ESM `ERR_MODULE_NOT_FOUND`; CJS worse, `require('./x')` finds the ESM `.js` twin and Node 22+ `require(esm)` then dies on that file's own extensionless import). Every consumer outside a bundler hit this: the payload CLI under plain node, `generate:types`, `generate:importmap`, ops scripts, codegen tools. No source changes, no API changes, and bundler consumers are unaffected — extensioned relative specifiers are universally resolvable. Two supporting changes made the wiring possible, both in repo scripts rather than package source. `fix-dist-extensions.mjs` now skips bundler-asset specifiers (`.css`, `.module.css`, `.scss`, fonts, images, shaders) by explicit extension allowlist instead of reporting them as unresolvable — that single gap is why the 13 prior adopters were exactly the 13 packages that ship no CSS, since `--strict` exited 1 on any package with a relative stylesheet import. Dotted MODULE names (`./config.meta`, `./x.variants`, `./y.demo`) are deliberately NOT treated as assets and still get `.js`/`.cjs` appended. `assert-node-loadable.mjs` gained the matching carve-outs so the new repo-wide CI gate reports real defects only: a resolution failure whose path lands under `node_modules` is a peer SKIP (next@15 has no exports map, so `next/image` fails as an absolute path), and a bundler-asset load failure is an environmental SKIP (CJS surfaces it as `SyntaxError: Unexpected token '.'` raised from inside the stylesheet). Verified before/after on four packages built one at a time: print 8 FAIL → 0, readout 22 FAIL → 0, ai 3 FAIL → 0, gamification 2 FAIL → 0 (its failure was the other signature — a `directory import` missing `/index`). cop was already clean on a fresh build, so the audit's "27 of 46 fail" figure includes at least one package whose local dist was merely stale.
  • 73081e6: Manifest metadata: `homepage`, `bugs`, `engines`. All 46 publishable manifests were missing the three fields a consumer sees before any code (2026-09-01 sale-readiness audit §6). Metadata only — no source, no build, no runtime change. - `homepage` deep-links to that package README on GitHub (`.../tree/main/packages/<dir>#readme`). Without it a registry page links to the monorepo root and the reader has to guess which of 46 folders they want. - `bugs.url` points at the repo issue tracker, so a paying customer has a place to report a defect that is not email. - `engines.node` is `>=22`, matching the root `engines` and `.nvmrc` set the same day. This is a real floor, not decoration: CI on Node 20 could not expand the glob the block packs use for `node --test`, and a package installed on Node 20 fails at a runtime the installer cannot connect back to the version. The forcing function ships with the change: `scripts/assert-manifest-metadata.mjs` (root `pnpm assert:manifest-metadata`, wired into `platform-discipline.yml` beside `assert:license-metadata`) fails when any publishable manifest lacks `description`, `repository.directory` matching its own folder, `homepage`, `bugs`, `engines.node` equal to the repo floor, `license`, `files` or `sideEffects`. It reported 138 violations before this change and 0 after.
  • Updated dependencies [57875ba]
  • Updated dependencies [b01ca1f]
  • Updated dependencies [0836ef5]
  • Updated dependencies [73081e6]
  • Updated dependencies [090e984]
  • Updated dependencies [73081e6] - @wabbit/tome-blocks-core@0.16.0
v0.2.25patch

71d3b09: Purge Vanguard/VNGD client lore and Star Citizen universe references from all non-SC packages (content and labels only — no schema field names, slugs, or enum values changed). - **dispatch**: demo content rewritten as an incident-war-room / ops-bridge scenario (SEV-1 bridge traffic, failover runbooks, recovered security-report transcript) plus neutral original fiction for inherently fictional variants (Relay Station Aurelia personal log, SV Aurelia ship log). Config field-description examples de-lored ("VANGUARD COMMAND", "LOG-2954-0847", "Stanton // Crusader Orbit", "UEES STALWART" → neutral equivalents). - **readout**: all 9 blocks' demo props rewritten as business-operations console data (deployment phases, sprint objectives, service status, perimeter traffic, on-call roster, infrastructure asset cards). Config examples de-lored. - **blocks-signal-theme**: demo props for the 33-block pack rewritten as an original search-and-rescue expedition serial ("Operation Long Wake", SV Aurelia, Meridian Reach) with zero Vanguard/SC references; config examples de-lored. Pack positioning (SC-tier bundling per OQ-4) unchanged. - **blocks-extras / blocks-content-writer**: Custom Hero and Post Hero meta descriptions stop name-dropping VNGD; "Callsign" field descriptions neutralized to "Author name or handle"; provenance comments neutralized. - **blocks-core**: BLOCK_CATALOG mirror entries refreshed for custom-hero and post-hero only; registry comment neutralized. - **blocks-gallery**: SourceBadge label for the `vngd` source value now renders "Legacy" (enum value unchanged). - **accounts / core / lms / ui / org / admin / motion / longform / cop / blocks**: internal provenance comments, shipped CSS comments, and consumer-visible field descriptions that named Vanguard/VNGD as a client replaced with neutral "upstream" phrasing; longform package description de-lored. Historical CHANGELOG entries left untouched.

  • 71d3b09: Purge Vanguard/VNGD client lore and Star Citizen universe references from all non-SC packages (content and labels only — no schema field names, slugs, or enum values changed). - **dispatch**: demo content rewritten as an incident-war-room / ops-bridge scenario (SEV-1 bridge traffic, failover runbooks, recovered security-report transcript) plus neutral original fiction for inherently fictional variants (Relay Station Aurelia personal log, SV Aurelia ship log). Config field-description examples de-lored ("VANGUARD COMMAND", "LOG-2954-0847", "Stanton // Crusader Orbit", "UEES STALWART" → neutral equivalents). - **readout**: all 9 blocks' demo props rewritten as business-operations console data (deployment phases, sprint objectives, service status, perimeter traffic, on-call roster, infrastructure asset cards). Config examples de-lored. - **blocks-signal-theme**: demo props for the 33-block pack rewritten as an original search-and-rescue expedition serial ("Operation Long Wake", SV Aurelia, Meridian Reach) with zero Vanguard/SC references; config examples de-lored. Pack positioning (SC-tier bundling per OQ-4) unchanged. - **blocks-extras / blocks-content-writer**: Custom Hero and Post Hero meta descriptions stop name-dropping VNGD; "Callsign" field descriptions neutralized to "Author name or handle"; provenance comments neutralized. - **blocks-core**: BLOCK_CATALOG mirror entries refreshed for custom-hero and post-hero only; registry comment neutralized. - **blocks-gallery**: SourceBadge label for the `vngd` source value now renders "Legacy" (enum value unchanged). - **accounts / core / lms / ui / org / admin / motion / longform / cop / blocks**: internal provenance comments, shipped CSS comments, and consumer-visible field descriptions that named Vanguard/VNGD as a client replaced with neutral "upstream" phrasing; longform package description de-lored. Historical CHANGELOG entries left untouched.
  • Updated dependencies [71d3b09] - @wabbit/tome-blocks-core@0.15.9
v0.2.24patch

108195b: useTicker: make `enabled` actually able to STOP a running ticker. `enabled` could only ever prevent a ticker from starting. Flipping it false after mount did nothing, silently. useGSAP computes `deferCleanup = dependencies.length && !revertOnUpdate`, and deferred cleanup runs only on unmount. So a dependency change re-invoked the effect body without first tearing down the previous run: the `enabled === false` early return was reached, `ticker.remove(callback)` never was, and the callback registered on the first render kept firing forever — while the call site read as though it had been switched off. Found the hard way. The marquee viewport gate (blocks-extras 0.15.3) passed `enabled: inViewport`, typechecked, built, shipped, and changed nothing measurable: the off-screen marquee kept mutating at ~127/s in production because its ticker was registered once and never removed. `revertOnUpdate` is now set only when a consumer actually passes `enabled`, so anyone relying on the existing defer-to-unmount lifecycle is unaffected. At time of writing the only `useTicker` consumers in the monorepo are Marquee and ImageMarquee, both of which pass `enabled`. Covered by `src/test/useTicker.test.tsx` — registration, teardown on flip, re-registration on flip back, and non-interference for consumers without `enabled`. The teardown test was verified to fail when `revertOnUpdate` is removed, rather than merely to pass as written.

  • 108195b: useTicker: make `enabled` actually able to STOP a running ticker. `enabled` could only ever prevent a ticker from starting. Flipping it false after mount did nothing, silently. useGSAP computes `deferCleanup = dependencies.length && !revertOnUpdate`, and deferred cleanup runs only on unmount. So a dependency change re-invoked the effect body without first tearing down the previous run: the `enabled === false` early return was reached, `ticker.remove(callback)` never was, and the callback registered on the first render kept firing forever — while the call site read as though it had been switched off. Found the hard way. The marquee viewport gate (blocks-extras 0.15.3) passed `enabled: inViewport`, typechecked, built, shipped, and changed nothing measurable: the off-screen marquee kept mutating at ~127/s in production because its ticker was registered once and never removed. `revertOnUpdate` is now set only when a consumer actually passes `enabled`, so anyone relying on the existing defer-to-unmount lifecycle is unaffected. At time of writing the only `useTicker` consumers in the monorepo are Marquee and ImageMarquee, both of which pass `enabled`. Covered by `src/test/useTicker.test.tsx` — registration, teardown on flip, re-registration on flip back, and non-interference for consumers without `enabled`. The teardown test was verified to fail when `revertOnUpdate` is removed, rather than merely to pass as written.
v0.2.23patch

dfccbc1: LenisProvider: skip the per-frame scroll write while Lenis is at rest. `lenis.raf()` was ticked unconditionally from GSAP's ticker. It writes scroll state on every frame it is handed — at rest or not — and each write forces a style recalculation, so an open tab paid a recalc per frame for as long as it stayed open. Measured on wabbit.com: 144 recalcs/s and ~8% of a core on a page nobody was touching, indefinitely. The same page with Lenis absent (`/block-review`, a native-scroll route) idles at 0 recalcs and ~1.6%. This is what triggers Chrome's "this tab is slowing your browser" intervention. The ticker now returns early when `isScrolling` is falsy. That cannot deadlock: every entry point sets the flag synchronously inside the input handler, before the next tick — wheel/touch via `onVirtualScroll` -> `scrollTo` ('smooth'), scrollbar/keyboard via `onNativeScroll` ('native'), and programmatic `scrollTo`. The idle branch still advances `lenis.time`, because Lenis derives `deltaTime = time - (this.time || time)`; leaving the clock stale would hand the first resumed frame a delta of the entire idle span, completing the ease instantly and snapping the scroll instead of easing it. No API change. Scroll feel is unchanged — only the at-rest cost goes away.

  • dfccbc1: LenisProvider: skip the per-frame scroll write while Lenis is at rest. `lenis.raf()` was ticked unconditionally from GSAP's ticker. It writes scroll state on every frame it is handed — at rest or not — and each write forces a style recalculation, so an open tab paid a recalc per frame for as long as it stayed open. Measured on wabbit.com: 144 recalcs/s and ~8% of a core on a page nobody was touching, indefinitely. The same page with Lenis absent (`/block-review`, a native-scroll route) idles at 0 recalcs and ~1.6%. This is what triggers Chrome's "this tab is slowing your browser" intervention. The ticker now returns early when `isScrolling` is falsy. That cannot deadlock: every entry point sets the flag synchronously inside the input handler, before the next tick — wheel/touch via `onVirtualScroll` -> `scrollTo` ('smooth'), scrollbar/keyboard via `onNativeScroll` ('native'), and programmatic `scrollTo`. The idle branch still advances `lenis.time`, because Lenis derives `deltaTime = time - (this.time || time)`; leaving the clock stale would hand the first resumed frame a delta of the entire idle span, completing the ease instantly and snapping the scroll instead of easing it. No API change. Scroll feel is unchanged — only the at-rest cost goes away.
v0.2.22patch

Updated dependencies [510036f] - @wabbit/tome-blocks-core@0.15.0

  • Updated dependencies [510036f] - @wabbit/tome-blocks-core@0.15.0
v0.2.21patch

Updated dependencies - @wabbit/tome-blocks-core@0.14.0

  • Updated dependencies - @wabbit/tome-blocks-core@0.14.0
v0.2.20patch

Updated dependencies [f4d55c9] - @wabbit/tome-blocks-core@0.13.0

  • Updated dependencies [f4d55c9] - @wabbit/tome-blocks-core@0.13.0
v0.2.19patch

Updated dependencies [e11d5a2] - @wabbit/tome-blocks-core@0.11.2

  • Updated dependencies [e11d5a2] - @wabbit/tome-blocks-core@0.11.2
v0.2.18patch

Updated dependencies [26dfa07]

  • Updated dependencies [26dfa07]
  • Updated dependencies [6bc419c]
  • Updated dependencies [36e537a]
  • Updated dependencies [36e537a]
  • Updated dependencies [36e537a]
  • Updated dependencies [36e537a]
  • Updated dependencies [a93f478]
  • Updated dependencies [5f78397]
  • Updated dependencies [5f78397]
  • Updated dependencies [aef2725] - @wabbit/tome-blocks-core@0.11.0 - @wabbit/tome-core@1.4.0
v0.2.17patch

Updated dependencies [66f394b] - @wabbit/tome-core@1.3.4 - @wabbit/tome-blocks-core@0.10.0

  • Updated dependencies [66f394b] - @wabbit/tome-core@1.3.4 - @wabbit/tome-blocks-core@0.10.0
v0.2.16patch

Updated dependencies - @wabbit/tome-core@1.3.3 - @wabbit/tome-blocks-core@0.10.0

  • Updated dependencies - @wabbit/tome-core@1.3.3 - @wabbit/tome-blocks-core@0.10.0
v0.2.15patch

Updated dependencies - @wabbit/tome-blocks-core@0.10.0

  • Updated dependencies - @wabbit/tome-blocks-core@0.10.0
v0.2.14patch

bed3f90: Docs-manifest emitter pipeline (W3 ship-readiness). `@wabbit/tome-blocks-core` now ships a standalone Node ESM CLI at `scripts/emit-docs-manifests.mjs` that emits per-package documentation manifests (index.json, packages/<slug>.json, changelog.json) by reading what packages already carry — READMEs, the payload-free `<pkg>/meta` block-usage barrels, package.json exports maps, and CHANGELOG.md. It is the docs-pipeline sibling of the gallery source extractor and is consumed by host sites at prebuild: `node node_modules/@wabbit/tome-blocks-core/scripts/emit-docs-manifests.mjs --output-dir <dir> --scope <scope.json>`. To let the emitter import block metadata uniformly without dragging Payload config into a build script, the `./meta` payload-free subpath (BlockMetaEntry[]) is extended to the remaining offered blocks packs — agency-essentials, catalog-pack, lms-pack, org-pack, and signal-theme — mirroring the existing editorial-pack / marketing-starter / content-writer / extras barrels. Each block's `BlockMeta` was relocated verbatim into a payload-free sibling meta module and re-imported by its block config; no meta values changed. Every supported-core package additionally adds `CHANGELOG.md` to its published `files` array so the next publish cascade ships changelogs the emitter can read from installed tarballs at prebuild.

  • bed3f90: Docs-manifest emitter pipeline (W3 ship-readiness). `@wabbit/tome-blocks-core` now ships a standalone Node ESM CLI at `scripts/emit-docs-manifests.mjs` that emits per-package documentation manifests (index.json, packages/<slug>.json, changelog.json) by reading what packages already carry — READMEs, the payload-free `<pkg>/meta` block-usage barrels, package.json exports maps, and CHANGELOG.md. It is the docs-pipeline sibling of the gallery source extractor and is consumed by host sites at prebuild: `node node_modules/@wabbit/tome-blocks-core/scripts/emit-docs-manifests.mjs --output-dir <dir> --scope <scope.json>`. To let the emitter import block metadata uniformly without dragging Payload config into a build script, the `./meta` payload-free subpath (BlockMetaEntry[]) is extended to the remaining offered blocks packs — agency-essentials, catalog-pack, lms-pack, org-pack, and signal-theme — mirroring the existing editorial-pack / marketing-starter / content-writer / extras barrels. Each block's `BlockMeta` was relocated verbatim into a payload-free sibling meta module and re-imported by its block config; no meta values changed. Every supported-core package additionally adds `CHANGELOG.md` to its published `files` array so the next publish cascade ships changelogs the emitter can read from installed tarballs at prebuild.
  • Updated dependencies [bed3f90]
  • Updated dependencies [850d51c] - @wabbit/tome-blocks-core@0.9.4 - @wabbit/tome-core@1.2.1
v0.2.13patch

Updated dependencies - @wabbit/tome-blocks-core@0.9.2

  • Updated dependencies - @wabbit/tome-blocks-core@0.9.2
v0.2.12patch

Updated dependencies [c7d0afc] - @wabbit/tome-blocks-core@0.9.0

  • Updated dependencies [c7d0afc] - @wabbit/tome-blocks-core@0.9.0
v0.2.11patch

Updated dependencies [249b670] - @wabbit/tome-blocks-core@0.8.0

  • Updated dependencies [249b670] - @wabbit/tome-blocks-core@0.8.0
v0.2.10patch

Updated dependencies [66c611c] - @wabbit/tome-blocks-core@0.7.0

  • Updated dependencies [66c611c] - @wabbit/tome-blocks-core@0.7.0
v0.2.9patch

Updated dependencies [a9801fe]

  • Updated dependencies [a9801fe]
  • Updated dependencies [baf401e]
  • Updated dependencies [4b2f368] - @wabbit/tome-core@1.1.0 - @wabbit/tome-blocks-core@0.6.2
v0.2.8patch

Updated dependencies [8947ff1] - @wabbit/tome-core@1.0.12 - @wabbit/tome-blocks-core@0.5.9

  • Updated dependencies [8947ff1] - @wabbit/tome-core@1.0.12 - @wabbit/tome-blocks-core@0.5.9
v0.2.7patch

Updated dependencies [36dc023]

  • Updated dependencies [36dc023]
  • Updated dependencies [2612799] - @wabbit/tome-core@1.0.11 - @wabbit/tome-blocks-core@0.5.7
v0.2.4patch

**Re-publish: rewrite `workspace:*` to actual semver in dependencies.** Earlier 0.4.0/0.4.1 publishes used `npm publish` directly, which doesn't rewrite `workspace:*` deps. Verdaccio captured the literal `"workspace:*"` strings in the published `package.json` `dependencies` fields, so npm consumers (e.g. wabbit-site-core) failed to install with `EUNSUPPORTEDPROTOCOL workspace:*`. This changeset triggers a coordinated patch bump across the linked blocks-_ group (already 0.4.1 → 0.4.2) plus motion, lms-pack, catalog-pack, and the previously-untouched blocks-core. Re-publish flow uses `pnpm publish` which rewrites `workspace:_` to the actual version of the workspace dep at publish time. No source changes — purely a publish-pipeline correction.

  • **Re-publish: rewrite `workspace:*` to actual semver in dependencies.** Earlier 0.4.0/0.4.1 publishes used `npm publish` directly, which doesn't rewrite `workspace:*` deps. Verdaccio captured the literal `"workspace:*"` strings in the published `package.json` `dependencies` fields, so npm consumers (e.g. wabbit-site-core) failed to install with `EUNSUPPORTEDPROTOCOL workspace:*`. This changeset triggers a coordinated patch bump across the linked blocks-_ group (already 0.4.1 → 0.4.2) plus motion, lms-pack, catalog-pack, and the previously-untouched blocks-core. Re-publish flow uses `pnpm publish` which rewrites `workspace:_` to the actual version of the workspace dep at publish time. No source changes — purely a publish-pipeline correction.
  • Updated dependencies - @wabbit/tome-blocks-core@0.4.2
v0.2.3patch

Updated dependencies [b76f684] - @wabbit/tome-blocks-core@0.4.0

  • Updated dependencies [b76f684] - @wabbit/tome-blocks-core@0.4.0
v0.2.0minor

Initial publish to npm.wabbit.com — first registry release for the 5 non-block-pack packages. Companion to the existing sprint-3-blocks-split changeset (which handles the 11 linked block packages). Together these two changesets bring all 8 publish-pipeline-Phase-2-remediated packages to a coherent first-release cohort: - `@wabbit/tome-core` 0.1.0 → 0.2.0 - `@wabbit/tome-ui` 0.2.0 → 0.3.0 - `@wabbit/tome-motion` 0.1.0 → 0.2.0 - `@wabbit/tome-lms` 0.1.0 → 0.2.0 - `@wabbit/tome-lms-ui` 0.1.0 → 0.2.0 - `@wabbit/tome-blocks-core` 0.1.0 → 0.2.0 (via sprint-3) - `@wabbit/tome-blocks-extras` 0.1.0 → 0.2.0 (via sprint-3) - `@wabbit/tome-blocks-marketing-starter` 0.1.0 → 0.2.0 (via sprint-3) All 8 packages ship with metadata, dist/ output, exports map verified by P6 scratch-consumer smoke (35/35 resolutions), 'use client' + 'server-only' directives preserved through tsup bundle:false. Verdaccio v0 live since 2026-04-18 at npm.wabbit.com.

  • Initial publish to npm.wabbit.com — first registry release for the 5 non-block-pack packages. Companion to the existing sprint-3-blocks-split changeset (which handles the 11 linked block packages). Together these two changesets bring all 8 publish-pipeline-Phase-2-remediated packages to a coherent first-release cohort: - `@wabbit/tome-core` 0.1.0 → 0.2.0 - `@wabbit/tome-ui` 0.2.0 → 0.3.0 - `@wabbit/tome-motion` 0.1.0 → 0.2.0 - `@wabbit/tome-lms` 0.1.0 → 0.2.0 - `@wabbit/tome-lms-ui` 0.1.0 → 0.2.0 - `@wabbit/tome-blocks-core` 0.1.0 → 0.2.0 (via sprint-3) - `@wabbit/tome-blocks-extras` 0.1.0 → 0.2.0 (via sprint-3) - `@wabbit/tome-blocks-marketing-starter` 0.1.0 → 0.2.0 (via sprint-3) All 8 packages ship with metadata, dist/ output, exports map verified by P6 scratch-consumer smoke (35/35 resolutions), 'use client' + 'server-only' directives preserved through tsup bundle:false. Verdaccio v0 live since 2026-04-18 at npm.wabbit.com.
  • Updated dependencies
  • Updated dependencies [f2202cd] - @wabbit/tome-core@0.2.0 - @wabbit/tome-blocks-core@0.3.0