Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
bbf0fce
web: Pattern Lab's preview shows add layers the way the device does
patternflow-bot Oct 18, 2026
6bba03c
web: the Live Editor says why pasted code does not run
patternflow-bot Oct 19, 2026
ae93f27
web: community pages open when the browser blocks site data
patternflow-bot Oct 21, 2026
bef1137
web: the home page waits for the Pattern tab before fetching the code
patternflow-bot Oct 21, 2026
d8df3c2
web: the guide's tests give the same answer on a busy machine and a fast
patternflow-bot Oct 21, 2026
61ef7a4
web: Pattern Lab's "Copied" labels clear their timer when the panel
patternflow-bot Oct 21, 2026
edd6257
web: posthog-js loads after the page does
patternflow-bot Oct 21, 2026
2c7ba10
web: Closing Send or Publish from its backdrop keeps To hardware open
patternflow-bot Oct 21, 2026
5acec4a
web: Korean pages fetch 318 KB of Pretendard Hangul instead of 1.2 MB
patternflow-bot Oct 21, 2026
4eb0472
web: editing a deck no longer runs out after four changes
patternflow-bot Oct 21, 2026
14d80f1
web: the hero video has a stop button
patternflow-bot Oct 21, 2026
3067666
web: Pattern Lab's dialogs close on Esc, and its header menus close on a
patternflow-bot Oct 21, 2026
deb0041
web: the breadboard build guide fits the window from 1280px up, and
patternflow-bot Oct 21, 2026
7b841c5
web: the deck panel and the Send window stop waiting when the build
patternflow-bot Oct 21, 2026
f04324c
web: the Live Editor fits a phone screen
patternflow-bot Oct 21, 2026
6c4d1fc
docs: the build service docs describe the worker that runs today
patternflow-bot Oct 21, 2026
ed3d9fd
web: Pattern Lab's Pixel zoom follows the wheel's travel and holds the
patternflow-bot Oct 21, 2026
37b6e0b
web: the Live Editor's creation prompt gives the step one detent really
patternflow-bot Oct 21, 2026
a742185
web: community dialogs close with a thumb, and the atlas works from the
patternflow-bot Oct 21, 2026
e226525
web: Pattern Lab's Pixel panel opens with the whole picture in view
patternflow-bot Oct 21, 2026
acbe8da
web: the community rate limiter keeps an hour of builds through its
patternflow-bot Oct 21, 2026
c903df9
web: the project map's toggles fit a phone, and the map says which
patternflow-bot Oct 21, 2026
20403b6
web: changes from Patternflow-lab/Patternflow#130
patternflow-bot Oct 21, 2026
aa32509
web: the home tabs' link rows draw a focus ring, and each tab's title is
patternflow-bot Oct 21, 2026
5573fa0
web: a desk run of `check:drift` reports a skipped `links-absolute` as
patternflow-bot Oct 21, 2026
4025dd0
web: links drawn as buttons and cards keep their look on hover
patternflow-bot Oct 21, 2026
258bcf5
web: two unimported files and six uncalled exports are gone
patternflow-bot Oct 21, 2026
2c6a8fc
web: the 3D device and the Inside globe hold still for reduced motion
patternflow-bot Oct 21, 2026
652f971
docs: the docs index, the repository map and the contributor guide
patternflow-bot Oct 21, 2026
021eebf
web: the atlas says why it did not save a pin
patternflow-bot Oct 21, 2026
f4e3c5a
web: the guide's panel simulator fails a test when a firmware number it
patternflow-bot Oct 21, 2026
b3233ab
web: a pattern page stops counting the lines Pattern Lab writes on its
patternflow-bot Oct 21, 2026
5a29872
web: the atlas fits a phone
patternflow-bot Oct 21, 2026
bf1a654
web: the site's typecheck catches unused locals and parameters, switch
patternflow-bot Oct 21, 2026
bd20601
web: community fields a screen reader could not name now have names
patternflow-bot Oct 21, 2026
0486a9c
web: the home page's tabs open in a browser without WebGL
patternflow-bot Oct 21, 2026
6ceac0f
web: the home page poster comes at the width it is drawn
patternflow-bot Oct 22, 2026
34c5090
web: the Build and Pattern tabs, and the home page on a phone, no longer
patternflow-bot Oct 22, 2026
4f98d1d
web: community write routes answer a `null` body with a 400
patternflow-bot Oct 22, 2026
2dea66f
web: Pattern Lab and the Live Editor say when pasted code was cut off
patternflow-bot Oct 22, 2026
a8f01b0
web: Pattern Lab's Recent and Panels menus open inside a phone screen
patternflow-bot Oct 22, 2026
26a2ecb
web: changes from Patternflow-lab/Patternflow#150
patternflow-bot Oct 22, 2026
1676e1d
web: copy buttons in Pattern Lab and the Live Editor say "Copy failed"
patternflow-bot Oct 22, 2026
c98f122
web: sharing from Pattern Lab measures the code the way the community
patternflow-bot Oct 22, 2026
ea3efab
web: the community API no longer lets an edit move a pattern to MIT or
patternflow-bot Oct 22, 2026
985bd09
web: five community windows close on Esc and hand the focus back
patternflow-bot Oct 22, 2026
ebb01d0
web: the community atlas stands its filter chips above the map on a
patternflow-bot Oct 22, 2026
2ea1b3f
web: six pages stop prefetching the home page's 3D code
patternflow-bot Oct 22, 2026
33b467b
web: pages no longer preload fonts their text doesn't use
patternflow-bot Oct 22, 2026
b98361e
web: a wrapping knob on a range other than 0..1 hands the pattern every
patternflow-bot Oct 22, 2026
21d3783
web: a mask over a 0% layer in Pattern Lab gates nothing in the exports
patternflow-bot Oct 22, 2026
896c6d9
docs: changelog for 50 workshop fork PRs
Oct 22, 2026
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
52 changes: 52 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ A pin on the map is one entry in [`web/src/components/sections/InsideGlobe/build

Inside includes builds, projects derived from Patternflow, and places where it is used. Add one entry to `web/src/components/sections/InsideGlobe/builds.ts`: a short `title`, `maker`, public `location`, `date`, `description`, and any external `links`. Photos are optional. Keep existing `id` and `slug` values stable so shared links keep working.

Choose one primary `category`: `builds` for assembled devices and enclosure changes, `projects` for ports and new tools, or `in-use` for installations, performances and other uses. This is separate from `kind`, which preserves the existing build/collaboration relationship and marker style. A maker can have several entries: a new tool and a later exhibition are different records. Link to the maker's own documentation for ongoing updates; a short introduction here is enough. Do not add unannounced work or assume an event happened from a sale or a planned appearance.
Choose one primary `category`: `builds` for assembled devices and enclosure changes, `projects` for ports and new tools, or `in-use` for installations, performances and other uses. This is separate from `kind`, which says what the pin is and picks its marker on the globe: `build`, `collaboration`, `sold` or `showing`, each explained in the comment above `BuildKind`. A collaboration, a sale or a showing names the pin it grew out of in `originId`, and the globe draws a line back to it. Left out, the line goes to the first build in the file. A maker can have several entries: a new tool and a later exhibition are different records. Link to the maker's own documentation for ongoing updates; a short introduction here is enough. Do not add unannounced work or assume an event happened from a sale or a planned appearance.

Classify the subject of the entry, not its surroundings. A completed device photographed in a studio or DJ booth is still a `builds` entry. Use `in-use` when the entry documents actual use in an exhibition, performance or installation; a sale or delivery alone is not enough. Leave a category empty until a qualifying case is available.

Expand Down
2 changes: 1 addition & 1 deletion docs/EDITIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ deliberately re-pinned in the same commit.
feature code that recompiles against a checkout, in-tree or out. Widening
is tail-append only (the rule and its reason are written on the struct);
the compiler surfaces every break at build, and `build.sh all` makes sure
"builds" means all three compositions. The two composition filenames and
"builds" means all five compositions. The two composition filenames and
their macros are the out-of-tree seam - renamed spellings are shimmed, and
shims get deleted only after their consumers migrate.

Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ The interactive guide at [patternflow.work/guide](https://patternflow.work/guide
## Records

- [`investigations/`](investigations/) — dated post-mortems, and the cleanup's plans. `npm run doc-map` in `web/` writes the two lists here: `2026-10-doc-map.csv`, every link in the tree and whether it resolves, and `2026-10-doc-parity.csv`, every Korean/English pair and which side is missing or short
- [`rfc-cleanup.md`](rfc-cleanup.md) and its [progress log](rfc-cleanup-progress.md) — the October 2026 tidy-up before the any-resolution work, done on 16 October. It changed where things live and what CI checks, and nothing the firmware or the site does. §2.9 lists the writing it locked
- [`releases/`](releases/) — every release's changelog section as written, one file each (`vX.Y.Z.md`), back to v1.0.0; `CHANGELOG.md` at the root keeps the three newest in full and links the rest. `v3.0.0-notes.md` and `v3.1.0-notes.md` are long-form notes for two July 2026 releases, beside the v3.0.0 launch checklist; notes since 3.2 are on [GitHub Releases](https://github.com/engmung/Patternflow/releases)
- [`manifesto.md`](manifesto.md) — why Patternflow exists, and (section 6) how we treat each other
- [`images/`](images/), [`media/`](media/) — assets the guides and the site reference
8 changes: 6 additions & 2 deletions docs/REPOSITORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,13 @@ Filenames are lowercase with underscores. Tags are `vX.Y.Z`; the firmware source

The site, the firmware and the release notes hold absolute `blob/main/…` links into this tree, and a pull request that breaks one fails `check:links-absolute`. Before renaming or moving any of these, grep `web/src`, `web/content`, `firmware/patternflow/console` and `firmware/patternflow/features/*/*_index.h`:

- `README.md`, `BUILD_GUIDE.md` (the site links its section anchors — §1, §2, §4, §8, §8.2 and §10 when this was written — so a renamed heading breaks them), `FEATURE_GUIDE.md`, `PATTERN_GUIDE.md`
- `README.md`, `BUILD_GUIDE.md` (the site links its section anchors — §1, §2, §4, §8, §8.2 and §10 when this was written — so a renamed heading breaks them), `FEATURE_GUIDE.md`, `PATTERN_GUIDE.md`, `CHANGELOG.md`, `CONTRIBUTING.md` and `.github/SUPPORT.md` (the issue forms link the last two)
- `docs/AUDIO_GUIDE.md`, `docs/assembly/README.md`, `docs/midi-ableton.md`, `docs/midi-spec.md` (the last two are baked into the Audio edition's console pages)
- `docs/EDITIONS.md`, `docs/rest-api.md`, `firmware/README.md`, `hardware/bom/bom_v3.9.csv`
- `docs/EDITIONS.md`, `docs/rest-api.md`, `docs/osc-spec.md`, `docs/mqtt-spec.md`, `docs/audio-ws-spec.md`, `docs/pfst-v2-spec.md`, `docs/director-midi.md` (the features page links each of these)
- `docs/panel-compatibility.md`, `docs/legacy/BUILD_GUIDE_v2.md`, `docs/LICENSE-SUMMARY.md`, `docs/releases/v2.0.0.md`, `firmware/README.md`, `firmware/CUSTOM_PATTERNS.md`, `hardware/README.md`, `hardware/bom/bom_v3.9.csv`, `tools/patternflow-audio-android/README.md`
- `hardware/case/README.md`, and each folder in `hardware/case/remixes/` with the files in it. The Build panel's case cards link them by name: a README, a `print_layout.3mf`, the mbchars case's `assembly.md` and `bom.md`
- `web/src/app/compliance/` — the `/compliance` URL is printed on the box. Never move, redirect or noindex it.

Folders are linked too. The features page links each feature's folder in `firmware/patternflow/features/`, and the site's Build guide links files in `hardware/case/bed_256mm/`, `hardware/case/bed_330mm/` and `hardware/pcb/`. Every row, with the file the link sits in, is in [`investigations/2026-10-doc-map.csv`](investigations/2026-10-doc-map.csv) under the kind `absolute-blob`. `npm run doc-map` in `web/` writes that list again from the tree as it is.

`.github/scripts/check_links.py` checks the *relative* links in every tracked markdown file and runs on every pull request that touches one. `check:links-absolute` (`web/scripts/doc-map.ts --check absolute`, in `drift.yml`) checks the absolute ones on every pull request, against the tree or the tag a link names.
24 changes: 14 additions & 10 deletions docs/SERVICES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Patternflow Server Services & Worker Management

Patternflow 커뮤니티 웹 서버 및 C++ 펌웨어 웹플래시 컴파일 빌드 워커 서비스 구성과 운영 방법 가이드입니다.
Patternflow 커뮤니티 웹 서버와, 패턴 C++ 헤더를 `.pfm` 모듈로 굽는 빌드 워커 서비스 구성과 운영 방법 가이드입니다.

---

Expand Down Expand Up @@ -32,10 +32,10 @@ RestartSec=3
OOM 킬은 `dmesg -T | grep -i "killed process"` 로 봅니다.

### ② `patternflow-worker.service`
- **역할**: C++ 펌웨어 빌드 워커 (`scripts/build-worker.ts`)
- **설명**: 웹플래시 요청 대기열(`queued`)을 수신하여 `arduino-cli`를 이용해 ESP32-S3 바이너리를 컴파일합니다.
- **역할**: 패턴 모듈 빌드 워커 (`scripts/build-worker.ts`)
- **설명**: 빌드 대기열(`queued`)에서 잡을 하나씩 가져가 헤더마다 `firmware/toolchain/build_module.py`와 Xtensa 컴파일러로 ESP32-S3용 `.pfm` 모듈을 굽습니다. 펌웨어 이미지 통째 빌드는 2026-08-12(`4c13474`)에 끝났고, 그 뒤로 워커는 `arduino-cli`를 부르지 않습니다.
- **위치**: `/etc/systemd/system/patternflow-worker.service`
- **환경변수 중요 사항**: `Environment=PATH`에 `arduino-cli` 설치 경로(`~/.local/bin` 또는 `/usr/local/bin`) 포함 필수
- **환경변수 중요 사항**: 워커는 `python`(다른 이름이면 `PYTHON_PATH`)과 `PF_XTENSA_BIN`이 가리키는 컴파일러(아래 2단계)를 띄웁니다. `Environment=PATH`에는 Python이 있어야 하고, 예전에 넣은 `arduino-cli` 경로는 이제 쓰이지 않습니다.

#### 워커는 격리된 채로 돈다 — `hardening.conf` (2026-09-04)

Expand Down Expand Up @@ -93,9 +93,10 @@ strace로 확인한 전부다: 데이터 디렉터리(DB·WAL·산출물), 워
것으로 재현했다. 두 단계 중 첫째는 끝났다:

1. **시크릿은 유닛 밖 (완료, 2026-09-04).** 워커가 필요로 하는 변수
(`COMMUNITY_ENABLED`, `BUILD_ENABLED`, `BUILD_FQBN`, `COMMUNITY_DB_PATH`)는
root 전용 `/etc/patternflow/worker.env`(0600)에서 `EnvironmentFile=`로
받는다. `.env.local`은 `InaccessiblePaths`로 막으면 워커가 못 뜬다 —
(`COMMUNITY_ENABLED`, `BUILD_ENABLED`, `COMMUNITY_DB_PATH`, 2단계의
`PF_XTENSA_BIN`)는 root 전용 `/etc/patternflow/worker.env`(0600)에서
`EnvironmentFile=`로 받는다. 그날 같이 넣은 `BUILD_FQBN`은 통째 이미지
빌드의 보드 옵션이라 8월 12일 뒤로 읽는 코드가 없다. `.env.local`은 `InaccessiblePaths`로 막으면 워커가 못 뜬다 —
`scripts/loadEnv.ts`의 `existsSync`는 접근 불가 파일에도 `true`를 돌려주고,
그다음 `process.loadEnvFile`이 EACCES에 예외를 던진다. 그래서
`BindReadOnlyPaths=/dev/null:…/.env.local`로 **빈 파일로 보이게** 한다:
Expand Down Expand Up @@ -314,8 +315,11 @@ npm run build:enqueue

## 3. 자주 발생하는 문제 & 조치법 (Troubleshooting)

- **웹플래시 요청이 계속 `queued`에서 안 넘어감**:
- **빌드 요청이 계속 `queued`에서 안 넘어감**:
- `patternflow-worker.service`가 켜져 있는지 확인: `sudo systemctl status patternflow-worker.service`
- 꺼져 있다면 재시작: `sudo systemctl restart patternflow-worker.service`
- **`spawn arduino-cli ENOENT` 에러 발생**:
- `patternflow-worker.service` 파일 내 `PATH` 환경변수에 `arduino-cli` 설치 경로가 올바르게 지정되었는지 확인.
- **빌드 오류가 `The build service's compiler is not available right now. No Xtensa compiler found`로 시작함**:
- 워커가 `xtensa-esp32s3-elf-g++`를 찾지 못했습니다. `/etc/patternflow/worker.env`의 `PF_XTENSA_BIN`이 래퍼 디렉터리(`/etc/patternflow/xtensa-sandbox`)를 가리키는지, 래퍼가 부르는 `~/.arduino15/packages/esp32/tools/esp-x32/2601`이 그대로 있는지 확인.
- 오류 전문은 `npm run build:status -- <BUILD_ID>`의 `--- error ---` 아래에 나옵니다.
- **빌드 오류에 `[cannot run python: spawn python ENOENT]`가 나옴**:
- 유닛의 `PATH`에 `python`이 없습니다. `worker.env`에 `PYTHON_PATH=python3`처럼 실행 파일 이름이나 경로를 넣고 워커를 재시작.
43 changes: 29 additions & 14 deletions web/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
NEXT_PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com

# ── Roadmap ─────────────────────────────────────────────────────────────────
# /api/roadmap reads the repository's open issues from the GitHub API on the
# server. A token raises GitHub's rate limit; the repository is public, so the
# route works without one.
#GITHUB_TOKEN=

# ── Community (self-hosted deployment only) ──────────────────────────────────
# The community runs where this flag is set (the Raspberry Pi / VPS). Leave it
# unset on Vercel — community pages then show a pointer to the community host.
Expand Down Expand Up @@ -36,27 +42,36 @@ NEXT_PUBLIC_COMMUNITY_URL=https://community.patternflow.work
# here or cross-origin sign-in and publishing are rejected.
COMMUNITY_ALLOWED_ORIGINS=https://patternflow.work

# ── Firmware build service (community host with a worker) ────────────────────
# Server side: enables POST /api/community/builds. Needs arduino-cli installed
# and `npm run worker` running. Compiling submitted C++ is arbitrary code
# execution at compile time — keep this off unless the worker's unit carries
# the sandbox in docs/SERVICES.md (no network, read-only system, limits).
# ── Pattern module builds (community host with a worker) ────────────────────
# Server side: enables POST /api/community/builds and the module cache. Needs
# `npm run worker` running, which compiles each pattern header into a .pfm
# module with firmware/toolchain/build_module.py and the Xtensa compiler. It
# has not built whole firmware images since 12 August. Compiling submitted
# C++ is arbitrary code execution at compile time — keep this off unless the
# worker's unit carries the sandbox in docs/SERVICES.md (no network,
# read-only system, limits).
#BUILD_ENABLED=1
# Client side: shows the "Build firmware" buttons. Set both, or neither.
# Client side: shows the deck, "Send to my Patternflow" and Pattern Lab's
# "To hardware". Set both, or neither.
#NEXT_PUBLIC_BUILD_ENABLED=1
# Overrides for the worker (defaults are usually right in a repo checkout):
#FIRMWARE_SRC_DIR=/home/pi/Patternflow/firmware/patternflow
#BUILD_WORK_DIR=/home/pi/patternflow-data/build-worker
#BUILD_ARTIFACT_DIR=/home/pi/patternflow-data/builds
#ARDUINO_CLI_PATH=arduino-cli
#
# BUILD_FQBN — normally leave this unset. The built-in default already pins the
# board options firmware/README.md requires (PSRAM, flash size, partition
# scheme, CDC on boot), and a build is refused if an override drops any of
# them: leaving one out compiles against the board defaults and produces
# firmware that boots but is not the firmware we release.
# To inspect the available options: arduino-cli board details --fqbn esp32:esp32:esp32s3
#BUILD_FQBN=esp32:esp32:esp32s3:PSRAM=opi,FlashSize=16M,PartitionScheme=app3M_fat9M_16MB,CDCOnBoot=cdc,USBMode=hwcdc
# The directory holding xtensa-esp32s3-elf-g++ and the nm beside it. Unset, the
# worker looks where the ESP32 Arduino core installs its compiler
# (ARDUINO_DIRECTORIES_DATA, then ~/.arduino15 and the macOS and Windows
# equivalents), then in PlatformIO (PLATFORMIO_CORE_DIR, else ~/.platformio).
# The Pi points it at the bwrap wrappers in docs/SERVICES.md.
#PF_XTENSA_BIN=/etc/patternflow/xtensa-sandbox
#
# PF_TARGET_ABI — normally leave this unset, which builds descriptor 2 for a
# pattern that reads the absolute knob tier. 1 makes a module that also
# installs on firmware older than v3.5.1, and compiles that tier out: a
# Director show then sets values the pattern cannot read. Changing it changes
# the toolchain revision, so the worker rebakes every public header.
#PF_TARGET_ABI=1

# Moderators — comma-separated USERNAMES (not ids) who may remove other
# people's patterns, posts and comments. Unset means nobody can, which is the
Expand Down
Loading
Loading