bklit-playground

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bklit Playground Skill

Bklit Playground Skill

Monorepo contributors only. Use this skill automatically whenever the user is building a new chart, editing an existing chart, tuning chart props, or debugging animation — before shipping via bklit-ship.
仅面向Monorepo贡献者使用。 当用户构建新图表、编辑现有图表、调整图表属性或调试动画时,自动使用此技能——在通过bklit-ship发布之前使用。

When to use (auto-trigger)

使用时机(自动触发)

Apply this skill when the user:
  • Asks to build, prototype, or edit a chart
  • Adds or changes chart props, settings, data, styling, or animation
  • Mentions the playground, local chart preview, or
    /playground
  • Is iterating on a chart before it lives in
    packages/ui
Do not wait for the user to name this skill — scaffold or update the playground as part of the chart work.
当用户出现以下操作时应用此技能:
  • 请求构建、制作原型或编辑图表
  • 添加或修改图表属性、设置、数据、样式或动画
  • 提及沙箱(playground)、本地图表预览或
    /playground
    路径
  • 在将图表移入
    packages/ui
    之前进行迭代开发
无需等待用户指定此技能——在处理图表相关工作时直接搭建或更新沙箱。

How agents discover this (route is gitignored)

代理如何发现此技能(路径已被git忽略)

The playground page is not in git — only the skill, template, and shared components are. Agents find the workflow via:
  1. AGENTS.md
    (repo root) — chart work → read this skill, copy template →
    page.tsx
  2. apps/web/app/playground/README.md
    — same copy command and pointers (committed)
  3. This skill
    .agents/skills/bklit-playground/SKILL.md
    (committed; auto-trigger description)
  4. Template
    .agents/skills/bklit-playground/templates/page.tsx
    (committed source of truth)
  5. Shared UI
    apps/web/components/editor/
    ,
    apps/web/components/playground/
    (committed)
If
apps/web/app/playground/page.tsx
is missing, create it by copying the template. Do not invent a new layout.
沙箱页面不在git仓库中——仅技能、模板和共享组件会被提交。代理可通过以下途径找到该工作流:
  1. AGENTS.md
    (仓库根目录)——图表开发工作 → 阅读此技能,复制模板 →
    page.tsx
  2. apps/web/app/playground/README.md
    ——包含相同的复制命令和指引(已提交)
  3. 此技能文档——
    .agents/skills/bklit-playground/SKILL.md
    (已提交;自动触发说明)
  4. 模板文件——
    .agents/skills/bklit-playground/templates/page.tsx
    (已提交的基准文件)
  5. 共享UI组件——
    apps/web/components/editor/
    apps/web/components/playground/
    (已提交)
如果
apps/web/app/playground/page.tsx
不存在,通过复制模板创建。请勿自行设计新布局。

Default playground layout

默认沙箱布局

The playground is a full-height editor shell (not a docs page with a header):
RegionPurpose
Left paneAnimation / motion controls only
CenterDot-grid canvas, rulers, resizable chart frame, bottom menu bar
Right paneChart props, data, styling, and settings controls
Mobile: side panes collapse to sheet triggers (top-left = motion, top-right = controls). Fixed viewport, 4:3 chart frame, pinch-to-zoom enabled.
沙箱是一个全屏高度的编辑器外壳(而非带页眉的文档页面):
区域用途
左侧面板仅用于动画/动效控制
中间区域点阵网格画布、标尺、可调整大小的图表框架、底部菜单栏
右侧面板图表属性、数据、样式和设置控制
移动端: 侧边面板会折叠为触发按钮(左上角=动效,右上角=控制)。固定视口,图表框架为4:3比例,支持捏合缩放。

Default empty state

默认空状态

When first scaffolded, the playground has:
  • Empty left pane — placeholder until the chart uses motion
  • Empty right pane — placeholder until controls are wired
  • Empty chart frame
    PlaygroundEmptyState
    alert:
Use the playground skill to start building a new chart, or ask it to edit an existing chart. Your agent will automatically add the necessary controls.
Copy the template verbatim for new playgrounds:
.agents/skills/bklit-playground/templates/page.tsx
  → apps/web/app/playground/page.tsx
Visit
http://localhost:3000/playground
while
pnpm dev
is running.
首次搭建时,沙箱包含:
  • 空左侧面板——占位符,直到图表使用动效
  • 空右侧面板——占位符,直到控件被关联
  • 空图表框架——
    PlaygroundEmptyState
    提示:
使用沙箱技能开始构建新图表,或请求编辑现有图表。你的代理会自动添加必要的控件。
新建沙箱时请完全复制模板内容:
.agents/skills/bklit-playground/templates/page.tsx
  → apps/web/app/playground/page.tsx
