# Adapter Implementation Source: https://docs.elata.bio/adapter-implementation Build a device adapter that plugs into BleTransport and emits stable headband frames. Once your protocol inventory is complete, build the adapter. The goal is to isolate device-specific BLE and packet logic while preserving the shared Elata transport contract for apps. ## Recommended Shape For browser BLE integrations, the adapter should satisfy the `BleDeviceLike` shape expected by `@elata-biosciences/eeg-web-ble`. That means the device layer handles discovery, session setup, subscription, and packet decoding, while `BleTransport` handles the app-facing transport surface. ## Implementation Order Define the `requestDevice` filters and any optional services required to find the device cleanly in the browser picker. Connect to GATT, resolve characteristics, and do any startup writes that are required before streaming can begin. Turn vendor packets into `number[][]` where each row is one time step and the row width matches `numEegChannels`. Expose `samplingRate`, `eegNames`, `numEegChannels`, and related device metadata accurately. Unsubscribe, stop the stream safely, and release the session without leaking resources. ## Minimal Adapter Skeleton ```ts theme={null} import type { BleDeviceLike } from "@elata-biosciences/eeg-web-ble"; export class VendorBleDevice implements BleDeviceLike { isAthena = false; samplingRate = 250; eegNames = ["CH1", "CH2"]; numEegChannels = 2; opticsChannelCount = 0; getBoardInfo() { return { device_name: "VENDOR_DEVICE" }; } getCharacteristicInfo() { return { characteristics: [] }; } async prepareSession() { // Connect to GATT, resolve characteristics, and initialize streaming state } async releaseSession() { // Tear down subscriptions and release the browser session } async startStream(eegCb, _ppgCb) { // Subscribe to notifications and emit decoded EEG rows eegCb([[0, 0]]); } async stopStream() { // Stop device streaming and unsubscribe } } ``` ## What the Adapter Must Own | Responsibility | Adapter owns it? | | ---------------------------------------- | ------------------------------------- | | Device discovery | yes | | GATT connection and characteristic setup | yes | | Packet decoding | yes | | Accurate metadata | yes | | App-facing transport lifecycle | usually through `BleTransport` | | Normalized frame delivery to apps | through the shared transport contract | ## Packet Decoding Rules Keep the decoder boring and deterministic. | Rule | Why it matters | | ------------------------------------ | ----------------------------------------------- | | Reject malformed packets early | Prevents bad rows from reaching apps | | Preserve channel order | Keeps downstream features and models consistent | | Batch rows only when needed | Avoids hidden latency and timestamp confusion | | Track packet counters when available | Helps detect drops or corruption | | Separate EEG from aux logic cleanly | Makes debugging and testing easier | ## Session Lifecycle Rules Your adapter should make these transitions unsurprising: | Stage | Good behavior | | -------- | ----------------------------------------------------- | | Discover | only matching devices are shown | | Connect | required services and characteristics resolve clearly | | Start | stream begins once, without duplicate subscriptions | | Stop | notifications stop cleanly | | Release | the session can be started again later | ## Reliability Notes `startStreaming()` is the safest default for app consumers because it combines connect and start. Your adapter should still make the underlying `connect()` and `start()` steps reliable on their own. If the device exposes auxiliary signals such as PPG, optics, IMU, or battery, map them only when the semantics are clear. Do not force Muse-specific assumptions onto non-Muse hardware. ## Related Docs * [EEG BLE Getting Started](/sdk/eeg-web-ble/getting-started) * [Transport Contract](./transport-contract) * [Testing and Validation](./testing-and-validation) * [Muse Device](/sdk/eeg-web-ble/muse-device) ## Next Turn the adapter into a reliable transport under real failure conditions. Package the integration with the docs and caveats other teams need. # List activity Source: https://docs.elata.bio/api-reference/apps/activity /api-reference/openapi.yaml GET /apps/{tokenAddress}/activity Buys, sells, and lifecycle events for an app, newest first. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Get app Source: https://docs.elata.bio/api-reference/apps/get /api-reference/openapi.yaml GET /apps/{tokenAddress} Returns detailed information for a single app, including social links, team, and artifacts. # List holders Source: https://docs.elata.bio/api-reference/apps/holders /api-reference/openapi.yaml GET /apps/{tokenAddress}/holders Paginated list of app token holders, ranked by balance. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # List apps Source: https://docs.elata.bio/api-reference/apps/list /api-reference/openapi.yaml GET /apps Returns all apps with metadata. Supports filtering and cursor pagination. # Search apps Source: https://docs.elata.bio/api-reference/apps/search /api-reference/openapi.yaml GET /apps/search Full-text search across name, symbol, and description. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # App snapshot Source: https://docs.elata.bio/api-reference/market/app /api-reference/openapi.yaml GET /market/apps/{tokenAddress} Token price, market cap, FDV, 24h volume, holders, and curve progress for a single app. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # OHLCV candles Source: https://docs.elata.bio/api-reference/market/candles /api-reference/openapi.yaml GET /market/apps/{tokenAddress}/candles OHLCV candle series for an app token. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Bonding curve state Source: https://docs.elata.bio/api-reference/market/curve /api-reference/openapi.yaml GET /market/apps/{tokenAddress}/curve Reserves, current price, slope, and graduation threshold for an app's bonding curve. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # ELTA snapshot Source: https://docs.elata.bio/api-reference/market/elta /api-reference/openapi.yaml GET /market/elta Extended ELTA price snapshot with 24h change and source attribution. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Leaderboard Source: https://docs.elata.bio/api-reference/market/leaderboard /api-reference/openapi.yaml GET /market/leaderboard Top apps ranked by 24h volume, market cap, or holder growth. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Get prices (legacy) Source: https://docs.elata.bio/api-reference/market/prices /api-reference/openapi.yaml GET /prices Current ELTA price data used by the App Store UI. # API Reference Source: https://docs.elata.bio/api-reference/overview REST API for the Elata App Store at app.elata.bio. The Elata App Store exposes a REST API at `https://app.elata.bio/api`. This tab is the source of truth for that surface — every page is generated from a single OpenAPI 3.1 spec at [`api-reference/openapi.yaml`](https://github.com/elata-biosciences/docs/blob/main/api-reference/openapi.yaml). It is the API surface third-party builders need to discover apps, run launch preflight, render market widgets, show user portfolios, surface claimable rewards, and bootstrap SDKs against the right contracts. For the higher-level integration narrative (iframe embedding, on-chain reads, transaction patterns), see [Builders → API Overview](/builders/api-overview). *** ## Status legend Every operation in this reference carries an `x-elata-status`: | Status | Meaning | | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | | **stable** | Implemented today on `app.elata.bio/api`. Safe to depend on. | | **proposed** | Designed in the spec but **not yet implemented**. The spec is the contract the backend will build against. Subject to change. | | **planned** | Acknowledged but not yet designed. Reserved namespace. | The currently `stable` operations are: * `GET /apps` * `GET /apps/{tokenAddress}` * `GET /prices` Everything else in this tab is `proposed`. *** ## Base URL ``` https://app.elata.bio/api ``` *** ## Authentication Most reads are public. Personalized endpoints under **Portfolio** and **Rewards** require a SIWE-issued JWT bearer token. ```http theme={null} Authorization: Bearer ``` The token is obtained via [Sign-In With Ethereum](https://eips.ethereum.org/EIPS/eip-4361) against `app.elata.bio`. The JWT's `sub` claim is the wallet address; requests whose path `{address}` does not match the `sub` are rejected. *** ## Rate limits | Endpoint class | Limit | | -------------- | ----------- | | Read endpoints | 100 req/min | | Heavy queries | 10 req/min | For heavy on-chain reads, bring your own RPC provider in production (Alchemy, Infura, QuickNode). *** ## Sections Discovery, detail, search, holders, activity. Validate a launch before sending a transaction. Prices, candles, bonding-curve state, leaderboards. Per-wallet holdings, history, P\&L. Claimable rewards, programs, claim payloads. Runtime config for SDKs and AI agents. *** ## On-chain interfaces For Solidity contract interfaces, ABIs, and deployed addresses: * [elata-protocol](https://github.com/elata-biosciences/elata-protocol) — Solidity source and deployment scripts * [elata-appstore](https://github.com/elata-biosciences/elata-appstore) — Frontend reference, including ABIs in `src/abi/` * [Resources → Smart Contracts](/resources/smart-contracts) — current deployed addresses # Get portfolio Source: https://docs.elata.bio/api-reference/portfolio/get /api-reference/openapi.yaml GET /portfolio/{address} Aggregate portfolio for a wallet: ELTA, veELTA, app token holdings, USD value, and unrealized P&L. **Status: proposed.** Requires a SIWE-issued bearer token whose `sub` matches `{address}`. # Portfolio history Source: https://docs.elata.bio/api-reference/portfolio/history /api-reference/openapi.yaml GET /portfolio/{address}/history Trade and transfer history for a wallet, cursor-paginated. **Status: proposed.** Requires a SIWE-issued bearer token whose `sub` matches `{address}`. # List positions Source: https://docs.elata.bio/api-reference/portfolio/positions /api-reference/openapi.yaml GET /portfolio/{address}/positions Per-app token positions for a wallet. **Status: proposed.** Requires a SIWE-issued bearer token whose `sub` matches `{address}`. # Validate launch Source: https://docs.elata.bio/api-reference/preflight/launch /api-reference/openapi.yaml POST /preflight/launch Validates a candidate app payload against current launch requirements before any transaction is sent. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Check name Source: https://docs.elata.bio/api-reference/preflight/name-available /api-reference/openapi.yaml GET /preflight/name-available Returns whether a candidate app name is available. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Get requirements Source: https://docs.elata.bio/api-reference/preflight/requirements /api-reference/openapi.yaml GET /preflight/requirements Current launch requirements (minimum ELTA, fee schedule, image dimensions, metadata schema). **Status: proposed.** Designed to mirror `/apps/build/launch-requirements` so the live UI and the docs share a single source of truth. # Check symbol Source: https://docs.elata.bio/api-reference/preflight/symbol-available /api-reference/openapi.yaml GET /preflight/symbol-available Returns whether a candidate app token symbol is available. **Status: proposed.** This endpoint is designed here but not yet implemented on `app.elata.bio/api`. # Claude Code Source: https://docs.elata.bio/apps/ai-tools/claude-code Use Claude Code to build tokenized apps with the Elata protocol and Biometric SDK. ## Overview Claude Code can help you build Elata apps by generating frontend code, integrating SDK packages, and interacting with protocol contracts. This guide covers setup and key workflows. *** ## Setup 1. Install Claude Code globally: ```bash theme={null} npm install -g @anthropic-ai/claude-code ``` 2. Navigate to your project directory and run: ```bash theme={null} claude ``` 3. Create a `CLAUDE.md` file in your project root with the context below. *** ## CLAUDE.md Template Create this file at the root of your project to give Claude Code context about Elata development: ```markdown theme={null} # Project Context This is an Elata app built on the Elata protocol. ## Key References - Protocol docs: https://docs.elata.bio/apps/what-are-elata-apps - SDK docs: https://docs.elata.bio/sdk/overview - App store: https://app.elata.bio ## SDK Packages - `@elata-biosciences/rppg-web` - Camera-based heart rate (primary integration) - `@elata-biosciences/eeg-web` - EEG signal processing - `@elata-biosciences/eeg-web-ble` - Web Bluetooth for Muse headsets - `@elata-biosciences/create-elata-demo` - App scaffolder ## Protocol Contracts - AppFactory: deploys app token stacks - AppRegistry: on-chain app metadata - AppBondingCurve: constant-product price discovery - FeeRouterV2: fee routing to treasury and contributors - ContributorSplit: pull-based contributor payouts ## Stack - Frontend: React + Vite - Biosignals: Elata SDK (WASM) - Contracts: Solidity (Foundry) - Chain: Ethereum / Base ## Writing Standards - No em-dashes - Practical, concise code - Use TypeScript ``` *** ## Key Workflows ### Scaffold a New App Ask Claude Code to scaffold using the Elata CLI: ```text theme={null} > Scaffold a new rPPG app using create-elata-demo ``` ### Integrate the Biometric SDK ```text theme={null} > Add camera-based heart rate to my app using @elata-biosciences/rppg-web. > Use createRppgSession with auto backend and diagnostics. ``` ### Connect to Protocol Contracts ```text theme={null} > Add a component that reads the current bonding curve price for my app token. > Use ethers.js to call AppBondingCurve.getPrice(). ``` ### Build Tournament UI ```text theme={null} > Create a tournament listing page that shows active tournaments from the > TournamentFactory contract and lets users join with their app tokens. ``` *** ## Tips Point Claude Code at the SDK docs (`docs.elata.bio/sdk/overview`) and protocol docs (`docs.elata.bio/apps/build/overview`) when asking it to generate integration code. It produces better results with explicit documentation references. * Start with `create-elata-demo` to get a working scaffold, then iterate with Claude Code * Ask Claude Code to explain SDK code before modifying it * Use the `--template rppg` flag for camera apps, `--template eeg` for EEG apps *** ## Next What the protocol gives builders Biometric SDK packages # Cursor Source: https://docs.elata.bio/apps/ai-tools/cursor Use Cursor to build tokenized apps with the Elata protocol and Biometric SDK. ## Overview Cursor's AI features can accelerate Elata app development. This guide covers project rules setup and key workflows for building with the protocol and SDK. *** ## Setup 1. Install Cursor from [cursor.sh](https://cursor.sh) 2. Open your Elata project 3. Create `.cursor/rules.md` with the template below *** ## Cursor Rules Template Create `.cursor/rules.md` in your project root: ```markdown theme={null} # Elata Development Rules ## Project Context This is an Elata app built on the Elata protocol with biometric SDK integration. ## Key References - Protocol docs: https://docs.elata.bio/apps/what-are-elata-apps - SDK docs: https://docs.elata.bio/sdk/overview - App store: https://app.elata.bio ## SDK Packages - `@elata-biosciences/rppg-web`: Camera-based heart rate (createRppgSession) - `@elata-biosciences/eeg-web`: EEG signal processing (initEegWasm, band_powers) - `@elata-biosciences/eeg-web-ble`: Web Bluetooth headband transport (BleTransport) - `@elata-biosciences/create-elata-demo`: App scaffolder ## Protocol Architecture - AppFactory: deploys app token stacks (10M supply, 50/25/25 split) - AppBondingCurve: constant-product price discovery, graduates at 42k ELTA - FeeRouterV2: routes fees to treasury (20%) and contributors (80%) - ContributorSplit: pull-based payout to named contributors ## Code Standards - TypeScript, React, Vite - No em-dashes in docs or comments - Use createRppgSession for browser rPPG (not raw RppgProcessor) - Use BleTransport.startStreaming() for BLE (not separate connect/start) - Initialize WASM before using SDK analysis functions ``` *** ## Key Workflows ### Scaffold and Extend Start with a scaffold, then use Cursor to extend: ```bash theme={null} pnpm create @elata-biosciences/elata-demo my-app -- --template rppg cd my-app pnpm install ``` Open in Cursor and ask it to add features on top of the scaffold. ### SDK Integration Patterns When asking Cursor to integrate the SDK, reference the specific entry points: * **rPPG:** `createRppgSession({ video, backend: "auto", faceMesh: "off" })` * **EEG:** `initEegWasm()` then `band_powers(samples, sampleRate)` * **BLE:** `new BleTransport({ deviceOptions: { athenaDecoderFactory } })` ### Contract Interaction Ask Cursor to generate contract interaction code by providing the contract name and method: * Read bonding curve state: `AppBondingCurve.getReserves()` * Check app status: `AppRegistry.getApp(appId)` * Join tournament: `Tournament.join(entryFee)` *** ## Tips Add the Elata SDK docs and protocol docs as documentation sources in Cursor's settings. This improves code generation quality for SDK-specific patterns. *** ## Next What the protocol gives builders Biometric SDK packages # Windsurf Source: https://docs.elata.bio/apps/ai-tools/windsurf Use Windsurf to build tokenized apps with the Elata protocol and Biometric SDK. ## Overview Windsurf's AI coding features work well for building Elata apps. This guide covers workspace rules setup and key workflows. *** ## Setup 1. Install Windsurf from [windsurf.ai](https://windsurf.ai) 2. Open your Elata project 3. Create `.windsurf/rules.md` with the template below *** ## Windsurf Rules Template Create `.windsurf/rules.md` in your project root: ```markdown theme={null} # Elata Development Rules ## Project Context This is an Elata app built on the Elata protocol with biometric SDK integration. ## Key References - Protocol docs: https://docs.elata.bio/apps/what-are-elata-apps - SDK docs: https://docs.elata.bio/sdk/overview ## SDK Packages - `@elata-biosciences/rppg-web`: Camera-based rPPG (createRppgSession) - `@elata-biosciences/eeg-web`: EEG processing (initEegWasm, band_powers) - `@elata-biosciences/eeg-web-ble`: Web Bluetooth (BleTransport) ## Protocol Contracts - AppFactory: deploys token stacks - AppBondingCurve: constant-product price discovery - FeeRouterV2: fee routing (80% contributors, 20% treasury) - ContributorSplit: pull-based contributor payouts ## Standards - TypeScript, React, Vite - Use createRppgSession for rPPG (not raw processor) - Use BleTransport.startStreaming() for BLE - No em-dashes ``` *** ## Key Workflows ### Getting Started Scaffold an app first, then open in Windsurf: ```bash theme={null} pnpm create @elata-biosciences/elata-demo my-app -- --template rppg cd my-app && pnpm install ``` ### Common Prompts **Add biometric features:** * "Add camera heart rate monitoring using createRppgSession from rppg-web" * "Add EEG band power visualization using eeg-web" * "Connect to a Muse headset using BleTransport from eeg-web-ble" **Add protocol features:** * "Show the current bonding curve price from AppBondingCurve" * "Create a tournament join button that calls Tournament.join()" * "Display the user's staking position from the StakingVault" *** ## Tips Reference the SDK docs at `docs.elata.bio/sdk/overview` in your prompts when asking Windsurf to generate integration code. *** ## Next What the protocol gives builders Biometric SDK packages # App Lifecycle Source: https://docs.elata.bio/apps/app-lifecycle From registration through bonding curve to graduation and live DEX trading. ## Overview Every Elata app follows the same lifecycle: register, launch a token, trade on a bonding curve, graduate to a DEX pair, and operate with full community tools. ```mermaid theme={null} flowchart LR REG["Register App"] --> LAUNCH["Launch Token"] LAUNCH --> CURVE["Bonding Curve"] CURVE --> GRAD["Graduation"] GRAD --> DEX["DEX Trading"] DEX --> OPS["Operate"] ``` *** ## Phase A: Registration Register your app by calling `AppFactory` with metadata and a Safe wallet address. * **Cost:** 10 ELTA registration fee * **What happens:** App appears in the store immediately (without a token) * **Requirements:** A Safe multisig wallet to control the app Your app exists on-chain and is visible in the app store, but has no token yet. *** ## Phase B: Token Launch Deploy the full token stack by sending 100 ELTA as the bonding curve seed. * **Cost:** 100 ELTA seed (total with registration: 110 ELTA) * **What gets deployed:** App Token (10M supply), Bonding Curve, Staking Vault, Vesting Wallet, Ecosystem Vault **Token distribution:** | Destination | Share | Amount | | --------------- | ----- | ---------------- | | Bonding curve | 50% | 5,000,000 tokens | | Team vesting | 25% | 2,500,000 tokens | | Ecosystem vault | 25% | 2,500,000 tokens | After deployment, the bonding curve enters `PENDING` state. *** ## Bonding Curve Once activated, the curve enters `ACTIVE` state and trading begins. **How it works:** * Constant-product formula: `reserveELTA * reserveToken = k` * Price rises as more ELTA is deposited; falls as tokens are sold back * 1% trading fee on each trade (configurable by governance) **Early access:** For the first 6 hours, buyers need 100 XP to participate. This prevents sniping. **Lifecycle states:** | State | Description | | ----------- | ------------------------------------- | | `PENDING` | Deployed, not yet activated | | `ACTIVE` | Trading is live | | `GRADUATED` | Reserves hit the graduation threshold | | `CANCELLED` | App cancelled before graduation | *** ## Graduation Graduation triggers when ELTA reserves in the bonding curve reach **42,000 ELTA**. When graduation happens: Remaining tokens and ELTA reserves are paired on a DEX. The liquidity position is locked for **730 days** (2 years). All trading moves from the bonding curve to the DEX pair. *** ## Post-Graduation After graduation, your app token trades freely on the DEX. The protocol continues to handle: * **Fee routing** through the FeeRouter * **Transfer tax** (up to 2%, LP-keyed) * **Contributor payouts** via the ContributorSplit contract * **Community tools** (tournaments, items, staking) *** ## Next What you need to launch Price discovery mechanics Token design and distribution # App Metadata and Listing Source: https://docs.elata.bio/apps/build/app-metadata How your app appears in the store, metadata standards, and image requirements. ## Store Listing Fields When you register an app, you provide metadata that appears in the app store: | Field | Required | Description | | ------------ | -------- | ------------------------------------- | | Name | Yes | Display name for your app | | Description | Yes | Short summary shown on the store card | | Logo | Yes | Square image for the app icon | | Category | Yes | Focus, Gaming, Wellness, or Research | | Website | No | External link to your app | | Social links | No | Twitter, Discord, GitHub, etc. | | Team members | No | Public team display | *** ## NFT Metadata Standard App tokens and in-app items follow ERC-721 with ERC-4906 metadata update signaling. This means metadata changes emit on-chain events that marketplaces can listen to for auto-refresh. Example metadata JSON: ```json theme={null} { "name": "My Elata App Token", "description": "Access token for the My App ecosystem", "image": "ipfs://QmExample.../logo.png", "external_url": "https://myapp.example.com", "attributes": [ { "trait_type": "Category", "value": "Gaming" }, { "trait_type": "Version", "value": "1.0" } ] } ``` *** ## Image Requirements | Asset | Recommended Size | Format | | ------------ | ---------------- | ----------- | | App logo | 500x500px | PNG or SVG | | Token image | 1000x1000px | PNG | | Store banner | 1200x630px | PNG or WebP | Use square images for logos and token images. Non-square images will be cropped in the store. *** ## Storage Options | Option | Best For | Notes | | -------------------------- | ----------- | --------------------------------------------------- | | IPFS (Pinata, NFT.Storage) | Production | Recommended. Decentralized and permanent. | | Arweave | Production | Alternative permanent storage. | | Centralized HTTP | Development | Fine for testing. Do not use for production tokens. | Once metadata is referenced on-chain, changing the underlying content at the same URI does not trigger an ERC-4906 update. Use `setTokenURI` to point to new content and emit the update event. *** ## Updating Metadata After launch, your Safe can update app metadata by calling the appropriate registry function. Token metadata updates follow the ERC-4906 pattern: set a new URI and emit the `MetadataUpdate` event so marketplaces and indexers refresh. *** ## Next Deploy your app on-chain What to do after launch Create in-app items # Launch Requirements Source: https://docs.elata.bio/apps/build/launch-requirements Everything you need before deploying an app on the Elata protocol. ## What You Need Before launching, make sure you have: Every app is controlled by a Safe. Create one at [safe.global](https://safe.global) with your team members as signers. 10 ELTA for registration + 100 ELTA for the bonding curve seed. Both are paid to the protocol during launch. Name, description, logo, social links. See [App Metadata and Listing](/apps/build/app-metadata) for the full spec. Phase A registers your app (10 ELTA). Phase B deploys the token stack (100 ELTA). See [App Lifecycle](/apps/app-lifecycle) for details. *** ## Cost Breakdown | Item | Cost | What It Does | | ------------------ | ------------ | -------------------------------------------------- | | Registration fee | 10 ELTA | Registers app metadata and Safe in AppRegistry | | Bonding curve seed | 100 ELTA | Seeds the initial ELTA reserve for price discovery | | **Total** | **110 ELTA** | Full launch | The registration fee is non-refundable. The bonding curve seed becomes part of the trading reserve and is not directly withdrawable. *** ## Safe Wallet Setup The Safe multisig is the owner of your app on-chain. It controls: * Contributor split configuration * Team vesting wallet * Ecosystem vault * App metadata updates Set up your Safe before starting the launch process. Add all core team members as signers with an appropriate threshold (e.g., 2-of-3 for a small team). *** ## Network Options | Network | Gas Cost | Use Case | | ---------------------- | ------------------ | ----------------------- | | Ethereum Mainnet | \~\$260 at 20 gwei | Production | | Base | \~\$2-5 | Production (lower cost) | | Sepolia / Base Sepolia | Free | Testing | Start on a testnet to validate your launch flow before spending real ELTA. Use the faucet to get test tokens. *** ## Next Step-by-step launch flow Metadata fields and listing Full lifecycle overview # Launch Your App Source: https://docs.elata.bio/apps/build/launch-your-app Step-by-step launch flow using current protocol contracts. ## Overview Launching an Elata app is a two-phase process. Phase A registers your app. Phase B deploys the full token stack. **Total cost:** 110 ELTA (10 ELTA registration + 100 ELTA bonding curve seed). *** ## Phase A: Register (10 ELTA) Register your app metadata and Safe wallet address through the AppFactory. 1. Prepare your Safe multisig wallet 2. Approve 10 ELTA for the AppFactory contract 3. Call `registerApp()` with metadata and your Safe address 4. Your app appears in the store immediately (no token yet) *** ## Phase B: Deploy Token Stack (100 ELTA) Deploy the full token infrastructure by seeding the bonding curve. 1. Approve 100 ELTA for the AppFactory contract 2. Call `deployToken()` from your Safe 3. The protocol deploys: App Token, Bonding Curve, Staking Vault, Vesting Wallet, Ecosystem Vault **What gets deployed:** | Contract | Purpose | | ----------------- | ----------------------------------------- | | App Token | ERC-20 with 10M supply | | Bonding Curve | Constant-product price discovery | | Staking Vault | Token holder staking | | Vesting Wallet | 25% team allocation with vesting schedule | | Ecosystem Vault | 25% ecosystem reserves | | Contributor Split | Revenue distribution to contributors | *** ## Post-Launch State After Phase B, your bonding curve is in `PENDING` state. Activate it to begin trading. The curve moves through: `PENDING` to `ACTIVE` to `GRADUATED` (or `CANCELLED`). Creator allocation (team vesting) is subject to vesting schedules. Tokens vest linearly over the configured period. *** ## Important * Transfer tax (up to 2%) applies to token transfers that touch allowlisted LPs * Fee routing begins immediately when trading starts * The 100 ELTA seed becomes part of the bonding curve reserve and is not directly withdrawable *** ## Next Store listing and metadata What to do after launch How price discovery works # Builder Overview Source: https://docs.elata.bio/apps/build/overview What the protocol gives you and what you avoid building yourself. ## What You Get The Elata protocol provides a ready-made launch and fee-routing stack for tokenized applications. As a builder, you deploy your app through the protocol and receive: * An ERC-20 app token with 10M supply * A bonding curve for price discovery * Fee routing through FeeRouter and ContributorSplit * A staking vault for token holders * Team vesting and ecosystem vaults * In-app item (NFT) infrastructure * Tournament and competition tooling *** ## What You Avoid Building Yourself | Component | Protocol Handles It | | ------------------------------- | ---------------------------------------------- | | Token creation and distribution | AppFactory deploys with 50/25/25 split | | Price discovery | Constant-product bonding curve with graduation | | Liquidity provisioning | Automated DEX pair creation and LP lock | | Fee collection and routing | FeeRouter splits to treasury and contributors | | Revenue distribution | ContributorSplit with pull-based claims | *** ## Protocol Defaults | Parameter | Value | | ----------------- | ---------------------------- | | Launch cost | 110 ELTA (10 fee + 100 seed) | | Token supply | 10,000,000 per app | | Curve allocation | 50% (5M tokens) | | Team vesting | 25% (2.5M tokens) | | Ecosystem vault | 25% (2.5M tokens) | | Graduation target | 42,000 ELTA in reserves | | LP lock duration | 730 days | *** ## Core Contracts | Contract | Purpose | | ------------------ | ---------------------------------------------------- | | `AppFactory` | Deploys app token stack | | `AppRegistry` | On-chain mapping of appId to ownerSafe, token, curve | | `AppToken` | ERC-20 token per app | | `AppBondingCurve` | Constant-product price discovery | | `FeeRouterV2` | Single routing surface for all fee kinds | | `ContributorSplit` | Pull-based payout for app contributors | *** ## Next What you need to launch Step-by-step launch flow How fees are routed # Post-Launch Checklist Source: https://docs.elata.bio/apps/build/post-launch-checklist What to do after deploying your app token on the Elata protocol. ## Immediate Actions After Phase B deployment, the curve starts in `PENDING` state. Activate it to begin trading. Early access gating (100 XP required) applies for the first 6 hours. Check the app store at [app.elata.bio](https://app.elata.bio) to confirm metadata, logo, and description appear correctly. Configure the ContributorSplit contract through your Safe. Add team members and set their share percentages. This determines how app revenue is distributed. Add Twitter, Discord, GitHub, and team member info to your app listing so users can find your community. *** ## Launch Week The first week sets the tone for your app's community. Focus on visibility and first purchases. * **Announce** on Twitter and Discord with your app store link * **Distribute XP** to early supporters so they can participate during the early access window * **Run an inaugural tournament** to drive engagement and token activity * **Create an access pass item** if your app has gated features * **Monitor holder distribution** to ensure healthy early spread *** ## Ongoing Operations After the initial launch, shift focus to sustained growth: * **Track graduation progress** toward the 42,000 ELTA threshold * **Run regular tournaments** to maintain engagement * **Adjust contributor splits** as your team grows * **Review analytics** for holder concentration and trading volume *** ## Next Community growth playbook Run competitive events Track app health metrics # Choose Your Path Source: https://docs.elata.bio/apps/choose-your-path Whether you want to build an app or participate as a user, start here. ## For Builders You want to launch and operate a tokenized app on Elata. The protocol handles token economics, fee routing, and community infrastructure. What builders get and what you avoid building Prerequisites: Safe wallet, ELTA, metadata Step-by-step launch flow What to do after launch *** ## For Users You want to discover apps, buy tokens, stake, and participate in governance. Find and evaluate apps How buying and trading works Staking and rewards Lock ELTA for voting power *** ## Not Sure? Start with [What Are Elata Apps?](/apps/what-are-elata-apps) for the big picture, or jump to [What You Can Build](/apps/what-you-can-build) to see real examples. # App Tokens Source: https://docs.elata.bio/apps/design/app-tokens Token creation, distribution, transfer tax, and lifecycle for Elata apps. ## How App Tokens Work Each Elata app receives its own ERC-20 token with a fixed supply of **10,000,000 tokens**. The token is created during Phase B of the [launch process](/apps/build/launch-your-app). *** ## Distribution | Destination | Share | Amount | Purpose | | ------------------- | ----- | --------- | ---------------------------------------- | | Bonding curve | 50% | 5,000,000 | Liquidity for price discovery | | Team vesting wallet | 25% | 2,500,000 | Team incentives, vests linearly | | Ecosystem vault | 25% | 2,500,000 | Community incentives, controlled by Safe | *** ## Design Purposes App tokens serve three main functions: 1. **Bootstrap distribution:** the bonding curve makes tokens available to early supporters at a price that rises with demand 2. **App incentives:** builders use tokens for tournaments, items, staking, and community rewards 3. **Fee routing:** trading fees and transfer taxes flow through FeeRouter to the treasury and contributor split *** ## Transfer Tax App tokens support an optional transfer tax of up to 2% (protocol-wide cap). The tax applies only when: * Neither the sender nor the receiver is tax-exempt * The transfer touches an allowlisted liquidity pool (LP-keyed) Transfers between regular wallets that do not involve an LP are not taxed. Transfer tax is not retroactive. It applies from the moment it is configured. Builders configure it through their Safe. *** ## Token Lifecycle 1. **Phase B deployment:** 10M tokens minted, distributed 50/25/25 2. **Bonding curve active:** tokens tradeable on the curve 3. **Graduation:** remaining curve tokens and ELTA pair on a DEX, LP locked for 730 days 4. **Post-graduation:** tokens trade freely on the DEX with fee routing active 5. **Burns:** item purchases burn tokens, reducing supply over time *** ## Next Price discovery mechanics How fees are routed Token burn through items # Bonding Curve Basics Source: https://docs.elata.bio/apps/design/bonding-curve-basics How price discovery works on Elata launch curves, from seeding to graduation. ## Core Model Elata launch curves use constant-product reserves: ```text theme={null} k = reserveElta * reserveToken ``` When someone buys: ```text theme={null} newReserveElta = reserveElta + eltaIn newReserveToken = k / newReserveElta tokensOut = reserveToken - newReserveToken ``` Price rises as more ELTA enters the reserve. Selling tokens reverses the direction. *** ## Default Constants | Parameter | Value | | ----------------- | ----------------------- | | Total launch cost | 110 ELTA | | Seed ELTA | 100 ELTA | | Creation fee | 10 ELTA | | App token supply | 10,000,000 | | Curve allocation | 5,000,000 (50%) | | Graduation target | 42,000 ELTA in reserves | | LP lock | 730 days | *** ## Curve Lifecycle The `AppBondingCurve` contract follows a state machine: | State | Description | | ----------- | -------------------------------------- | | `PENDING` | Deployed, not yet activated | | `ACTIVE` | Trading is live | | `GRADUATED` | Reserves reached the graduation target | | `CANCELLED` | App cancelled before graduation | Additional behavior: * Permissionless activation after a configurable delay * Force graduation after deadline * Creator-only cancel while in `PENDING` state *** ## Fees On Curve * Default trading fee: **1%** (from `AppFeeRouter.feeBps`) * Fee is paid on top of the buy amount * Fees accumulate and are swept into FeeCollector as `TRADING_FEE` The trading fee is configurable by governance. Check current protocol parameters for the active rate. *** ## Graduation When the ELTA reserve reaches **42,000 ELTA** (or the deadline triggers force graduation): A Uniswap V2 pair is created or loaded for the app token and ELTA. Remaining token reserves and ELTA reserves are added as liquidity. LP tokens are locked in LpLocker for **730 days**. Bonding curve trading is disabled. All trading moves to the DEX. *** ## Early Access Gate For the first **6 hours** after launch, buyers need **100 XP** to participate on the curve. This prevents sniping by requiring demonstrated protocol participation. The gate parameters are configurable by governance. *** ## Next Token distribution and lifecycle How fees are routed Full lifecycle overview # Community Systems Source: https://docs.elata.bio/apps/design/community-systems Contributor splits, veELTA governance, and protocol-level community mechanics. ## Contributor Splits Each app has a ContributorSplit contract controlled by the app's Safe. This is the mechanism for distributing app revenue to team members and contributors. ```mermaid theme={null} flowchart LR FEES["App Fees"] --> ROUTER["FeeRouter"] ROUTER --> TREASURY["Treasury (20%)"] ROUTER --> SPLIT["ContributorSplit (80%)"] SPLIT --> C1["Contributor 1"] SPLIT --> C2["Contributor 2"] SPLIT --> CN["Contributor N"] ``` **Key properties:** * Pull-based: contributors claim their share, the protocol does not push payments * Managed exclusively by the app's Safe (add, remove, or adjust share percentages) * Supports up to 150-200 contributors per app * Default split: 80% to contributors, 20% to protocol treasury (adjustable via governance) Contributors must actively claim their payouts. Unclaimed funds remain in the contract until withdrawn. *** ## veELTA and Governance veELTA is the vote-escrow mechanism for protocol governance. Users lock ELTA tokens for a chosen duration and receive voting power in return. | Parameter | Value | | ------------------ | ------------------------------------ | | Lock duration | 7 to 730 days | | Voting power boost | 1x (7 days) to 2x (730 days), linear | | Fee yield | None (V2 design) | **Boost formula:** ```text theme={null} boost = 1 + (lockDuration / maxDuration) veELTA = lockedAmount * boost ``` veELTA is used exclusively for governance voting. It does not entitle holders to fee yields. This design choice mitigates securities risk under the Howey test. **Position management:** create a lock, increase the locked amount, extend the duration, or unlock the principal after expiry. *** ## Protocol-Level Decisions Governance proposals are submitted through the ElataGovernor contract and executed via the ElataTimelock. Changes to protocol parameters (fee splits, graduation thresholds, trading fees) require governance approval. Key parameters controlled by governance: | Parameter | Default | Range | | -------------------- | ----------- | --------------------- | | Trading fee | 1% | Governance-set | | Transfer tax cap | 2% | Protocol-wide maximum | | Treasury take | 20% | Adjustable | | Graduation threshold | 42,000 ELTA | Governance-set | | LP lock duration | 730 days | Governance-set | *** ## Next How fees are routed User guide for locking ELTA # Fee Flow for Apps Source: https://docs.elata.bio/apps/design/fee-flow How fees flow through FeeCollector, FeeSwapper, and ContributorSplit. ## Overview All protocol and app fees flow through the same contracts but are routed differently based on their `FeeKind`. ```mermaid theme={null} flowchart LR subgraph sources ["Fee Sources"] BC["Bonding Curve
(TRADING_FEE)"] AT["App Token
(TRANSFER_TAX)"] AF["App Factory
(LAUNCH_FEE)"] MOD["App Modules
(CONTENT_SALE, TOURNAMENT_FEE, OTHER)"] end subgraph pipeline ["Pipeline"] FC["FeeCollector"] FS["FeeSwapper"] end subgraph destinations ["Destinations"] TR["Treasury"] CS["ContributorSplit"] end BC --> FC AT --> FC AF --> FC MOD --> FC FC --> FS FS --> TR FS --> CS ``` *** ## FeeKind Routing Every fee is tagged with a `FeeKind` that determines where it goes: | FeeKind | Routing | | ---------------- | ------------------------------- | | `LAUNCH_FEE` | 100% treasury | | `TRADING_FEE` | 80% contributors / 20% treasury | | `TRANSFER_TAX` | 80% contributors / 20% treasury | | `CONTENT_SALE` | 80% contributors / 20% treasury | | `TOURNAMENT_FEE` | 80% contributors / 20% treasury | | `OTHER` | 80% contributors / 20% treasury | Default treasury take: **20%** (2000 bps), configurable per-app by governance. *** ## FeeCollector The accounting layer. It tracks pending fee balances indexed by `(appId, FeeKind, asset)`. * Receives ELTA deposits via `depositElta(appId, kind, amount)` * Receives app token deposits for transfer tax * Sweeps accumulated balances to FeeSwapper via `sweep(appId, kind, asset)` * Sweeping is permissionless (anyone can trigger it) *** ## FeeSwapper The routing layer (implements `IFeeRouterV2`): 1. If the app is **paused** in AppRegistry, 100% goes to treasury 2. If the fee kind is `LAUNCH_FEE`, 100% goes to treasury 3. Otherwise: treasury gets its take, the rest goes to ContributorSplit Contributors receive their share through pull-based claims, not automatic distribution. They must actively claim their payouts from the ContributorSplit contract. *** ## ContributorSplit Each app has a ContributorSplit contract deployed at registration: ```mermaid theme={null} flowchart TB FS["FeeSwapper"] -->|"deposit"| CS["ContributorSplit"] SAFE["App Owner Safe"] -->|"setContributors()"| CS CS -->|"release()"| C1["Contributor A"] CS -->|"release()"| C2["Contributor B"] CS -->|"release()"| CN["Contributor N"] ``` * **Shares-based:** each contributor has a share weight; payouts are proportional * **Max 200 contributors** (factory default, governance-configurable) * **Pull claims:** contributors call `release(asset, account)` to withdraw * **Owner Safe controlled:** only the app's Safe can modify contributors *** ## Next Price discovery mechanics Governance and contributor splits Token design and distribution # Incentives and Access Source: https://docs.elata.bio/apps/design/incentives-and-access Points system, early access gating, and how protocol incentives work. ## Elata Points System Elata points are non-transferable ERC20Votes token used for governance weight and protocol access. It cannot be bought or sold. Points are distributed through Merkle-tree-based epochs. Each epoch adds points to qualifying addresses. Reductions only happen through operator revocation, not natural decay. Points are additive only. Once earned, it stays unless explicitly revoked by an operator. *** ## How Points are Earned | Activity | Description | | ------------------------ | ------------------------------------------------------------------ | | Launching an app | Builders who deploy through the protocol earn Points | | Staking ELTA | Long-term ELTA stakers receive Points based on duration | | Governance participation | Voting on proposals earn Points | | Protocol activity | Active trading, tournament participation, and community engagement | Point distribution is managed by addresses with the `XP_OPERATOR_ROLE`. Operators publish epochs and manage distributions. Each distribution ID is tracked to prevent double-issuance. *** ## Early Access Gate New app launches include a **6-hour early access window**. During this period, only users with at least \*\*100 Points \*\*can buy tokens on the bonding curve. If you do not have 100 Points, you cannot participate in the first 6 hours of a new app's bonding curve. After the window closes, anyone can trade. This mechanism prevents sniping by requiring demonstrated protocol participation before early access. *** ## What Points Unlock * **Early access** to new app token launches (100 point minimum) * **Governance weight** in protocol-level decisions via ERC20Votes * **Future incentive eligibility** as the protocol expands reward mechanisms Points are not a financial instrument. It represents participation and is not designed to have monetary value. *** ## Next Governance and contributor splits Token design and distribution # Analytics and Health Source: https://docs.elata.bio/apps/operate/analytics-and-health Metrics to track, holder distribution signals, and what healthy patterns look like. ## Key Metrics Track these metrics to understand your app's health: | Metric | What It Tells You | Healthy Signal | | ------------------------ | --------------------------------- | ----------------------------------------- | | Unique holders | Community size | Steady growth over time | | Trading volume | Market activity | Consistent volume, not just launch spikes | | Graduation progress | Distance to 42,000 ELTA threshold | Steady accumulation | | Staking ratio | % of supply locked | 30-50% of circulating supply | | Tournament participation | Community engagement | Growing or stable participation rates | *** ## Holder Distribution Holder concentration is one of the strongest health indicators for an app token. | Pattern | Signal | Action | | ------------------------------- | ----------------------- | --------------------------------------- | | Top 5 wallets hold \< 30% | Healthy distribution | Continue current strategy | | Top 5 wallets hold 30-50% | Moderate concentration | Encourage broader distribution | | Top 5 wallets hold > 50% | High concentration risk | Run events and incentives to distribute | | Many wallets with tiny holdings | Wide but shallow | Focus on engagement depth | High concentration in a few wallets creates sell pressure risk. If a single holder exits, it can significantly impact the price on the bonding curve. *** ## Health Signals **Positive signals:** * Growing unique holder count week over week * Staking ratio above 30% * Regular tournament participation * Item purchases creating token burns * Organic trading volume (not just bot activity) **Warning signals:** * Declining holder count * Staking ratio below 10% * No tournament or item activity * Volume concentrated in a few wallets * Large unstaking events *** ## What To Do With This Data Use analytics to guide your operating decisions: * **Low engagement?** Run a tournament or create a new access-pass item * **Holder concentration too high?** Distribute ecosystem vault tokens to new users * **Staking dropping?** Review your staking incentives and lock durations * **Close to graduation?** Announce the milestone and create urgency *** ## Next Community growth playbook Run competitive events Create in-app items # Grow Your Community Source: https://docs.elata.bio/apps/operate/grow-your-community Community growth playbook for app builders on the Elata protocol. ## Overview Once your app is live, community growth comes from three levers: competitions, collectibles, and commitment tools. This page covers the strategic playbook. For the specific mechanics, see the dedicated pages below. *** ## Launch Week Playbook The first week sets the tone. Focus on visibility, first purchases, and establishing a community heartbeat. 1. **Announce everywhere.** Post your app store link on Twitter, Discord, and any relevant communities. 2. **Run an inaugural tournament.** Even a small prize pool generates activity and creates early trading volume. 3. **Create a soulbound access pass.** Gate a feature behind an item purchase to give early supporters something exclusive. 4. **Distribute XP** to your community so they can participate during the 6-hour early access window. 5. **Set up social links and team display** on your app listing. *** ## After Launch Shift from launch buzz to sustained engagement: * **Run tournaments regularly** (weekly or bi-weekly) to maintain trading volume and participation * **Release new items** to create ongoing token burn pressure * **Monitor holder distribution** and address concentration risks early * **Adjust contributor splits** as your team and contributor base grows * **Engage stakers** with exclusive access or governance participation *** ## Social Presence Set up and maintain these channels: | Platform | Purpose | | --------- | ------------------------------------------------------ | | Twitter/X | Announcements, launch events, milestone updates | | Discord | Community discussion, support, tournament coordination | | GitHub | Open source code, contribution tracking | | Telegram | Quick updates, regional communities | | Website | Product landing page, documentation | *** ## Team Display Add team members to your app listing. Visible teams build trust and help users evaluate new apps. Update this as your team grows. *** ## What Works * **Consistency beats intensity.** Regular small events outperform rare large ones. * **Burns create interest.** Item purchases that burn tokens give holders a reason to watch supply dynamics. * **Staking shows conviction.** A healthy staking ratio signals long-term community health. * **Transparency builds trust.** Public contributor splits, visible team, and open governance. *** ## Next Run competitive events Create in-app items Track app metrics # Items and Unlocks Source: https://docs.elata.bio/apps/operate/items-and-unlocks Create ERC-721 items for gating, collectibles, and in-app utility. ## Creating Items Items adhere to the ERC-721 standard, and are created through the InAppContent721 contract. Each item has: | Property | Description | | ---------- | ------------------------------------------------------- | | Name | Display name for the item | | Price | Cost in app tokens (burned on purchase) | | Soulbound | Whether the item is transferable or locked to the buyer | | Max supply | Optional cap on total mints | *** ## Item Types | Type | Purpose | Example | | ----------- | ------------------------------------------ | -------------------------------------------- | | Access Pass | Gate features or content | "Pro Mode" unlock, exclusive dashboard | | Cosmetic | Visual customization | Profile borders, badges, themes | | Power-up | Temporary or persistent gameplay advantage | Double XP for 24 hours | | Collectible | Limited-edition tokens | Launch day commemorative, achievement badges | *** ## Burn Mechanics All item purchases burn 100% of the app tokens spent. This creates direct deflationary pressure on the app token supply. When a user buys an item: 1. App tokens are transferred from the buyer 2. Tokens are burned (sent to the zero address) 3. The item is minted to the buyer There is no treasury cut or fee on item purchases. The entire price is removed from circulation. *** ## Feature Gating Use items to gate app features. Check ownership in your frontend: ```javascript theme={null} const hasAccess = await contract.balanceOf(userAddress) > 0; if (hasAccess) { // Show premium feature } else { // Show purchase prompt } ``` For soulbound items, `balanceOf` is the only check needed since the item cannot be transferred away. *** ## Soulbound vs Transferable | Property | Soulbound | Transferable | | ---------------------------- | --------------------------- | ----------------------- | | Can be sold or traded | No | Yes | | Appears on secondary markets | No | Yes | | Best for | Access passes, achievements | Collectibles, cosmetics | | Ownership check | Wallet-locked | Can change hands | Use soulbound items for access gates and feature unlocks. Use transferable items for collectibles and cosmetics that users may want to trade. *** ## Next Run competitive events Community growth playbook Token design and distribution # Staking for Apps Source: https://docs.elata.bio/apps/operate/staking-for-apps App-level staking as a builder tool for engagement and commitment signals. ## Why App Staking Staking lets token holders lock their app tokens to signal commitment. For builders, it provides: * A measure of community conviction * Reduced circulating supply (less sell pressure) * A tool for tiered access or rewards *** ## Setting Up Staking Each app receives a staking vault as part of the token launch. To enable staking: The staking vault is deployed automatically during Phase B (token launch). No additional deployment is needed. Use your Safe to set staking parameters: minimum stake duration, reward rates (if applicable), and any access tiers. Let users know staking is live and what they get for participating. *** ## What Users See From the user perspective, staking is straightforward: | Action | Description | | ------------- | --------------------------------------------------------------- | | Stake | Lock app tokens in the vault for a chosen duration | | Unstake | Withdraw tokens after the lock period ends | | View position | Check locked amount, duration remaining, and any earned rewards | Stakers appear in holder analytics as committed participants, distinct from short-term traders. *** ## Staking as a Builder Tool Use staking data to: * **Gate features** by requiring a minimum staked balance * **Weight governance** by giving stakers more influence in app-level decisions * **Reward loyalty** with tournament entry, item discounts, or priority access * **Track health** by monitoring the ratio of staked to circulating tokens A healthy staking ratio (30-50% of circulating supply) indicates strong community conviction. Track this in your [analytics dashboard](/apps/operate/analytics-and-health). *** ## Next Community growth playbook Track app health metrics # Tournaments Source: https://docs.elata.bio/apps/operate/tournaments Time-boxed competitions with smart contract payouts for Elata apps. ## What Is A Tournament? A tournament is a time-boxed competition that runs inside an Elata app. Entry fees build a prize pool, winners are determined by app-defined rules, and payouts happen automatically through smart contracts. Each tournament is: * A single-use event with a clear start and end time * Funded by entry fees in the app's token * Governed by transparent, on-chain fee splits *** ## How Tournaments Work The app builder creates a tournament through the TournamentFactory contract. This deploys a fresh Tournament contract, registers it under the app, and applies fee settings. During the entry window, players pay an entry fee in the app's token. The contract collects fees and builds the prize pool. Players compete under the app's rules. Scoring and results are determined by the app's logic. The tournament creator (or an authorized address) finalizes results. The contract calculates prize allocations based on the final standings. Winners claim their share of the prize pool. Unclaimed rewards remain in the contract until withdrawn. *** ## Tournament Economics | Recipient | Share | | ---------- | ----- | | Winners | 96.5% | | Protocol | 2.5% | | Token burn | 1% | These defaults are configurable per tournament. *** ## Example Use Cases Weekly leaderboard competitions with escalating prize pools. Players compete for high scores, and the top 10% split the pot. 30-day meditation challenges tracked through EEG or rPPG. Participants who meet daily targets share the reward pool. Focus sprints where participants compete on sustained attention metrics. Best performers earn from the prize pool. Data collection campaigns where participants contribute quality biosignal data. Compensation is proportional to data quality and quantity. *** ## Why Tournaments Matter | For | Benefit | | ------------- | -------------------------------------------------------------------------------- | | Users | Earn rewards, competitive engagement, community connection | | Builders | Drive trading volume, create engagement loops, attract new users | | Token holders | Tournament fees route through the fee pipeline, activity increases token utility | As a builder, you are responsible for tournament integrity. Set clear rules, use fair scoring, and finalize results promptly. *** ## Next Community growth playbook Create in-app items How fees are routed # Buy and Trade Source: https://docs.elata.bio/apps/users/buy-and-trade How buying works during the bonding curve phase and after graduation. ## Two Trading Phases Every app token goes through two phases: | Phase | Where You Trade | How Price Works | | ----------- | ---------------------- | --------------------------------------------------------- | | **Raising** | Bonding curve (in-app) | Constant-product formula: price rises as more ELTA enters | | **Live** | DEX (e.g., Uniswap) | Free market with locked liquidity | *** ## Bonding Curve Phase During the raising phase, you buy tokens directly from the bonding curve using ELTA. **What to know:** * Price is determined by the curve formula (`reserveELTA * reserveToken = k`) * Each purchase pushes the price up; each sale pushes it down * A 1% trading fee applies to each trade * The first 6 hours have an early access gate requiring 100 XP **How to buy:** 1. Go to the app's detail page on [app.elata.bio](https://app.elata.bio) 2. Connect your wallet 3. Enter the amount of ELTA you want to spend 4. Confirm the transaction *** ## Graduation The bonding curve graduates when ELTA reserves reach **42,000 ELTA**. When this happens: 1. Remaining tokens and ELTA reserves are paired on a DEX 2. LP tokens are locked for **730 days** (2 years) 3. All trading moves from the bonding curve to the DEX After graduation, the token trades like any other DEX-listed token with an established liquidity pool. *** ## Transfer Tax App tokens may have a transfer tax of up to **2%**. The tax applies only on transfers that touch an allowlisted liquidity pool (LP-keyed). Regular wallet-to-wallet transfers are not taxed. *** ## Fee Awareness When you trade on the bonding curve: * **1% trading fee** is collected and routed through the fee pipeline * Fees are split between contributors (80%) and protocol treasury (20%) When you trade on a DEX after graduation: * Standard DEX swap fees apply * Transfer tax (if configured) applies on LP-involving transfers *** ## Next Lock tokens for rewards How price discovery works # Explore Apps Source: https://docs.elata.bio/apps/users/explore-apps Discover and evaluate apps deployed on the Elata protocol. ## The App Store Browse neurotech apps at [app.elata.bio](https://app.elata.bio). Each app has its own token, bonding curve, and community tools. Go to the App Store *** ## Finding Apps The main page shows all launched apps with their icon, name, token symbol, status, and creator address. ### App Statuses | Status | Meaning | | ----------- | ------------------------------------------- | | **Raising** | Bonding curve active, price discovery phase | | **Live** | Graduated to DEX, free market trading | *** ## App Detail Pages Click any app to see: * **Overview:** icon, name, token price, creator, description, social links * **Trading:** buy form (if raising), price chart, trading history, DEX link (if live) * **Community:** holder distribution, staking stats, team members, tournaments * **Play:** embedded game/app with full-screen option *** ## Playing Apps Most Elata apps run directly in your browser. 1. Go to the app's detail page 2. Click the "Play" button 3. Use full-screen for the best experience Some apps require wallet connection for saving progress, accessing premium features, participating in tournaments, or verifying item ownership. Apps may support EEG devices or camera-based rPPG. Check the app description for compatibility requirements. *** ## App Categories | Category | Examples | | ------------ | ------------------------------------------------------------ | | **Focus** | Attention trainers, flow detectors, brain-feedback pomodoros | | **Gaming** | Mind-controlled games, neurofeedback challenges | | **Wellness** | Meditation, stress tracking, breathwork | | **Research** | Data collection, cognitive tests, experiments | *** ## Early Access New app launches have a **6-hour early access window**. During this period, you need at least **100 XP** to buy tokens on the bonding curve. XP is earned through protocol participation, data contributions, and community activities. It is non-transferable. XP is the only way to access early launch windows. There is no way to buy or transfer it. See [Incentives and Access](/apps/design/incentives-and-access) for details. *** ## Evaluating Apps Before participating, check: * **Creator address:** look it up on the block explorer * **Team members:** verify identities if shown * **Social links:** confirm they are official channels * **Trading volume:** higher volume means more liquidity * **Holder distribution:** check for concentration risk Start small and learn how the system works before committing significant funds. Tokens can go to zero. *** ## Your Dashboard Access your personal dashboard at [app.elata.bio/dashboard](https://app.elata.bio/dashboard) to see holdings, staked positions, claimable rewards, and transaction history. *** ## Help * Discord: [#support](https://discord.gg/GqS9CstffK) * Twitter: [@elata\_bio](https://x.com/elata_bio) * GitHub: [Issues](https://github.com/elata-biosciences) Click "Connect Wallet" in the header. Choose your wallet provider (MetaMask, Coinbase Wallet, etc.) and approve the connection. Elata is currently on Ethereum Sepolia (testnet). Your wallet should prompt you to switch automatically. Follow [@elata\_bio](https://x.com/elata_bio) on X/Twitter and DM your wallet address to request free testnet ELTA. *** ## Next How buying and trading works Staking and rewards # Stake and Earn Source: https://docs.elata.bio/apps/users/stake-and-earn How staking works for app tokens and what you can earn. ## What Staking Offers Each Elata app has a staking vault where you can lock your app tokens. Staking provides: * A way to signal commitment to the app community * Potential access to gated features (if the builder configures it) * Reduced circulating supply, which can support token price * Governance weight in app-level decisions (where applicable) *** ## How To Stake 1. Go to the app's detail page on [app.elata.bio](https://app.elata.bio) 2. Navigate to the staking section 3. Choose the amount of app tokens to stake 4. Confirm the transaction Your staked tokens are locked for the duration you choose. After the lock period ends, you can unstake and withdraw. *** ## XP and Protocol Rewards Beyond app-level staking, you can earn XP through protocol-wide participation: | Activity | What You Earn | | ------------------------ | ---------------------------------- | | App token staking | Community standing, feature access | | ELTA staking (veELTA) | Governance voting power | | Protocol participation | XP (non-transferable) | | Tournament participation | Prize pool rewards (in app tokens) | XP is earned through active participation, not passive holding. See [Incentives and Access](/apps/design/incentives-and-access) for details. *** ## Before You Stake Check these before locking tokens: * **Fee routing:** understand how the app's fees are split (see [Fee Flow](/apps/design/fee-flow)) * **Lock duration:** tokens are locked for the chosen period and cannot be withdrawn early * **App health:** review holder distribution and trading volume in the app's analytics * **Staking ratio:** a healthy range is 30-50% of circulating supply *** ## ELTA Staking (veELTA) For protocol-level governance, you can lock ELTA tokens to receive veELTA (voting power). This is separate from app token staking. See [veELTA and Governance](/apps/users/veelta-governance) for details on lock durations and voting mechanics. *** ## Next Lock ELTA for voting power Find apps to participate in # veELTA and Governance Source: https://docs.elata.bio/apps/users/veelta-governance How ELTA locking translates to voting power and governance participation. ## What veELTA Is veELTA is the vote-escrow token for Elata protocol governance. You receive veELTA by locking ELTA tokens for a chosen duration. * Lock ELTA for 7 to 730 days * Receive voting power proportional to your lock amount and duration * Unlock your principal after the lock period expires veELTA is used exclusively for governance. It does not entitle holders to fee yields. *** ## Lock Parameters | Parameter | Range | | ------------- | ---------------- | | Minimum lock | 7 days | | Maximum lock | 730 days | | Minimum boost | 1x (at 7 days) | | Maximum boost | 2x (at 730 days) | *** ## Boost Formula Voting power scales linearly with lock duration: ``` boost = 1 + (lockDuration / maxDuration) veELTA = lockedAmount * boost ``` **Example:** Locking 1,000 ELTA for 365 days gives you: * boost = 1 + (365 / 730) = 1.5x * veELTA = 1,000 \* 1.5 = 1,500 veELTA voting power *** ## Position Management | Action | What It Does | | -------- | ------------------------------------- | | Create | Lock ELTA for a chosen duration | | Increase | Add more ELTA to an existing lock | | Extend | Increase the lock duration | | Unlock | Withdraw principal after lock expires | *** ## When To Lock Consider locking ELTA when: * You want to participate in governance proposals * You plan to hold ELTA long-term anyway * You want to influence protocol direction (fee parameters, graduation thresholds, etc.) Longer locks give more voting power per ELTA. If you are unsure about duration, start with a shorter lock and extend later. *** ## Governance Participation veELTA voting power is used for protocol-level governance proposals submitted through the ElataGovernor contract: * **Parameter changes:** trading fees, transfer tax caps, treasury take percentages * **Protocol upgrades:** contract changes, new features * **Community decisions:** incentive distributions, partnership approvals Proposals go through a timelock (ElataTimelock) before execution, giving the community time to review changes. *** ## Next App token staking Governance mechanics in detail # What Are Elata Apps? Source: https://docs.elata.bio/apps/what-are-elata-apps Tokenized applications on the Elata protocol with built-in economics, governance, and community tools. ## The Idea Elata SDK (4) Leading to our iOS/Android launch, we will implement an abstracted version of the user interface, running all economic features under the hood. Transfers, fees, and other economic variables will get routed under the hood and be out-of-sight from end users. Under the hood, an Elata app is a tokenized application deployed on the Elata protocol. Each app gets its own ERC-20 token, a bonding curve for price discovery, a staking vault, contributor splits, and governance hooks. You build the product. The protocol handles token launch, fee routing, liquidity, and community infrastructure. *** ## What You Get When You Launch Every app deployed through the protocol receives: | Component | What It Does | | --------------------- | ------------------------------------------------------------------- | | **App Token** | ERC-20 with 10M supply, distributed 50/25/25 (curve/team/ecosystem) | | **Bonding Curve** | Constant-product price discovery until graduation at 42,000 ELTA | | **Staking Vault** | Lets token holders stake and signal commitment | | **Vesting Wallet** | 25% team allocation with configurable vesting | | **Ecosystem Vault** | 25% reserved for ecosystem incentives | | **Contributor Split** | Pull-based payout system for up to 150-200 contributors | Total launch cost: **110 ELTA** (10 ELTA registration fee + 100 ELTA bonding curve seed). ELTA is the protocol's native token with a fixed 77M supply. *** ## How It Works 1. **Register** your app with metadata and a Safe wallet (10 ELTA). 2. **Launch** the token stack with a 100 ELTA seed. 3. **Trade** on the bonding curve while the app builds traction. 4. **Graduate** when reserves hit 42,000 ELTA, creating a locked DEX liquidity pair. 5. **Operate** with community tools: tournaments, items, staking, and governance. The full sequence is covered in [App Lifecycle](/apps/app-lifecycle). *** ## Who This Is For * **Builders** who want to launch a tokenized app without building their own economic infrastructure * **Users** who want to discover, trade, and participate in app ecosystems * **Communities** that benefit from transparent fee routing and governance *** ## Next Builder or user? Full launch-to-graduation arc Start building # What You Can Build Source: https://docs.elata.bio/apps/what-you-can-build App categories, real examples, and what the protocol makes possible. ## App Categories Elata apps span four main categories. Each uses the same protocol infrastructure but targets different user behaviors. | Category | What It Does | Example Use Case | | ------------ | ------------------------------------------------ | ---------------------------------------------------------- | | **Focus** | Attention training, productivity enhancement | Neurofeedback sessions that reward sustained attention | | **Gaming** | Competitive or casual games with token mechanics | Chess with neural HUD overlays, reaction-time contests | | **Wellness** | Health monitoring, breathing, meditation | Guided breathwork with live EEG or rPPG biometric feedback | | **Research** | Data collection, citizen science, experiments | EEG data studies with participant token incentives | *** ## What Makes An Elata App Different An Elata app is not just a web app with a token bolted on. The protocol gives you: * **Price discovery** through bonding curves that graduate to DEX liquidity * **Fee routing** that splits revenue between contributors and the protocol treasury * **Community tools** like tournaments, NFT items, and staking * **Governance hooks** so token holders can participate in app-level decisions You focus on the product experience. The protocol handles the economics. *** ## Building With Biometrics Many Elata apps use the [Biometric SDK](/sdk/overview) to add real-time biosignal processing: * **Camera rPPG** for heart rate, stress, and arousal feedback (no hardware needed) * **EEG via Web Bluetooth** for brain-signal analysis with Muse headsets * **Signal processing** for band powers, calmness models, and alpha detection These integrations are optional. You can build an Elata app with or without biometrics. *** ## Next How apps launch and graduate Start building See what's live # Development Source: https://docs.elata.bio/development Preview changes locally to update your docs **Prerequisites**: * Node.js version 19 or higher * A docs repository with a `docs.json` file Follow these steps to install and run Mintlify on your operating system. ```bash theme={null} npm i -g mint ``` Navigate to your docs directory where your `docs.json` file is located, and run the following command: ```bash theme={null} mint dev ``` A local preview of your documentation will be available at `http://localhost:3000`. ## Custom ports By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. For example, to run Mintlify on port 3333, use this command: ```bash theme={null} mint dev --port 3333 ``` If you attempt to run Mintlify on a port that's already in use, it will use the next available port: ```md theme={null} Port 3000 is already in use. Trying 3001 instead. ``` ## Mintlify versions Please note that each CLI release is associated with a specific version of Mintlify. If your local preview does not align with the production version, please update the CLI: ```bash theme={null} npm mint update ``` ## Validating links The CLI can assist with validating links in your documentation. To identify any broken links, use the following command: ```bash theme={null} mint broken-links ``` ## Deployment If the deployment is successful, you should see the following: Screenshot of a deployment confirmation message that says All checks have passed. ## Code formatting We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. ## Troubleshooting This may be due to an outdated version of node. Try the following: 1. Remove the currently-installed version of the CLI: `npm remove -g mint` 2. Upgrade to Node v19 or higher. 3. Reinstall the CLI: `npm i -g mint` Solution: Go to the root of your device and delete the `~/.mintlify` folder. Then run `mint dev` again. Curious about what changed in the latest CLI version? Check out the [CLI changelog](https://www.npmjs.com/package/mintlify?activeTab=versions). # Elata Points Source: https://docs.elata.bio/elata-eco-points Earned, non-transferable participation points that unlock early access to app launches and track real contribution across Elata. This page reflects the current `dev` branch of `elata-protocol`. Some internal files and parameters still use `XP` naming. On this page, **Points** and **XP** refer to the same participation primitive. Elata Points are Elata's onchain participation primitive. They are earned, not bought, and they stay bound to the wallet that earned them. At the contract level, `ElataPoints` is a non-transferable token with voting checkpoints. Transfers between wallets are disabled, while authorized operators can award, revoke, or publish claimable Merkle distributions. ## Why Points exist New app curves can reserve the first part of a launch for wallets that hold enough points. Points show real participation because they cannot be traded or transferred. Points are checkpointed for governance-style voting and historical balance lookups. The system favors real participation over simple buying power. ## Core rules | Property | Current behavior | | ------------- | ------------------------------------------- | | Contract | `src/experience/ElataPoints.sol` | | Name / symbol | `Elata Points` / `POINTS` | | Transferable | No | | Tradeable | No | | Decimals | 18 | | Minting paths | Operator award, signed update, Merkle claim | | Revocable | Yes, by authorized operators | | Checkpointed | Yes | Points are soulbound, but they are not irreversible. They cannot be transferred, but they **can** be revoked by an authorized operator to correct bad data, fraudulent awards, or an incorrect distribution. ## How points are issued ### 1. Direct operator awards Authorized operators can mint points directly to a wallet. Use this when the protocol already knows a wallet earned points and wants to credit it immediately. ### 2. Signed awards The contract also supports signed point updates. This lets an authorized operator approve an award offchain, while the user or frontend submits the claim onchain later. ### 3. Merkle distributions For larger batches, operators can publish a Merkle root for a distribution. Users then claim their allocation by submitting the distribution ID, amount, and Merkle proof. This is the cleanest path for epoch-based distributions because it keeps onchain storage small while still letting each user verify and claim their own allocation. ## Early access on app launches Points matter most during the first phase of a new app token launch. By default, each bonding curve uses: * **100 points minimum** * **6 hour early-access window** During that window, the bonding curve checks the buyer's points balance. If the wallet is below the threshold, the purchase fails. After the window ends, the curve is open to everyone. The launch gate is configurable through governance, so the minimum points threshold and early-access duration can change over time. ## Claim flow 1. The protocol calculates a new points distribution offchain. 2. An authorized operator generates the canonical Merkle JSON and publishes a root onchain. 3. The frontend loads the matching distribution file and verifies it against the onchain distribution metadata. 4. The user submits a claim with their proof. 5. The contract marks the claim as used, mints the points, and auto-delegates to self if the wallet has not delegated before. ## What points are not * Points are **not** ELTA * Points are **not** veELTA * Points are **not** transferable rewards * Points are **not** a market asset Think of them as earned access and participation weight, not money. ## FAQ No. Points are earned or claimed through protocol-defined distribution paths. They are not designed to be bought on a market. No. Transfers are disabled at the contract level. Yes, in limited cases. Authorized operators can revoke points to correct bad awards or a faulty distribution. Not for basic participation. Points mainly matter during gated launch windows and in any reputation-weighted flows built on top of the points contract. Points stay attached to the wallet address that earned them. Losing access to that wallet means losing access to those points. ## Security model * Transfers are disabled in the token contract itself * Only authorized operator addresses can award, revoke, or publish Merkle roots * Distribution claims are one-time per wallet per distribution * Published distribution metadata can be matched against the onchain data hash * Points auto-delegate on first mint or claim so checkpoint tracking works without extra user steps ## Related pages ELTA supply, app launch costs, and fee routing. The full protocol lifecycle from app launch to fee flow. Local setup and contract-level development docs. Get a local environment running and explore the protocol. # Elata Points Source: https://docs.elata.bio/elata-points Non-transferable reputation points that gate early access, weight funding votes, and track meaningful participation across the Elata ecosystem. Elata Points are the protocol's on-chain reputation primitive. Points are earned by participating in the ecosystem: playing apps, submitting data, and engaging in governance and therefore, cannot be bought, sold, or transferred. Your points balance signals genuine contribution and unlocks privileged access across the protocol. Points live in the `ElataPoints` smart contract (`src/experience/ElataPoints.sol`) and is soulbound, meaning it is permanently bound to the address that earned it. *** ## Why Points Matters Points holders meeting the minimum threshold get a 6-hour head start on every new app token launch, buying from the bonding curve before the general public Points determines your voting weight in the weekly LotPool funding round, where the community allocates treasury ELTA to research proposals and development grants Because points are non-transferable and earned exclusively through participation, they serve as an unfakeable signal of commitment to the ecosystem *** ## How Points Work Unlike ELTA (which is a tradeable ERC-20), points are a non-transferable point balance tracked on-chain. It accumulates over time as you interact with the protocol and can never be sent to another address or listed on a market. ### Core Properties | Property | Detail | | :----------------- | :----------------------------------------------------------------------------------------------------------------- | | **Contract** | [`ElataPoints.sol`](https://github.com/Elata-Biosciences/elata-protocol/blob/vNext/src/experience/ElataPoints.sol) | | **Token standard** | Non-standard (non-transferable, soulbound) | | **Transferable** | No | | **Burnable** | No. Points are permanent once earned | | **Mintable by** | Authorized protocol operator(s) via role-based access | | **Chain** | Same chain as the core Elata Protocol deployment | Points cannot be purchased with ELTA or any other token. Any claim to sell or transfer points are fraudulent. The contract enforces non-transferability at the smart contract level. *** ## Earning points Points are awarded for meaningful, verifiable participation across three categories: Engage with neurotech applications in the Elata ecosystem, such as neurofeedback sessions, brain-training games, meditation experiences, EEG-based interactions, and more. Each qualifying session or milestone earns points proportional to the depth of engagement. Submit biosensor data (EEG, eye-tracking, or other biometric signals) to research experiments or app-level data pipelines. Data contributions that pass validation earn points, rewarding users who actively power the ecosystem's scientific infrastructure. Vote on proposals, participate in funding rounds, and engage in protocol discussions. Active governance participants earn points that further amplifies their future influence. Points are designed to reward consistent, genuine participation rather than one-time actions. Engage regularly across multiple categories for the fastest accumulation. *** ## Early Access Gating One of the most impactful functions for points is gating access to new app token launches on the bonding curve. When a new app is launched via `AppFactory`, its token begins selling on a constant-product bonding curve (`x*y=k`). The initial supply is 10,000,000 app tokens with 50% allocated to the curve. For the first 6 hours after launch, only wallets holding at least 100 XP can buy from the curve. This gives active ecosystem participants first access at the earliest (and lowest) prices. After the 6-hour window, the curve opens to all buyers regardless of XP balance. The 1% trading fee applies to all trades throughout the curve's lifecycle. Once the curve collects 42,000 ELTA, liquidity auto-deploys to Uniswap V2 and LP tokens are locked for 2 years. Free-market trading begins. The default gate parameters (100 points minimum, 6-hour window) are configurable through governance. These values represent the current protocol defaults on the `vNext` branch. *** ## Funding Allocation Points play a central role in how the protocol supports capital expenditures: Each week, the LotPool governance mechanism opens a funding round where the community votes to allocate ELTA from the treasury to submitted proposals — research studies, open-source tools, neurotech hardware, and more. Your voting weight in LotPool is determined by your points balance, not your ELTA holdings or veELTA position. This separates financial stake from contribution-based influence, ensuring that the people who have participated most actively in the ecosystem have the greatest say over where funding goes Every point counts equally. Your share of total points supply determines your proportional weight in each funding round Funding rounds run on a weekly cycle. Proposals are submitted, the community votes, and winning proposals receive ELTA from the treasury *** ## Points vs veELTA vs ELTA The protocol uses three distinct primitives for different functions. Understanding how they interact is key to navigating the ecosystem: | | **ELTA** | **veELTA** | **Elata Points** | | :------------------ | :----------------------- | :------------------------------- | :---------------------------- | | **Type** | ERC-20 token | Vote-escrowed ELTA | Non-transferable points | | **Transferable** | Yes | No | No | | **How to get** | Buy, earn, or receive | Lock ELTA (7–730 days) | Participate in ecosystem | | **Governance role** | None directly | On-chain proposal & voting power | Funding vote weight (LotPool) | | **Revenue share** | None directly | 15% of protocol fees | None directly | | **Launch access** | Required to buy on curve | No special access | Gates 6-hour early window | | **Boost mechanic** | N/A | 1×–2× linear by lock duration | Accumulates over time | ELTA is the economic primitive (money). veELTA is the governance primitive (voting power + revenue). XP is the reputation primitive (contribution signal + funding influence). All three work together to align incentives across the ecosystem. *** ## Points Distribution Architecture Points are minted by authorized operators — protocol-level contracts and admin roles that can verify qualifying actions. The distribution system is designed with these principles: The `ElataPoints` contract uses a role-based access pattern. Only addresses granted the operator role can mint new XP. This role is managed by the protocol's multisig admin, ensuring no single actor can inflate XP balances arbitrarily. Wherever possible, point-earning actions are verified on-chain. For example, completing a bonding curve purchase, voting on a governance proposal, or staking ELTA. Off-chain actions (such as data submissions) flow through an authorized backend operator that validates participation before minting. Unlike ELTA (which has a fixed 77M supply), XP has no hard cap. However, points can only be minted in response to verified actions. There is no passive emission or time-based inflation. Growth is organic and participation-driven. Like all protocol contracts, `ElataPoints` is non-upgradeable. The minting logic and non-transferability guarantees are permanently enforced at the contract level with no proxy pattern or admin override. *** ## Frequently Asked Questions No. Points cannot be purchased, traded, or transferred. It is exclusively earned through verified participation in the ecosystem. Any entity claiming to sell points are fraudulent. Points are bound to your on-chain address. If you lose access to your wallet, your points are not recoverable. Secure your keys carefully. No. Once earned, points are permanent and do not decrease. Your balance can only grow as you continue to participate. No. You can buy ELTA, trade on bonding curves (after the early-access window), stake, and participate in governance without any points. Points provide additional benefits, such as early launch access and funding vote weight. However, points are not a hard requirement for basic protocol usage. The current default threshold is 100 Points. This grants access to the 6-hour early buy window on new app token launches. Both the threshold and the window duration are configurable through governance. No. All Elata protocol contracts are non-upgradeable and immutable after deployment. The rules governing points minting and non-transferability cannot be changed post-deployment. *** ## Security Considerations The points system inherits the same security posture as the rest of the Elata Protocol: * **Non-upgradeable**: No proxy patterns, no admin upgrade keys * **Role-based minting**: Only authorized operator addresses can mint points, managed by multisig * **Soulbound enforcement**: Transfer functions are disabled at the contract level, not just by convention * **Open source**: Full contract source is available for public review and audit The protocol is currently pending an external security audit before mainnet deployment. All contracts, including `ElataPoints`, are open-source on the `vNext` branch and available for community review. Explore the ElataPoints contract on the `vNext` branch of the Elata Protocol repository. *** ## Related Pages Lock ELTA for veELTA: governance voting power and protocol revenue share Full protocol architecture, app lifecycle, and fee flow overview ELTA supply, distribution, and economic model breakdown # New file Source: https://docs.elata.bio/home/ELTA-Economy Description of your new file. # Structure Source: https://docs.elata.bio/home/governance/structure ## Governance Structure Elata governance uses on-chain governor and timelock contracts with veELTA voting power. ## Core Parameters (Current Defaults) | Parameter | Value | | ------------------ | -------------- | | Voting delay | 1 day | | Voting period | 7 days | | Proposal threshold | 0.1% of supply | | Quorum | 4% of supply | | Timelock delay | 48 hours | ## Notes * veELTA voting power comes from ELTA lock amount and lock duration. * Critical protocol parameters are timelock-gated. # Operating Teams Source: https://docs.elata.bio/home/governance/teams *** Elata’s internal units are referred to as teams - which are essentially working groups - composed of Elata members. They are tasked by the member community to perform a set of thematic activities in line with the mission and vision of Elata. **JOINING A TEAM** If you are interested in joining an Elata team, please complete [this](https://tally.so/r/wkPZ71) form to declare your interest. The following teams comprise Elata's organizational structure: 1. **Development team** 2. **Operations team** 3. **Engineering team** 4. **Engagement team** Teams are supposed to encourage member involvement. Their purpose is to incentivize efficiency and results by rewarding members and contributors based on their performance. *** ## Development team Responsible for screening, segmenting, and seeking projects for Elata to finance and develop, and is responsible for the following: * Critically analyzes inbound and outbound investment opportunities; uses scientific and clinical analysis to gauge likelihood of regulatory approval and positive patient outcomes. * Organizes, reviews, and segments all inbound and outbound opportunities for Elata’s research dealings. * Works together with engagement and engineering teams to ensure opportunities pursued fall in line with community interest. * Works together with operations team and licensing offices/project managers to assume IP ownership. *** ## Operations team Operations ensures security practices, legal needs, promotes transparency, and fulfills ancillary needs that relieve logistical burden from other teams, and is responsible for: * Asset management; oversees technical and product development of all digital, physical, and intangible assets owned or managed by Elata, ensuring they align with the DAO's strategic goals. * Manage legal affairs related to Elata's operations, including compliance, contracts, and regulatory affairs. * Design and refine the economic models, including token distribution, incentives, and financial sustainability strategies. * Implement and maintain security measures to protect assets, data, and member information from threats, ensuring the integrity and safety of all operations. *** ## Engineering team The Engineering Team builds and maintains the core technology stack powering Elata’s mission. From open-source neuroimaging hardware that captures brainwave or behavioral data to decentralized software that processes and protects these data streams, this team bridges cutting-edge innovations in neuroscience, ML/AI, cryptography, and web services. They are responsible for the following: * Developing open-source hardware for capturing relevant biomarkers or treating mental health issues (e.g., EEG, TMS, light/actigraphy sensors). * Designing secure, privacy-preserving data pipelines, including those leveraging zero-knowledge proofs. * Creating machine learning models aimed at mental health applications, especially computational neuroscience and psychiatry. * Maintaining and expanding Elata’s suite of web services, such as our open-source news aggregator, contributor portals, and governance tools. * Working in tandem with other teams to translate open-source insights into practical and profitable solutions that sustain the DAO. *** ## Engagement team The engagement team carries a broad responsibility which is to promote Elata initiatives across various channels, act as liaison between community members and projects, provides updates to community, and ensures collaboration with external partnerships. They are responsible for the following: * Educate and raise awareness about the significance of Elata Biosciences through targeted outreach and educational programs. * Cultivate and sustain a vibrant, supportive community, ensuring active member participation and retention. * Promote the growth and visibility of Elata, enhancing its reputation and reach within relevant communities. * Drive business development by forging partnerships and collaborations that align with Elata’s mission and can amplify its impact. *** ## Stewardship & Core Each team is guided by a steward, which are elected by [ELTA](/o/WFdlYgzLkzXseCEviHTq/s/Jfp0pu5VZ5XDDYs5IrR4/~/changes/108/operating-model/the-elta-token/elta-overview) holders. Stewards act as leaders, ensuring the smooth operation and direction of their respective working groups. ElataCore is an advisory group that represents various groups of stakeholders. They are not a “Board of Directors”, but rather the opposite: ElataCore supports the Stewards. ElataCore is accountable to tokenholders, who define the scope of ElataCore's executive power over operational decisions and may refine these at any time in a new governance proposal. Each ElataCore member is chosen to support a specific strategic objective of the DAO. In that sense, holders of our tokens are represented by ElataCore, but the token holders are the overseeing and superior entity that governs ElataCore through proposals. To facillitate impartial decision-making, a clear separation between ElataCore and stewards will be indicated in Governance initiatives. This allows ElataCore to prioritize the highest-impact initiatives while stewards provide unbiased oversight. However, resource and contributor limitations may necessitate some overlap. The ultimate goal remains a clear and practical division between the two groups. # Integrate your device with the Elata SDK Source: https://docs.elata.bio/integrate Integrate a headset or biosignal device into the Elata EEG BLE stack with a simple, reliable path. This guide is for device companies that want their hardware to work with the Elata SDK. The target is simple: your device should plug into the shared Elata transport boundary and emit stable frames that apps can trust. Review the shared frame and transport types before writing adapter code. Confirm Web Bluetooth, browser, and platform constraints first. ## What You Are Building A production-ready integration should do three things well: 1. connect reliably 2. stream frames in a stable, predictable format 3. recover cleanly when the device, browser, or radio link misbehaves In Elata terms, that means converging on `HeadbandTransport` and `HeadbandFrameV1` instead of exposing vendor-specific packet layouts directly. Apps should depend on the shared Elata transport contract, not on raw vendor packets. That keeps downstream integrations simple and makes device support easier to maintain. ## The Fast Path Decide whether your device belongs upstream in `eeg-web-ble`, in a separate package, or in an app-local adapter. Use [Integration Paths](./integration-paths) to make that decision early. Gather your GATT services, characteristics, packet format, sample rate, channel names, timestamp behavior, and known firmware quirks. See [Protocol Requirements](./protocol-requirements). Build the device layer that handles discovery, session setup, packet decoding, and frame emission. Start from [Adapter Implementation](./adapter-implementation). Test connect, start, stop, disconnect, malformed packets, reconnects, and frame correctness before tuning anything downstream. Use [Testing and Validation](./testing-and-validation). Package the integration with platform notes, tested firmware versions, and support expectations. See [Submission and Support](./submission-and-support). ## What You Need Before You Start | Requirement | Why it matters | | ------------------------ | -------------------------------------------------------------------------------- | | Device protocol details | You need a complete byte-level picture before implementation starts. | | A supported browser path | Web Bluetooth requires Chrome or Edge in a secure context. | | Stable channel metadata | Apps need consistent channel order, names, and sample rates. | | A clear ownership model | Decide early whether this will live upstream, in a vendor package, or privately. | If you have not reviewed the current BLE flow yet, read [EEG BLE Getting Started](/sdk/eeg-web-ble/getting-started) first. ## Guide Map Choose where the integration should live and how it should be owned. The shared interfaces your device must satisfy. The protocol and metadata inventory to collect before coding. Build the device adapter and connect it to `BleTransport`. Make the integration reliable under normal and failure conditions. Hand off the integration with the docs and caveats partners need. ## Reliability First A device integration is not done when it streams once on a happy path. It is done when: | Done means | Notes | | -------------------------------- | -------------------------------------------------------------- | | `connect()` is predictable | discovery and session setup succeed or fail clearly | | `start()` produces stable frames | row width, channel order, and sample rate stay correct | | `stop()` is clean | the session stops without leaving the device in a bad state | | `disconnect()` is clean | the browser session releases resources correctly | | failures are surfaced clearly | apps can react to disconnects, retries, and unsupported states | ## Related Docs * [Headband Transport](/sdk/eeg-web/headband-transport) * [EEG BLE Getting Started](/sdk/eeg-web-ble/getting-started) * [Muse Device](/sdk/eeg-web-ble/muse-device) * [Compatibility](/sdk/operations/compatibility) * [Troubleshooting](/sdk/operations/troubleshooting) ## Next Pick the right ownership and packaging model before coding. Confirm the frame and lifecycle expectations your adapter must satisfy. # Integration Paths Source: https://docs.elata.bio/integration-paths Choose the right packaging and ownership model for a device integration. Use this page before you write adapter code. The right path depends on whether the integration is broadly useful, whether it needs vendor SDKs or native bridges, and whether it will be maintained as a public SDK surface. ## Recommended Default If the device is likely to be useful to the wider Elata SDK audience, put it upstream in `@elata-biosciences/eeg-web-ble`. That keeps transport behavior centralized and avoids parallel adapters across multiple apps. ## Choose By Outcome | Path | Best when | Why | | --------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------- | | Upstream device module in `eeg-web-ble` | The device is broadly useful and works through browser BLE | Best default for public SDK support | | Separate package under `packages/` | You need a vendor SDK, a license gate, or a localhost/native bridge | Keeps heavier integrations isolated | | App-local adapter | You are proving a concept or shipping a private integration | Fastest path when no shared package is needed | ## Path 1: Upstream in `eeg-web-ble` Choose this when: * the device can work through Web Bluetooth in a browser * the integration is likely to be reused by more than one app * you want one shared implementation of transport behavior This path usually means: 1. add a device module under the BLE package 2. reuse `BleTransport` 3. add mocked tests 4. update consumer docs and device notes This is the best path for a public, durable integration that should feel like a first-class part of the SDK. ## Path 2: Separate Package Choose this when the device needs more than a clean browser BLE flow. Typical reasons: | Situation | Why a separate package helps | | --------------------------------- | ----------------------------------------------------- | | Licensed or heavy vendor SDK | Keeps extra dependencies out of the main BLE package | | Localhost helper or native bridge | Lets you ship a bridge-specific transport cleanly | | Independent release cadence | Lets the vendor or partner own versioning and support | The package should still expose a `HeadbandTransport`, or a thin wrapper around one, so app code stays consistent with the rest of the Elata stack. ## Path 3: App-Local Adapter Choose this when speed matters more than reuse. This is a good fit for: * a private customer deployment * a fast proof of concept * evaluation work before a public package exists Keep the contract the same even if the code stays private. That makes it easier to move upstream later. ## Decision Order If multiple apps would benefit, start by assuming an upstream path. If Web Bluetooth will not work, or if a native bridge is required, move to a separate package. Shared support usually belongs upstream. Vendor-owned release lines often fit better in a separate package. No matter where the code lives, the app-facing contract should still be `HeadbandTransport` and `HeadbandFrameV1`. ## Paths to Avoid Do not choose an app-local adapter just because it is easy in the first hour. That usually creates extra work later if the integration becomes public. Do not push a heavy, bridge-based, or licensed integration into the shared BLE package either. Keep the public package lean. ## Related Docs * [EEG BLE Getting Started](/sdk/eeg-web-ble/getting-started) * [Transport Contract](./transport-contract) * [Adapter Implementation](./adapter-implementation) * [Compatibility](/sdk/operations/compatibility) ## Next Review the shared interfaces your chosen path must still satisfy. Gather the protocol details you need before implementation begins. # How Elata Works Source: https://docs.elata.bio/learn/how-it-works Current protocol architecture and value flow ## Architecture Three practical layers: 1. **Launch layer**: `AppFactory`, `AppRegistry`, `AppBondingCurve`, `AppToken` 2. **Fee layer**: `FeeCollector`, `FeeSwapper`, `ContributorSplit` 3. **Governance layer**: `ELTA`, `VeELTA`, `ElataPoints`, governor/timelock/config *** ## App Lifecycle 1. Register app and contributor split. 2. Launch token stack (`10,000,000` app supply). 3. Run active curve distribution (`x*y=k`). 4. Graduate to LP at target/deadline. 5. Continue app-level fee routing post-graduation. *** ## Fee Flow ```mermaid theme={null} graph LR A[LaunchAndTradingAndTransferFees] --> B[FeeCollector] B --> C[FeeSwapper] C --> D[Treasury] C --> E[ContributorSplit] ``` Routing policy: * launch fee -> treasury * app-revenue fee kinds -> contributors + treasury (default `80/20`) * paused app -> treasury For full details on fee kinds, routing, and configuration, see the [Fee Flow for Apps](/apps/design/fee-flow) reference. *** ## XP and veELTA * XP gates early buys during launch windows (default `100 XP`, `6h`). * veELTA provides time-weighted voting power via ELTA locks (`7-730` days, `1x-2x` boost). *** ## Security Posture * fixed ELTA supply (`77,000,000`) * explicit curve lifecycle states * LP lock on graduation * explicit fee-kind taxonomy * per-app fee accounting (no unbounded global sweeps) # What is Elata? Source: https://docs.elata.bio/learn/protocol-overview ## Overview Elata is an app-launch protocol designed specifically for biosignal and neurotech applications. It combines three capabilities that don't currently exist together anywhere: browser-based biosignal acquisition SDKs, on-device processing that keeps all user data local, and an economic app-launch system that lets anyone in the world ship a neurotech product with built-in monetization. Blockchain provides the best execution framework for this project because it ensures builders can access instant price discovery for their inventions, users are able to parttake in the economic upside they help generate when using apps, and most importantly to ensure anyone in the world can participate with ease. Network: Live on Base Sepolia (testnet). Mainnet on Base coming soon. npm install an SDK, launch an app with a native token, and ship in minutes. Find apps, trade tokens, stake for rewards, participate in governance. *** ## Why This Exists Consumer devices have quietly become biosignal acquisition tools. When modeled and executed well, smartphone camera can accurately infer heart rate measurements, respiratory rate, track pupil dialation and eye movements, and even get relatively accurate inferences on cognitive states. Furthermore, at-home consumer EEG headsets can capture brainwave data that required clinical-grade hardware a decade ago. The sensors are already in people's pockets. What doesn't exist yet is a standardized application layer for building on top of these signals. Today, every company that processes biosignal data — from meditation apps to driver-drowsiness systems — does so by extracting user data to centralized servers. Users never see the value their data generates, and Builders must recreate proprietary signal-processing pipelines from scratch. And anyone outside of well-funded markets is simply excluded. Elata addresses this with three design decisions: 1. Published SDKs that standardize biosignal acquisition across devices, installable as npm packages. 2. **On-device processing** where all raw data stays on the user's device and never gets extracted — by anyone, including Elata. Model improvements aggregate across the network via parameter updates, not raw signals, so the network gets smarter without compromising privacy. 3. **Permissionless app launch** with deterministic on-chain mechanics — bonding curves, fee routing, and graduation — so any builder, anywhere, can ship a biosignal app with aligned economics and no gatekeepers. *** ## What Elata Does ### Biosignal Acquisition Elata ships published npm packages for browser-based biosignal capture: | Package | What It Does | | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `@elata-biosciences/rppg-web` | Heart rate, respiratory rate, and stress measurement from any standard webcam via rPPG. No wearable hardware required. | | `@elata-biosciences/eeg-web` | Browser-based EEG data acquisition for web applications. | | `@elata-biosciences/eeg-web-ble` | Connect consumer EEG headsets via Web Bluetooth directly in the browser. | These packages standardize data across devices into a shared format. Hardware makers gain an app ecosystem; builders get a shared data layer instead of rebuilding signal processing from scratch. All processing runs in the browser, on the user's device. ### Data Architecture Raw biodata never leaves the user's device. Machine learning runs at the edge using on-device inference. Model parameter updates (meaning not raw data) aggregate across the network. Each user's local model improves from the network's collective learning without any individual's signals being transmitted, stored, or made accessible to anyone. Not only does this mechanism ensure privacy and security of sensitive data, but it also uniquely addresses the nuances inherent to biodata (namely the unique and often unpredictible differences between individual users' biological profiles). More users means better models for everyone, without data extraction. ### App Launch Protocol Short version: **register app → launch app token → trade on curve → graduate to LP**. * **Pay 110 ELTA total** (`10` creation fee + `100` seed). The protocol deploys the entire app stack automatically. * **Launch a 10,000,000 supply app token**. Default allocation: `50%` curve, `25%` vesting, `25%` ecosystem. * **1% trading fee** routed through the fee pipeline: `FeeCollector` → `FeeSwapper` → `RewardsDistributor`. * **Revenue split**: `70%` to app stakers, `15%` to veELTA holders, `15%` to treasury. * No smart contract development needed. Account abstraction can hide wallets and gas entirely from end users. * **Browse apps** on the [App Store](https://app.elata.bio). * **Buy app tokens** during the active bonding-curve phase. * **Stake app tokens** to receive `70%` of the trading fees that app generates. * **Lock ELTA for veELTA** (`7`–`730` days, `1x`–`2x` boost) for protocol-level fee share and governance voting power. * **Track graduation** — at `42,000 ELTA`, LP is created and locked for `2 years`. *** ## Why Onchain? Two properties of this design make it such that any design except for blockchain would be incredibly impractical: **Value return instead of value extraction:** Users who stake into apps are elligible to recieve a portion of the economic value those apps generate. As is the case with any type of bio-data, the traditional model creates a perverse incentive for companies to harvest users data without returning value. Elata inverts this: data stays on the user's device, and economic participation is opt-in. **Permissionless global access:** Anyone in the world can build on, use, or stake into biosignal applications without providing personal information or requiring a specific form of identification. Builders and users may participate pseudonymously if they please. To prevent value extraction by bad actors, all developers implement core protocol primitives via open APIs that call ecosystem-native contracts only, and the entire onboarding process is completely seamless (no ID, SSN, etc) for all participants. *** ## Key Components | Component | What It Does | | ------------------ | ------------------------------------------------------------------------------------------------------------ | | **ELTA** | Base protocol token. Fixed `77,000,000` supply, minted once at deployment. | | **veELTA** | Vote-escrow token from locking ELTA (`7`–`730` days). Linear boost `1x`–`2x`. Governance voting + fee share. | | **App Tokens** | Per-app tokens. Fixed `10,000,000` supply. Launched on bonding curves. | | **Bonding Curves** | Constant-product (`x·y=k`) launch trading until graduation at `42,000 ELTA`. | | **Fee Pipeline** | `FeeCollector` → `FeeSwapper` → `RewardsDistributor`. `1%` trading fee. `70/15/15` split. | | **Biometric SDKs** | `rppg-web`, `eeg-web`, `eeg-web-ble`. Browser-based biosignal acquisition. On-device processing. | | **Elata Open EEG** | Open-source 8-channel EEG hardware (Raspberry Pi 5 + ADS1299). Rust signal processing. | *** ## Choose your path Step-by-step walkthrough of the protocol lifecycle ELTA supply, distribution, and ecosystem mechanics Elata-native rPPG, EEG, and BLE libraries Select your modality and deploy a neurosignal app in minutes Fee routing, staking economics, and protocol information modules Collection of discontinued and/or active Open Source Projects created by Elata *** ## Links * [Apps Ecosystem](https://app.elata.bio) * [GitHub](https://github.com/elata-biosciences) * [Discord](https://discord.gg/GqS9CstffK) * [Twitter/X](https://x.com/elata_bio) # Revenue Model Source: https://docs.elata.bio/learn/revenue-model How fees are collected and routed in the current protocol ## Overview The current fee system uses explicit fee kinds and a two-step pipeline: 1. `FeeCollector` records pending balances per app, fee kind, and asset. 2. `FeeSwapper` routes each fee kind according to policy. No inflation is required for this flow; fees come from protocol usage. *** ## Fee Sources | Source | Mechanic | | ----------------- | ----------------------------------------------- | | Launch fee | `10 ELTA`, tagged `LAUNCH_FEE` | | Curve trading fee | Configured in `AppFeeRouter` (default `1%`) | | Transfer tax | LP-keyed in `AppToken` (default `1%`, max `2%`) | | Module fees | `CONTENT_SALE`, `TOURNAMENT_FEE`, `OTHER` | *** ## Routing Policy ```mermaid theme={null} graph TD A[FeesFromApps] --> B[FeeCollector] B --> C[FeeSwapper] C --> D[LaunchFeeToTreasury100] C --> E[AppRevenueToContributorSplit] C --> F[AppRevenueToTreasury] ``` ### Rules * `LAUNCH_FEE` routes `100%` to treasury. * App-revenue fee kinds route to contributor split + treasury. * Default app-revenue take is `80% contributors / 20% treasury`. * If app is paused in `AppRegistry`, routing is `100%` treasury. *** ## Worked Example Assume a curve buy where `actualEltaIn = 1,000` and fee bps is `100`: | Component | Amount | | ------------ | ------------- | | Trade amount | 1,000 ELTA | | Trading fee | 10 ELTA | | Fee kind | `TRADING_FEE` | With default app-revenue routing: | Recipient | Amount | | ---------------- | ------ | | ContributorSplit | 8 ELTA | | Treasury | 2 ELTA | Contributors claim from `ContributorSplit` based on configured shares. *** ## Key Defaults | Metric | Value | | --------------------------- | --------------------------------- | | Launch fee | `10 ELTA` | | Seed ELTA | `100 ELTA` | | Curve fee baseline | `1%` | | Transfer tax baseline | `1%` | | Launch fee routing | `100% treasury` | | App-revenue routing default | `80% contributors / 20% treasury` | *** ## Next Full lifecycle and equations Builder launch flow # Tokenomics Source: https://docs.elata.bio/learn/tokenomics ELTA token supply, distribution, and veELTA mechanics ## ELTA Token ELTA is the protocol base token used for launches, curve trading, and governance/staking flows. **Contract**: ELTA is currently deployed on Ethereum Sepolia (testnet). View on [Etherscan](https://sepolia.etherscan.io/address/0x2AEb03A678A1e1E99a2AeEb4CeFCD0263A2D3587). Mainnet deployment coming soon. *** ## Supply | | | | -------------- | ------------------------- | | **Max supply** | 77,000,000 ELTA | | **Decimals** | 18 | | **Model** | Fixed supply, minted once | Hard cap. No inflation path in current token contract. ## What ELTA Does **Launch apps** — `110 ELTA` total (`100` seed + `10` creation fee) **Trade** — All app tokens trade against ELTA **Stake** — Lock ELTA as veELTA for governance-weighted voting power **Govern** — vote through governor/timelock system *** ## veELTA Lock ELTA → get veELTA. Longer lock = more veELTA. | | | | ------------ | ------------------ | | **Min lock** | 7 days | | **Max lock** | 730 days (2 years) | | **Boost** | 1x to 2x | ### Math $$ \text{veELTA} = \text{ELTA} \times \left(1 + \frac{\text{Days Locked}}{730}\right) $$ | Lock | Boost | 1,000 ELTA → | | ------- | ----- | ------------ | | 7 days | 1.01x | 1,010 veELTA | | 1 year | 1.5x | 1,500 veELTA | | 2 years | 2x | 2,000 veELTA | ### Properties * **Non-transferable** — can't sell or send veELTA * **One lock per wallet** — can add to it or extend, but only one * **No decay** — veELTA stays constant until unlock * **Full return** — get all your ELTA back when lock expires No early unlock. Choose duration carefully. *** ## App Tokens Each app launches with its own ERC-20: | | | | ------------------- | ------------------ | | **Supply** | 10,000,000 | | **Bonding curve** | 50% | | **Vesting wallet** | 25% | | **Ecosystem vault** | 25% | | **Graduation** | 42,000 ELTA raised | ### Transfer Fee Default transfer tax is `1%` (max `2%`) and is LP-keyed: it only applies when transfers touch allowlisted liquidity-pool addresses. *** ## Fee Sources | Source | Rate | | ------------- | ---------------------- | | **Trading** | 1% | | **Launches** | 10 ELTA | | **Transfers** | 1% (default) | | **Modules** | Configurable by module | Current routing policy in V2 pipeline: * `LAUNCH_FEE` -> `100%` treasury * App-revenue fee kinds -> default `80%` contributors / `20%` treasury (governance configurable) *** ## Summary * **77M max** — fixed forever * **10M app supply per launch** — fixed by current factory defaults * **Lock longer = more voting power** — veELTA boost up to 2x * **Explicit fee kinds** — launch fee and app-revenue kinds are routed differently *** ## Next Fee mechanics and math Start earning # New file Source: https://docs.elata.bio/onchain-build Description of your new file. # Protocol Requirements Source: https://docs.elata.bio/protocol-requirements Collect the protocol, BLE, and metadata details needed before coding a device adapter. Do this work before implementation starts. A clean protocol inventory prevents most integration delays and avoids the common failure mode where the adapter works only for one test session or one firmware version. ## Required Handoff Collect this information for every device and firmware line you plan to support. | Area | What to capture | | --------------- | ------------------------------------------------------------ | | Discovery | device name patterns, service UUIDs, filters | | GATT layout | characteristics, direction, notification/read/write behavior | | Packet format | framing, byte order, headers, counters, checksums | | EEG payload | channel names, channel count, sample rate, units, scaling | | Timing | device timestamps, local timestamps, sequence behavior | | Session control | any commands required to start or stop streaming | | Failure modes | disconnect behavior, low battery behavior, firmware quirks | ## BLE Inventory Template Use this as the minimum intake format: ```md theme={null} ## Device - Model: - Firmware: - Transport: Web Bluetooth / bridge / native helper ## Discovery - Device name prefix: - Primary service UUIDs: - Required optional services: ## Characteristics - UUID: - purpose: - read / write / notify: - notes: ## EEG payload - channel names: - channel count: - sample rate: - units and scaling: - timestamp source: ## Session control - how streaming starts: - how streaming stops: - reconnect notes: ``` ## Packet Questions You Should Answer Early | Question | Why it matters | | --------------------------------------------- | ------------------------------------------------------- | | How does a packet start and end? | The decoder needs a deterministic framing rule. | | Is there a packet counter or sequence field? | This helps detect drops, reordering, and corruption. | | Is there a checksum or CRC? | This helps reject bad packets safely. | | How are samples packed? | The decoder needs the exact byte layout and endianness. | | Can multiple time steps arrive in one packet? | This affects row batching and timestamp handling. | | What changes across firmware versions? | You need predictable version gating and test coverage. | ## Metadata Rules Your adapter should never guess the basics. | Metadata | Rule | | ------------- | ----------------------------------------------------- | | Channel names | Use a documented, stable order | | Channel count | Match the emitted EEG rows exactly | | Sample rate | Use the true output rate for the active mode | | Units | Document whether values are raw, scaled, or converted | | Clock source | Clearly state `device` or `local` | Do not tune models or downstream app logic until this metadata is verified. Most reliability issues start here. ## Browser and Platform Questions This guide focuses on device integration, but platform constraints still matter. Confirm these before planning a browser BLE rollout: | Question | What to confirm | | ---------------------------------------- | --------------------------------------------- | | Does the device work over Web Bluetooth? | Chromium browsers only for this workflow | | Does it require a secure context? | `https://` or `localhost` | | Does it need a native helper? | If yes, use a separate package or bridge path | | Does Safari or iOS matter? | Browser Web Bluetooth is not available there | See [Compatibility](/sdk/operations/compatibility) for the current platform expectations. ## Definition of Ready You are ready to implement when you can answer all of the following without guessing: 1. which transport path you are taking 2. how the browser discovers the device 3. how the session starts and stops 4. how packet bytes become EEG rows 5. how timestamps and channel metadata should be emitted 6. what caveats apply by firmware, browser, or platform ## Related Docs * [Integration Paths](./integration-paths) * [Transport Contract](./transport-contract) * [Compatibility](/sdk/operations/compatibility) * [Troubleshooting](/sdk/operations/troubleshooting) ## Next Use the protocol inventory to implement a clean device layer. Turn protocol assumptions into repeatable tests. # Quickstart Source: https://docs.elata.bio/quickstart Start building awesome documentation in minutes ## Get started in three steps Get your documentation site running locally and make your first customization. ### Step 1: Set up your local environment During the onboarding process, you created a GitHub repository with your docs content if you didn't already have one. You can find a link to this repository in your [dashboard](https://dashboard.mintlify.com). To clone the repository locally so that you can make and preview changes to your docs, follow the [Cloning a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) guide in the GitHub docs. 1. Install the Mintlify CLI: `npm i -g mint` 2. Navigate to your docs directory and run: `mint dev` 3. Open `http://localhost:3000` to see your docs live! Your preview updates automatically as you edit files. ### Step 2: Deploy your changes Install the Mintlify GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app). Our GitHub app automatically deploys your changes to your docs site, so you don't need to manage deployments yourself. For a first change, let's update the name and colors of your docs site. 1. Open `docs.json` in your editor. 2. Change the `"name"` field to your project name. 3. Update the `"colors"` to match your brand. 4. Save and see your changes instantly at `http://localhost:3000`. Try changing the primary color to see an immediate difference! ### Step 3: Go live 1. Commit and push your changes. 2. Your docs will update and be live in moments! ## Next steps Now that you have your docs running, explore these key features: Learn MDX syntax and start writing your documentation. Make your docs match your brand perfectly. Include syntax-highlighted code blocks. Auto-generate API docs from OpenAPI specs. **Need help?** See our [full documentation](https://mintlify.com/docs) or join our [community](https://mintlify.com/community). # Create Elata Demo Source: https://docs.elata.bio/sdk/create-elata-demo Scaffold Elata starter apps from published templates. ## What This Package Is `@elata-biosciences/create-elata-demo` is a CLI scaffolder that generates ready-to-run Elata web apps. Use it when you want a clean scaffolded app or a consumer-facing reference project. *** ## When To Use It Use this package when you want: * the fastest path to a working Elata app * a reference project that matches the published package surface * a known-good baseline before integrating packages into an existing app Do not start with repo-internal demos when this package already covers your use case. *** ## Templates The scaffolder exposes three user-facing app starters: | Template | Description | | ----------- | ------------------------------------------------------------------------------- | | `rppg-demo` | React + Vite rPPG starter app | | `eeg-demo` | React + Vite EEG starter app with synthetic data and browser EEG wiring | | `eeg-ble` | Muse-compatible EEG starter with Chrome or Bluefy-on-iOS Web Bluetooth guidance | Short aliases are also supported: | Alias | Resolves to | | ------ | ----------- | | `rppg` | `rppg-demo` | | `eeg` | `eeg-demo` | | `ble` | `eeg-ble` | | `ble` | `eeg-ble` | *** ## Install And Invocation This package is usually invoked without installing it permanently: ```bash pnpm theme={null} pnpm create @elata-biosciences/elata-demo my-app pnpm dlx @elata-biosciences/create-elata-demo my-app ``` ```bash npm theme={null} npm create @elata-biosciences/elata-demo my-app npx @elata-biosciences/create-elata-demo my-app ``` *** ## List Available Templates ```bash pnpm theme={null} pnpm dlx @elata-biosciences/create-elata-demo -- --list-templates ``` ```bash npm theme={null} npx @elata-biosciences/create-elata-demo -- --list-templates ``` *** ## Recommended Usage ```bash pnpm theme={null} # Interactive template chooser pnpm create @elata-biosciences/elata-demo my-app # rPPG starter app (alias) pnpm create @elata-biosciences/elata-demo my-app -- --template rppg # EEG starter app pnpm create @elata-biosciences/elata-demo my-app -- --template eeg-demo # EEG starter app (alias) pnpm create @elata-biosciences/elata-demo my-app -- --template eeg # EEG starter app with BLE alias pnpm create @elata-biosciences/elata-demo my-app -- --template eeg-ble # Short BLE alias pnpm create @elata-biosciences/elata-demo my-app -- --template ble ``` ```bash npm theme={null} # Interactive template chooser npm create @elata-biosciences/elata-demo my-app # rPPG starter app (alias) npm create @elata-biosciences/elata-demo my-app -- --template rppg # EEG starter app npm create @elata-biosciences/elata-demo my-app -- --template eeg-demo # EEG starter app (alias) npm create @elata-biosciences/elata-demo my-app -- --template eeg # EEG starter app with BLE alias npm create @elata-biosciences/elata-demo my-app -- --template eeg-ble # Short BLE alias npm create @elata-biosciences/elata-demo my-app -- --template ble ``` When the CLI is run interactively without `--template`, it prompts you to pick a template. In non-interactive runs, it falls back to `rppg-demo`. If you omit the project directory, the CLI also prompts for the project name. *** ## What You Get Each generated app includes: * a minimal Vite + React app shell * Elata packages pinned to a compatible set of versions * a template-specific `README.md` * a `build` script that type-checks and runs `vite build` After scaffolding: ```bash pnpm theme={null} cd my-app pnpm install pnpm run dev ``` ```bash npm theme={null} cd my-app npm install npm run dev ``` *** ## What Happens Behind The Scenes The scaffolder binary: 1. Prompts for the app type first when running interactively without `--template` 2. Prompts for `projectName` when missing 3. Validates the selected starter name 4. Copies the chosen template into the target directory 5. Renames `_gitignore` to `.gitignore` 6. Rewrites placeholders like `__APP_NAME__` and package-version placeholders *** ## Workspace Caveat If you scaffold a new app inside another `pnpm` workspace and that app is not added to the workspace globs, run this from the parent directory: ```bash pnpm theme={null} pnpm --dir my-app --ignore-workspace install pnpm --dir my-app --ignore-workspace run dev ``` ```bash npm theme={null} cd my-app npm install npm run dev ``` *** ## Repo Verification The package is tested from the repo with: ```bash theme={null} pnpm --dir packages/create-elata-demo test ./run.sh test create-elata-demo ``` The second command also smoke-tests each template by scaffolding, installing dependencies, and running a build. *** ## When To Use The Scaffolder vs. Examples | If you want... | Use | | -------------------------------------------------------------------- | ---------------------------------------------------------- | | A clean, self-contained scaffolded app with pinned deps | `create-elata-demo` | | A full product-shaped reference with routing, game loops, and charts | [Example Apps](/sdk/guides/example-apps) | | To modify the SDK itself | In-repo dev demos (`eeg-demo/`, `packages/rppg-web/demo/`) | *** ## Next Scaffold and run a starter app Package decision guide Full reference implementations # Getting Started Source: https://docs.elata.bio/sdk/eeg-web-ble/getting-started Connect to EEG headband devices over Web Bluetooth ## When To Use This Package Use `@elata-biosciences/eeg-web-ble` when your app needs: * browser-side discovery of Muse-compatible devices * live EEG streaming over Web Bluetooth * normalized headband frames for app logic or downstream analysis Install it alongside `@elata-biosciences/eeg-web`. *** ## Installation ```bash theme={null} pnpm add @elata-biosciences/eeg-web-ble @elata-biosciences/eeg-web ``` `eeg-web-ble` depends on `eeg-web` for shared frame types and the WASM module. *** ## Requirements * Browser with **Web Bluetooth** support (Chrome/Edge on desktop or Android) * Served from a **secure context** (`https://` or `localhost`) * Safari/iOS does **not** support Web Bluetooth. See [platform notes](/sdk/overview) for alternatives *** ## Basic Usage `startStreaming()` is the recommended default. It wraps `connect()` and `start()` together and avoids the common mistake of connecting successfully but never beginning to stream. ```typescript theme={null} import { initEegWasm, AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; import { BleTransport } from "@elata-biosciences/eeg-web-ble"; // Initialize WASM first await initEegWasm(); // Create transport const transport = new BleTransport({ deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), }, }); // Handle incoming EEG frames transport.onFrame = (frame) => { console.log(`EEG samples: ${frame.eeg.samples.length} rows`); console.log(`Channels: ${frame.eeg.channelNames.join(", ")}`); }; // Handle connection status changes transport.onStatus = (status) => { console.log(`Transport: ${status.state}`, status.reason || ""); }; // Connect and start streaming (triggers Bluetooth device picker) await transport.startStreaming(); // ... later await transport.stop(); ``` *** ## BleTransport Lifecycle | Method | What it does | | ------------------ | ---------------------------------------------------------- | | `startStreaming()` | Recommended: connects and starts the stream in one call | | `connect()` | Opens Bluetooth device picker, pairs, and prepares session | | `start()` | Begins EEG data stream; `onFrame` callbacks fire | | `stop()` | Stops the data stream; connection stays open | | `disconnect()` | Releases the Bluetooth session | *** ## BleTransportOptions ```typescript theme={null} const transport = new BleTransport({ sourceName: "my-app-ble", // name tag in frame.source deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), // for Athena headbands logger: (msg) => console.debug(msg), onDisconnected: () => console.warn("Device disconnected"), }, }); ``` | Option | Type | Description | | --------------- | ------------------- | ----------------------------------------------- | | `sourceName` | `string` | Identifier included in `HeadbandFrameV1.source` | | `deviceOptions` | `MuseDeviceOptions` | Passed to underlying `MuseBleDevice` | | `device` | `BleDeviceLike` | Inject a custom device implementation | *** ## Athena Support Muse S headbands with Athena firmware require an Athena decoder factory. Include it up front to keep both classic and Athena flows covered: ```typescript theme={null} import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; import { BleTransport } from "@elata-biosciences/eeg-web-ble"; const transport = new BleTransport({ deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), }, }); ``` Athena headbands provide 8 EEG channels, optics, accelerometer/gyroscope, and battery data in each frame. *** ## Device Info After connecting, you can query device metadata: ```typescript theme={null} await transport.connect(); const isAthena = transport.getIsAthena(); const boardInfo = transport.getBoardInfo(); const channelNames = transport.getEegNames(); ``` *** ## Platform Caveats * Safari and iOS do not provide usable Web Bluetooth support for this workflow. * For Safari and iOS, use a native BLE shell, companion bridge, or hybrid WebView strategy with `@elata-biosciences/eeg-web` frame contracts as the boundary. * Firmware variants may differ in command behavior. *** ## Next Step-by-step BLE streaming guide Protocol details, characteristics, and compatibility End-to-end streaming and processing guide # Muse Device Source: https://docs.elata.bio/sdk/eeg-web-ble/muse-device MuseBleDevice internals, protocol details, and compatibility ## MuseBleDevice `MuseBleDevice` is the low-level Web Bluetooth class that handles device pairing, GATT characteristic subscriptions, and packet decoding. `BleTransport` wraps it to provide the normalized `HeadbandTransport` interface. You typically do not use `MuseBleDevice` directly. Use `BleTransport` instead. *** ## Supported Protocols | Protocol | Headbands | EEG Channels | Extra Data | | ----------- | ------------------------ | ------------------------------- | ------------------------ | | **Classic** | Muse 2, Muse S (classic) | 4 (TP9, AF7, AF8, TP10) | PPG (3 channels) | | **Athena** | Muse S (Athena firmware) | 8 (TP9, AF7, AF8, TP10, AUX1-4) | Optics, accgyro, battery | Protocol is auto-detected during connection based on device characteristics. *** ## Classic Protocol Classic Muse headbands expose 4 EEG channels at 256 Hz. Each channel has its own GATT characteristic: | Characteristic | Channel | | -------------- | ------- | | `273e0003-...` | TP9 | | `273e0004-...` | AF7 | | `273e0005-...` | AF8 | | `273e0006-...` | TP10 | PPG is available on 3 additional characteristics (`PPG1`, `PPG2`, `PPG3`). *** ## Athena Protocol Athena headbands use a different packet format with two main characteristics: | Characteristic | Data | | -------------- | ------------------------------------ | | `273e0013-...` | EEG (8 channels, multiplexed) | | `273e0014-...` | Auxiliary (optics, accgyro, battery) | Athena requires a decoder factory. Without one, connection will fail: ```typescript theme={null} import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; const transport = new BleTransport({ deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), }, }); ``` *** ## MuseDeviceOptions ```typescript theme={null} interface MuseDeviceOptions { athenaDecoderFactory?: AthenaDecoderFactory; sleepMs?: (ms: number) => Promise; logger?: (message: string) => void; onDisconnected?: () => void; } ``` *** ## MuseBoardInfo Returned by `getBoardInfo()` after connection: ```typescript theme={null} interface MuseBoardInfo { device_name: string; sample_rate_hz: number; // 256 channel_count: number; // 4 or 8 eeg_channel_names: string[]; board_id: number; protocol: "classic" | "athena"; optics_channel_count: number; description: string; } ``` *** ## Browser Compatibility | Browser | Platform | Status | | ---------- | ------------------------------ | ------------- | | Chrome 56+ | Windows, macOS, Linux, Android | Supported | | Edge 79+ | Windows, macOS | Supported | | Opera 43+ | Desktop | Supported | | Safari | macOS, iOS | Not supported | | Firefox | All | Not supported | Web Bluetooth requires HTTPS. It will not work on `http://` (except `localhost` for development). *** ## Safari/iOS Workarounds Three strategies for iOS support: 1. **Native app shell** (recommended): implement BLE in Swift with CoreBluetooth, bridge frames to web UI 2. **Companion bridge**: native app streams frames over WebSocket/WebRTC to the web app 3. **Hybrid WebView**: `WKWebView` with native message handlers for BLE In all cases, use the `HeadbandFrameV1` schema as the interface boundary so browser and native transports emit the same frame shape. *** ## Next Transport API and connection guide Frame schema and transport interface # Getting Started Source: https://docs.elata.bio/sdk/eeg-web/getting-started Install and initialize the @elata-biosciences/eeg-web WASM package ## When To Use This Package Use `@elata-biosciences/eeg-web` when your app needs: * EEG analysis APIs in the browser * shared EEG web contracts used by higher-level integrations * browser-side access to Elata WASM models and signal-processing helpers This package does not implement Bluetooth device connection. Add `@elata-biosciences/eeg-web-ble` if you also need live Muse-compatible browser transport. New to the SDK? Start by scaffolding a demo app with `create-elata-demo` before wiring packages manually. See the [First App tutorial](/sdk/tutorials/first-app). *** ## Installation ```bash pnpm theme={null} pnpm add @elata-biosciences/eeg-web ``` ```bash npm theme={null} npm install @elata-biosciences/eeg-web ``` Requirements: Node.js 20+ for server-side usage and local repo tooling; modern browser with WebAssembly support for in-browser usage. *** ## WASM Initialization Before using any signal processing or model APIs, initialize the WASM module: ```typescript theme={null} import { initEegWasm } from "@elata-biosciences/eeg-web"; await initEegWasm(); ``` `initEegWasm` is idempotent. Calling it multiple times returns the same promise. For synchronous initialization (e.g., in a Web Worker): ```typescript theme={null} import { initEegWasmSync } from "@elata-biosciences/eeg-web"; initEegWasmSync(wasmModule); ``` *** ## Basic Usage Compute band powers from EEG data: ```typescript theme={null} import { initEegWasm, band_powers } from "@elata-biosciences/eeg-web"; await initEegWasm(); const sampleRate = 256; const eegSamples = new Float64Array(/* ... your EEG data ... */); const powers = band_powers(eegSamples, sampleRate); console.log("Alpha:", powers.alpha); console.log("Beta:", powers.beta); console.log("Theta:", powers.theta); console.log("Delta:", powers.delta); console.log("Gamma:", powers.gamma); ``` *** ## Package Structure `@elata-biosciences/eeg-web` is a thin TypeScript wrapper around WASM bindings generated by `wasm-bindgen`: * `initEegWasm` / `initEegWasmSync`: WASM initialization helpers * Headband frame types: normalized data schema for EEG transports * All WASM APIs: re-exported from the generated bindings ### Key Exports * `initEegWasm` * `initEegWasmSync` * `band_powers` * `WasmAlphaBumpDetector` * `WasmAlphaPeakModel` * `WasmCalmnessModel` * `AthenaWasmDecoder` * `createRppgPipeline` Generated `wasm-bindgen` exports are re-exported for compatibility and SDK debugging. Avoid instantiating generated wrappers directly unless you are intentionally debugging the SDK itself. *** ## Next Not sure if this is the right package? See the decision guide. Step-by-step integration tutorial Band powers, FFT, spectrum analysis Alpha bump detection, calmness scoring Frame schema and transport interface # Headband Transport Source: https://docs.elata.bio/sdk/eeg-web/headband-transport Normalized frame schema and transport interface for EEG headband devices ## HeadbandFrameV1 The canonical data frame emitted by all headband transports. Every implementation (BLE, native bridge, synthetic) produces this same shape: ```typescript theme={null} interface HeadbandFrameV1 { schemaVersion: "v1"; source: string; // e.g., "muse-ble" sequenceId: number; emittedAtMs: number; eeg: HeadbandSignalBlock; // always present ppgRaw?: HeadbandSignalBlock; // PPG (if available) optics?: HeadbandSignalBlock; // Athena optics accgyro?: HeadbandSignalBlock; // Athena accelerometer/gyroscope battery?: HeadbandBatteryBlock; // battery level } ``` *** ## HeadbandSignalBlock A block of time-series samples for one or more channels: ```typescript theme={null} interface HeadbandSignalBlock { sampleRateHz: number; channelNames: string[]; // e.g., ["TP9", "AF7", "AF8", "TP10"] channelCount: number; samples: number[][]; // rows of [ch0, ch1, ch2, ch3] timestampsMs?: number[]; clockSource?: "device" | "local"; } ``` *** ## HeadbandTransportState Transport lifecycle states: | State | Description | | -------------- | --------------------------------- | | `Idle` | Transport created, not connected | | `Connecting` | Connection in progress | | `Connected` | Connected, not streaming | | `Streaming` | Actively receiving frames | | `Degraded` | Connected but experiencing issues | | `Reconnecting` | Attempting to reconnect | | `Disconnected` | Disconnected from device | | `Error` | Unrecoverable error | *** ## HeadbandTransport Interface All transports implement this interface: ```typescript theme={null} interface HeadbandTransport { onFrame?: (frame: HeadbandFrameV1) => void; onStatus?: (status: HeadbandTransportStatus) => void; connect(): Promise; disconnect(): Promise; start(): Promise; stop(): Promise; } ``` **Lifecycle:** ```mermaid theme={null} stateDiagram-v2 [*] --> Idle Idle --> Connecting: connect() Connecting --> Connected: success Connected --> Streaming: start() Streaming --> Connected: stop() Connected --> Disconnected: disconnect() Streaming --> Disconnected: disconnect() Connecting --> Error: failure Streaming --> Degraded: signal issues Degraded --> Streaming: recovery Disconnected --> Connecting: connect() ``` *** ## HeadbandTransportStatus Status updates emitted via `onStatus`: ```typescript theme={null} interface HeadbandTransportStatus { state: HeadbandTransportState; atMs: number; reason?: string; errorCode?: string; recoverable?: boolean; details?: Record; } ``` *** ## Usage Pattern ```typescript theme={null} const transport: HeadbandTransport = /* BleTransport or other */; transport.onFrame = (frame) => { const eegSamples = frame.eeg.samples; // Process each row: [tp9, af7, af8, tp10] }; transport.onStatus = (status) => { console.log(`State: ${status.state}`, status.reason); }; await transport.connect(); await transport.start(); // ... later await transport.stop(); await transport.disconnect(); ``` *** ## Next Connect to headband devices End-to-end streaming guide # Analysis Models Source: https://docs.elata.bio/sdk/eeg-web/models Alpha bump detection, alpha peak tracking, and calmness scoring ## WasmAlphaBumpDetector Detects alpha bumps, which are transient increases in alpha band power that indicate state transitions. ```typescript theme={null} import { initEegWasm, WasmAlphaBumpDetector } from "@elata-biosciences/eeg-web"; await initEegWasm(); const detector = new WasmAlphaBumpDetector(); // Feed samples and check for bumps const bumpDetected = detector.process(samples, sampleRateHz); ``` *** ## WasmAlphaPeakModel Tracks the individual alpha peak frequency (typically 8-13 Hz) which varies per person. ```typescript theme={null} import { WasmAlphaPeakModel } from "@elata-biosciences/eeg-web"; const model = new WasmAlphaPeakModel(); // Feed EEG data to refine peak estimate model.process(samples, sampleRateHz); const peakHz = model.peak_frequency(); ``` *** ## WasmCalmnessModel Computes a calmness score based on the ratio of alpha to beta power. Higher alpha relative to beta generally indicates a more relaxed state. ```typescript theme={null} import { WasmCalmnessModel } from "@elata-biosciences/eeg-web"; const model = new WasmCalmnessModel(); model.process(samples, sampleRateHz); const score = model.score(); // 0.0 to 1.0 ``` *** ## AthenaWasmDecoder Decodes raw Athena protocol packets from Muse S (Athena firmware) headbands. Used as a factory parameter for `BleTransport`: ```typescript theme={null} import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; const decoder = new AthenaWasmDecoder(); decoder.reset(); decoder.set_use_device_timestamps(true); decoder.set_clock_kind("monotonic"); decoder.set_reorder_window_ms(50); const output = decoder.decode(rawBytes); ``` The Athena decoder is typically not used directly. It is passed as a factory to [`BleTransport`](/sdk/eeg-web-ble/getting-started): ```typescript theme={null} import { BleTransport } from "@elata-biosciences/eeg-web-ble"; import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; const transport = new BleTransport({ deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), }, }); ``` *** ## Next Band powers, FFT, spectrum analysis Frame schema and transport interface # Signal Processing Source: https://docs.elata.bio/sdk/eeg-web/signal-processing Band power analysis, FFT, and spectrum computation ## Band Powers Compute standard EEG frequency band powers from a sample array: ```typescript theme={null} import { initEegWasm, band_powers } from "@elata-biosciences/eeg-web"; await initEegWasm(); const powers = band_powers(samples, sampleRateHz); // powers.delta 0.5-4 Hz // powers.theta 4-8 Hz // powers.alpha 8-13 Hz // powers.beta 13-30 Hz // powers.gamma 30-100 Hz ``` `band_powers` returns a `WasmBandPowers` object with named fields for each standard band. *** ## Individual Band Functions For targeted analysis, use individual band functions: ```typescript theme={null} import { alpha_power, beta_power, theta_power, delta_power, gamma_power, custom_band_power, } from "@elata-biosciences/eeg-web"; const alpha = alpha_power(samples, sampleRateHz); const beta = beta_power(samples, sampleRateHz); const theta = theta_power(samples, sampleRateHz); const delta = delta_power(samples, sampleRateHz); const gamma = gamma_power(samples, sampleRateHz); // Custom frequency range const mu = custom_band_power(samples, sampleRateHz, 8.0, 12.0); ``` *** ## Power Spectrum Compute the full power spectrum via FFT: ```typescript theme={null} import { compute_power_spectrum, get_fft_frequencies } from "@elata-biosciences/eeg-web"; const spectrum = compute_power_spectrum(samples, sampleRateHz); const frequencies = get_fft_frequencies(samples.length, sampleRateHz); // spectrum[i] is the power at frequencies[i] Hz ``` *** ## Input Format All signal processing functions expect: | Parameter | Type | Description | | -------------- | ---------------------------- | ---------------------------------------- | | `samples` | `Float64Array` or `number[]` | Single-channel EEG time series | | `sampleRateHz` | `number` | Sampling rate in Hz (e.g., 256 for Muse) | For multi-channel data (e.g., from `HeadbandFrameV1.eeg.samples`), extract individual channels and process them separately: ```typescript theme={null} const frame: HeadbandFrameV1 = /* ... from transport ... */; const channelIndex = 0; // TP9 const channelSamples = frame.eeg.samples.map(row => row[channelIndex]); const powers = band_powers(new Float64Array(channelSamples), frame.eeg.sampleRateHz); ``` *** ## Next Alpha bump detection, calmness scoring Install and initialize eeg-web # rPPG Architecture Source: https://docs.elata.bio/sdk/guides/architecture-rppg Pipeline design, component breakdown, and distribution strategy for the rPPG + Ocular Proxy system. This is an architecture reference, not a tutorial. For integration guidance, see [rPPG In A Browser App](/sdk/guides/rppg-browser) and [rppg-web Getting Started](/sdk/rppg-web/getting-started). ## Summary The rPPG system extracts heart rate and optional ocular features from camera video, then produces calibrated, probabilistic bandpower proxies with confidence scores. A hybrid model keeps capture and vision in JS or native code, while DSP and metrics live in shared Rust/WASM/FFI modules. *** ## Goals * Single processing core for web, iOS, Android, and desktop * On-device processing (no raw video leaves the device) * Stable metrics with explicit confidence and quality gating * Clear separation between capture/vision and DSP ## Non-Goals * Replacing clinical EEG or producing diagnostic-grade signals * Reconstructing full multi-channel EEG from webcam * Shipping training pipelines in production builds *** ## High-Level Pipeline ```mermaid theme={null} flowchart LR CAM["Camera Capture"] --> ROI["Face/ROI Tracking"] ROI --> PIX["ROI Pixel Stats"] PIX --> DSP["rPPG DSP Core"] DSP --> FUS["Optional Fusion"] FUS --> MET["Metrics + Confidence"] ``` 1. **Camera capture** via `getUserMedia` (web) or native camera APIs 2. **Face/ROI tracking** using MediaPipe tasks 3. **ROI pixel stats** extracting average RGB and green channel values 4. **rPPG DSP core** with bandpass filtering, temporal normalization, and HR/HRV estimation 5. **Optional fusion** combining ocular features with rPPG signals 6. **Metrics + confidence** for app consumption *** ## Components ### Capture and ROI (Platform-Specific) | Platform | Capture | Face Detection | | ------------- | ------------------ | -------------------------------- | | Web | `getUserMedia` | MediaPipe tasks (face/landmarks) | | iOS / Android | Native camera APIs | Native MediaPipe | **Output:** timestamped ROI statistics (average R/G/B, quality flags). ### rPPG DSP Core (Shared Rust Module) The core Rust module consumes `{timestamp, intensity}` samples and runs: * Temporal normalization * Bandpass filtering (0.7-4.0 Hz for heart rate) * Periodogram HR estimation with ACF fallback and harmonic checks **Output:** `bpm`, `confidence`, `signal_quality`, and optional debug data. ### Ocular Features (Optional) Optional capture-side features used for fatigue and arousal fusion: * Blink rate and PERCLOS (percentage of eye closure) * Gaze stability * Pupil dynamics These support fatigue/arousal estimation, not "EEG replacement." ### Fusion and Sentiment (Optional, Modular) A separate module consuming rPPG + ocular features to produce coarse indices: * `fatigue_index` * `arousal_score` * `focus_proxy` Can be JS/ONNX or native ML. Kept independent of the rPPG core. *** ## Distribution Strategy | Target | Approach | Package | | ------------- | ------------------------------------------------------------------------------------------------ | ----------------------------- | | Web | Rust to WASM via the internal `elata-rppg-wasm` crate, wrapped by `rppg-web` for a stable TS API | `@elata-biosciences/rppg-web` | | Native | Rust to FFI via the internal `elata-rppg-ffi` crate | Internal binding crate | | Compatibility | Constructors also available through the internal `elata-eeg-wasm` / `elata-eeg-ffi` crates | `@elata-biosciences/eeg-web` | Camera and MediaPipe stay outside WASM, handled by browser or native APIs. *** ## Quality, Calibration, and Uncertainty * Always publish a signal quality index (SQI) * Require per-user baseline (60-120 seconds) for proxy metrics * Emit confidence or prediction intervals for proxy metrics * Gate app behavior on SQI and confidence For the calibration API that fuses Muse PPG with camera rPPG, see [Calibration and Fusion](/sdk/rppg-web/calibration). *** ## Benchmarking * Use pyVHR offline for algorithm validation and regression tests * Compare HR error under motion, lighting, and elevated HR conditions * Use strict splits (leave-one-subject/context out) *** ## Next Install and use the rPPG package Muse PPG calibration models End-to-end webcam pipeline MediaPipe face detection # Choosing the right package Source: https://docs.elata.bio/sdk/guides/choose-the-right-package Pick the right Elata SDK package for your use case and avoid common setup mistakes. ## Recommended Decision Order 1. If you are evaluating the SDK or starting a new app, use [`create-elata-demo`](/sdk/create-elata-demo) first. 2. If you already have an app and know which capability you need, add the published package for that capability. 3. Only drop to repo-internal workflows if you are actively modifying the SDK inside the monorepo. *** ## New Project Or Evaluation The best starting point when you want a working app quickly. *** ## EEG In A Browser App Use `@elata-biosciences/eeg-web` when you need: * browser-side EEG WASM APIs * signal processing and model functions * shared types used by browser integrations Signal processing, band powers, and analysis models *** ## Browser BLE For Muse-Compatible Devices Use `@elata-biosciences/eeg-web-ble` when you need: * browser BLE discovery and streaming * normalized headband frames * a transport layer for Muse-compatible EEG devices You should generally install `@elata-biosciences/eeg-web` alongside it. Connect to headband devices over Web Bluetooth *** ## Camera-Based rPPG Use `@elata-biosciences/rppg-web` when you need: * browser-side rPPG processing * packaged WASM backend loading * demo helpers for camera-driven prototypes Heart rate from camera via face detection *** ## Local Repo Development Use `./run.sh sync-to` only if you are modifying `packages/eeg-web` inside the monorepo and want to link the local package into another app. Do not use `sync-to` as the normal onboarding path for new SDK consumers. *** ## Paths To Avoid These paths create unnecessary friction for most consumers. Only use them if you have a specific reason. * **Avoid starting from `./run.sh sync-to` for new apps.** It is a local `eeg-web` development helper, not a general setup flow. * **Avoid treating in-repo dev demos as the normal install path.** They are useful references, but `create-elata-demo` is the cleaner consumer starting point. * **Avoid assuming a scaffolded app is broken if `pnpm install` behaves strangely inside another workspace.** Check the `pnpm --ignore-workspace` workflow first. *** ## Next Scaffold your first app Full reference implementations Browser, device, and tooling support # EEG + BLE integration Source: https://docs.elata.bio/sdk/guides/eeg-ble-integration Connect a Muse-compatible headband in the browser, stream EEG frames, and compute band powers with the Elata SDK. Use this guide when you want the full browser EEG flow in one place. You will initialize the EEG WASM layer, connect over Web Bluetooth, stream frames, and turn those frames into app-ready metrics. ## What this guide covers This guide shows how to combine `@elata-biosciences/eeg-web` and `@elata-biosciences/eeg-web-ble` into a single browser flow. By the end, you will be able to: * initialize the EEG WASM runtime * connect to a Muse-compatible headband from a browser * receive normalized `HeadbandFrameV1` frames * compute real-time band powers from incoming EEG samples * stop cleanly and recover from disconnects ## Before you start You need: * `@elata-biosciences/eeg-web` * `@elata-biosciences/eeg-web-ble` * Chrome or Edge with Web Bluetooth support * `https://` or `localhost` * a Muse 2 or Muse S headband Safari and iOS do not support this browser BLE workflow. For those platforms, use a native BLE shell, a bridge app, or another transport layer and keep `@elata-biosciences/eeg-web` as your processing boundary. ## Choose the right starting point Scaffold an EEG BLE demo if you want the fastest path to a reference app. Learn the browser EEG processing package before adding device transport. Review the transport package, lifecycle methods, and platform constraints. Follow the step-by-step version if you want a tutorial before this end-to-end guide. ## Install the packages ```bash theme={null} pnpm add @elata-biosciences/eeg-web @elata-biosciences/eeg-web-ble ``` ```bash theme={null} npm install @elata-biosciences/eeg-web @elata-biosciences/eeg-web-ble ``` `@elata-biosciences/eeg-web-ble` depends on `@elata-biosciences/eeg-web` for shared frame types and the EEG WASM layer. ## Integration flow Initialize the EEG WASM module before you create a transport or call analysis helpers. ```ts theme={null} import { initEegWasm } from "@elata-biosciences/eeg-web"; await initEegWasm(); ``` Include an Athena decoder up front so both classic and Athena-compatible headbands work through the same setup. ```ts theme={null} import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; import { BleTransport } from "@elata-biosciences/eeg-web-ble"; const transport = new BleTransport({ sourceName: "my-app", deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), logger: (msg) => console.debug("[BLE]", msg), }, }); ``` Use `onStatus` for UI state and `onFrame` for EEG data. ```ts theme={null} import type { HeadbandFrameV1 } from "@elata-biosciences/eeg-web"; transport.onStatus = (status) => { const el = document.getElementById("status"); if (el) el.textContent = status.state; }; transport.onFrame = (frame: HeadbandFrameV1) => { console.log("channels", frame.eeg.channelNames); console.log("rows", frame.eeg.samples.length); }; ``` Browser BLE flows usually need a click or another user gesture to open the device picker. ```ts theme={null} async function connectHeadband() { try { await transport.connect(); await transport.start(); } catch (err) { console.error("Connection failed:", err); } } ``` In simpler app flows, `startStreaming()` is often the safest default because it combines `connect()` and `start()` in one call. Compute band powers per channel as frames arrive. ```ts theme={null} import { band_powers } from "@elata-biosciences/eeg-web"; transport.onFrame = (frame: HeadbandFrameV1) => { const { eeg } = frame; for (let ch = 0; ch < eeg.channelCount; ch++) { const channelSamples = eeg.samples.map((row) => row[ch]); const powers = band_powers( new Float64Array(channelSamples), eeg.sampleRateHz, ); console.log( `${eeg.channelNames[ch]}: alpha=${powers.alpha.toFixed(2)} beta=${powers.beta.toFixed(2)}`, ); } }; ``` ## Full example ```ts theme={null} import { initEegWasm, band_powers, AthenaWasmDecoder, } from "@elata-biosciences/eeg-web"; import type { HeadbandFrameV1 } from "@elata-biosciences/eeg-web"; import { BleTransport } from "@elata-biosciences/eeg-web-ble"; await initEegWasm(); const transport = new BleTransport({ sourceName: "my-app", deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), logger: (msg) => console.debug("[BLE]", msg), }, }); transport.onStatus = (status) => { const el = document.getElementById("status"); if (el) el.textContent = status.state; }; transport.onFrame = (frame: HeadbandFrameV1) => { const { eeg } = frame; for (let ch = 0; ch < eeg.channelCount; ch++) { const channelSamples = eeg.samples.map((row) => row[ch]); const powers = band_powers( new Float64Array(channelSamples), eeg.sampleRateHz, ); console.log( `${eeg.channelNames[ch]}: alpha=${powers.alpha.toFixed(2)} beta=${powers.beta.toFixed(2)}`, ); } }; try { await transport.connect(); await transport.start(); } catch (err) { console.error("Connection failed:", err); } ``` ## Clean shutdown Stop the stream and release the Bluetooth session when the user leaves the view or closes the page. ```ts theme={null} async function shutdown() { await transport.stop(); await transport.disconnect(); } window.addEventListener("beforeunload", shutdown); ``` ## Handle reconnection If a disconnect is recoverable, try to reconnect and restart the stream. ```ts theme={null} transport.onStatus = (status) => { if (status.state === "disconnected" && status.recoverable) { console.log("Attempting reconnect..."); setTimeout(async () => { try { await transport.connect(); await transport.start(); } catch (error) { console.error("Reconnect failed:", error); } }, 2000); } }; ``` ## Understand the transport lifecycle | Method | What it does | | ------------------ | ----------------------------------------------------- | | `startStreaming()` | Connects and starts the stream in one call | | `connect()` | Opens the Bluetooth picker and prepares the session | | `start()` | Begins the EEG stream and triggers `onFrame` | | `stop()` | Stops the stream but keeps the Bluetooth session open | | `disconnect()` | Releases the Bluetooth session | ## Device notes Works with the standard browser BLE flow. Use `athenaDecoderFactory` during transport creation. Athena devices expose richer frame content, including 8 EEG channels plus additional sensor data. You can also inspect metadata after connecting: ```ts theme={null} await transport.connect(); const isAthena = transport.getIsAthena(); const boardInfo = transport.getBoardInfo(); const channelNames = transport.getEegNames(); ``` If you are testing across Muse variants, keep the Athena decoder factory enabled from day one so you do not need a separate transport setup later. ## Architecture at a glance The browser EEG BLE flow usually looks like this: 1. initialize `@elata-biosciences/eeg-web` 2. create a `BleTransport` 3. connect from a user gesture 4. receive `HeadbandFrameV1` frames 5. compute app metrics such as band powers, scores, or state transitions 6. render charts, scores, or adaptive UI in your app ## Integration tips * Buffer frames before analysis for more stable results * Use `Float64Array` when calling `band_powers` * Keep BLE connection logic behind explicit user actions * Move frame handling into app state instead of leaving it in `console.log` * Start with a demo app if you need a working reference project first * Test with synthetic data first during development if no headband is available `band_powers` is most useful with roughly 1 to 2 seconds of data. At 256 Hz, that is about 256 to 512 samples. ## Where to go next Review device behavior, protocol details, and compatibility notes. See the transport package API and platform caveats in more detail. Follow the tutorial version of this workflow with app-oriented steps. Integrate browser EEG processing into an app before adding BLE transport. Learn the frame schema and transport boundary used by EEG flows. Pair this EEG workflow with the browser camera pipeline when you need multimodal biometrics. # EEG in a browser App Source: https://docs.elata.bio/sdk/guides/eeg-browser Add Elata EEG WASM APIs to an existing browser application. Use this page if you want the package model for browser EEG, not a full integration walkthrough. If you want numbered steps for an existing app, use [Add EEG To An Existing Browser App](/sdk/tutorials/eeg-existing-app). If you want the scaffold path, use [Build Your First Elata App](/sdk/tutorials/first-app). If you want a running app without manual wiring, scaffold with [create-elata-demo](/sdk/create-elata-demo) first. EEG is **optional** in the usual Elata journey: **camera rPPG** is the primary browser integration for many apps. Add `eeg-web` when you need brain-signal analysis; add **`eeg-web-ble`** alongside it when you need **Web Bluetooth** for a Muse-compatible headset. EEG measures electrical activity from the brain using a wearable headset. In browser apps, developers usually use EEG to stream headset samples, compute features such as band powers, and drive feedback, dashboards, adaptive UX, or interactive experiences. Concrete app examples include: * meditation or breath-training apps that adapt guidance to focus or calmness * neurofeedback experiences that reward attention or steadiness * simulated athletic-performance or training apps that react to mental state * games or creative tools that change difficulty, pacing, or effects based on live EEG features *** ## Install ```bash pnpm theme={null} pnpm add @elata-biosciences/eeg-web ``` ```bash npm theme={null} npm install @elata-biosciences/eeg-web ``` *** ## What `eeg-web` Gives You `@elata-biosciences/eeg-web` provides: * browser-side EEG WASM initialization * signal-processing and model exports such as `band_powers` * shared types and contracts used by higher-level browser integrations This package does not handle Bluetooth device connection by itself. Add `@elata-biosciences/eeg-web-ble` if you also need browser BLE transport. *** ## Minimal Integration ```ts theme={null} import { initEegWasm, band_powers } from "@elata-biosciences/eeg-web"; await initEegWasm(); const eegData = new Float32Array([0, 1, 0, -1]); const powers = band_powers(eegData, 256); console.log("alpha", powers.alpha); ``` *** ## Typical Integration Flow 1. Initialize the packaged WASM runtime with `initEegWasm()`. 2. Pass browser-side EEG sample buffers into the exported analysis functions. 3. If you later need live device transport, combine this package with `eeg-web-ble`. *** ## When To Use The EEG Template Instead Prefer the scaffolded `eeg-demo` template when you want: * a known-good Vite setup * a reference for how bundled WASM assets should be served * a synthetic-data app that runs without hardware *** ## Common Gotchas * `band_powers()` takes a **single-channel** `Float32Array`, not `number[]`. Convert with `new Float32Array(samples[channelIdx])` before passing. Passing a plain array will cause a WASM runtime error. For a Muse headband (4 channels: TP9, AF7, AF8, TP10), use a frontal channel (AF7 = index 1, or AF8 = index 2) for cognitive state features, or average across channels. * `WasmCalmnessModel.process()` expects **interleaved** samples: `[s0_ch0, s0_ch1, s1_ch0, s1_ch1, ...]`. The `frame.eeg.samples` layout is per-channel. Convert before passing. * `WasmCalmnessModel` needs `channelCount` at construction, but `channelCount` only arrives on the first frame. Construct the model inside your first-frame handler. * If `initEegWasm()` fails, your app may not be loading the packaged `wasm/` assets correctly. * If you need a live headset connection, `eeg-web` alone is not enough. * If you are only evaluating the SDK, the scaffolded app is faster than manual setup. *** ## Next Step-by-step integration tutorial Connect a Muse headset Package API and exports Common failures and fixes # Example Applications Source: https://docs.elata.bio/sdk/guides/example-apps Open source browser apps built with Elata EEG, Web Bluetooth, and rPPG packages. These are full product-shaped integrations with routing, sessions, charts, and game loops. They go beyond the `create-elata-demo` starter templates and show what a complete app looks like. ## Featured Apps Guided breathing with live EEG and rPPG biometric monitoring. 3D flight simulator with post-session neural analytics. Brain-reactive arcade gameplay that responds to mental state. Chess against Stockfish with a neural HUD overlay. Stress-modulated reaction game with results tracking. *** ## What These Apps Demonstrate Each app is a standalone repository that uses the published `@elata-biosciences` packages: | Package | Purpose | | -------------------------------- | ----------------------------------- | | `@elata-biosciences/eeg-web` | EEG signal processing and models | | `@elata-biosciences/eeg-web-ble` | Web Bluetooth headband streaming | | `@elata-biosciences/rppg-web` | Camera-based heart rate measurement | These apps are useful as reference implementations when you need to see how a real product wires up SDK sessions, state management, charts, and cleanup. *** ## When To Use These vs. `create-elata-demo` | If you want to... | Start here | | ---------------------------------------------------------------------- | --------------------------------------------- | | Get a working app in under a minute | [`create-elata-demo`](/sdk/create-elata-demo) | | See a complete product with routing, game loops, or data visualization | One of the example apps above | | Compare your integration against a known-good reference | Either path works | *** ## Next Scaffold a starter app Package decision guide Primary browser integration # Federated Learning roadmap and privacy Source: https://docs.elata.bio/sdk/guides/federated-learning How Elata plans to use federated learning, why it is on the roadmap, and how it preserves user privacy. Federated learning is a roadmap direction, not the default production integration path today. Federated learning is on the Elata roadmap for future model-improvement flows. Today, Elata SDK focuses on local on-device and in-browser processing paths. As federated capabilities are introduced, the goal is to let apps contribute to global model quality improvements without sending raw biosignal data to a central server. ## What Federated Learning Means Here In an Elata federated setup, app instances would train or adapt model weights locally, then send only constrained update artifacts for aggregation. The intended direction is: 1. process and train locally in the user environment 2. send model updates instead of raw EEG or camera frames 3. aggregate updates across many participants 4. return improved shared model versions to clients ## Why It Is On The Roadmap Federated learning is a strong fit for biosignal products because it can improve model quality across device types and usage contexts while reducing privacy exposure. Planned benefits include: * better cross-user and cross-device robustness over time * faster model iteration without requiring centralized raw-data collection * clearer privacy posture for sensitive physiological signals ## How It Preserves Privacy Federated learning helps preserve privacy by changing what leaves the device: * raw biosignal inputs stay local by default * shared artifacts are model updates, not full raw signal streams * aggregation combines many updates before model rollout Federated learning is not a complete privacy guarantee by itself. In production systems, it is typically paired with controls such as secure transport, authentication, update validation, and additional privacy techniques. ## Current Status Federated learning is a roadmap direction, not the default production integration path today. For current integrations, use the existing package entrypoints: * EEG: `@elata-biosciences/eeg-web` and `@elata-biosciences/eeg-web-ble` * rPPG: `@elata-biosciences/rppg-web` ## Next Browser EEG integration Camera-based rPPG integration Browser and device support # Remote sensing in a browser App Source: https://docs.elata.bio/sdk/guides/rppg-browser Add browser-based camera rPPG with the supported Elata session helpers. Use this page if you want the integration model for browser rPPG. If you want numbered steps for an existing app, use [Add Camera-Based rPPG To An Existing Browser App](/sdk/tutorials/rppg-existing-app). If you want the scaffold path, use [Build Your First Elata App](/sdk/tutorials/first-app). This is the **primary** browser biosignal path for most products: no headset required before you ship meaningful signal UX. rPPG stands for remote photoplethysmography. It estimates pulse-related changes from camera video, usually from a face region, without requiring a wearable sensor. In browser apps, developers usually use rPPG to turn a live camera stream into heart-rate-style metrics, diagnostics, and wellness-oriented feedback. Concrete app examples include: * deception or bluffing games that react to pulse changes during key moments * stress or arousal feedback in training and social experiences * breathing and relaxation flows that show physiological response over time * biofeedback-oriented health or wellness apps that want camera-based pulse signals without extra hardware *** ## Install ```bash pnpm theme={null} pnpm add @elata-biosciences/rppg-web ``` ```bash npm theme={null} npm install @elata-biosciences/rppg-web ``` *** ## Recommended vs. Advanced Use `createRppgSession()` for browser apps. It handles WASM init, frame capture, ROI orchestration, diagnostics, and cleanup. **Recommended:** * Use `createRppgSession()` for browser apps. * Use `createManagedRppgSession()` when you want built-in restart behavior after a terminal processor failure. * Use `createRppgPipeline()` from `@elata-biosciences/eeg-web` only if you intentionally need low-level sample ingestion. **Advanced:** * Use `RppgProcessor`, `DemoRunner`, custom backends, or generated WASM bindings only if you need custom orchestration and understand the runtime lifecycle already. * If you are not debugging the SDK itself, do not start with generated WASM exports. *** ## Minimal Integration ```ts theme={null} import { createRppgSession } from "@elata-biosciences/rppg-web"; const session = await createRppgSession({ video: videoEl, sampleRate: 30, backend: "auto", faceMesh: "off", onDiagnostics: (diagnostics) => { console.log(diagnostics.state.status, diagnostics.faceTrackingMode); console.log(diagnostics.framesSeen, diagnostics.totalSamplesReceived); console.log(diagnostics.issues, diagnostics.processorFailure); }, onError: (error) => { console.error(error.code, error.message); }, }); console.log(session.getMetrics()); ``` *** ## Typical Integration Flow 1. Acquire a camera stream in the browser and attach it to a `video` element. 2. Call `createRppgSession({ video, backend: "auto" })`. 3. Read metrics from `session.getMetrics()`. 4. Surface diagnostics from `onDiagnostics` or `session.getDiagnostics()`. 5. Stop the session during cleanup with `await session.stop()`. `createRppgSession()` owns WASM init, FaceMesh loading, frame scheduling, ROI selection, diagnostics, and cleanup. Use `session.state` or `diagnostics.state` to distinguish: * normal `running` * startup fallback or degraded setup via `degraded` * terminal runtime processor failure via `failed` If you intentionally choose `faceMesh: "off"`, the session stays in supported `video_frame` mode and is not reported as a FaceMesh failure by default. If your app needs explicit asset paths instead of the default `/pkg/*` lookup, pass one or more of: ```ts theme={null} const session = await createRppgSession({ video: videoEl, wasmJsUrl: "/assets/rppg_wasm.js", wasmBinaryUrl: "/assets/rppg_wasm_bg.wasm", }); ``` Advanced apps can also provide `wasmImporter` directly. *** ## Managed Restart Flow If you want the SDK to own restart timing after terminal processor failures, use the managed wrapper: ```ts theme={null} import { createManagedRppgSession } from "@elata-biosciences/rppg-web"; const managed = await createManagedRppgSession({ video: videoEl, faceMesh: "off", maxRetries: 3, retryDelayMs: 1500, onStateChange: (state) => { console.log(state.status, state.retryCount, state.lastError?.code); }, }); ``` The managed wrapper exposes high-level states such as `starting`, `running`, `retrying`, and `failed`, while still letting apps drop down to the underlying `RppgSession` when needed. *** ## Advanced Helpers Use `getTraceSnapshot()` when you need recent waveform or debug points for charts, debug panels, or regression capture: ```ts theme={null} const trace = session.getTraceSnapshot(300); console.log(trace.points); console.log(trace.lastSample); console.log(trace.backendFailure); ``` For peak/threshold waveform debug from the trace data, use `computeTraceWaveformDebug()`: ```ts theme={null} import { computeTraceWaveformDebug } from "@elata-biosciences/rppg-web"; const waveform = computeTraceWaveformDebug(session.getTraceSnapshot(300)); console.log(waveform.peaks); ``` Use `normalizeRppgError()` instead of parsing raw message text in app code: ```ts theme={null} import { normalizeRppgError } from "@elata-biosciences/rppg-web"; const normalized = normalizeRppgError(session.lastError, session.getDiagnostics()); console.log(normalized?.code); console.log(normalized?.message); console.log(normalized?.guidance); ``` This gives apps stable categories such as `wasm_init_failed`, `backend_unavailable`, `camera_not_playing`, and `processor_failed`. If you want a single app-facing snapshot with restart status, publish gating, trace data, and stable messages, use `createRppgAppAdapter()`: ```ts theme={null} import { createManagedRppgSession, createRppgAppAdapter, } from "@elata-biosciences/rppg-web"; const managed = await createManagedRppgSession({ video, faceMesh: "off", }); const adapter = createRppgAppAdapter(); const app = adapter.getSnapshot(managed); if (app.canPublish) { console.log(app.publishBpm); } console.log(app.status, app.message); ``` If you want the SDK to own the recurring snapshot loop too, use `createRppgAppMonitor()`: ```ts theme={null} import { createManagedRppgSession, createRppgAppMonitor, } from "@elata-biosciences/rppg-web"; const managed = await createManagedRppgSession({ video, faceMesh: "off", }); const monitor = createRppgAppMonitor(managed, { intervalMs: 500 }); monitor.subscribe((snapshot) => { console.log(snapshot.status, snapshot.publishBpm); }); monitor.start(); ``` `createRppgSession()` now waits for the video element to start playing by default. If you need to coordinate that step yourself, call `ensureVideoPlaying()` directly: ```ts theme={null} import { ensureVideoPlaying } from "@elata-biosciences/rppg-web"; await ensureVideoPlaying(video, { timeoutMs: 5000 }); ``` *** ## When To Use The rPPG Template Instead Prefer the scaffolded `rppg-demo` template when you want: * a known-good browser camera app * a reference for packaged WASM asset loading * a faster comparison point when debugging your own integration *** ## Common Gotchas * If `session.backendMode` is `unavailable`, your app is probably not serving the packaged `pkg/` assets correctly. * If `session.state.status` is `failed`, treat that processor backend as terminal and recreate the session instead of continuing to poll metrics from it. * If you see "backend pipeline has no push\_sample API", you likely bypassed the safe wrapper path. Start with `createRppgSession()` for browser apps, or `initEegWasm()` plus `createRppgPipeline()` for low-level ingestion. * If you hit `wasmrppgpipeline_new`, initialize the WASM module before creating low-level pipelines and avoid calling generated constructors directly. * If you see deprecated init warnings, route startup through `initEegWasm()` instead of forwarding raw strings, URLs, or buffers to the generated init exports. * If camera access fails, confirm the page has permission to use `getUserMedia`. * If `session.lastError` is non-null, use its `code` and `message` to surface the real capture or processor failure instead of retrying blindly. * If you are just evaluating the SDK, the scaffolded app is much faster than building the whole browser pipeline yourself. *** ## Version Guidance If you install both `@elata-biosciences/rppg-web` and `@elata-biosciences/eeg-web`, prefer matching versions. They are developed and verified together in the same repo. *** ## Next Step-by-step rPPG integration Package API and exports Pipeline design and components Common failures and fixes # Camera Integration Source: https://docs.elata.bio/sdk/guides/rppg-camera Add camera-based heart rate to a browser app with the Elata rPPG Web SDK. Use this guide when you want live camera-based heart rate in a browser app. Start with the quick path first. Move to the manual pipeline only if you need lower-level control. ## What this guide covers This guide shows how to: * capture webcam frames in the browser * detect a face and extract a face region * feed samples into the rPPG processor * read live BPM and signal quality * improve estimates with Muse PPG when available ## Before you start ```bash pnpm theme={null} pnpm add @elata-biosciences/rppg-web ``` ```bash npm theme={null} npm install @elata-biosciences/rppg-web ``` * `@elata-biosciences/rppg-web` installed * Browser with camera access (`getUserMedia`) and WebAssembly support * HTTPS or localhost for development You need: * `@elata-biosciences/rppg-web` * a browser with camera access and WebAssembly support * `https://` or `localhost` rPPG works best when the face is well lit, mostly still, and fully visible in frame. ## Choose a starting point Scaffold a working browser app if you want the fastest path to a reference implementation. Learn the package entry points and the higher-level browser API. See the lower-level camera and face-detection primitives used in this guide. Add Muse-based calibration when you want stronger estimates. ## Quick integration For most apps, use `DemoRunner`. It handles frame capture, face detection, ROI extraction, and processing in one flow. ```bash theme={null} pnpm add @elata-biosciences/rppg-web ``` ```bash theme={null} npm install @elata-biosciences/rppg-web ``` ```ts theme={null} import { RppgProcessor, MediaPipeFrameSource, DemoRunner, } from "@elata-biosciences/rppg-web"; const source = new MediaPipeFrameSource(); const processor = new RppgProcessor("wasm", 30); const runner = new DemoRunner(source, processor, { useSkinMask: true, onStats: () => { const metrics = processor.getMetrics(); document.getElementById("bpm")!.textContent = metrics.bpm?.toFixed(0) ?? "--"; document.getElementById("quality")!.textContent = `${((metrics.quality ?? 0) * 100).toFixed(0)}%`; }, }); await runner.start(); ``` Show BPM only when signal quality is above your app's threshold. A threshold around `0.5` is a practical starting point. ## Manual pipeline Use the manual path when you want tighter control over face tracking, sampling, or how your app renders intermediate results. ```ts theme={null} import { MediaPipeFaceFrameSource, loadFaceMesh, } from "@elata-biosciences/rppg-web"; const faceMesh = await loadFaceMesh(); const source = new MediaPipeFaceFrameSource(faceMesh); ``` ```ts theme={null} import { RppgProcessor } from "@elata-biosciences/rppg-web"; const processor = new RppgProcessor("wasm", 30, 10); ``` The third argument sets a 10-second analysis window. ```ts theme={null} import { averageGreenInROI } from "@elata-biosciences/rppg-web"; source.onFrame = (frame) => { if (!frame.roi) return; const { x, y, w, h } = frame.roi; const green = averageGreenInROI(frame, x, y, w, h); processor.pushSample( frame.timestampMs ?? performance.now(), green, ); }; ``` ```ts theme={null} await source.start(); setInterval(() => { const metrics = processor.getMetrics(); console.log("BPM:", metrics.bpm, "quality:", metrics.quality); }, 1000); ``` ## Add Muse calibration If a Muse device is available, you can use its PPG as a reference signal to improve camera-based estimates. ```ts theme={null} import { RppgProcessor } from "@elata-biosciences/rppg-web"; const processor = new RppgProcessor("wasm", 30); processor.updateMuseMetrics(museBpm, 0.9, performance.now()); ``` For a fuller fusion workflow, including `MuseFusionCalibrator` and calibration models, continue to [/sdk/rppg-web/calibration](/sdk/rppg-web/calibration). ## Quality checklist Use this checklist before debugging the pipeline: * keep lighting even across the face * reduce head movement * wait 5 to 10 seconds before trusting early BPM output * make sure a face ROI is actually being detected * enable `useSkinMask` when you use `DemoRunner` ## Where to go next Learn the package surface and the higher-level browser session API. Understand the camera and face-detection primitives in more detail. Improve estimates with Muse-based calibration and multi-source fusion. Start from a working reference app if you want a faster onboarding path. # Web Bluetooth with supported devices Source: https://docs.elata.bio/sdk/guides/web-bluetooth Stream Muse-compatible EEG devices from supported Chromium browsers. Use this page if you want the transport model and platform constraints, not a full walkthrough. If you want numbered steps for an existing app, use [Stream Muse-Compatible EEG Over Web Bluetooth](/sdk/tutorials/eeg-ble-live-stream). If you want the scaffold path, use [Build Your First Elata App](/sdk/tutorials/first-app). **Role in the SDK:** camera **rPPG** is the usual first app. **EEG** is optional when you need brain signals. **Web Bluetooth** (`eeg-web-ble` with `eeg-web`) enables a live Muse-compatible headset. It is transport for EEG, not a parallel primary product to rPPG. *** ## Start With A Known-Good Scaffolded App If you want the fastest path to a working browser BLE example, scaffold the EEG starter app first: ```bash pnpm theme={null} pnpm create @elata-biosciences/elata-demo my-app -- --template eeg-ble cd my-app pnpm install pnpm run dev ``` ```bash npm theme={null} npm create @elata-biosciences/elata-demo my-app -- --template eeg-ble cd my-app npm install npm run dev ``` Use the rest of this guide when you want to add the same browser BLE flow to an existing app. *** ## Requirements * Chrome, Edge, or Bluefy on iOS * `https://` or `localhost` * Bluetooth enabled on the machine * A supported Muse-compatible EEG device Supported device classes: * Muse 2 and Muse S classic BLE devices * Muse S Athena protocol v2 devices * The synthetic Muse-compatible BLE bridge used for testing For browser BLE, use Chrome on desktop or Android, or Bluefy on iOS. Do not expect Safari itself to handle this workflow. *** ## Install ```bash pnpm theme={null} pnpm add @elata-biosciences/eeg-web @elata-biosciences/eeg-web-ble ``` ```bash npm theme={null} npm install @elata-biosciences/eeg-web @elata-biosciences/eeg-web-ble ``` *** ## Minimal Integration ```ts theme={null} import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; import { BleTransport } from "@elata-biosciences/eeg-web-ble"; const transport = new BleTransport({ deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), }, }); transport.onFrame = (frame) => { console.log(frame.eeg.samples.length); }; transport.onStatus = (status) => { console.log(status.state, status.reason); }; await transport.connect(); await transport.start(); ``` *** ## Typical Flow 1. Confirm the app is running in a secure context. 2. Construct `BleTransport`. 3. Provide `athenaDecoderFactory` if you need Athena support. 4. Subscribe to frame and status callbacks. 5. Call `connect()` and then `start()`. *** ## When To Use The BLE Template Instead Prefer the scaffolded `eeg-demo` app, or the dedicated `eeg-ble` starter, when you want: * a quick environment check for browser BLE support * a reference for transport startup and status handling * a simpler starting point than wiring the callbacks from scratch *** ## Common Gotchas * If `navigator.bluetooth` is missing, you are likely in an unsupported browser or non-secure context. * If the device chooser never appears, confirm Bluetooth is enabled and the page is served from `https://` or `localhost`. * If Athena devices fail to decode, make sure you pass an `athenaDecoderFactory` backed by `@elata-biosciences/eeg-web`. * If you need a normal iOS browser path, plan for a native bridge or hybrid strategy instead of Safari. The browser BLE guidance here assumes Bluefy on iOS. *** ## Next Step-by-step streaming guide Browser EEG package model Transport API and options Common failures and fixes # Contributing EEG Transports Source: https://docs.elata.bio/sdk/maintainers/contributing-eeg-transports How to add headset transports beyond the built-in Muse path for the Elata browser EEG stack. The canonical, detailed guide lives in the SDK monorepo: **[docs/contributing-eeg-transports.md](https://github.com/Elata-Biosciences/elata-bio-sdk/blob/main/docs/contributing-eeg-transports.md)** ## Summary * **`@elata-biosciences/eeg-web-ble`** is the shared **Web Bluetooth** transport package. It includes a **built-in Muse** implementation and is **not limited to Muse** for contributions. * **Layout:** `src/transport/` (`BleTransport`) vs `src/devices/muse/` (Muse protocol). Add new vendors under `src/devices//`. * New hardware should converge on **`HeadbandTransport`** and **`HeadbandFrameV1`** from **`@elata-biosciences/eeg-web`**. * Prefer a **new device module** in `eeg-web-ble`, a **`BleTransport` `device` adapter**, or a **sibling package** under `packages/` when the integration is large or needs a bridge. ## Recommended Default For Generally Useful Devices Use an **upstream contribution inside `eeg-web-ble`**: * `packages/eeg-web-ble/src/devices//...` for protocol, GATT, and decode logic * reuse `src/transport/bleTransport.ts` for transport and frame behavior * type adapters against exported `BleDeviceLike` from `@elata-biosciences/eeg-web-ble` * add mocked Web Bluetooth tests in `src/__tests__/` * update package docs, maintainer docs, and SDK docs together * add a changeset if the change should ship Open a GitHub issue before large protocol or packaging changes. Follow the repo **[CONTRIBUTING guide](https://github.com/Elata-Biosciences/elata-bio-sdk/blob/main/CONTRIBUTING.md)** for PRs, tests, and changesets. If you need a handoff-ready checklist for external partners, use: * [Vendor Headset Onboarding Checklist](/sdk/maintainers/vendor-headset-onboarding) # Related Repos Source: https://docs.elata.bio/sdk/maintainers/related-repos Developer-facing context for the public Elata protocol repository and package surfaces that matter when working on the SDK. The SDK monorepo is not the whole public developer surface. If you are maintaining browser integrations, validating real product behavior, or following app-launch flows end to end, you will usually need the public protocol repo alongside this one, plus the published npm package surface: * `../elata-protocol` * [@elata-biosciences/create-elata-demo on npm](https://www.npmjs.com/package/@elata-biosciences/create-elata-demo) * [@elata-biosciences/eeg-web on npm](https://www.npmjs.com/package/@elata-biosciences/eeg-web) * [@elata-biosciences/eeg-web-ble on npm](https://www.npmjs.com/package/@elata-biosciences/eeg-web-ble) * [@elata-biosciences/rppg-web on npm](https://www.npmjs.com/package/@elata-biosciences/rppg-web) Use this page as the quick map for when it matters and where developers should start. ## Public Developer Surfaces | Surface | Reach for it when you need to... | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `../elata-protocol` | understand app launches, local chain setup, deployment outputs, ABIs, XP claim tooling, or protocol behavior that SDK-integrated apps depend on | | `@elata-biosciences/*` on npm | send developers to the public install path, package docs, and canonical package entrypoints | ## Published Packages When docs need public links for developers, prefer the package pages: | Package | npm page | | -------------------------------------- | ------------------------------------------------------------------------------ | | `@elata-biosciences/create-elata-demo` | [npm page](https://www.npmjs.com/package/@elata-biosciences/create-elata-demo) | | `@elata-biosciences/eeg-web` | [npm page](https://www.npmjs.com/package/@elata-biosciences/eeg-web) | | `@elata-biosciences/eeg-web-ble` | [npm page](https://www.npmjs.com/package/@elata-biosciences/eeg-web-ble) | | `@elata-biosciences/rppg-web` | [npm page](https://www.npmjs.com/package/@elata-biosciences/rppg-web) | Lead with these package pages when the goal is helping developers install or evaluate the SDK without cloning repos. ## Example Applications These browser apps are maintained as separate repositories and deploy to GitHub Pages. They are useful when validating real-world integration patterns, UX for neurofeedback, or multi-package composition: | App | Demo | Source | | --------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------- | | Breathwork Trainer | [GitHub Pages](https://wkyleg.github.io/breathwork-trainer/) | [wkyleg/breathwork-trainer](https://github.com/wkyleg/breathwork-trainer) | | NeuroFlight | [GitHub Pages](https://wkyleg.github.io/neuroflight/) | [wkyleg/neuroflight](https://github.com/wkyleg/neuroflight) | | Monkey Mind: Inner Invaders | [GitHub Pages](https://wkyleg.github.io/monkey-mind/) | [wkyleg/monkey-mind](https://github.com/wkyleg/monkey-mind) | | Neuro Chess | [GitHub Pages](https://wkyleg.github.io/neuro-chess/) | [wkyleg/neuro-chess](https://github.com/wkyleg/neuro-chess) | | Reaction Trainer | [GitHub Pages](https://wkyleg.github.io/reaction-trainer/) | [wkyleg/reaction-trainer](https://github.com/wkyleg/reaction-trainer) | Consumer-facing documentation for developers lives on [Example Applications](/sdk/guides/example-apps). ## `elata-protocol` This repo owns the on-chain protocol surface: app launches, bonding curves, fee routing, staking, governance, XP, and deployment or config generation. For SDK developers, the important question is usually not "how do I contribute to the contracts?" but "what does an app developer need to know about the protocol their app will launch against or read from?" That makes this repo relevant when browser or WASM work intersects with: * contract ABI changes that downstream apps consume * local environments that need deployed protocol addresses * XP claim and Merkle workflows * app-launch lifecycle assumptions reflected in docs, demos, or SDK examples * launch, staking, fee, or governance concepts that developers need to understand to build on the ecosystem correctly ### Start Here | Need | Start with | | ---------------------------------------------------- | --------------------------------------------- | | Overview of protocol primitives and app-launch model | `../elata-protocol/README.md` | | Fast local chain setup | `../elata-protocol/QUICKSTART.md` | | App-launch lifecycle and developer assumptions | `../elata-protocol/docs/APP_LAUNCH_GUIDE.md` | | Contract math, fee routing, and protocol rules | `../elata-protocol/docs/PROTOCOL_SUMMARY.md` | | System design and contract relationships | `../elata-protocol/docs/ARCHITECTURE.md` | | Deeper local environment details | `../elata-protocol/docs/LOCAL_DEVELOPMENT.md` | ### Common Developer Flows ```bash theme={null} cd ../elata-protocol npm run local:up npm run xp:generate cat deployments/local.json ``` ### What SDK Developers Usually Need From It * `npm run local:up` brings up Anvil, deploys contracts, seeds test data, and produces the addresses and state that app developers need for local launch and integration testing. * `docs/APP_LAUNCH_GUIDE.md` is the best public place to understand what developers are actually launching into: app registration, token launch, vesting, graduation, and fee behavior. * `docs/PROTOCOL_SUMMARY.md` is the better source when SDK docs need to explain fee routing, launch parameters, or on-chain assumptions without copying logic into this repo. * If a developer report sounds like an SDK bug but only reproduces with real launches, fee routing, staking, or XP state, the protocol repo is usually the next place to verify assumptions. ## Working Model Use the repos together in this order when tracing developer-facing issues: 1. Start in `elata-bio-sdk` for package APIs, docs, and browser-side behavior. 2. Point developers to the published `@elata-biosciences` npm packages when the task is installation, evaluation, or package-level integration. 3. Move to `../elata-protocol` if the issue depends on contracts, addresses, launches, fee routing, staking, governance, or XP roots. ## Keep The Default Path Clear For consumer-facing docs, continue to lead with SDK packages and `@elata-biosciences/create-elata-demo`, ideally with links to the public npm package pages. The public protocol repo is supporting context for SDK and ecosystem developers, not the default onboarding path for SDK consumers. # Releasing Source: https://docs.elata.bio/sdk/maintainers/releasing Release, changeset, and recovery workflow for published Elata SDK packages. ## Published Packages This repository currently publishes: * `@elata-biosciences/eeg-web` * `@elata-biosciences/eeg-web-ble` * `@elata-biosciences/rppg-web` * `@elata-biosciences/ppg-web` * `@elata-biosciences/create-elata-demo` ## Quick Reference | Step | Command | | -------------------------------------- | ------------------------------------------------------ | | Add a changeset | `./run.sh changeset` | | Apply changesets and update changelogs | `./run.sh bump` | | Run the release preflight | `./run.sh release-check all` | | Build, publish, tag, and push | `./run.sh release` (defaults to npm dist-tag `latest`) | | Semver bump all packages, then publish | `./run.sh release patch`, `minor`, or `major` | | Publish on the `next` dist-tag | `./run.sh release next` or `./run.sh release all next` | ## Maintainer Workflow 1. Apply changesets with `./run.sh bump`. 2. Review the version and changelog diff, then commit it. 3. Run `./run.sh release-check all`. 4. Publish with `./run.sh release` (defaults to npm dist-tag `latest`), or `./run.sh release next` for `next`. Optional: `./run.sh release patch`, `minor`, or `major` bumps every publishable package with `pnpm version` before publishing. Prefer `./run.sh bump` when cutting a Changesets release so changelogs stay accurate. Release order is fixed in `run.sh`: `eeg-web` -> `eeg-web-ble` -> `rppg-web` -> `ppg-web` -> `create-elata-demo` ## Contributor Expectation If a user-facing package change should ship, include a changeset in the PR. ## Safe Publish Flow Publish to a non-`latest` channel first: ```bash theme={null} ./run.sh release next ``` After verification, promote or publish as `latest`. ## If A Bad Version Is Published You cannot overwrite an existing version number. Instead: 1. Deprecate the bad version. 2. Publish a fixed patch version. 3. Move the `latest` dist-tag to the fixed version. `npm unpublish` is restricted and should not be part of normal recovery. # Repo Workflows Source: https://docs.elata.bio/sdk/maintainers/repo-workflows Canonical maintainer commands and source-of-truth guidance for the Elata SDK monorepo. ## Canonical Commands Use `run.sh` from the repo root whenever possible: ```bash theme={null} ./run.sh doctor ./run.sh dev all ./run.sh build all ./run.sh test ./run.sh verify-all ``` ## What To Use For Common Jobs | Job | Source of truth | | ------------------------------------------------------ | --------------------------------------------------------------------------------------- | | New demo app flow | `@elata-biosciences/create-elata-demo` | | Consumer-facing install path and package landing pages | [npm package pages](https://www.npmjs.com/package/@elata-biosciences/create-elata-demo) | | Consumer-facing package docs | package `README.md` files | | SDK build, test, release orchestration | `run.sh` | | Public app-launch, protocol, and XP context | `../elata-protocol` | | Release policy and recovery | [/sdk/maintainers/releasing](/sdk/maintainers/releasing) | | Repo and package ownership questions | `docs/repo-map.md` in `elata-bio-sdk` | ## Repo Interrogation Order When you need to confirm whether something is current or canonical: 1. Check the repo `README.md`. 2. Check `run.sh` for command behavior. 3. Check the relevant package `package.json`. 4. Check the nearest package README or docs page. 5. Search the repo with `rg`. ## Verification Rules Of Thumb * Scaffolder changes: `./run.sh test create-elata-demo` * Consumer onboarding or packaging changes: `pnpm smoke:consumers` * `run.sh` changes: run the narrowest affected command, then broaden if release paths changed * Release tooling changes: `./run.sh verify-all` if feasible * Docs that mention onboarding: verify the `create-elata-demo` path and the parent-workspace caveat ## Backward Compatibility Notes * `scripts/dev-link.sh` remains a thin wrapper around `run.sh sync-to`. * `sync-to` remains useful for local `packages/eeg-web` development. * Consumer onboarding should still point to `create-elata-demo`, not `sync-to`. ## Related Repos If you are debugging beyond package boundaries, also use the public protocol repo: * `../elata-protocol` for contracts, local Anvil deployments, config generation, XP tooling, and simulations See [Related Repos](/sdk/maintainers/related-repos) for the developer-focused map. # Vendor Headset Onboarding Checklist Source: https://docs.elata.bio/sdk/maintainers/vendor-headset-onboarding Step-by-step checklist for external device companies adding headset support to the Elata browser EEG stack. Use this checklist when a hardware vendor wants to add headset support. The canonical repo guide lives in the SDK monorepo: * [docs/vendor-headset-onboarding-checklist.md](https://github.com/Elata-Biosciences/elata-bio-sdk/blob/main/docs/vendor-headset-onboarding-checklist.md) ## Fast Path Summary 1. Confirm protocol and GATT docs: UUIDs, packet format, sample rate, channel map, and timestamps. 2. Choose the integration path: * `eeg-web-ble` device module at `src/devices//` * sibling package such as `packages/eeg-web-` for bridge-heavy flows * app-local adapter for private proofs of concept 3. Converge on `HeadbandTransport` and `HeadbandFrameV1`. 4. Add mocked BLE and packet tests. 5. Update docs and add a changeset for publishable changes. For architecture and package expectations, see: * [Contributing EEG Transports](/sdk/maintainers/contributing-eeg-transports) # Compatibility Source: https://docs.elata.bio/sdk/operations/compatibility Current browser, device, and Node.js expectations for the Elata SDK. ## Package And Tooling Expectations | Surface | Browser runtime | Node.js | Notes | | -------------------------------------- | ------------------------------------------ | ------- | ----------------------------------------------------- | | `@elata-biosciences/create-elata-demo` | n/a | `>= 18` | CLI scaffolder only | | `@elata-biosciences/eeg-web` | modern browser with WebAssembly | `>= 20` | browser usage depends on serving packaged WASM assets | | `@elata-biosciences/eeg-web-ble` | Chrome or Edge with Web Bluetooth | `>= 20` | depends on `@elata-biosciences/eeg-web` | | `@elata-biosciences/rppg-web` | modern browser with camera and WebAssembly | `>= 20` | packaged WASM assets must be reachable by the browser | *** ## Browser Support | Workflow | Chrome / Edge | Safari macOS | Safari iOS | Notes | | ----------------------------------- | --------------------------- | ------------- | --------------------------------- | -------------------------------- | | `create-elata-demo` | n/a | n/a | n/a | scaffolder runs in Node | | EEG WASM with `eeg-web` | Supported | Supported | Supported | requires packaged `wasm/` assets | | Muse browser BLE with `eeg-web-ble` | Supported in secure context | Not supported | Not supported | requires Web Bluetooth | | rPPG with `rppg-web` | Supported | Supported | Supported with camera permissions | requires packaged `pkg/` assets | *** ## Web Bluetooth Expectations * Use Chrome or Edge. * Run on `https://` or `localhost`. * Enable Bluetooth on the machine. * Expect Safari and iOS browser BLE to be unsupported for this workflow. `eeg-web-ble` requires Web Bluetooth and an `https://` origin or `localhost`. Safari and iOS do not support Web Bluetooth for Muse browser workflows. *** ## Supported Device Classes * Muse 2 and Muse S classic BLE devices * Muse S Athena protocol v2 devices * The synthetic Muse-compatible BLE bridge used for testing *** ## Safari And iOS Notes * `eeg-web` can be used as a browser-side WASM package on Safari when your app serves its packaged assets correctly. * `eeg-web-ble` is not a Safari or iOS browser workflow. Use a native app shell with CoreBluetooth or a companion bridge app streaming frames over WebSocket. * `rppg-web` can run on Safari and iOS, but camera permissions and packaged WASM delivery still need to be correct. *** ## Package Manager Notes Generated demo apps work with `pnpm` or `npm`. This repo prefers `pnpm` for local development. If you scaffold a demo app inside another `pnpm` workspace and do not add it to that workspace, use: ```bash pnpm theme={null} pnpm --dir my-app --ignore-workspace install pnpm --dir my-app --ignore-workspace run dev ``` ```bash npm theme={null} cd my-app npm install npm run dev ``` *** ## Related Common failures and fixes Package decision guide Protocol details and browser support # Troubleshooting Source: https://docs.elata.bio/sdk/operations/troubleshooting Common setup failures and the fastest checks for Elata SDK integrations. ## `pnpm install` Did Not Create `node_modules` In My Scaffolded App You likely created the app inside another `pnpm` workspace. Run from the parent directory: ```bash pnpm theme={null} pnpm --dir my-app --ignore-workspace install pnpm --dir my-app --ignore-workspace run dev ``` ```bash npm theme={null} cd my-app npm install npm run dev ``` *** ## Web Bluetooth Is Unavailable Check the following: * Use Chrome or Edge * Run on `https://` or `localhost` * Make sure Bluetooth is enabled on the machine * Do not expect this workflow to work in Safari or iOS *** ## `loadWasmBackend()` Returned `null` Make sure your app is serving the packaged `pkg/rppg_wasm.js` and `pkg/rppg_wasm_bg.wasm` assets from a path the browser can reach. If you are unsure, compare your app with the scaffolded `rppg-demo` app. *** ## `initEegWasm()` Failed Your app is probably not serving the packaged `wasm/` assets from `@elata-biosciences/eeg-web` correctly. Compare your asset layout with the scaffolded `eeg-demo` app. If you are using Vite, the two common fixes are: add `vite-plugin-wasm` and `vite-plugin-top-level-await`, or import the WASM asset URL directly and pass it to `initEegWasm(wasmUrl)`. *** ## I Am Not Sure Which Package I Need Start with [Choose The Right Package](/sdk/guides/choose-the-right-package). If you still just want the fastest path, use `create-elata-demo`. *** ## Next Package decision guide Browser, device, and tooling support # Getting Started Source: https://docs.elata.bio/sdk/overview Cross-platform SDK for EEG signal processing, BLE headband connectivity, and rPPG ## Elata SDK The Elata SDK is a cross-platform biosignal SDK spanning EEG device pipelines, browser transports, and rPPG processing for web and native clients. It provides four npm packages and a set of Rust crates that compile to WASM and native targets. **Repository**: [github.com/Elata-Biosciences/elata-bio-sdk](https://github.com/Elata-Biosciences/elata-bio-sdk) *** ## Architecture ```text theme={null} ┌──────────────────────────────────────────────────────┐ │ Elata SDK │ ├──────────────────────────────────────────────────────┤ │ Platform Bindings │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ WASM │ │ Swift │ │ Kotlin │ │ │ │ (Browser)│ │ (iOS) │ │(Android) │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ └─────────────┴─────────────┘ │ │ │ │ │ Models Layer │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ Alpha Bump │ │ Calmness │ │ │ │ Detector │ │ Model │ │ │ └────────┬────────┘ └────────┬────────┘ │ │ └────────┬──────────┘ │ │ Signal Processing │ │ │ ┌─────────────────────────────────────┐ │ │ │ FFT │ Band Power │ Filtering │ │ │ └─────────────────────────────────────┘ │ │ ▲ │ │ HAL Layer │ │ │ ┌─────────────────────────────────────┐ │ │ │ EegDevice Trait │ │ │ │ connect() │ start_stream() │ read() │ │ │ └─────────────────────────────────────┘ │ └──────────────────────────────────────────────────────┘ ``` *** ## Quick Start The fastest path is to scaffold a demo app with `create-elata-demo`: ```bash theme={null} # rPPG web demo (default template) npm create @elata-biosciences/elata-demo my-app # EEG web demo npm create @elata-biosciences/elata-demo my-app -- --template eeg-demo # EEG Web Bluetooth demo npm create @elata-biosciences/elata-demo my-app -- --template eeg-ble ``` After scaffolding: ```bash theme={null} cd my-app pnpm install pnpm run dev ``` If you're scaffolding inside an existing `pnpm` workspace, use `pnpm --dir my-app --ignore-workspace install` instead. *** ## Choose the Right Package | Goal | Start here | Notes | | ------------------------------------------------------ | -------------------------------------- | ---------------------------------------------------- | | Scaffold a new demo app | `@elata-biosciences/create-elata-demo` | Fastest path for evaluation and onboarding | | Run EEG WASM APIs in the browser | `@elata-biosciences/eeg-web` | Signal processing, models, and WASM helpers | | Connect to a Muse-compatible EEG device in the browser | `@elata-biosciences/eeg-web-ble` | Requires `eeg-web` and Web Bluetooth | | Run camera-based rPPG in a browser app | `@elata-biosciences/rppg-web` | Includes processor, backend loader, and demo helpers | *** ## npm Packages | Package | Version | Description | | ------------------------------------------------------------------------------------------------------------ | ------- | -------------------------------------------------------- | | [`@elata-biosciences/create-elata-demo`](https://www.npmjs.com/package/@elata-biosciences/create-elata-demo) | 0.1.16 | Demo scaffolder with rPPG, EEG, and EEG BLE templates | | [`@elata-biosciences/eeg-web`](https://www.npmjs.com/package/@elata-biosciences/eeg-web) | 0.1.16 | EEG WASM bindings: signal processing, band power, models | | [`@elata-biosciences/eeg-web-ble`](https://www.npmjs.com/package/@elata-biosciences/eeg-web-ble) | 0.1.16 | Web Bluetooth transport for EEG headband devices | | [`@elata-biosciences/rppg-web`](https://www.npmjs.com/package/@elata-biosciences/rppg-web) | 0.1.16 | rPPG pipeline: heart rate from camera via face detection | ### Add packages to an existing app ```bash theme={null} # EEG signal processing (WASM) pnpm add @elata-biosciences/eeg-web # BLE headband connectivity (requires eeg-web) pnpm add @elata-biosciences/eeg-web-ble @elata-biosciences/eeg-web # rPPG (camera-based heart rate) pnpm add @elata-biosciences/rppg-web ``` **Requirements**: Node.js 18+, modern browser with WebAssembly support. *** ## Rust Crates The SDK is built on Rust crates that compile to WASM and native targets. The primary public Rust crates are the core and protocol crates; synthetic and binding crates are mainly internal packaging surfaces. | Crate | Purpose | | ------------------ | ------------------------------------------------------------- | | `elata-eeg-hal` | Core HAL traits: `EegDevice`, `SampleBuffer`, `ChannelConfig` | | `elata-eeg-signal` | FFT, band power analysis, filtering | | `elata-eeg-models` | Alpha Bump Detector, Calmness Model | | `elata-rppg` | rPPG pipeline core | | `elata-muse-proto` | Muse classic and Athena protocol | *** ## Device Support | Device | Protocol | Channels | Status | | ---------------- | ----------- | --------------------------- | ------------ | | Muse 2 | Classic BLE | 4 EEG (TP9, AF7, AF8, TP10) | Supported | | Muse S | Classic BLE | 4 EEG + PPG | Supported | | Muse S (Athena) | Athena v2 | 8 EEG + optics + accgyro | Supported | | Synthetic Bridge | BLE bridge | Configurable | Testing only | *** ## Compatibility | Surface | Chrome / Edge | Safari macOS | Safari iOS | Node.js | | ------------------- | ------------- | ------------- | ----------------------------------- | ------------------------------ | | `create-elata-demo` | n/a | n/a | n/a | `>= 18` | | `eeg-web` | Supported | Supported | Supported | `>= 20` for local repo tooling | | `eeg-web-ble` | Supported | Not supported | Not supported | `>= 20` for local repo tooling | | `rppg-web` | Supported | Supported | Supported (with camera permissions) | `>= 20` for local repo tooling | `eeg-web-ble` requires Web Bluetooth and an `https://` origin or `localhost`. Safari and iOS do not support Web Bluetooth for Muse browser workflows. Use a native app shell with CoreBluetooth or a companion bridge app streaming frames over WebSocket. *** ## Build from Source ```bash theme={null} git clone https://github.com/Elata-Biosciences/elata-bio-sdk.git cd elata-bio-sdk ./run.sh install # Install dependencies ./run.sh build all # Release build (WASM + TS) ./run.sh test # Run all tests ./run.sh demo eeg # Launch EEG demo ./run.sh demo rppg # Launch rPPG demo ``` *** ## Next Signal processing and models Connect to headband devices Heart rate from camera Package decision guide Full reference implementations Scaffold a starter app # Calibration & Fusion Source: https://docs.elata.bio/sdk/rppg-web/calibration Muse PPG calibration and multi-source heart rate fusion ## Overview When a Muse headband with PPG is available alongside camera-based rPPG, the SDK supports **sensor fusion**, using the contact PPG as a reference to calibrate and improve camera-based heart rate estimates. *** ## MuseFusionCalibrator Fuses Muse PPG readings with camera rPPG estimates for improved accuracy: ```typescript theme={null} import { RppgProcessor, MuseFusionCalibrator } from "@elata-biosciences/rppg-web"; const processor = new RppgProcessor("wasm", 30); const calibrator = new MuseFusionCalibrator(); // Feed Muse PPG readings (from headband) calibrator.updateMuse(museBpm, quality, timestampMs); // Feed camera rPPG readings calibrator.updateCamera(cameraBpm, cameraQuality, timestampMs); // Get fused result const fused = calibrator.fuse(cameraBpm, cameraQuality, timestampMs); ``` The `RppgProcessor` also has a built-in Muse integration: ```typescript theme={null} processor.updateMuseMetrics(museBpm, quality, timestampMs); ``` *** ## MuseCalibrationModel A simple regression model that learns the relationship between camera and contact BPM over time: ```typescript theme={null} import { MuseCalibrationModel } from "@elata-biosciences/rppg-web"; const model = new MuseCalibrationModel(); // Train with paired observations model.train(spectralBpm, acfBpm, trueBpm); // Check if enough data collected if (model.isTrained()) { const predictedBpm = model.predict(spectralBpm, acfBpm); } // Persistence const snapshot = model.getSnapshot(); model.loadSnapshot(snapshot); model.reset(); ``` *** ## BPM Evidence Types The processor produces evidence from multiple analysis methods: ```typescript theme={null} type BpmEvidenceSource = "spectral" | "acf" | "tracker" | "muse" | "calibrated"; type BpmEvidence = { source: BpmEvidenceSource; bpm: number; quality: number; timestampMs: number; }; type BpmResolutionResult = { bpm: number; quality: number; source: BpmEvidenceSource; evidence: BpmEvidence[]; }; type FusionSource = "camera" | "muse" | "fused"; ``` *** ## Muse PPG Filter Apply Muse-style bandpass filtering to PPG samples: ```typescript theme={null} import { museStyleFilter } from "@elata-biosciences/rppg-web"; const filtered = museStyleFilter(ppgSamples, sampleRate); ``` *** ## Calibration Workflow ```mermaid theme={null} flowchart TD MUS["Muse Headband PPG"] -->|"updateMuse(bpm)"| CAL["MuseFusionCalibrator"] CAM["Camera rPPG"] -->|"updateCamera(bpm)"| CAL CAL -->|"fuse()"| FUSED["Fused BPM Estimate"] CAM -->|"spectral + ACF"| MOD["MuseCalibrationModel"] MUS -->|"true BPM"| MOD MOD -->|"predict()"| CALIBRATED["Calibrated Camera BPM"] ``` 1. Start with camera-only rPPG 2. When a Muse headband connects, feed its PPG as ground truth 3. The calibration model learns the camera-to-contact mapping 4. Once trained, camera-only estimates are corrected using the learned model 5. The fusion calibrator combines both sources for maximum accuracy *** ## Next Camera capture and face detection End-to-end webcam pipeline # Frame Sources Source: https://docs.elata.bio/sdk/rppg-web/frame-sources Camera capture and face detection with MediaPipe ## FrameSource Interface All frame sources implement this interface: ```typescript theme={null} interface FrameSource { onFrame: ((frame: Frame) => void) | null; start(): Promise; stop(): Promise; } type Frame = { data: Uint8ClampedArray | number[]; // RGBA pixel data width: number; height: number; roi?: ROI; rois?: ROI[]; timestampMs?: number; }; type ROI = { x: number; y: number; w: number; h: number }; ``` *** ## MediaPipeFrameSource Captures camera frames and uses MediaPipe for face detection, providing a face ROI with each frame: ```typescript theme={null} import { MediaPipeFrameSource } from "@elata-biosciences/rppg-web"; const source = new MediaPipeFrameSource(); source.onFrame = (frame) => { // frame.roi contains the detected face bounding box // frame.data contains the camera image pixels console.log("Face ROI:", frame.roi); }; await source.start(); // ... later await source.stop(); ``` *** ## MediaPipeFaceFrameSource A more specialized variant that uses MediaPipe FaceMesh for precise facial landmark detection. Provides multiple ROIs for forehead, cheeks, etc.: ```typescript theme={null} import { MediaPipeFaceFrameSource, loadFaceMesh } from "@elata-biosciences/rppg-web"; const faceMesh = await loadFaceMesh(); const source = new MediaPipeFaceFrameSource(faceMesh); source.onFrame = (frame) => { // frame.rois may contain multiple face regions console.log("Face regions:", frame.rois?.length); }; await source.start(); ``` *** ## loadFaceMesh Helper to load the MediaPipe FaceMesh model: ```typescript theme={null} import { loadFaceMesh } from "@elata-biosciences/rppg-web"; const faceMesh = await loadFaceMesh(); ``` *** ## DemoRunner `DemoRunner` orchestrates a frame source and `RppgProcessor` together, handling ROI extraction, skin masking, and stats reporting: ```typescript theme={null} import { DemoRunner, MediaPipeFrameSource, RppgProcessor } from "@elata-biosciences/rppg-web"; import type { DemoRunnerOptions } from "@elata-biosciences/rppg-web"; const source = new MediaPipeFrameSource(); const processor = new RppgProcessor("wasm", 30); const options: DemoRunnerOptions = { useSkinMask: true, onStats: (stats) => { console.log(`Green: ${stats.intensity}, Skin: ${stats.skinRatio}, FPS: ${stats.fps}`); }, }; const runner = new DemoRunner(source, processor, options); await runner.start(); // ... later await runner.stop(); ``` ### DemoRunnerOptions | Option | Type | Default | Description | | ------------------------- | ------------- | ------- | ---------------------------------------------- | | `roi` | `ROI \| null` | `null` | Fixed ROI override (null = use face detection) | | `sampleRate` | `number` | - | Override sample rate | | `roiSmoothingAlpha` | `number` | - | Exponential smoothing for ROI jitter | | `useSkinMask` | `boolean` | `false` | Apply YCbCr skin tone mask | | `skinRatioSmoothingAlpha` | `number` | - | Smooth the skin ratio metric | | `onStats` | `function` | - | Callback with per-frame statistics | *** ## ROI Helper Extract average green channel intensity from a region of interest: ```typescript theme={null} import { averageGreenInROI } from "@elata-biosciences/rppg-web"; const intensity = averageGreenInROI(frame, roi.x, roi.y, roi.w, roi.h); ``` *** ## Next Muse PPG calibration models Install and configure rppg-web # Getting Started Source: https://docs.elata.bio/sdk/rppg-web/getting-started Camera-based heart rate measurement with @elata-biosciences/rppg-web ## What is rPPG? Remote photoplethysmography (rPPG) extracts heart rate from subtle color changes in facial skin captured by a standard camera. No contact sensor is needed, just a webcam. *** ## When To Use This Package Use `@elata-biosciences/rppg-web` when your app needs: * camera-based biosignal processing in the browser * a higher-level rPPG session API instead of raw WASM orchestration * diagnostics and app-facing helpers around rPPG sessions *** ## Installation ```bash pnpm theme={null} pnpm add @elata-biosciences/rppg-web ``` ```bash npm theme={null} npm install @elata-biosciences/rppg-web ``` Requirements: Node.js 20+, browser with camera access and WebAssembly support. *** ## Recommended Usage: `createRppgSession` For most browser apps, start with `createRppgSession()`. It handles WASM init, frame capture, ROI orchestration, diagnostics, and cleanup. ```typescript theme={null} import { createRppgSession } from "@elata-biosciences/rppg-web"; const session = await createRppgSession({ video: videoEl, sampleRate: 30, backend: "auto", faceMesh: "off", onDiagnostics: (diagnostics) => { console.log(diagnostics.state.status, diagnostics.faceTrackingMode); console.log(diagnostics.framesSeen, diagnostics.totalSamplesReceived); }, }); const metrics = session.getMetrics(); console.log("BPM:", metrics.bpm); // Stop and release camera on cleanup await session.stop(); ``` Use `createManagedRppgSession()` if you also want automatic restart after terminal processor failures. *** ## Diagnostics Guidance Every session diagnostics payload includes state, issue codes, sampling stats, and processor failure information. * If `session.state.status` becomes `failed`, treat the underlying processor as terminal and recreate the session. * If `backend: "auto"` falls back to an unavailable backend mode, diagnostics report that state instead of failing silently. *** ## Advanced: `RppgProcessor` For custom orchestration, drop to `RppgProcessor` directly. Only use this when you need something `createRppgSession()` does not provide. If you are debugging, compare against `createRppgSession()` first. ```typescript theme={null} import { RppgProcessor } from "@elata-biosciences/rppg-web"; const processor = new RppgProcessor("wasm", 30); // backend, sampleRate // Feed green-channel intensity from face ROI each frame processor.pushSample(performance.now(), greenIntensity); const metrics = processor.getMetrics(); console.log("BPM:", metrics.bpm); ``` ### Constructor ```typescript theme={null} new RppgProcessor(backend: Backend, sampleRate: number, windowSeconds?: number) ``` | Parameter | Type | Description | | --------------- | ---------------------- | ------------------------------------- | | `backend` | `"wasm"` or `"native"` | Processing backend | | `sampleRate` | `number` | Expected frames per second (e.g., 30) | | `windowSeconds` | `number` | Analysis window length (default: 10) | ### Pushing Samples ```typescript theme={null} processor.pushSample(timestampMs, intensity); // green channel only processor.pushSampleRgb(timestampMs, r, g, b, skinRatio?); processor.pushSampleRgbMeta(timestampMs, r, g, b, skinRatio?, motion?, clipRatio?); ``` ### Metrics | Field | Type | Description | | ------------- | -------- | --------------------------- | | `bpm` | `number` | Estimated heart rate in BPM | | `quality` | `number` | Signal quality (0 to 1) | | `spectralBpm` | `number` | Spectral analysis estimate | | `acfBpm` | `number` | Autocorrelation estimate | | `confidence` | `number` | Overall confidence | *** ## Key Exports * `createRppgSession` * `createManagedRppgSession` * `RppgProcessor` * `loadWasmBackend` * `createRppgAppAdapter` * `createRppgAppMonitor` * `normalizeRppgError` * `computeTraceWaveformDebug` * `ensureVideoPlaying` *** ## Next Step-by-step integration guide MediaPipe face detection and camera capture Muse fusion and calibration models End-to-end rPPG setup # Stream EEG over Web Bluetooth Source: https://docs.elata.bio/sdk/tutorials/eeg-ble-live-stream Build a browser EEG flow that discovers a supported device, connects, and starts receiving frames. Use this page if you already have a browser app and need the recommended existing-app BLE transport path. If you want the scaffold path instead, use [Quickstart](/sdk/tutorials/first-app). If you only need the transport model first, use [Web Bluetooth With Supported Devices](/sdk/guides/web-bluetooth). This tutorial builds on the browser EEG package and adds live Web Bluetooth transport with `@elata-biosciences/eeg-web-ble`. Use this when your app needs real headset data in Chrome or Edge. This step **turns on Web Bluetooth** for a Muse-compatible headset on top of the EEG stack. It comes **after** you are committed to EEG (and usually **after** [rPPG](/sdk/guides/rppg-browser) if your product also uses camera biosignals). ## Before You Start You need: * Chrome or Edge * `https://` or `localhost` * Bluetooth enabled on the machine * a supported Muse-compatible device * `@elata-biosciences/eeg-web` installed alongside `@elata-biosciences/eeg-web-ble` Safari and iOS are not supported for this browser BLE workflow. ## What You Will Build You will: 1. install the BLE transport package 2. create a `BleTransport` 3. subscribe to frame and status events 4. connect and start streaming ## Step 1: Install The Packages ```bash pnpm theme={null} pnpm add @elata-biosciences/eeg-web @elata-biosciences/eeg-web-ble ``` ```bash npm theme={null} npm install @elata-biosciences/eeg-web @elata-biosciences/eeg-web-ble ``` ## Step 2: Transport module + connect (single paste) Use one module so imports, handlers, and lifecycle stay together (for example `src/headbandBle.ts`). Call `connectHeadband()` from a **button** click (browser BLE requires a user gesture). ```ts headbandBle.ts theme={null} import { AthenaWasmDecoder } from "@elata-biosciences/eeg-web"; import { BleTransport } from "@elata-biosciences/eeg-web-ble"; let transport: BleTransport | null = null; export function createHeadbandTransport() { const next = new BleTransport({ deviceOptions: { athenaDecoderFactory: () => new AthenaWasmDecoder(), }, }); next.onStatus = (status) => { console.log("status", status.state, status.reason); }; next.onFrame = (frame) => { console.log("eeg samples", frame.eeg.samples.length); }; return next; } export async function connectHeadband() { transport = createHeadbandTransport(); try { await transport.startStreaming(); } catch (error) { console.error("BLE start failed", error); } } ``` Why include `athenaDecoderFactory` up front: * it keeps Athena-compatible devices working * it uses the supported decoder path from `@elata-biosciences/eeg-web` * it avoids a common failure mode later when testing across device variants `startStreaming()` is the recommended default because it handles the common `connect()` plus `start()` sequence in one call and avoids a frequent mistake where apps connect successfully but never actually begin streaming. ## Step 3: Turn Frames Into App State Once `onFrame` starts firing, move the data into your own app state instead of leaving it only in `console.log`. The usual pattern is: 1. receive `HeadbandFrameV1` frames 2. extract EEG samples or metadata 3. compute or forward the values your app cares about 4. render charts, scores, or adaptation logic ## Step 4: Clean Up On Route Or Component Exit When the current view is leaving, stop streaming so later reconnect attempts start from a clean state. Add this next to the helpers above (same module as `transport`). Append to **headbandBle.ts**: ```ts theme={null} export async function stopHeadband() { if (!transport) return; await transport.stop(); transport = null; } ``` If you prefer finer-grained lifecycle control, you can still call `connect()` and `start()` separately. The tutorial uses `startStreaming()` because it is the safest default for most app integrations. ## Step 5: Handle Browser And Platform Constraints If the chooser never appears or `navigator.bluetooth` is missing, check these first: * the page is running on `https://` or `localhost` * you are using Chrome or Edge * Bluetooth is enabled * the target device is powered on and available ## Athena And Classic Devices This repo supports: * Muse 2 and Muse S classic BLE devices * Muse S Athena protocol v2 devices Including `athenaDecoderFactory` is the simplest supported way to keep both flows covered. ## Common Problems * `navigator.bluetooth` is undefined: unsupported browser or insecure context * No device chooser appears: Bluetooth disabled or page not running on a secure origin * Athena decoding fails: make sure you passed `athenaDecoderFactory` * You need Safari or iOS support: this browser package is not the right path; use a native or bridge strategy ## Next Transport API and options EEG runtime and models Transport model overview # Add EEG to an existing browser app Source: https://docs.elata.bio/sdk/tutorials/eeg-existing-app Step by step, wire Elata EEG processing into a browser app and verify the WASM path works. Use this page if you already have a browser app and want the recommended existing-app EEG integration path. If you want the scaffold path instead, use [Quickstart](/sdk/tutorials/first-app). If you only need the package model first, use [EEG In A Browser App](/sdk/guides/eeg-browser). This tutorial shows the recommended path for adding `@elata-biosciences/eeg-web` to an existing browser application. EEG is **optional** in the typical Elata journey. **Camera rPPG** is the usual primary integration unless your product needs brain-signal features. Use this when your app needs EEG analysis APIs in the browser. If you also need live headset transport, you will add `@elata-biosciences/eeg-web-ble` after this tutorial. ## What You Will Build You will: 1. install `@elata-biosciences/eeg-web` 2. initialize the EEG WASM runtime 3. run a simple analysis call 4. verify your app can serve the packaged WASM assets ## Step 1: Install The Package ```bash pnpm theme={null} pnpm add @elata-biosciences/eeg-web ``` ```bash npm theme={null} npm install @elata-biosciences/eeg-web ``` ## Step 2: Create A Small EEG Module Create a small module in your app so the integration stays isolated and easy to test (for example `src/eeg.ts`): ```ts eeg.ts theme={null} import { initEegWasm, band_powers } from "@elata-biosciences/eeg-web"; let eegInitPromise: Promise | null = null; async function ensureEegReady() { if (!eegInitPromise) { eegInitPromise = initEegWasm(); } await eegInitPromise; } export async function analyzeExampleEeg() { await ensureEegReady(); const eegData = new Float32Array([0.2, 0.5, 0.1, -0.3, -0.4, 0.1, 0.2, 0.6]); const powers = band_powers(eegData, 256); return powers; } ``` Why this shape: * `initEegWasm()` should run before using analysis helpers * the module-level Promise avoids repeated initialization, including concurrent calls * keeping it in one file makes it easier to swap in real samples later ## Step 3: Call It From Your UI For example, in a component or entry file: ```ts theme={null} import { analyzeExampleEeg } from "./eeg"; const powers = await analyzeExampleEeg(); console.log("alpha", powers.alpha); console.log("beta", powers.beta); ``` At this stage you are not using a real headset yet. You are proving that the browser app can load the runtime and execute the EEG functions correctly. ## Step 4: Verify The WASM Asset Path Run your app in development and confirm the module initializes without errors. If `initEegWasm()` fails, the most likely problem is that your bundler or app deployment is not serving the packaged `wasm/` assets correctly. This is the first thing to fix before adding more product logic. If you are using Vite, the two common fixes are: 1. add `vite-plugin-wasm` and `vite-plugin-top-level-await`, then keep using `await initEegWasm()` 2. import the WASM asset URL directly and pass it to `initEegWasm(wasmUrl)` The guide at [EEG In A Browser App](/sdk/guides/eeg-browser) shows both patterns. If you are stuck, compare your app against the scaffolded `eeg-demo` app before assuming the package itself is broken. ## Step 5: Replace Example Data With Real App Data Once the example call works, swap the placeholder array with actual EEG sample buffers from your app. The common pattern is: 1. receive or load EEG samples 2. normalize them into typed arrays 3. call Elata analysis helpers 4. map the result into app state, feedback, scoring, or visualizations That last step is where your product behavior lives. ## When To Add `eeg-web-ble` Add `@elata-biosciences/eeg-web-ble` when you need live browser transport from a supported Muse-compatible headset. Do not start there if the plain EEG runtime is not working yet. Get WASM loading working first, then add transport. ## Common Problems * `initEegWasm()` throws: your app is probably not loading packaged `wasm/` assets correctly * You expected device discovery: `eeg-web` does not do Bluetooth transport by itself * You are evaluating the SDK from scratch: start with [Build Your First Elata App](/sdk/tutorials/first-app) instead of manual setup ## Next Stream Muse EEG over BLE Package API and exports Integration overview # Build your first Elata App Source: https://docs.elata.bio/sdk/tutorials/first-app Scaffold a working app first, then use it as the reference point for deeper SDK integration. Use this page if you are new to the SDK and want one successful scaffolded app running locally before you integrate anything manually. If you want the full map (**rPPG primary**, **EEG optional**, **Bluetooth to connect a headset**) with scaffold vs step-by-step vs overview, use [Build A Browser App](/sdk/overview). The goal is simple: get a working app running locally, understand which template maps to which sensor workflow, and know where to go next. ## What You Will Build You will scaffold one of the published starter apps with `@elata-biosciences/create-elata-demo`. Pick the template that matches your goal: * `rppg-demo`: **primary**: camera-based pulse/rPPG app * `eeg-demo`: **optional**: browser EEG processing with synthetic data * `eeg-ble` alias: **Bluetooth**: use the EEG starter app with the BLE-focused alias when you want a Muse-compatible headset flow ## Why Start Here This is the recommended default because it gives you: * a working app structure * pinned compatible package versions * a reference implementation you can compare your own app against Do this before cloning repo demos or using internal maintainer workflows. ## Step 1: Choose A Template Use this decision table: | If you want to... | Choose | | ------------------------------------------------------------- | ------------------------------ | | Build the default camera-based app (no extra hardware) | `rppg-demo` | | Add browser EEG only (synthetic or offline samples first) | `eeg-demo` | | Enable a Muse-compatible headset over Bluetooth (Chrome/Edge) | `eeg-ble` alias for `eeg-demo` | If you are unsure, start with `rppg-demo`. ## Step 2: Scaffold The App Start with the interactive chooser: ```bash pnpm theme={null} pnpm create @elata-biosciences/elata-demo my-app ``` ```bash npm theme={null} npm create @elata-biosciences/elata-demo my-app ``` If you prefer the explicit default path instead, scaffold `rppg-demo` directly: ```bash pnpm theme={null} pnpm create @elata-biosciences/elata-demo my-app -- --template rppg ``` ```bash npm theme={null} npm create @elata-biosciences/elata-demo my-app -- --template rppg ``` If you want to see the full template list first: ```bash pnpm theme={null} pnpm dlx @elata-biosciences/create-elata-demo -- --list-templates ``` ```bash npm theme={null} npx @elata-biosciences/create-elata-demo -- --list-templates ``` The full alias and template matrix lives on [create-elata-demo](/sdk/create-elata-demo). ## Step 3: Install And Run Copy **one** column (pnpm or npm), then run each line in order: ```bash pnpm theme={null} cd my-app pnpm install pnpm run dev ``` ```bash npm theme={null} cd my-app npm install npm run dev ``` ## Step 4: Confirm What You Have Once the app starts, verify the expected behavior: * `rppg-demo`: asks for camera access and starts a pulse-style session * `eeg-demo`: loads EEG processing in the browser and shows synthetic-data-driven output * `eeg-ble` alias for `eeg-demo`: adds Bluetooth pairing and streaming guidance for a supported Muse-compatible headset on top of EEG If your goal is just evaluation, stop here first and learn from the generated app before integrating into an existing codebase. ## Step 5: Understand The Generated App Each scaffolded app gives you: * a minimal Vite + React shell * Elata packages already wired in * a `README.md` with template-specific notes * a `build` script so you can confirm the app compiles cleanly This is meant to be your known-good baseline. When a manual integration goes wrong later, compare your app against this generated one before assuming the package is broken. ## Common Gotcha: Scaffolding Inside Another `pnpm` Workspace If you create `my-app` inside another repository that already has a `pnpm-workspace.yaml`, `pnpm install` may attach to the parent workspace instead of the generated app. Run these **one line at a time** from the parent directory (adjust `my-app` if needed): ```bash pnpm theme={null} pnpm --dir my-app --ignore-workspace install pnpm --dir my-app --ignore-workspace run dev ``` ```bash npm theme={null} cd my-app npm install npm run dev ``` ## Where To Go Next You already have a running scaffold. The recommended order is **camera rPPG first** (most people’s primary app), **browser EEG second if the product needs brain signals**, then **Web Bluetooth to connect a headset** (transport on top of EEG). Each step splits the same way: **stay on the scaffold** or **integrate into an app you already have**. ### Next: Camera (rPPG): primary Pick the row that matches you: | Your situation | What to do next | | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **New app**: you will keep building from the generated `rppg-demo` scaffold | Use [rPPG In A Browser App](/sdk/guides/rppg-browser) for the integration model, then [rppg-web](/sdk/rppg-web/getting-started) while you change the template. For scaffold CLI details: [create-elata-demo](/sdk/create-elata-demo). | | **Existing app**: you need rPPG inside a codebase you already ship | Follow [Add Camera-Based rPPG To An Existing Browser App](/sdk/tutorials/rppg-existing-app) step by step. | ### Then: Browser EEG: optional (no headset yet) | Your situation | What to do next | | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **New app**: extend or respin `eeg-demo` | [EEG In A Browser App](/sdk/guides/eeg-browser), then [eeg-web](/sdk/eeg-web/getting-started). Scaffold reference: [create-elata-demo](/sdk/create-elata-demo). | | **Existing app** | [Add EEG To An Existing Browser App](/sdk/tutorials/eeg-existing-app). | ### Then: Enable Bluetooth headset (Muse-compatible) | Your situation | What to do next | | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **New app**: extend `eeg-demo` via the `eeg-ble` alias path | [Web Bluetooth With Supported Devices](/sdk/guides/web-bluetooth), then [eeg-web-ble](/sdk/eeg-web-ble/getting-started) (and [eeg-web](/sdk/eeg-web/getting-started)). | | **Existing app** | [Stream Muse-Compatible EEG Over Web Bluetooth](/sdk/tutorials/eeg-ble-live-stream). If WASM is not wired yet, do the EEG row above first. | ### Full map For the same choices in one place in **priority order** (rPPG, then EEG, then Bluetooth), use [Build A Browser App](/sdk/overview). ### Example Apps Full product-shaped reference implementations Package decision guide # Add camera-based rPPG to an existing browser App Source: https://docs.elata.bio/sdk/tutorials/rppg-existing-app Build a working browser rPPG flow with createRppgSession, diagnostics, and cleanup. Use this page if you already have a browser app and want the recommended existing-app integration path. If you want the scaffold path instead, use [Quickstart](/sdk/tutorials/first-app). If you only need the mental model first, use [rPPG In A Browser App](/sdk/guides/rppg-browser). This tutorial shows the recommended app integration path for `@elata-biosciences/rppg-web`. Camera rPPG is the **primary** browser integration for many Elata products. No headset required. The core idea is simple: let `createRppgSession()` own the browser runtime, video processing loop, and diagnostics while your app owns the UI. This is the usual **next tutorial** after [Build Your First Elata App](/sdk/tutorials/first-app) when you choose the **existing app** branch for camera rPPG. If you are **extending the scaffold** instead, stay on `rppg-demo` and use [rPPG In A Browser App](/sdk/guides/rppg-browser) plus [rppg-web](/sdk/rppg-web/getting-started). ## What You Will Build You will: 1. install `@elata-biosciences/rppg-web` 2. request camera access 3. attach the stream to a `video` element 4. start `createRppgSession()` 5. read metrics and diagnostics 6. stop the session during cleanup ## Step 1: Install The Package ```bash pnpm theme={null} pnpm add @elata-biosciences/rppg-web ``` ```bash npm theme={null} npm install @elata-biosciences/rppg-web ``` ## Step 2: Prepare A Video Element Your app needs a `video` element that can receive the camera stream. ```html index.html (or your component markup) theme={null} ``` The important parts are: * `autoplay` so playback can start once the stream is attached * `playsinline` for mobile browser behavior * `muted` to keep autoplay rules out of the way ## Step 3: Acquire Camera Access ```ts camera setup theme={null} const videoEl = document.getElementById("camera") as HTMLVideoElement; const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" }, audio: false, }); videoEl.srcObject = stream; await videoEl.play(); ``` At this point your browser app should already be showing the camera preview. ## Step 4: Start `createRppgSession()` ```ts rPPG session theme={null} import { createRppgSession } from "@elata-biosciences/rppg-web"; const session = await createRppgSession({ video: videoEl, sampleRate: 30, backend: "auto", faceMesh: "off", onDiagnostics: (diagnostics) => { console.log("status", diagnostics.state.status); console.log("frames", diagnostics.framesSeen); console.log("samples", diagnostics.totalSamplesReceived); console.log("issues", diagnostics.issues); }, onError: (error) => { console.error(error.code, error.message); }, }); ``` This is the recommended starting point for most browser apps. It handles: * packaged WASM backend init * frame capture * ROI/session orchestration * diagnostics emission * cleanup support ## Step 5: Read Metrics In Your UI ```ts theme={null} const metrics = session.getMetrics(); console.log(metrics); ``` In a real app you would poll or subscribe through your own UI state layer and show the values that matter to your product. ## Step 6: Clean Up Correctly When the component, route, or page is leaving, stop the session and release the camera stream. Run these in order (same `session` and `stream` as above): ```ts theme={null} await session.stop(); ``` ```ts theme={null} for (const track of stream.getTracks()) { track.stop(); } ``` This matters more than it looks. It keeps later sessions from inheriting stale camera or runtime state. ## Full example (single paste) Use this when you want one file to drop into a Vite + React app (for example replace the contents of `src/App.tsx`). It includes camera setup, session start, and cleanup on unmount. ```tsx App.tsx theme={null} import { useEffect, useRef, useState } from "react"; import { createRppgSession, type RppgSession } from "@elata-biosciences/rppg-web"; export default function App() { const videoRef = useRef(null); const sessionRef = useRef(null); const streamRef = useRef(null); const [line, setLine] = useState("Starting…"); useEffect(() => { let cancelled = false; async function run() { const video = videoRef.current; if (!video) return; let stream: MediaStream; try { stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" }, audio: false, }); } catch { setLine("Camera permission denied."); return; } if (cancelled) { stream.getTracks().forEach((t) => t.stop()); return; } streamRef.current = stream; video.srcObject = stream; await video.play().catch(() => undefined); const sampleRate = stream.getVideoTracks()[0]?.getSettings().frameRate ?? 30; try { const session = await createRppgSession({ video, sampleRate, backend: "auto", faceMesh: "off", onDiagnostics: (d) => { setLine(`status=${d.state.status} backend=${d.backendMode}`); }, onError: (e) => setLine(`${e.code}: ${e.message}`), }); if (cancelled) { await session.dispose(); return; } sessionRef.current = session; } catch (e) { setLine(e instanceof Error ? e.message : "Session failed"); } } void run(); return () => { cancelled = true; void sessionRef.current?.dispose(); sessionRef.current = null; streamRef.current?.getTracks().forEach((t) => t.stop()); streamRef.current = null; }; }, []); return (

{line}

); } ``` This example uses a React `ref` on `