npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@storyboard-os/core

v1.1.0

Published

Generic storyboard primitives — frame, connection, annotation, template, validation. No domain-specific content.

Readme


@storyboard-os/core

Storyboard OS 平台的基础架构。它定义了所有领域模块都会使用的通用类型,包括:帧、连接、注释、故事板、模板以及结构验证。

@storyboard-os/core 没有依赖项,并且不包含任何特定领域的词汇。它不知道什么是角色扮演游戏任务、剧本场景或战役地图。领域模块会导入这些通用类型,并使用自己的内容模式和帧类型进行定制。


安装

npm install @storyboard-os/core
# or
pnpm add @storyboard-os/core

它提供的功能

StoryboardFrame 是一个叙事片段,是任何故事板的原子单元。

interface StoryboardFrame<
  TFrameType extends string = string,
  TContent = unknown,
  TAnnotationType extends string = string,
> {
  id: string;
  type: TFrameType;
  title: string;
  summary: string;
  position: { x: number; y: number };
  size: { width: number; height: number };
  content: TContent;
  annotations: FrameAnnotation<TAnnotationType>[];
}

领域模块会绑定类型参数。

// In @storyboard-os/rpg-domain:
type StoryboardFrame = CoreFrame<StoryboardFrameType, FrameContent, FrameAnnotationType>;

注释

每个帧的作者备注,由领域模块定义。

interface FrameAnnotation<TAnnotationType extends string = string> {
  id: string;
  type: TAnnotationType;
  text: string;
}

连接

连接是首类实体,而不是隐藏在 frame.links 中。连接类型驱动视觉渲染(笔画粗细、虚线模式),并携带语义信息。

type StoryboardConnectionType =
  | 'sequence'      // linear progression
  | 'choice'        // player-driven branch
  | 'consequence'   // outcome arc driven by state change
  | 'optional'      // conditional / skippable path
  | 'fallback';     // alternate route if primary is blocked

interface StoryboardConnection {
  id: string;
  fromFrameId: string;
  toFrameId: string;
  type: StoryboardConnectionType;
  label?: string;
}

故事板

包含 ID 和标题的帧和连接的集合。

interface Storyboard<TFrame extends AnyStoryboardFrame = AnyStoryboardFrame> {
  id: string;
  title: string;
  description?: string;
  templateId?: string;
  frames: TFrame[];
  connections: StoryboardConnection[];
  canvasWidth?: number;
  canvasHeight?: number;
}

项目

一个浅层容器,用于存储一个或多个故事板。它不是一个领域数据库,而只是提供足够的结构,可以将相关的故事板组织在名称下。

interface StoryboardProject<TStoryboard extends Storyboard = Storyboard> {
  id: string;
  title: string;
  description?: string;
  storyboards: TStoryboard[];
}

模板

用于从起始点创建特定领域的故事板的工厂。

interface StoryboardTemplateDefinition<
  TId extends string = string,
  TStoryboard extends Storyboard = Storyboard,
> {
  id: TId;
  name: string;
  description: string;
  frameCount: number;
  bestFor: string;
  createStoryboard: (input: CreateStoryboardInput) => TStoryboard;
}

interface CreateStoryboardInput {
  id: string;
  title: string;
  description?: string;
}

结构验证

validateStoryboard 检查适用于任何故事板的不变条件,无论领域如何:重复的帧 ID、损坏的连接引用、缺少必需字段以及无效的帧尺寸。

import { validateStoryboard } from '@storyboard-os/core';

const result = validateStoryboard(storyboard);

if (!result.valid) {
  for (const error of result.errors) {
    console.error(error.code, error.message, error.frameId ?? error.connectionId);
  }
}

错误代码

| 代码 | 含义 | |---|---| | EMPTY_STORYBOARD | 故事板中没有帧 | | DUPLICATE_FRAME_ID | 两个帧具有相同的 ID | | MISSING_TITLE | 帧没有标题 | | MISSING_TYPE | 帧没有类型 | | MISSING_SUMMARY | 帧没有摘要 | | INVALID_DIMENSIONS | 帧的宽度或高度小于 40 像素的最小值 | | BROKEN_CONNECTION_FROM | 连接的 fromFrameId 引用了不存在的帧 | | BROKEN_CONNECTION_TO | 连接的 toFrameId 引用了不存在的帧 |

领域模块首先调用 validateStoryboard,然后在其之上添加自己的领域规则。@storyboard-os/rpg-domain 导出了 validateRpgStoryboard,它执行的就是这个操作。


扩展平台

要在 @storyboard-os/core 之上构建第二个模块:

// 1. Define your frame type union
type ScreenplayFrameType = 'scene' | 'beat' | 'sequence' | 'act_break';

// 2. Define your content shape
interface ScreenplayContent {
  sceneHeading: string;
  action: string;
  dialogue: string[];
  characterPresent: string[];
}

// 3. Specialize the generic frame type
import type { StoryboardFrame as CoreFrame } from '@storyboard-os/core';
type ScreenplayFrame = CoreFrame<ScreenplayFrameType, ScreenplayContent, 'note' | 'revision'>;

// 4. Build your domain package — validateStoryboard handles the structural layer

架构位置

@storyboard-os/core          ← you are here
  └── (no dependencies)

@storyboard-os/rpg-domain
  └── @storyboard-os/core

@storyboard-os/canvas
  └── (no platform deps — pure Konva + React)

apps/rpg-storyboard
  └── all @storyboard-os/* packages

@storyboard-os/core 位于依赖链的底部。它不从平台导入任何内容。下游模块会向上导入,它们永远不会向下导入。


信任模型

@storyboard-os/core 是一个纯 TypeScript 库。它没有运行时效果,没有 I/O,没有网络访问,也没有副作用。validateStoryboard 函数读取您传入的故事板对象,并返回一个纯结果对象。没有任何内容被存储、记录或传输。