MCPcopy Index your code
hub / github.com/0xGF/boneyard

github.com/0xGF/boneyard @v1.8.2 sqlite

repository ↗ · DeepWiki ↗ · release v1.8.2 ↗
369 symbols 833 edges 104 files 27 documented · 7%
README

Boneyard

boneyard

Pixel-perfect skeleton loading screens, extracted from your real UI. No manual measurement, no hand-tuned placeholders.

Works with React, Preact, Vue, Svelte 5, Angular, and React Native.

Quick start

npm install boneyard-js

React

import { Skeleton } from 'boneyard-js/react'

function BlogPage() {
  const { data, isLoading } = useFetch('/api/post')
  return (
    <Skeleton name="blog-card" loading={isLoading}>
      {data && <BlogCard data={data} />}
    </Skeleton>
  )
}

With <Suspense> / useSuspenseQuery

Drop in <BoneSuspense> anywhere you'd use a <Suspense> boundary. The skeleton renders as the fallback at runtime, and the CLI captures bones from the resolved children at build time.

import { BoneSuspense } from 'boneyard-js/react'

function Page() {
  return (
    <BoneSuspense name="user-card">
      <UserCard />  {/* uses useSuspenseQuery */}
    </BoneSuspense>
  )
}

No initialData or placeholderData required — the build-time --wait window lets the query resolve naturally. Pass a fixture if the query can't finish in time.

Vue

<script setup>
import Skeleton from 'boneyard-js/vue'
import './bones/registry'
const loading = ref(true)
</script>

<template>
  <Skeleton name="card" :loading="loading">
    <Card />
  </Skeleton>
</template>

Svelte 5

<script>
  import Skeleton from 'boneyard-js/svelte'
  import '$lib/bones/registry'
  let loading = true
</script>

<Skeleton name="card" {loading}>
  <Card />
</Skeleton>

Preact

import { Skeleton } from 'boneyard-js/preact'

function BlogPage() {
  const { data, isLoading } = useFetch('/api/post')
  return (
    <Skeleton name="blog-card" loading={isLoading}>
      {data && <BlogCard data={data} />}
    </Skeleton>
  )
}

Angular

import { SkeletonComponent } from 'boneyard-js/angular'

@Component({
  imports: [SkeletonComponent],
  template: `
    <boneyard-skeleton name="card" [loading]="isLoading">
      <app-card />
    </boneyard-skeleton>
  `
})

React Native

import { Skeleton } from 'boneyard-js/native'

<Skeleton name="profile-card" loading={isLoading}>
  <ProfileCard />
</Skeleton>
npx boneyard-js build --native --out ./bones
# Open your app on device — bones capture automatically

Dynamic Type: Generate bones at default font scale. Boneyard automatically scales bone positions at runtime to match the user's text size setting.

Generate bones

# CLI — works with any framework
npx boneyard-js build

# Watch mode — re-captures on HMR changes
npx boneyard-js build --watch

# React Native — scans from device
npx boneyard-js build --native

Then import the registry once in your app entry:

import './bones/registry'

Vite plugin

For Vite-based projects (React, Preact, Vue, Svelte), use the plugin instead of the CLI — no second terminal needed:

// vite.config.ts
import { boneyardPlugin } from 'boneyard-js/vite'

export default defineConfig({
  plugins: [boneyardPlugin()]
})

Bones are captured automatically when the dev server starts and re-captured on every HMR update.

How it works

Web: The CLI (or Vite plugin) opens a headless browser, visits your app, finds every <Skeleton name="...">, and snapshots their layout at multiple breakpoints.

React Native: The <Skeleton> component auto-scans in dev mode when the CLI is running. It walks the fiber tree, measures views via UIManager, and sends bone data to the CLI. Zero overhead in production.

All frameworks output the same .bones.json format — cross-platform compatible.

CLI flags

Flag Default Description
[url] auto-detected URL to visit
--breakpoints 375,768,1280 Viewport widths, comma-separated
--wait 800 ms to wait after page load
--out ./src/bones Output directory
--force Skip incremental cache
--watch Re-capture on HMR changes
--native React Native device scanning
--no-scan Skip filesystem route scanning
--cdp Connect to existing Chrome via debug port
--env-file Load env vars from file

Props

