Skip to main content

aidd-ecs

Enforces @adobe/data/ecs best practices. Use this whenever @adobe/data/ecs is imported, when creating or modifying Database.Plugin definitions, or when working with ECS components, resources, transactions, actions, systems, or services.

소스 정보

저장소
paralleldrive/riteway
최근 소스 활동
2026년 3월 17일 20:30
감지된 SKILL.md 언어
영어
스타
1,196
포크
40

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
3 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
aidd-ecs
description
Enforces @adobe/data/ecs best practices. Use this whenever @adobe/data/ecs is imported, when creating or modifying Database.Plugin definitions, or when working with ECS components, resources, transactions, actions, systems, or services.
# Database.Plugin authoring Plugins are created with `Database.Plugin.create()` from `@adobe/data/ecs`. ## Property order (enforced at runtime) Properties **must** appear in this exact order. All are optional. ```sudolang PluginPropertyOrder [ "extends — Plugin, base plugin to extend" "services — (db) => ServiceInstance, singleton service factories" "components — schema object, ECS component schemas" "resources — { default: value as Type }, global resource schemas" "archetypes — ['comp1', 'comp2'], standard ECS archetypes; storage tables for efficient insertions" "computed — (db) => Observe<T>, computed observables" "transactions — (store, payload) => void, synchronous deterministic atomic mutations" "actions — (db, payload) => T, general functions" "systems — { create: (db) => fn | void }, per-frame (60fps) or init-only" ] Constraints { Properties must appear in this exact order; wrong order throws at runtime } ``` --- ## Composition **Single extension** — one plugin extends another: ```ts export const authPlugin = Database.Plugin.create({ extends: environmentPlugin, services: { auth: db => AuthService.createLazy({ services: db.services }), }, }); ``` **Combine** — `extends` accepts only one plugin. To extend from multiple use Database.Plugin.combine: ```ts export const generationPlugin = Database.Plugin.create({ extends: Database.Plugin.combine(aPlugin, bPlugin), computed: { max: db => Observe.withFilter( Observe.fromProperties({ a: db.observe.resources.a, b: db.observe.resources.b }), ({ a, b }) => Math.max(a, b) ) }, }); ``` **Final composition** — combine all plugins into the app plugin: ```ts export const appPlugin = Database.Plugin.combine( corePlugin, themePlugin, dataPlugin, authPlugin, uiPlugin, featurePlugin ); export type AppPlugin = typeof appPlugin; export type AppDatabase = Database.Plugin.ToDatabase<AppPlugin>; ``` --- ## Property details ### services Factory functions creating singleton services. Extended plugin services initialize first, so `db.services` has access to them. ```ts services: { environment: _db => EnvironmentService.create(), } ``` ### components Schema objects defining ECS component data. Use schema imports from type namespaces or inline schemas. See [data-modeling.md](data-modeling.md) for a simple example. ```ts components: { layout: Layout.schema, layoutElement: { default: null as unknown as HTMLElement, transient: true }, layoutLayer: F32.schema, }, ``` Non-persistable values (e.g. HTML elements, DOM refs) must use `transient: true` — excluded from serialization. ### resources Global state not tied to entities. Use `as Type` to provide the compile-time type — without it the value is treated as a const literal. See [data-modeling.md](data-modeling.md) for patterns. ```ts resources: { themeColor: { default: 'dark' as ThemeColor }, themeScale: { default: 'medium' as ThemeScale }, }, ``` Use `null as unknown as Type` for resources initialized later in a system initializer: ```ts resources: { connection: { default: null as unknown as WebSocket }, }, ``` ### archetypes Standard ECS archetypes. Used for querying and inserting related components. See [data-modeling.md](data-modeling.md) for a simple example. ```ts archetypes: { Layout: ['layout', 'layoutElement', 'layoutLayer'], }, ``` ### computed Factory returning `Observe<T>` or `(...args) => Observe<T>`. Receives full db. ```ts computed: { max: db => Observe.withFilter( Observe.fromProperties({ a: db.observe.resources.a, b: db.observe.resources.b, }), ({ a, b }) => Math.max(a, b) ), }, ``` ### transactions Synchronous, deterministic atomic mutations. Receive `store` and a payload. Store allows direct, immediate mutation of all entities, components, and resources. ```ts transactions: { updateLayout: (store, { entity, layout }: { entity: Entity; layout: Layout }) => { store.update(entity, { layout }); }, setThemeColor: (store, color: ThemeColor) => { store.resources.themeColor = color; }, }, ``` ```sudolang StoreAPI { "store.update(entity, data)" = "update entity components" "store.resources.x = value" = "mutate resources" "store.get(entity, 'component')" = "read component value" "store.read(entity)" = "read all entity component values" "store.read(entity, archetype)" = "read entity component values in archetype" "store.select(archetype.components, { where })" = "query entities" } ``` ### actions General functions with access to the full db. Can return anything or nothing. UI components that call actions MUST never consume returned values — call for side effects only. Consuming return values violates unidirectional flow (data down via Observe, actions up as void). Call at most one transaction per action; multiple transactions corrupt the undo/redo stack. ```ts actions: { generateNewName: async (db) => { const generatedName = await db.services.nameGenerator.generateName(); db.transactions.setName(generatedName); }, getAuth: db => db.services.auth, }, ``` ### systems `create` receives db and may optionally return a per-frame function (60fps) or just initialize values. Always called synchronously when `database.extend(plugin)` runs. ```ts systems: { ui_state_plugin_initialize: { create: db => { db.transactions.registerViews(views); }, }, layout_plugin__system: { create: db => { const observer = new ResizeObserver(/* ... */); Database.observeSelectDeep(db, db.archetypes.Layout.components)(entries => { // react to entity changes }); }, }, }, ``` **System scheduling** (optional): ```ts systems: { physics: { create: db => () => { /* per-tick work */ }, schedule: { before: ['render'], after: ['input'], during: ['simulation'], }, }, }, ``` ```sudolang Schedule { before: "hard ordering constraints" after: "hard ordering constraints" during: "soft preference for same execution tier" } ``` --- ## Naming conventions ```sudolang PluginNaming { file: "*-plugin.ts (kebab-case) — e.g. layout-plugin.ts" export: "*Plugin (camelCase) — e.g. layoutPlugin" system: "plugin_name__system (snake_case, double underscore) — e.g. layout_plugin__system" initSystem: "plugin_name_initialize — e.g. ui_state_plugin_initialize" } ``` --- ## Type utilities ```ts export type MyDatabase = Database.Plugin.ToDatabase<typeof myPlugin>; export type MyStore = Database.Plugin.ToStore<typeof myPlugin>; ``` --- ## Execute ```sudolang fn whenCreatingOrModifyingPlugin() { Constraints { Verify property order matches (extends, services, components, resources, archetypes, computed, transactions, actions, systems) Use extends for single-parent; Database.Plugin.combine() for multiple peers Ensure services only access db.services from extended plugins (not forward references) Export type *Database = Database.Plugin.ToDatabase<typeof *Plugin> when consumers need typed db access Follow naming conventions for files, exports, and systems } } ``` ## Additional resources - [data-modeling.md](data-modeling.md) — Components, resources, and archetypes (particle simulation example)
GitHub에서 보기