pnpm dev
运行时访问
http://localhost:3000/playground

Control wiring rules

控件关联规则

As you add chart functionality, automatically wire controls — do not leave panes empty once the chart uses those settings.
添加图表功能时,自动关联控件——一旦图表使用了相关设置,请勿让面板保持为空。

Right pane — chart props & settings

右侧面板——图表属性与设置

Pass
controlGroups
to
EditorShell
. Each group maps
StudioUrlState
keys to sidebar controls.
  1. Prefer existing groups from
    apps/web/lib/studio/registry-control-groups.ts
    :
    • lineChartControlGroups
      ,
      barChartControlGroups
      ,
      gaugeControlGroups
      , etc.
  2. Add new controls when introducing props:
    • Extend the chart's group in
      registry-control-groups.ts
      , or
    • Define inline groups with helpers from
      apps/web/lib/studio/sidebar-control-templates.ts
      (
      controlGroup
      ,
      dataGroup
      ,
      lineGroup
      ,
      designGroup
      , …)
  3. Wire state with
    usePlaygroundState({ chart: "your-chart", … })
    or chart-specific hooks built on top of it.
tsx
import { lineChartControlGroups } from "@/lib/studio/registry-control-groups";

<EditorShell
  controlGroups={lineChartControlGroups}
  showMotionControls={false} // see left pane rules
  chartState={chartState}
/>
Rule: every new tunable prop the user adds → add a matching control to the right pane (same
key
as
StudioUrlState
).
controlGroups
传入
EditorShell
。每个组将
StudioUrlState
键映射到侧边栏控件。
  1. 优先使用现有组,来自
    apps/web/lib/studio/registry-control-groups.ts
    • lineChartControlGroups
      barChartControlGroups
      gaugeControlGroups
  2. 添加新控件以适配新增属性:
    • registry-control-groups.ts
      中扩展对应图表的组,或
    • 使用
      apps/web/lib/studio/sidebar-control-templates.ts
      中的辅助函数定义内联组(
      controlGroup
      dataGroup
      lineGroup
      designGroup
      等)
  3. 关联状态使用
    usePlaygroundState({ chart: "your-chart", … })
    或基于它构建的图表专属钩子。
tsx
import { lineChartControlGroups } from "@/lib/studio/registry-control-groups";

<EditorShell
  controlGroups={lineChartControlGroups}
  showMotionControls={false} // 参考左侧面板规则
  chartState={chartState}
/>
规则: 用户添加的每个可调整新属性 → 需在右侧面板添加匹配的控件(与
StudioUrlState
使用相同的
key
)。

Left pane — animation only

左侧面板——仅用于动画

Set
showMotionControls={true}
when the chart uses enter/reveal/motion (CSS reveal, Motion, spring/ease).
The left pane renders
MotionControl
(duration, ease/spring, curve editor, presets). Do not put data or styling controls here.
tsx
<EditorShell
  showMotionControls
  controlGroups={lineChartControlGroups}
  chartState={chartState}
/>
Wire motion into the chart with helpers from
apps/web/lib/studio/motion-config.ts
and pass
replayKey
from
useReplayKey()
to remount/replay.
Rule: animation-related settings → left pane only. Everything else → right pane.
当图表使用入场/展示/动效(CSS展示、Motion、弹簧/缓动)时,设置
showMotionControls={true}
左侧面板渲染
MotionControl
(时长、缓动/弹簧、曲线编辑器、预设)。请勿在此放置数据或样式控件。
tsx
<EditorShell
  showMotionControls
  controlGroups={lineChartControlGroups}
  chartState={chartState}
/>
使用
apps/web/lib/studio/motion-config.ts
中的辅助函数将动效关联到图表,并传递
useReplayKey()
返回的
replayKey
以重新挂载/重播动效。
规则: 动画相关设置 → 仅放在左侧面板。其他所有设置 → 放在右侧面板。

Scaffold checklist

搭建检查清单

When starting or resetting a playground:
  • Copy template →
    apps/web/app/playground/page.tsx
    (gitignored)
  • EditorShell
    +
    EditorChartFrame
    +
    usePlaygroundState
    +
    useReplayKey
  • controlGroups={[]}
    and
    showMotionControls={false}
    until chart is wired
  • PlaygroundEmptyState
    inside the chart frame until a chart component renders
When wiring a chart:
  • Replace
    PlaygroundEmptyState
    with the chart component
  • Set
    controlGroups
    to the matching registry groups (+ new groups for new props)
  • Set
    showMotionControls={true}
    if the chart animates
  • Pass
    chartState.displayState
    /
    chartState.state
    into the chart
  • Pass
    replayKey
    and wire
    onReplay
    from
    useReplayKey()
  • Colocate prototype components under
    apps/web/components/playground/
    until shipping
