镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,6 @@ concurrency:
permissions: {}

jobs:
format:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Setup environment
uses: ./.github/actions/setup

- name: Check formatting
run: pnpm format:check

lint:
runs-on: ubuntu-latest
permissions:
Expand Down
96 changes: 44 additions & 52 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

1. **Plan first:** Create a detailed plan and get explicit user approval before
making changes.
2. **Quality gates:** Every change must pass `pnpm format:check`, `pnpm lint`,
`pnpm test`, and `pnpm build` (or `pnpm integrate` for the full pipeline)
before being considered complete.
2. **Quality gates:** Every change must pass `pnpm lint`, `pnpm test`, and
`pnpm build` (or `pnpm integrate` for the full pipeline) before being
considered complete.
3. **Documentation:** Update `README.md`, `AGENTS.md`, configuration files, and
any other documentation affected by your changes. Clean as you go — take
ownership of every file you touch.
Expand Down Expand Up @@ -53,7 +53,7 @@ not `behavior`, `licence` not `license`, `centre` not `center`).

### Package Management

- **Package manager:** pnpm (`pnpm@12.3.4` via the `packageManager` field —
- **Package manager:** pnpm (`pnpm@12.16.1` via the `packageManager` field —
Corepack manages the exact version, never install pnpm globally)
- **Node.js engine:** `>=24.20.0` (declared in `package.json` `engines`)
- **Lock file:** `pnpm-lock.yaml` is committed. NEVER delete or regenerate it
Expand All @@ -66,35 +66,35 @@ not `behavior`, `licence` not `license`, `centre` not `center`).
- **Babel plugin override:** `pnpm-workspace.yaml` redirects
`@babel/plugin-proposal-private-methods` (deprecated upstream) to
`npm:@babel/plugin-transform-private-methods@^7.29.7`. The 7.x line is the
correct target while `eslint-plugin-react-compiler@19.1.0-rc.2` resolves
`@babel/core` 7.29.x — the v8 plugin requires `@babel/core ^8.0.0` and fails
the strict peer gate. Revisit when the react-compiler plugin migrates to Babel
8
- **p5 dev resolution pinned:** the devDependency `p5` is pinned to exactly
`2.3.2` because upstream `2.3.3` was published without its `types/` files
(despite the manifest declaring them), breaking type checking. The
`p5 >= 2.0.0` peer dependency contract is unchanged. Revisit when p5.js
republishes a complete 2.3.3+
correct target while `babel-plugin-react-compiler` resolves `@babel/core`
7.29.x — the v8 plugin requires `@babel/core ^8.0.0` and fails the strict peer
gate. Revisit when the react-compiler plugin migrates to Babel 8
- **p5 dev resolution:** the devDependency `p5` tracks the latest complete 2.x
release (currently pinned to exactly `2.3.4` because upstream `2.3.3` was
published without its `types/` files despite the manifest declaring them,
breaking type checking — `2.3.4` republished them). The `p5 >= 2.0.0` peer
dependency contract is unchanged. Revisit the exact pin if a later 2.x release
ships incomplete types again
- **Peer dependencies are a contract:** `p5`, `react`, and `react-dom` are peer
dependencies. The library code must never import anything beyond these at
runtime — `@p5-wrapper/common` and `react-error-boundary` are the only runtime
dependencies

### Formatting and Linting

