boneyard README

The project's README from github.com/0xGF/boneyard. As one markdown file: README.md.

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()

Star History

Star History Chart

License

MIT

boneyard (0xGF/boneyard)

Searching Database…

这是什么?Boneyard 直接根据你真实的界面生成像素级精确的骨架加载屏,不需要你手动绘制占位图形。
它是库,还是也带一个 CLI 工具?它是一个 JavaScript 库(提供各框架的专用入口),同时还附带一个 CLI / Vite 插件,通过无头浏览器渲染你的应用来采集布局数据。
我怎样在自己的应用里跑起来?把组件放到你原本会渲染加载边界的位置,运行 CLI(基于 Vite 的项目则运行 Vite 插件)来采集骨架数据,然后在应用入口处导入一次生成的注册表即可。
它支持哪些框架?React、Preact、Vue、Svelte 5、Angular 和 React Native,每个框架都有专门的包导出,例如 boneyard-js/react 或 boneyard-js/vue。
React Native 的骨架采集方式和网页有什么不同?是的。在网页端,CLI 通过无头浏览器捕获布局;而在 React Native 上,组件会在开发模式下遍历 Fiber 树,并用 UIManager 测量视图来自动扫描。两种方式在生产环境中都没有额外开销。
谁会用到这个工具?使用 React、Vue、Svelte、Angular 或 React Native 构建应用、并希望获得准确的骨架加载屏而无需手动测量布局的前端开发者。
它能处理移动端的文字大小变化吗?可以。对于 React Native,它会以默认字体比例生成骨架块,并在运行时自动缩放骨架块的位置,以匹配用户设置的文字大小(Dynamic Type)。
骨架块有哪些动画样式?骨架块通过 animate 属性支持三种动画样式:pulse(默认)、shimmer 和 solid,还可以选择设置错峰延迟和淡出过渡。
如果真实数据在采集时无法及时加载,我能提供模拟内容吗?可以。传入带有模拟内容的 fixture 属性,这样如果真实数据加载得不够快,CLI 在构建时采集骨架仍有内容可以测量。
开发时它会自动重新采集骨架吗?使用 Vite 插件时,开发服务器启动时会采集骨架,并且在每次 HMR 更新时自动重新采集;CLI 也支持 --watch 标志,作用相同。
Creator
0xGF
Size
1.2 MB
Stars
7.5K
Age
6mo
Commits · 90 Days