启动或重置沙箱时:
  • 复制模板 →
    apps/web/app/playground/page.tsx
    (已被git忽略)
  • 包含
    EditorShell
    +
    EditorChartFrame
    +
    usePlaygroundState
    +
    useReplayKey
  • 初始设置
    controlGroups={[]}
    showMotionControls={false}
    ,直到图表完成关联
  • 在图表框架内使用
    PlaygroundEmptyState
    ,直到渲染出图表组件
关联图表时:
  • 用图表组件替换
    PlaygroundEmptyState
  • controlGroups
    设置为匹配的注册组(+为新属性添加新组)
  • 如果图表包含动画,设置
    showMotionControls={true}
  • chartState.displayState
    /
    chartState.state
    传入图表组件
  • 传递
    replayKey
    并关联
    useReplayKey()
    onReplay
  • 将原型组件放在
    apps/web/components/playground/
    下,直到发布

Committed building blocks

已提交的构建模块

Do not rebuild these — import from committed paths:
ExportPathPurpose
EditorShell
@/components/editor/editor-shell
Full editor layout
EditorChartFrame
@/components/editor/editor-chart-frame
Resizable chart container
PlaygroundEmptyState
@/components/playground/playground-empty-state
Default empty chart message
usePlaygroundState
@/components/playground/use-playground-state
Local studio-like state
useReplayKey
@/components/playground/use-replay-key
[key, replay]
remount hook
PlaygroundLineChart
@/components/playground/playground-line-chart
Reference line chart wiring
lineChartControlGroups
@/lib/studio/registry-control-groups
Example right-pane groups
Legacy components (
PlaygroundShell
,
PlaygroundToolbar
,
ResizablePreview
) are superseded by the editor shell — do not use them in new playgrounds.
请勿重新构建这些模块——从已提交的路径导入:
导出内容路径用途
EditorShell
@/components/editor/editor-shell
完整编辑器布局
EditorChartFrame
@/components/editor/editor-chart-frame
可调整大小的图表容器
PlaygroundEmptyState
@/components/playground/playground-empty-state
默认空图表提示
usePlaygroundState
@/components/playground/use-playground-state
类本地工作室状态
useReplayKey
@/components/playground/use-replay-key
[key, replay]
重新挂载钩子
PlaygroundLineChart
@/components/playground/playground-line-chart
参考折线图关联示例
lineChartControlGroups
@/lib/studio/registry-control-groups
右侧面板组示例
旧版组件(
PlaygroundShell
PlaygroundToolbar
ResizablePreview
)已被编辑器外壳取代——请勿在新沙箱中使用。

Example: line chart playground

示例:折线图沙箱

tsx
"use client";

import { useState } from "react";
import { EditorChartFrame } from "@/components/editor/editor-chart-frame";
import { EditorShell } from "@/components/editor/editor-shell";
import type { ViewportPreset } from "@/components/editor/viewport-presets";
import { resolveViewportSize } from "@/components/editor/viewport-presets";
import { PlaygroundLineChart } from "@/components/playground/playground-line-chart";
import { usePlaygroundLineChartState } from "@/components/playground/use-playground-line-chart-state";
import { useReplayKey } from "@/components/playground/use-replay-key";
import { lineChartControlGroups } from "@/lib/studio/registry-control-groups";

export default function PlaygroundPage() {
  const chartState = usePlaygroundLineChartState();
  const [replayKey, replay] = useReplayKey();
  const [viewport, setViewport] = useState<ViewportPreset | null>("desktop");
  const [size, setSize] = useState(() =>
    resolveViewportSize("desktop", 960)
  );

  return (
    <EditorShell
      chartState={chartState}
      controlGroups={lineChartControlGroups}
      onReplay={replay}
      onSizeChange={(width, height) => setSize({ width, height })}
      onViewportChange={setViewport}
      showMotionControls
      size={size}
      viewport={viewport}
    >
      {({ size: frameSize, boundsRef, onResize, mobileViewport }) => (
        <EditorChartFrame
          boundsRef={boundsRef}
          height={frameSize.height}
          onResize={onResize}
          resizable={!mobileViewport}
          width={frameSize.width}
        >
          <PlaygroundLineChart
            committedState={chartState.state}
            motionCurveDragging={chartState.motionCurveDragging}
            replayKey={replayKey}
            state={chartState.displayState}
          />
        </EditorChartFrame>
      )}
    </EditorShell>
  );
}
tsx
"use client";