- **Prettier** is the formatter (this project does not use Biome — do not
introduce it). Config lives at `config/prettier/prettier.json`, key rules:
`printWidth: 80`, `arrowParens: "avoid"`, `trailingComma: "none"`,
`proseWrap: "always"` (all Markdown prose is hard-wrapped at 80 columns),
imports sorted by `@trivago/prettier-plugin-sort-imports`
- **ESLint** is the linter. Config lives at `config/eslint/eslint.config.ts` and
extends `eslint` recommended, `typescript-eslint` strict and stylistic, and
`eslint-plugin-react-compiler` recommended with project-aware TypeScript
parsing. Type-aware linting runs via `jiti` — keep the config a `.ts` file
- **React Compiler:** The React Compiler ESLint rules are enabled. Components
must follow the Rules of React strictly — no manual memoisation where the
compiler can handle it, no mutating props or render-time side effects. Do not
disable these rules
- **Biome** is the formatter and linter. Config lives at the repository-root
`biome.json`, key rules: 2-space indentation, double quotes, semicolons
always, `proseWrap: "always"` (all Markdown prose is hard-wrapped at 80
columns), imports organised by Biome's `assist` `organizeImports` action,
linter `recommended` preset plus `useBlockStatements: "error"`. The `$schema`
key points at `./node_modules/@biomejs/biome/configuration_schema.json` so it
always tracks the installed Biome version. `pnpm format` runs
`biome check --write .`; `pnpm lint` runs `biome check .` (formatting check
plus lint)
- **React Compiler:** The React Compiler Babel plugin
(`babel-plugin-react-compiler`) is active in the build. Components must follow
the Rules of React strictly — no manual memoisation where the compiler can
handle it, no mutating props or render-time side effects
- **No comments:** Do not add comments to source files. The code should be
self-documenting. The only permitted exceptions are `@ts-expect-error` /
`@ts-ignore` suppressions with a `@see` reference (see
Expand All @@ -112,34 +112,28 @@ not `behavior`, `licence` not `license`, `centre` not `center`).
`paths` and `config/vite/common.ts` — and MUST be kept in sync when changed
- **Import style:** Use `import { type Foo }` inline type imports, matching the
existing code. Imports of contracts across the alias boundaries follow the
sorted import order enforced by Prettier
organised import order enforced by Biome
- **Type assertions:** Avoid `as` casts in library code. No `@ts-expect-error`
or `@ts-ignore` suppressions currently exist; if one is ever needed, it must
carry a `@see` reference and be verified against upstream issue or PR links
- **Version pinned to 6.0.3:** `typescript` is an exact pin
(`"typescript": "6.0.3"`, no caret), deliberately held back from v7.
typescript-eslint does not currently support TypeScript 7 — its
[supported range](https://typescript-eslint.io/packages/parser) is
`>=4.8.4 <6.1.0`, and the Go-based TypeScript 7 is not yet feature compatible
with the JavaScript-based v6 API that typescript-eslint builds on. Upstream
support is tracked in
[typescript-eslint#10940](https://github.com/typescript-eslint/typescript-eslint/issues/10940)
and cannot land before TypeScript 7.1.x at the earliest. Do not bump past
`6.0.x` or widen the pin without confirming upstream support. Do NOT run
- **Version pinned to the latest 6.x.x:** `typescript` is an exact pin (no
caret), deliberately held back from v7. TypeScript 7 is Go-based and not yet
feature compatible with the JavaScript-based v6 API that the build toolchain
(`vite`, `vite-plugin-dts`, `@microsoft/api-extractor`) builds on. Do not bump
past `6.0.x` or widen the pin without confirming toolchain support. Do NOT run
TypeScript 7 side by side with v6 as an interim measure — we wait for full
feature parity before migrating, no half measures

### Quality Gates

Every change must pass before being considered complete:

- `pnpm format:check` — formatting
- `pnpm lint` — linting
- `pnpm lint` — formatting check + linting (Biome)
- `pnpm test` — testing
- `pnpm build` — type checking (`tsc`) plus component and demo builds

`pnpm integrate` runs format check → lint → test → build in one command and is
the closest local mirror of CI.
`pnpm integrate` runs lint → test → build in one command and is the closest
local mirror of CI.

### Git Safety

Expand Down Expand Up @@ -264,7 +258,8 @@ legally certify a contribution — the human submitter reviews the AI-generated
code, takes full responsibility for it, and adds any certification trailers
themselves. Following the rules the Linux kernel team enforce for AI coding
assistants, an agent's role in a commit ends at the message body — no
`Signed-off-by`, no `Co-authored-by`, no other trailers or sign-offs. See [AI
`Signed-off-by`, no `Co-authored-by`, no other trailers or sign-offs. See
[AI
Coding Assistants — The Linux Kernel documentation]
(https://docs.kernel.org/process/coding-assistants.html), integrated into this
ruleset on 2026-09-03.
Expand Down Expand Up @@ -369,9 +364,8 @@ Everything exported from `src/main.tsx` is public API and semver-protected:
├── tests/ # Vitest tests for component behaviour
│ ├── components/
│ └── setup.ts # Test bootstrap (canvas mock, cleanup)
├── biome.json # Biome formatter + linter config (repo root)
├── config/
│ ├── eslint/eslint.config.ts
│ ├── prettier/prettier.json
│ └── vite/
│ ├── vite.config.ts # Mode switch: lib (test + library) vs demo
│ ├── common.ts # Shared path aliases
Expand Down Expand Up @@ -412,24 +406,22 @@ Everything exported from `src/main.tsx` is public API and semver-protected:
| :--------------------- | :--------------------------------------------------------- |
| `pnpm install` | Install dependencies (updates lockfile — commit the diff). |
| `pnpm dev` | Run the Vite dev server with the demo app. |
| `pnpm format` | Format all files with Prettier. |
| `pnpm format:check` | Check formatting without writing. |
| `pnpm lint` | Run ESLint (type-aware). |
| `pnpm lint:fix` | Run ESLint with autofix. |
| `pnpm format` | Format and lint-fix all files with Biome. |
| `pnpm lint` | Check formatting and lint with Biome. |
| `pnpm test` | Run the Vitest suite. |
| `pnpm test:coverage` | Run tests with coverage (what CI runs). |
| `pnpm test:watch` | Watch mode. |
| `pnpm build:component` | Type check + build the npm library. |
| `pnpm build:demo` | Build the demo app only. |
| `pnpm build` | Clean and build component + demo. |
| `pnpm integrate` | format:check → lint → test → build (CI mirror). |
| `pnpm integrate` | lint → test → build (CI mirror). |

## CI/CD

- **CI** (`continuous-integration.yml`): Runs on all PRs to `main` and
`workflow_dispatch`. Jobs: `format`, `lint`, `test` (with coverage artifact
and clover coverage delta comment), `build`, and `npm-dry-run` (validates the
npm publish would succeed). CI concurrency cancels in-progress runs. Uses the
`workflow_dispatch`. Jobs: `lint`, `test` (with coverage artifact and clover
coverage delta comment), `build`, and `npm-dry-run` (validates the npm publish
would succeed). CI concurrency cancels in-progress runs. Uses the
`./.github/actions/setup` composite action with
`pnpm install --frozen-lockfile`
- **CD** (`continuous-deployment.yml`): Runs on push to `main` and
Expand Down
32 changes: 15 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ using either the `Sketch` type or the `P5CanvasInstance` type:
import * as React from "react";
import { P5Canvas, Sketch } from "@p5-wrapper/react";

const sketch: Sketch = p5 => {
const sketch: Sketch = (p5) => {
p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

p5.draw = () => {
Expand Down Expand Up @@ -200,7 +200,7 @@ function sketch(p5) {

p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

p5.updateWithProps = props => {
p5.updateWithProps = (props) => {
rotation = (props.rotation * Math.PI) / 180;
};

Expand All @@ -220,7 +220,7 @@ export function App() {

useEffect(() => {
const interval = setInterval(
() => setRotation(rotation => rotation + 100),
() => setRotation((rotation) => rotation + 100),
100
);

Expand All @@ -245,12 +245,12 @@ type MySketchProps = SketchProps & {
rotation: number;
};

const sketch: Sketch<MySketchProps> = p5 => {
const sketch: Sketch<MySketchProps> = (p5) => {
let rotation = 0;

p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

p5.updateWithProps = props => {
p5.updateWithProps = (props) => {
rotation = (props.rotation * Math.PI) / 180;
};

Expand All @@ -270,7 +270,7 @@ export function App() {

useEffect(() => {
const interval = setInterval(
() => setRotation(rotation => rotation + 100),
() => setRotation((rotation) => rotation + 100),
100
);

Expand Down Expand Up @@ -313,12 +313,12 @@ import React, { useCallback, useState } from "react";

type MySketchProps = SketchProps & { rotation: number };

const sketch: Sketch<MySketchProps> = p5 => {
const sketch: Sketch<MySketchProps> = (p5) => {
let rotation = 0;

p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

p5.updateWithProps = props => {
p5.updateWithProps = (props) => {
rotation = (props.rotation * Math.PI) / 180;
};

Expand Down Expand Up @@ -385,7 +385,7 @@ export function App() {

useEffect(() => {
const interval = setInterval(
() => setRotation(rotation => rotation + 100),
() => setRotation((rotation) => rotation + 100),
100
);

Expand Down Expand Up @@ -576,7 +576,7 @@ import React, { useEffect, useState } from "react";

await import("p5/lib/addons/p5.sound");

const sketch: Sketch = p5 => {
const sketch: Sketch = (p5) => {
let song: p5.SoundFile;
let button: p5.Element;

Expand Down Expand Up @@ -688,13 +688,11 @@ public API in `src/main.tsx` backwards compatible. Commits follow the
`fix:`, `chore:`, etc.) — emoji prefixes are only used by automated pull
requests.

The `typescript` dependency is pinned to `6.0.3` on purpose:
[typescript-eslint](https://typescript-eslint.io) does not support TypeScript 7
yet — the Go-based v7 is not feature compatible with the v6 API it builds on,
and upstream support cannot land before TypeScript 7.1.x. It is tracked in
[typescript-eslint#10940](https://github.com/typescript-eslint/typescript-eslint/issues/10940).
Please do not widen the pin in pull requests — we wait for full feature parity
before migrating to v7, no half measures.
The `typescript` dependency is pinned to the latest `6.x.x` release on purpose:
TypeScript 7 (Go-based) is not yet feature compatible with the JavaScript-based
v6 API that the build toolchain builds on. Please do not bump past `6.x.x` or
widen the pin in pull requests — we wait for full feature parity before
migrating to v7, no half measures.

#### AI-assisted contributions

Expand Down
95 changes: 95 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"files": {
"ignoreUnknown": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"linter": {
"enabled": true,
"rules": {
"preset": "recommended",
"style": {
"useBlockStatements": "error",
"useImportType": "off"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "none"
}
},
"json": {
"formatter": {
"enabled": true,
"trailingCommas": "none"
}
},
"css": {
"formatter": {
"enabled": true
},
"parser": {
"tailwindDirectives": true
}
},
"markdown": {
"formatter": {
"enabled": true,
"proseWrap": "always"
},
"parser": {
"frontmatter": true
}
},
"yaml": {
"formatter": {
"enabled": true
}
},
"overrides": [
{
"includes": ["**/pnpm-lock.yaml"],
"formatter": {
"enabled": false
},
"linter": {
"enabled": false
},
"assist": {
"enabled": false
}
},
{
"includes": ["**/CLAUDE.md"],
"formatter": {
"enabled": false
},
"linter": {
"enabled": false
},
"assist": {
"enabled": false
}
}
]
}
Loading
Loading