Changelog
What's new in boneyard.
HTTPS dev servers
The CLI and Vite plugin now work against dev servers running over TLS. Auto-detect tries http:// first (still the common case) and falls back to https:// on every port if nothing responds. The Vite plugin honours server.https from Vite config and constructs the capture URL as https://localhost:<port> when set. Playwright contexts now launch with ignoreHTTPSErrors: true so self-signed certs (mkcert, next --experimental-https, vite preview, Quasar https mode) don't fail at navigation. Fixes #80.
Previously-captured bones no longer drop out of the registry
The registry was regenerated from the current run's captures alone, so any skeleton whose route wasn't visited this run silently disappeared from the generated imports. Typical repro: capture /login unauthenticated, then add auth.cookies and re-run — /login now redirects to /dashboard for the authenticated headless browser, and the valid login.bones.json on disk gets orphaned from the registry. v1.8.0 single-page mode (#78) made this significantly worse — running build /dashboard would prune the registry down to that one skeleton. Fixed in both the CLI and the Vite plugin: previously-captured bones on disk are now seeded into the in-memory map at startup and preserved across runs. Fresh captures overwrite stale entries of the same name; --force still rebuilds from scratch. Watch-mode recapture no longer wipes the collected map either. Fixes #81.
Vite plugin no longer fails silently
Three places in the Vite plugin used to swallow errors silently — page.goto failures, empty captures, and most exceptions in the outer catch — leaving users staring at [boneyard] watching for skeleton changes... with no way to diagnose. The plugin now prints a per-route rundown when capture returns nothing (final path so redirects are visible, page title, data-boneyard marker count, any page.goto error). Redirects log at the first breakpoint as they happen. The outer catch logs all real failures; only the benign "Target closed" (dev-server restart) stays quiet. New debug: true plugin option turns on verbose per-step logging. Fixes #75 via #77.
Vite plugin reads boneyard.config.json (incl. auth)
routes, breakpoints, wait, out, and auth (cookies + headers, sanitized against the same allowlist/blocklist the CLI uses) are now honoured by the plugin as fallbacks. Plugin options still win when both are set. Authed pages behind cookie sessions can be captured in watch mode without a second terminal.
Vite plugin cdp reuses your Chrome session
Same fix as #73 in the CLI, ported to the plugin. browser.contexts()[0] ?? browser.newContext() — inherits cookies/auth from the Chrome window you point it at instead of spawning a fresh empty context.
npx boneyard-js build <url>/path now actually captures only that page
The CLI documents npx boneyard-js build http://localhost:3000/dashboard as the way to capture a "Specific page", but the implementation treated every URL as a starting point — link-following from the page, walking app/**/page.tsx for additional routes, adding anything in config.routes. So passing /dashboard/analytics still scanned the whole project. Now: when any URL has a non-root path, the CLI prints Specific page: 1 URL(s) — no link/filesystem crawl and visits exactly the URL(s) you passed. Bare-origin URLs (http://localhost:3000) and the auto-detect path keep crawling everything. Fixes #78.
Type-safe JSON bone imports
Consumer projects with resolveJsonModule: true (the default in most Vite / Next.js setups) were hitting TS2322 on every import _x from './x.bones.json' inside the auto-generated registry.ts. TypeScript infers JSON arrays as number[], not the tuple CompactBone describes. Widened AnyBone to accept the JSON-inferred shape and loosened SkeletonResult.bones from Bone[] to AnyBone[]. Runtime is unchanged — normalizeBone still validates tuple length. Fixes #72 via #74.
--cdp now actually reuses your Chrome session
The CLI help promised --cdp "reuses cookies, auth, state", but after chromium.connectOverCDP() the CLI called browser.newContext(), which spawned a fresh context that didn't inherit any session state. Every authed route 302'd to sign-in and skeleton capture returned No skeletons found. Now reuses the existing context when Chrome has one, falling back to newContext() only when there are no tabs. Authed pages behind Clerk / NextAuth / cookie sessions capture correctly again. Fixed via #73.
Test suite back to green
Two renderBones tests and their Vue equivalents were asserting that container bones (c: true) rendered with a lightened color, but the runtime has intentionally skipped them since v1.6 to avoid opacity overlap with child bones. Rewrote those tests to positively assert the skip, and removed the stray trueflag from compact-tuple fixtures that weren't testing container behavior. Suite is now 123 pass / 0 fail.
Add --version flag to the CLI
npx boneyard-js --version (or -v) now prints boneyard-js 1.7.8. Reads the version from the shipped package.json via import.meta.url so it works regardless of install location. Fixes #64.
Fix filesystem route discovery on Windows
path.dirname and path.join return backslash-separated paths on Windows, so the group-stripping regex in discoverRoutes() never matched. A reporter's SvelteKit route (protected)/(app)/(admin_devs)/test_page was being crawled with the groups intact, 404'ing their dev server. Added a toUrlPath() helper that normalizes separators before any regex or string op; applied to all 5 framework branches. Fixes #65.
Support explicit routes in boneyard.config.json
Some pages can't be reached by link-crawling or filesystem walking — Angular loadChildren lazy modules, auth-gated pages, custom routers. Added a routes field to the config that accepts plain paths ("/dashboard") or same-origin full URLs. They're merged in after filesystem discovery and crawled normally. Also updated the "nothing captured" error to point users at this option. Addresses #66.
Fix Angular skeletons capturing 0 bones
The Angular template had two unselected <ng-content> slots (one in the build-mode branch, one in the runtime branch). Angular deduplicates catch-all slots and only projects content into the last declared one — so during CLI capture the build branch rendered as an empty wrapper, producing a 0 × 0 container and no bones. Collapsed the split into a single template with one catch-all slot, controlling build vs. runtime with *ngIf around the skeleton overlay only. Fixes #62.
Fix skeleton bones not rendering on first frame in Next.js App Router
The mounted flag used useEffect which fires after paint, causing bones to not appear until frame 3. Switched to useLayoutEffect so bones render on the first visible client frame. Fixes blank skeleton flash for short loading states. Affects React and Preact.
Fix Angular component import error
The Angular package was shipping raw TypeScript instead of pre-compiled JavaScript, causing "Standard Angular field decorators are not supported in JIT mode" errors in Angular 17+. The component is now compiled with ngc using Ivy partial compilation, and the CLI correctly detects and captures skeletons in Angular projects.
Clean up dark mode detection across all frameworks
Removed mq.matches from the dark mode decision — only the .dark class determines dark mode. The matchMedia listener is kept as a safety net to trigger rechecks when the OS theme changes, catching apps that toggle .dark on non-<html> ancestors. Affects React, Preact, Vue, Svelte, Angular.
Fix stale defaults in JSDoc across all frameworks
Updated color defaults from rgba() to opaque hex values in JSDoc comments across React, Preact, React Native, and native. All color props accept any CSS color value.
Tune shimmer highlights
Adjusted shimmer highlight defaults to #f7f7f7 (light) / #2c2c2c (dark) for visible but not overpowering sweep.
Configurable shimmer via boneyard.config.json
New runtime config keys: shimmerColor, darkShimmerColor, speed, shimmerAngle. Values are baked into the generated registry. Per-component props still override.
Fix container bone opacity overlap
Container bones were rendering as semi-transparent with child bones stacked on top, creating darker overlap regions. Container bones are now skipped during rendering across all frameworks.
Fix dark mode detection
Reverted to .dark class-only detection. The prefers-color-scheme media query was incorrectly overriding app-level theme control. Skeleton now only responds to the .dark class on ancestors.
Opaque default bone colors
Switched from semi-transparent rgba() to opaque #f0f0f0 / #222222. Eliminates transparency stacking artifacts. Centralized all animation constants in shared.ts.
Fix --cookie CLI flag with config file
Fixed a ReferenceError when using --cookie — the config object was accessed before initialization. CLI cookies are now preserved when a config file is also loaded. (#57)
Consistent docs layout
Fixed content shifting between pages — standardized spacing, removed unnecessary flex wrapper, and added a page footer.
Skip redirected routes
The crawler now detects server-side redirects and skips them automatically, avoiding duplicate skeleton captures for aliased routes.
--cookie CLI flag
Pass cookies directly from the command line for quick auth-protected builds without editing the config file.
Per-skeleton crawler config
Override crawler settings (viewport, wait conditions, selectors) per skeleton in boneyard.config.json for guided crawling of complex pages.
Stagger & transition in global config
configureBoneyard() now accepts stagger and transition as global defaults. Added missing type definitions for Vue, Angular, and Svelte adapters.
Vite plugin routes option
The Vite plugin now accepts a routes option for multi-page skeleton capture. Framework-specific import paths are now used in the generated registry.
Docs improvements
Clarified that data-no-skeleton only affects capture, not runtime rendering.
Vite plugin
New boneyard-js/vite plugin for automatic bone capture during development. Includes browser cleanup, debounced rebuilds, and path sanitization.
Stagger & transition animations
New stagger and transition props across all five framework adapters. Bones can now fade in sequentially and transition smoothly when loading completes.
CLI docs page
Dedicated CLI page with full flag reference, examples, and Vite plugin setup instructions.
Fixes
- Table skeletons now use td/th as leaf tags instead of tr
- Fixed
getFiber()returning null on React Native 0.76+ dev builds - Improved validation and error handling across the CLI
Nuxt & Remix route scanning
Filesystem route discovery now supports Nuxt (pages/**/*.vue) and Remix / React Router v7 (app/routes/ flat routes), in addition to Next.js and SvelteKit.
Angular adapter
New boneyard-js/angular export with a standalone Angular 14+ component. OnPush change detection, dark mode auto-detection, content projection with [fixture] and [fallback] selectors.
Watch mode
--watch flag keeps the browser open and re-captures skeletons when your app changes. Listens for HMR events from Vite, Next.js, and Webpack.
Filesystem route scanning
The CLI now scans route folders (Next.js App/Pages Router, SvelteKit, Vite/Remix) to discover pages not linked in navigation. Use --no-scan to opt out.
Svelte 5 attachments
Refactored Svelte adapter to use @attach directives instead of onMount. Requires Svelte 5.29+. Added shimmer/solid animation modes and configureBoneyard().
Bun env file support
--env-fileflag loads environment variables from a file, useful for Bun runtime where env vars aren't inherited by subprocesses.
Framework auto-detection
The CLI reads your package.json to detect Vue, Svelte, Angular, or React and generates the correct registry imports automatically.
Vue 3 adapter
New boneyard-js/vue export with a native Vue 3 Skeleton component. Pulse, shimmer, and solid animations with scoped keyframes, dark mode auto-detection, and #fixture / #fallback slots.
Native device scanning
npx boneyard-js build --native captures bones directly from a running React Native app on device or simulator. Walks the React fiber tree, measures views via UIManager, and sends bone data to the CLI automatically.
Security hardening
CLI scan server now validates skeleton names, sanitizes output filenames against path traversal, and enforces a 5MB request body limit. Vue adapter sanitizes CSS radius values to prevent injection.
Docs restructure
Framework-organized sidebar with dedicated pages for React, React Native, Svelte, and Vue. New table of contents component and Svelte docs page.
Svelte 5 adapter
New boneyard-js/svelte export with a native Svelte 5 Skeleton component. Shared registry and build-mode logic extracted into a framework-neutral module.
React Native support
New boneyard-js/native export for iOS and Android. Uses RN Animated API for pulse animation, auto-detects dark mode via useColorScheme, and includes Metro bundler compatibility.
Compiled layout engine
New compileDescriptor() API for up to 105x faster relayouts. Automatic mutation detection rebuilds compiled state when descriptors change in place. See the Performance page.
Auth for protected routes
The CLI now supports auth.cookies and auth.headers in boneyard.config.json for generating skeletons on authenticated pages. Supports env[VAR] syntax for secrets.
Compact bone format
Bones are now stored as arrays [x, y, w, h, r] instead of objects — smaller JSON files, faster parsing. The runtime supports both formats for backwards compatibility.
Incremental builds
The CLI hashes each skeleton's DOM content and skips unchanged components on subsequent builds. Use --force to bypass the cache.
boneyard.config.json
One config file for both CLI and runtime defaults — breakpoints, output dir, color, animation style. Runtime defaults are auto-included in the generated registry.
Animation styles
The animate prop now accepts "pulse", "shimmer", or "solid" in addition to boolean values.
Responsive docs
New Responsive page showing how breakpoint detection and auto-selection works.
SSR rewrite
The SSR page now shows side-by-side examples with fixture data and explains the build-time snapshot flow.
Fixes
renderBonesnow uses%for x/w values (was px)- NaN validation in hex color parsing
- Fixed import paths in docs (
boneyard-js/react)
Initial public release. CLI-based skeleton extraction with Playwright, responsive breakpoints, dark mode detection, fixture support, and React component.