diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..78c6dde --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fdb85f3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Enforce LF for source and text files across platforms +*.js text eol=lf +*.mjs text eol=lf +*.cjs text eol=lf +*.ts text eol=lf +*.json text eol=lf +*.md text eol=lf +*.css text eol=lf +*.html text eol=lf + +# Keep binary files untouched +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.webp binary +*.mp4 binary +*.mp3 binary +*.woff binary +*.woff2 binary +*.ttf binary +*.otf binary \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..740ec94 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,103 @@ +name: CI + +on: + push: + branches: ['**'] # run on pushes to all branches + paths: + - 'src/**' + - 'plugins/**' + - 'examples/**' + - 'tests/**' + - 'package.json' + - 'vite.config.js' + - 'vitest.config.js' + - '.github/workflows/**' + pull_request: + branches: ['**'] # run on PRs against any branch + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + # Primary job: format/lint, webpack build, then tests with coverage. + build-and-test: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js (from .nvmrc) + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install dependencies + run: | + if [ -f package-lock.json ]; then + npm ci + else + npm install + fi + + - name: Prettier check + run: npm run format-check + + - name: ESLint + run: npm run lint + + # Use the webpack build for CI stability (dist via webpack) + - name: Build (webpack) + run: npm run build + + - name: Run tests (with coverage) + run: npm run test:coverage + env: + CI: true + + - name: Upload coverage artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage + path: coverage + if-no-files-found: ignore + + # Secondary job: attempt Vite build with mitigations; doesn't fail the PR if it breaks. + vite-build-linux: + runs-on: ubuntu-24.04 + continue-on-error: true + needs: build-and-test + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js (from .nvmrc) + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install dependencies + run: | + if [ -f package-lock.json ]; then + npm ci + else + npm install + fi + + - name: Diagnostics (platform and rollup) + run: | + node -e "console.log('platform:', process.platform, 'arch:', process.arch, 'node:', process.version)" + npm ls rollup @rollup/rollup-linux-x64-gnu vite || true + + # Workaround: ensure Linux native binary is present. Harmless if already resolved. + - name: Ensure rollup native linux package + run: npm i -D @rollup/rollup-linux-x64-gnu@^4 || true + + - name: Vite build (library) + run: npm run build:vite + env: + # Ask rollup to use JS fallback if native optional dep is still missing + ROLLUP_SKIP_NODEJS_NATIVE: '1' diff --git a/.gitignore b/.gitignore index b512c09..d478d64 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -node_modules \ No newline at end of file +node_modules +dist +.idea/ +coverage/ +.eslintcache \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..9ddb512 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,2 @@ +# Only format and lint what's staged (fast) +npx lint-staged diff --git a/.lintstagedignore b/.lintstagedignore new file mode 100644 index 0000000..4bf8391 --- /dev/null +++ b/.lintstagedignore @@ -0,0 +1,5 @@ +examples/vite-artoolkit/vendor/** +examples/vite-artoolkit/data/** +*.dat +*.hiro +*.map diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..59ba107 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.21.1 \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 1078082..847977a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,7 @@ types -dist \ No newline at end of file +dist +examples/vite-artoolkit/vendor/** +examples/vite-artoolkit/data/** +*.dat +*.hiro +*.map diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..7275e3d --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all", + "semi": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/README.md b/README.md index 546d33c..240a5ed 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,261 @@ # AR.js-core -An attempt to convert the Ar.js threex library into an agnostic library that can be used with any 3D library. \ No newline at end of file +An attempt to convert the Ar.js threex library into an agnostic library that can be used with any 3D library. + +## New: ECS Architecture + +AR.js Core now includes a modern Entity-Component-System (ECS) architecture with a plugin system! This provides: + +- Modular design with a clean plugin system +- Data-oriented ECS for efficient processing +- Event-driven architecture with pub/sub messaging +- Backward compatible with existing Source and Profile APIs + +### Quick Start with ECS + +```javascript +import { Engine, CaptureSystem, SOURCE_TYPES } from 'ar.js-core'; +import { webcamPlugin } from './plugins/source/webcam.js'; +import { defaultProfilePlugin } from './plugins/profile/default-policy.js'; + +// Create engine and register plugins +const engine = new Engine(); +engine.pluginManager.register(webcamPlugin.id, webcamPlugin); +engine.pluginManager.register(defaultProfilePlugin.id, defaultProfilePlugin); + +// Enable profile plugin (computes capability-based profile) +await engine.pluginManager.enable(defaultProfilePlugin.id, engine.getContext()); + +// Initialize webcam capture +await CaptureSystem.initialize( + { + sourceType: SOURCE_TYPES.WEBCAM, + sourceWidth: 640, + sourceHeight: 480, + }, + engine.getContext(), +); + +// Start the engine +engine.start(); +``` + +## Frame Pump + Video Viewport: streaming frames to detection plugins + +Detection plugins (e.g., ArtoolkitPlugin) expect frames to arrive as `ImageBitmap` via `engine:update`. The webcam source plugin provides a playing `