Prop Type Default Description
loading boolean Show skeleton or real content
name string Unique name (generates name.bones.json)
color string rgba(0,0,0,0.08) Bone fill color
darkColor string rgba(255,255,255,0.06) Bone color in dark mode
animate 'pulse' | 'shimmer' | 'solid' 'pulse' Animation style
stagger number | boolean false Stagger delay between bones in ms (true = 80ms)
transition number | boolean false Fade out duration when loading ends (true = 300ms)
boneClass string CSS class applied to each bone element
fixture ReactNode / Snippet / Slot Mock content for CLI capture (dev only)
initialBones ResponsiveBones Pass bones directly (overrides registry)
fallback ReactNode / Snippet / Slot Shown when loading but no bones available

Config file

{
  "breakpoints": [375, 768, 1280],
  "out": "./src/bones",
  "wait": 800,
  "color": "#e5e5e5",
  "animate": "pulse"
}

Save as boneyard.config.json. Per-component props override config values.

Package exports

Import Use
boneyard-js snapshotBones, renderBones, computeLayout
boneyard-js/react React <Skeleton>
boneyard-js/preact Preact <Skeleton> (no compat needed)
boneyard-js/vue Vue <Skeleton>
boneyard-js/svelte Svelte <Skeleton>
boneyard-js/angular Angular <boneyard-skeleton>
boneyard-js/native React Native <Skeleton>
boneyard-js/vite Vite plugin boneyardPlugin()

Links

Star History

Star History Chart

License

MIT

Extension points exported contracts — how you extend this code

Sides (Interface)
Resolved padding/margin — always four sides
packages/boneyard/src/layout.ts
TocItem (Interface)
(no doc)
apps/docs/src/components/toc.tsx
BoneyardConfig (Interface)
(no doc)
packages/boneyard/src/angular.ts
TocProps (Interface)
(no doc)
apps/docs/src/components/toc.tsx
BoneyardConfig (Interface)
(no doc)
packages/boneyard/src/react.tsx
ShowcaseStep (Interface)
(no doc)
apps/docs/src/components/skeleton-demo.tsx
SkeletonProps (Interface)
(no doc)
packages/boneyard/src/react.tsx
CellPosition (Interface)
(no doc)
apps/docs/src/components/ui/matrix.tsx

Core symbols most depended-on inside this repo

computeLayout
called by 42
packages/boneyard/src/layout.ts
cn
called by 32
apps/docs/src/lib/utils.ts
adjustColor
called by 24
packages/boneyard/src/shared.ts
normalizeBone
called by 24
packages/boneyard/src/types.ts
resolveResponsive
called by 16
packages/boneyard/src/shared.ts
fingerprintValue
called by 16
packages/boneyard/src/layout.ts
log
called by 13
packages/boneyard/src/vite.ts
renderBones
called by 12
packages/boneyard/src/runtime.ts

Shape

Function 269
Interface 62
Method 28
Class 10

Languages

TypeScript100%

Modules by API surface

packages/boneyard/src/layout.ts25 symbols
packages/boneyard/src/angular.ts24 symbols
packages/boneyard/src/native.tsx23 symbols
packages/boneyard/bin/cli.js23 symbols
packages/boneyard/src/react-native.tsx22 symbols
apps/docs/src/components/skeleton-demo.tsx19 symbols
packages/boneyard/src/native-scan.tsx18 symbols
packages/boneyard/src/vite.ts13 symbols
packages/boneyard/src/extract.ts13 symbols
apps/docs/src/components/ui/color-picker.tsx10 symbols
packages/boneyard/src/test-vue-preload.ts7 symbols
packages/boneyard/src/react.tsx7 symbols

Dependencies from manifests, versioned

@angular/common21.0.0 · 1×
@angular/compiler21.0.0 · 1×
@angular/compiler-cli21.0.0 · 1×
@angular/core21.0.0 · 1×
@codesandbox/sandpack-react2.20.0 · 1×
@types/node22.19.15 · 1×
@types/react19.0.0 · 1×
@types/react-dom19.0.0 · 1×
@types/react-native0.73.0 · 1×
@vue/compiler-sfc3.5.32 · 1×
@vue/server-renderer3.5.32 · 1×

For agents

$ claude mcp add boneyard \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact