Imported from flux3dp/beam-studio (
AGENTS.md). Install upstream withnpx skills add flux3dp/beam-studio. Copyright stays with the author.
AGENTS.md
This file provides guidance to coding agents (Claude Code, Codex) when working with code in this
repository. It is the single source of truth: .claude/CLAUDE.md is a symlink to this file, and
repo-specific agent skills live in .agents/skills/<name>/SKILL.md (.claude/skills is a symlink
to that directory). Edit the real files, never the symlinks.
Windows setup: Git for Windows defaults core.symlinks to false, in which case it checks the
two .claude paths out as plain text files containing the link target — and Claude Code then
silently sees no instructions and no skills. Before cloning, enable Developer Mode
(Settings → System → For developers) and run git config --global core.symlinks true. To repair a
clone that already went wrong:
git config core.symlinks true
del .claude\CLAUDE.md .claude\skills
git checkout HEAD -- .claude
If Developer Mode is unavailable, a directory junction needs no elevation and works the same way:
mklink /J .claude\skills ..\.agents\skills. macOS and Linux need no setup. Codex is unaffected
either way — it reads AGENTS.md and .agents/skills/, which are the real files.
Project Overview
Beam Studio is a companion application for FLUX Beam Series laser cutting/engraving machines. It's a monorepo using Nx with pnpm, providing both Electron desktop and web applications.
Development Commands
# Install dependencies
pnpm install
# Development
pnpm nx run app:dev # Build Electron app for development
pnpm nx run app:start # Start Electron app
pnpm nx run web:start # Start web dev server (http://localhost:8080)
# Building
pnpm nx run app:build # Build Electron app
pnpm nx run web:build # Build web app
# Testing
pnpm nx run core:test # Test core package
pnpm test # Test all projects
pnpm test -u # Test all projects and update snapshots
pnpm test <filename> # Run specific unit test file
pnpm nx run web:cy:dev # Run web E2E tests (Cypress)
# Linting & Type Checking
pnpm lint # Lint all projects
pnpm lint --fix # Lint all projects and fix issues
# Run affected projects (based on git changes)
pnpm nx affected:test # Test only affected projects
pnpm nx affected:lint # Lint only affected projects
Architecture
Monorepo Structure
- apps/app/ - Electron desktop application
- apps/web/ - Web application (PWA)
- packages/core/ - Shared business logic and React components
Technology Stack
- Frontend: React 19.2.4 with TypeScript 5.9.3
- Desktop: Electron 40.1.0
- UI: Ant Design 5.23.2 (with React 19 compatibility patch)
- Routing: React Router 7.13.0
- Graphics: react-konva 19.2.2, @react-three/fiber 9.5.0, Three.js, Canvas APIs
- Drag & Drop: @hello-pangea/dnd 18.0.1
- State Management: Zustand for cross-component state
- Build: Webpack 5, Nx 22.4.5
- Testing: Jest 30.2.0 (unit), Cypress (E2E)
Path Mappings
"@core/*": ["packages/core/src/web/*"]
// For app
"@core/implementations/*": ["apps/app/src/implementations/*"]
// For web
"@core/implementations/*": ["apps/web/src/implementations/*"]
Key Architecture Patterns
- Machine Communication: WebSocket-based via FLUXGhost API
- SVG Processing: Custom SVG editor with laser-specific operations
- State Management: Zustand for cross-component contexts, React hooks for component-local state
- Cross-Platform: Shared core logic between Electron and web apps
- Multi-Language: i18n support for 23 languages
Important Services & Components
- SVGEditor: Main editing canvas (packages/core/src/web/app/components/beambox/SvgEditor/)
- Device Management: packages/core/src/web/helpers/device/
- API Clients: packages/core/src/web/helpers/api/
- Canvas Operations: packages/core/src/web/app/svgedit/
- Undo/Redo: Command pattern via packages/core/src/web/app/svgedit/history/
Coding Conventions
Critical Rules
-
Linting: Do NOT fix lint issues during implementation sessions. Run
pnpm run lintafter completing the implementation to address any lint issues separately. -
Pattern Matching: Prefer
ts-patternoverswitch-casestatements for better type safety and exhaustive matching. Use.exhaustive()by default; use.otherwise()only when the input is truly open-ended. -
State Management: Prefer Zustand for cross-component state and contexts. Use React hooks for component-local state only.
-
React 19 Patterns:
- Use
use(Context)instead ofuseContext(Context)for consuming contexts - Use
<Context value={...}>instead of<Context.Provider value={...}>for context providers - Pass
refas a regular prop instead of usingReact.forwardRef - Use
useSearchParams()hook fromreact-routerfor query parameters
- Use
-
SVG data attributes: Every new persisted
data-*attribute on canvas elements must be whitelisted inpackages/core/public/js/lib/svgeditor/sanitize.js(per element tag — layer-group attributes go in theglist).sanitizeSvgruns on file load, so an unlisted attribute works during the session but is silently stripped when a saved file is reopened.
TypeScript
- Minimize use of
any. Useunknownor proper generics for type-safe code. anyis acceptable at legacy code boundaries but should be avoided in new code.- Prefer
as constobjects over enums for constants.
Async/Error Handling
- Prefer
async/awaitwithtry/catchblocks over promise chains with.catch().
Component Organization
- Simple components: Single file (Component.tsx, Component.module.scss)
- Complex components: Folder structure with index.tsx, styles, tests colocated
Styling
- Primary: Ant Design theming via ConfigProvider and theme tokens
- Secondary: SCSS modules when Ant Design theming is not flexible enough
Props Naming
- Use interface
ComponentNamePropsfor component props - Follow React conventions:
onActionfor callbacks,childrenfor nested content
Helpers vs Utils
- helpers/: Domain-specific logic (device communication, API clients, file operations)
- utils/: Generic utilities colocated with features (e.g.,
svgedit/utils/,components/Feature/utils/)
Zustand Store Organization
- Wide-scope stores: Centralized in
packages/core/src/web/app/stores/ - Feature-specific stores: Colocated with the feature
- Simple stores: Single
.tsfile - Complex stores: Folder with
index.ts,types.ts,utils/
i18n (Internationalization)
Language Files
Location: packages/core/src/web/app/lang/
Key Languages for Development
- en.ts (English) - Primary source of truth
- zh-tw.ts (Traditional Chinese) - Secondary key language
Adding New Translation Keys
- Add keys to
en.tsandzh-tw.tsduring development - Complete all other language files before creating PR
- Keys use nested object structure matching
ILanginterface - Use descriptive, hierarchical key names (e.g.,
alert.confirm,beambox.ai_generate.form.generate)
Formatted Strings
- Prefer
sprintf-jsfor strings with interpolated values, including translated strings.
Electron App Multi-Tab
Multi-Tab Architecture
Multi-tab functionality uses Electron BaseWindow with multiple WebContentsView (apps/app/src/node/tabManager.ts).
IPC Events
All IPC events are defined in @core/app/constants/ipcEvents.ts using the as const pattern with kebab-case values:
import { TabEvents, MenuEvents, MiscEvents } from '@core/app/constants/ipcEvents';
// Usage examples:
communicator.send(TabEvents.AddNewTab);
ipcMain.on(MenuEvents.MenuClick, handler);
communicator.sendSync(MiscEvents.AskForPermission, 'camera');
Available event groups:
TabEvents- Tab management and synchronizationBackendEvents- Backend service statusUpdateEvents- App update lifecycleNetworkEvents- Network testing and IP checksFontEvents- Font discovery and substitutionMenuEvents- Menu interactionsSvgEvents- SVG processingAuthEvents- Authentication (OAuth, account updates)MiscEvents- Miscellaneous (permissions, window events, etc.)TabConstants- Non-event tab configuration (e.g.,maxTab)
Tab State Synchronization
To synchronize data between tabs:
- Send TabEvents from source view via ipcRenderer to main process
- Main process broadcasts to other views via ipcMain
Important Configuration
- Nx Configuration: nx.json - workspace settings and build caching
- TypeScript: tsconfig.base.json - base configuration with path mappings
- ESLint: eslint.config.js - strict linting rules
- Jest: jest.config.ts files in each package
Development Tips
- Use
pnpm test(notpnpm run test) to run the test suite - Use
pnpm nx affected:*commands to only run tasks on changed projects - The web app runs on http://localhost:8080 during development
- Electron app requires external services (FLUXGhost, etc.) for full functionality, but works with limited features when unavailable
- When modifying shared code in packages/core, both apps will be affected
- Use path aliases (@core/*) instead of relative imports for core packages
- When writing class member functions with
this, prefer arrow functions to avoidthisbinding issues - Follow basic accessibility practices: proper labels, focus management, keyboard navigation
Areas Needing Improvement
These areas have been identified as needing standardization or documentation:
- Testing patterns: Mock patterns for external services need standardization
- API patterns: Request/response typing and error handling patterns need documentation
- Performance optimization: Canvas/SVG editor performance patterns to be established
- Security review: Input validation for file imports and machine commands
External Dependencies
The application relies on these external tools:
- FLUXGhost: WebSocket API for machine communication (Python-based, built separately). Full protocol reference lives in that repo:
../fluxghost/docs/architecture.mdand../fluxghost/docs/api/*.md(one doc per endpoint). The command strings andstatusvalues sent frompackages/core/src/web/helpers/api/*are string-matched against fluxghost'scmd_mapping— never rename them unilaterally, and after backend-affecting changes runuv run python tools/ws_smoke.pyin the fluxghost repo (hardware-free, must endALL PASS). - Swiftray: Backend service
- FluxSVG: SVG processing library
- Beamify: SVG to F-code converter