import { useState } from "react";
import { EditorChartFrame } from "@/components/editor/editor-chart-frame";
import { EditorShell } from "@/components/editor/editor-shell";
import type { ViewportPreset } from "@/components/editor/viewport-presets";
import { resolveViewportSize } from "@/components/editor/viewport-presets";
import { PlaygroundLineChart } from "@/components/playground/playground-line-chart";
import { usePlaygroundLineChartState } from "@/components/playground/use-playground-line-chart-state";
import { useReplayKey } from "@/components/playground/use-replay-key";
import { lineChartControlGroups } from "@/lib/studio/registry-control-groups";

export default function PlaygroundPage() {
  const chartState = usePlaygroundLineChartState();
  const [replayKey, replay] = useReplayKey();
  const [viewport, setViewport] = useState<ViewportPreset | null>("desktop");
  const [size, setSize] = useState(() =>
    resolveViewportSize("desktop", 960)
  );

  return (
    <EditorShell
      chartState={chartState}
      controlGroups={lineChartControlGroups}
      onReplay={replay}
      onSizeChange={(width, height) => setSize({ width, height })}
      onViewportChange={setViewport}
      showMotionControls
      size={size}
      viewport={viewport}
    >
      {({ size: frameSize, boundsRef, onResize, mobileViewport }) => (
        <EditorChartFrame
          boundsRef={boundsRef}
          height={frameSize.height}
          onResize={onResize}
          resizable={!mobileViewport}
          width={frameSize.width}
        >
          <PlaygroundLineChart
            committedState={chartState.state}
            motionCurveDragging={chartState.motionCurveDragging}
            replayKey={replayKey}
            state={chartState.displayState}
          />
        </EditorChartFrame>
      )}
    </EditorShell>
  );
}

Adding a new prop (agent workflow)

添加新属性(代理工作流)

When the user adds a chart prop like
strokeWidth
or
showMarkers
:
  1. Add the key to
    StudioUrlState
    /
    defaultStudioState
    if missing (
    apps/web/lib/studio/studio-parsers.ts
    )
  2. Add a control to the chart's group in
    registry-control-groups.ts
    (right pane)
  3. Wire the prop from
    chartState.displayState
    into the chart component
  4. If the prop affects animation timing/easing/reveal → ensure
    showMotionControls
    is on and use motion helpers
When the user adds animation behavior:
  1. Set
    showMotionControls={true}
    on
    EditorShell
  2. Wire
    getStudioCssRevealProps
    /
    studioMotionToTransition
    /
    motionSignature
    as appropriate
  3. Keep data/styling controls on the right pane
当用户添加
strokeWidth
showMarkers
等图表属性时:
  1. 如果缺失,将键添加到
    StudioUrlState
    /
    defaultStudioState
    中(
    apps/web/lib/studio/studio-parsers.ts
  2. registry-control-groups.ts
    中对应图表的组里添加控件(右侧面板)
  3. 将属性从
    chartState.displayState
    关联到图表组件
  4. 如果属性影响动画时长/缓动/展示 → 确保
    showMotionControls
    已开启,并使用动效辅助函数
当用户添加动画行为时:
  1. EditorShell
    上设置
    showMotionControls={true}
  2. 按需关联
    getStudioCssRevealProps
    /
    studioMotionToTransition
    /
    motionSignature
  3. 将数据/样式控件保留在右侧面板

Ship when ready

准备就绪后发布

When the API is stable, follow
.agents/skills/bklit-ship/SKILL.md
to move the chart into
packages/ui
, add docs, gallery examples, and registry entries.
当API稳定后,按照
.agents/skills/bklit-ship/SKILL.md
中的指引将图表移入
packages/ui
,添加文档、画廊示例和注册条目。

File reference

文件参考

ItemPath
Playground route (gitignored)
apps/web/app/playground/page.tsx
Template
.agents/skills/bklit-playground/templates/page.tsx
Editor components
apps/web/components/editor/
Playground helpers
apps/web/components/playground/
Control group registry
apps/web/lib/studio/registry-control-groups.ts
Control templates
apps/web/lib/studio/sidebar-control-templates.ts
Ship checklist
.agents/skills/bklit-ship/SKILL.md
Gitignore entry
.gitignore
apps/web/app/playground/
项目路径
沙箱路由(已被git忽略)
apps/web/app/playground/page.tsx
模板
.agents/skills/bklit-playground/templates/page.tsx
编辑器组件
apps/web/components/editor/
沙箱辅助工具
apps/web/components/playground/
控件组注册
apps/web/lib/studio/registry-control-groups.ts
控件模板
apps/web/lib/studio/sidebar-control-templates.ts
发布检查清单
.agents/skills/bklit-ship/SKILL.md
Git忽略条目
.gitignore
apps/web/app/playground/