diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..5808766bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,73 @@ +name: Bug report +description: Report a reproducible package bug in AuraGlass. +title: "[Bug]: " +labels: + - bug +body: + - type: markdown + attributes: + value: | + Use this for package behavior that is broken in a React or Next.js app. For visual-only regressions, use the visual regression template. + - type: textarea + id: summary + attributes: + label: Summary + description: What happened, and what did you expect instead? + placeholder: GlassCard renders with unreadable text in dark mode when... + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction + description: Provide a minimal reproduction, repository, StackBlitz, or exact code snippet. + placeholder: | + npm install aura-glass + import { GlassCard } from 'aura-glass'; + import 'aura-glass/styles'; + validations: + required: true + - type: input + id: version + attributes: + label: AuraGlass version + placeholder: 3.1.0 + validations: + required: true + - type: dropdown + id: framework + attributes: + label: Framework + options: + - React 18 + - React 19 + - Next.js 14 + - Next.js 15 + - Other + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: Include browser, Node, npm/pnpm/yarn, OS, and bundler if relevant. + placeholder: Node 20, npm 10, Chrome 124, macOS, Vite... + validations: + required: true + - type: textarea + id: logs + attributes: + label: Logs or screenshots + description: Paste relevant console output, stack traces, screenshots, or test failures. + render: shell + - type: checkboxes + id: checks + attributes: + label: Preflight + options: + - label: I import styles with `import 'aura-glass/styles';` where required. + required: true + - label: I am not importing from private `src` paths. + required: true + - label: I installed optional peer dependencies for any advanced component family I am using. + required: true diff --git a/.github/ISSUE_TEMPLATE/component_request.yml b/.github/ISSUE_TEMPLATE/component_request.yml new file mode 100644 index 000000000..a8086f5d2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/component_request.yml @@ -0,0 +1,52 @@ +name: Component request +description: Request a new component, recipe, or flagship enhancement. +title: "[Component]: " +labels: + - component-request +body: + - type: textarea + id: problem + attributes: + label: Product problem + description: What user workflow should AuraGlass support? + placeholder: We need a compact Liquid Glass billing plan comparison for SaaS settings pages. + validations: + required: true + - type: dropdown + id: category + attributes: + label: Category + options: + - Core surface + - Navigation + - Overlay + - Data and visualization + - Forms and inputs + - Media + - AI product UI + - Recipe or template + - Advanced or 3D + - Other + validations: + required: true + - type: textarea + id: api + attributes: + label: Suggested API or example + description: Include import names, props, and expected usage if you have a proposal. + render: tsx + - type: textarea + id: references + attributes: + label: Visual references + description: Link screenshots, product examples, or design notes. + - type: checkboxes + id: expectations + attributes: + label: Expected launch quality + options: + - label: Includes docs and examples. + - label: Works in compact catalog cards. + - label: Supports dark mode. + - label: Supports reduced motion where motion is present. + - label: Has focused tests. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..9b34d63cd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: AuraGlass documentation + url: https://auraglass.auraone.ai + about: Read setup, component, and release documentation before filing an issue. + - name: Security vulnerability + url: https://github.com/auraoneai/auraglass/security/policy + about: Report suspected vulnerabilities through the private security process. diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.yml b/.github/ISSUE_TEMPLATE/documentation_issue.yml new file mode 100644 index 000000000..a47d4b822 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation_issue.yml @@ -0,0 +1,37 @@ +name: Documentation issue +description: Report missing, stale, unclear, or inconsistent documentation. +title: "[Docs]: " +labels: + - documentation +body: + - type: input + id: page + attributes: + label: Page or file + placeholder: README.md, docs/guides/accessibility.md, /docs/getting-started + validations: + required: true + - type: textarea + id: problem + attributes: + label: What is wrong? + description: Explain what is missing, stale, confusing, or inconsistent. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected documentation + description: What should the page say or link to? + - type: checkboxes + id: areas + attributes: + label: Affected areas + options: + - label: Install or CSS import + - label: Next.js or SSR + - label: Peer dependencies + - label: Component props or examples + - label: Accessibility or reduced motion + - label: Performance or bundle size + - label: AI-agent guidance diff --git a/.github/ISSUE_TEMPLATE/visual_regression.yml b/.github/ISSUE_TEMPLATE/visual_regression.yml new file mode 100644 index 000000000..480a866af --- /dev/null +++ b/.github/ISSUE_TEMPLATE/visual_regression.yml @@ -0,0 +1,58 @@ +name: Visual regression +description: Report a rendering, layout, contrast, motion, or preview-quality regression. +title: "[Visual]: " +labels: + - visual-regression +body: + - type: textarea + id: summary + attributes: + label: Summary + description: Describe the visual issue and why it is a regression. + placeholder: GlassDataGrid clips row actions at mobile width... + validations: + required: true + - type: input + id: component + attributes: + label: Component or route + placeholder: GlassDataGrid, GlassCommandPalette, /components/data + validations: + required: true + - type: textarea + id: screenshots + attributes: + label: Screenshots or video + description: Attach before/after images, contact sheets, or a short clip. + validations: + required: true + - type: dropdown + id: viewport + attributes: + label: Viewport + options: + - Desktop + - Mobile + - Tablet + - Responsive range + - Storybook + - Website catalog + validations: + required: true + - type: textarea + id: checks + attributes: + label: Checks run + description: List any visual, Storybook, Playwright, or manual QA checks already run. + placeholder: npm run test:visual:ci + - type: checkboxes + id: issue_type + attributes: + label: Regression type + options: + - label: Clipping or overflow + - label: Unreadable contrast + - label: Empty or placeholder preview + - label: Motion or reduced-motion issue + - label: SSR or hydration visual mismatch + - label: Mobile layout issue diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..f9646a7f0 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,50 @@ +# Summary + +Describe the change and the user-facing behavior it affects. + +## Scope + +- [ ] Package source +- [ ] Documentation or README +- [ ] GitHub/community metadata +- [ ] Release evidence +- [ ] Tests or audit tooling +- [ ] Website handoff only; no website repo edits in this PR + +## Package Checks + +Run the focused checks that match the change. Do not mark a gate complete unless it was run on this branch. + +- [ ] `npm run typecheck` +- [ ] `npm run lint:check` +- [ ] `npm run lint:tokens` +- [ ] `npm run lint:styles` +- [ ] `npm test -- --runInBand` +- [ ] `npm run audit:components` +- [ ] `npm run audit:exports` +- [ ] `npm run audit:api` +- [ ] `npm run audit:runtime` +- [ ] `npm run build` +- [ ] `npm run verify:pack` +- [ ] `npm run test:integration:next -- --skip-build` +- [ ] `npm run release:dry-run` + +## Visual QA + +- [ ] Storybook preview checked +- [ ] Desktop viewport checked +- [ ] Mobile viewport checked +- [ ] Reduced motion checked +- [ ] Dark theme checked +- [ ] Screenshots or contact sheets attached when visual output changed + +## Documentation + +- [ ] README/npm-facing copy updated if public behavior changed +- [ ] Component docs updated if API or usage changed +- [ ] Changelog updated +- [ ] 3.1 evidence scaffold updated when a launch gate changed + +## Risk + +List known risks, follow-ups, and any gates intentionally not run. diff --git a/.github/workflows/deploy-storybook.yml b/.github/workflows/deploy-storybook.yml index 932fc29f3..40135af8a 100644 --- a/.github/workflows/deploy-storybook.yml +++ b/.github/workflows/deploy-storybook.yml @@ -8,6 +8,8 @@ on: permissions: contents: write + issues: write + pull-requests: write jobs: build-and-deploy: @@ -39,10 +41,11 @@ jobs: - name: Comment PR with Storybook URL if: github.event_name == 'pull_request' + continue-on-error: true uses: actions/github-script@v7 with: script: | - github.rest.issues.createComment({ + await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/design-system-compliance.yml b/.github/workflows/design-system-compliance.yml index d7d1fffa5..85b4f97c8 100644 --- a/.github/workflows/design-system-compliance.yml +++ b/.github/workflows/design-system-compliance.yml @@ -6,6 +6,11 @@ on: pull_request: branches: [ main, develop ] +permissions: + contents: read + issues: write + pull-requests: write + jobs: design-system-compliance: runs-on: ubuntu-latest @@ -71,6 +76,7 @@ jobs: - name: Comment PR with Design System Report if: github.event_name == 'pull_request' + continue-on-error: true uses: actions/github-script@v7 with: script: | @@ -82,7 +88,7 @@ jobs: report = '## Design System Report\n\nReport generation failed.'; } - github.rest.issues.createComment({ + await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/glass-pipeline.yml b/.github/workflows/glass-pipeline.yml index 227556df2..6d8d7a1a2 100644 --- a/.github/workflows/glass-pipeline.yml +++ b/.github/workflows/glass-pipeline.yml @@ -6,6 +6,11 @@ on: pull_request: branches: [main, develop] +permissions: + contents: read + issues: write + pull-requests: write + jobs: glass-quality-gates: name: Glass Quality Gates @@ -121,13 +126,14 @@ jobs: path: reports/glass/visual-tests/ - name: Comment on PR with test links + continue-on-error: true uses: actions/github-script@v7 with: script: | const fs = require('fs'); if (fs.existsSync('reports/glass/visual-tests/comprehensive-test.html')) { - github.rest.issues.createComment({ + await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/visual-regression.yml b/.github/workflows/visual-regression.yml index f0278cd13..2d83ea0f5 100644 --- a/.github/workflows/visual-regression.yml +++ b/.github/workflows/visual-regression.yml @@ -6,6 +6,11 @@ on: pull_request: branches: [main] +permissions: + contents: read + issues: write + pull-requests: write + jobs: visual-tests: runs-on: ubuntu-latest @@ -45,10 +50,11 @@ jobs: - name: Comment PR with visual changes if: github.event_name == 'pull_request' && failure() + continue-on-error: true uses: actions/github-script@v7 with: script: | - github.rest.issues.createComment({ + await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, diff --git a/.storybook/README.md b/.storybook/README.md index a98ed4022..6bed00bde 100644 --- a/.storybook/README.md +++ b/.storybook/README.md @@ -1,6 +1,6 @@ -# AuraGlass Storybook +# AuraGlass by AuraOne Storybook -AuraGlass Storybook is the presentation, QA, and developer-discovery surface for the 3.0 release. It covers the 356-component certified inventory while keeping generated audit coverage separate from curated public showroom examples. +AuraGlass by AuraOne Storybook is the presentation, QA, and developer-discovery surface for the 3.1 release. It covers the certified component inventory while keeping generated audit coverage separate from curated public showroom examples. ## Run Locally diff --git a/CHANGELOG.md b/CHANGELOG.md index 353e49ddb..6f2999871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,39 @@ # Changelog +## [3.1.0] - 2026-05-12 + +### Changed + +- Repositioned AuraGlass 3.1 around "Liquid Glass components for React and Next.js" with README copy focused on premium dashboards, AI products, media interfaces, accessible glassmorphism UI, and production React/Next.js adoption. +- Updated npm-facing package metadata to `3.1.0` with a clearer React Liquid Glass component-library description and launch keyword set for Liquid Glass, glassmorphism, dashboards, SaaS, AI UI, media UI, accessibility, motion, Tailwind, and shadcn-alternative discovery. +- Refocused the README away from raw inventory count as the first message and toward install, minimal usage, AuraGlass vs shadcn/ui, flagship components, recipes, theming, accessibility, SSR, optional peers, AI-agent guidance, and evidence links. + +### Added + +- Added 3.1 release/evidence scaffolding under `reports/3.1-release/` for package gates, flagship component readiness, website/catalog evidence handoff, accessibility and visual QA, recipes, and AI-agent readiness. +- Added GitHub issue templates for bug reports, visual regressions, component requests, and documentation issues. +- Added a pull request template with package, visual QA, documentation, and release-evidence checklists. +- Added public `SECURITY.md` and `CONTRIBUTING.md` files for vulnerability reporting and contribution expectations. +- Added the `aura-glass` CLI with `list`, `info`, and `add` commands for 3.1 launch recipes, including `--json`, `--dry-run`, `--force`, `--cwd`, and `--out` support. +- Added the public `aura-glass/registry` entrypoint with ten copyable launch recipes for dashboards, AI command centers, media surfaces, analytics, settings and billing, kanban, scheduling, collaboration, admin data, and ecommerce product panels. +- Added package export and install-smoke coverage for the CLI binary, registry recipes, styles export, and `useGlassProbes` subpath. + +### Fixed + +- Hardened flagship components for constrained app layouts, documentation cards, and recipe previews, including `GlassDashboard`, `GlassCommandPalette`, `GlassModal`, `GlassDrawer`, `GlassSidebar`, `GlassImageViewer`, `GlassFileUpload`, and `GlassKanbanBoard`. +- Added reduced-motion and playback guards to `GlassMusicVisualizer`. +- Made `GlassImageProcessingProvider` safe outside an explicit provider by returning a no-op context instead of crashing standalone consumers. +- Lazy-loaded optional AI service SDKs so `openai` and `@google-cloud/vision` remain optional feature-family dependencies instead of root-import hazards. +- Added public compatibility aliases for current launch naming, including `GlassNavbar`, `GlassMediaControls`, `LiquidGlassSourceTransition`, and `SmartShoppingCart`. + +### Verification + +- `npm run typecheck` +- `node scripts/ci/verify-cli.js` +- `npm run verify:pack` — passed install smoke for root imports, registry recipes, CLI bin, and styles export, with no nested `node_modules`, React runtimes, or dispatcher artifacts. +- `npm publish --dry-run --provenance --access public` — passed build, pack verification, React 18/Next integration smoke, React 19/Next integration smoke, and npm dry publish for `aura-glass@3.1.0`. +- Dry-run tarball: `aura-glass-3.1.0.tgz`, 8.1 MB package size, 43.0 MB unpacked size, 2,045 files, shasum `5406a76a13fe86ee87d356cfce5753e2173aaee3`. + ## [3.0.7] - Unreleased ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..a80299233 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,97 @@ +# Contributing To AuraGlass by AuraOne + +AuraGlass by AuraOne is a production React and Next.js Liquid Glass component system. Contributions should improve package reliability, developer adoption, visual quality, accessibility, SSR behavior, documentation, or release evidence without weakening the package boundary. + +## Before You Start + +- Work in the package repo: `/Users/gurbakshchahal/AuraGlass`. +- Do not edit the website repo from package changes. +- Do not revert unrelated changes from other contributors. +- Import public components from `aura-glass`, not private `src` paths. +- Include `import 'aura-glass/styles';` in examples that require package styles. +- Keep React and React DOM as peer dependencies. +- Keep optional feature-family peers optional. + +## Good First Change Areas + +- README, install, peer dependency, and docs clarity. +- Component examples that use public imports only. +- Focused bug fixes with tests. +- Accessibility and reduced-motion improvements. +- Compact or contained component behavior for docs/catalog previews. +- Token, style, export, or runtime audit coverage. +- Release evidence updates under `reports/`. + +## Component Quality Bar + +Components and recipes should be production-oriented: + +- dark theme works by default +- text contrast stays readable on glass surfaces +- keyboard focus is visible +- reduced-motion paths are respected +- SSR and hydration behavior are deterministic +- compact/contained modes work when the component appears in a preview card +- optional peers are documented by feature family +- examples avoid hidden website-only dependencies + +## Development Workflow + +Install dependencies: + +```bash +npm install +``` + +Run focused checks while developing: + +```bash +npm run typecheck +npm run lint:check +npm test -- --runInBand +``` + +Run package and audit checks as the change scope grows: + +```bash +npm run lint:tokens +npm run lint:styles +npm run audit:components +npm run audit:exports +npm run audit:api +npm run audit:runtime +npm run build +npm run verify:pack +``` + +Full release dry run: + +```bash +npm run release:dry-run +``` + +Do not publish, push, or create external GitHub/npm changes unless that is explicitly requested. + +## Pull Request Expectations + +Every PR should include: + +- clear summary of the change +- changed behavior or documentation surface +- tests/checks run +- screenshots or visual notes when UI output changed +- changelog update for public package behavior +- release evidence update when a 3.1 gate status changes + +Use the repository pull request template and leave unchecked any gate that was not run. + +## 3.1 Launch Evidence + +3.1 claims must be backed by checked-in evidence, not README text alone. Use these ledgers: + +- [reports/3.1-release/README.md](./reports/3.1-release/README.md) +- [reports/3.1-release/package-gates.md](./reports/3.1-release/package-gates.md) +- [reports/3.1-release/flagship-components.md](./reports/3.1-release/flagship-components.md) +- [reports/3.1-release/catalog-and-website-evidence.md](./reports/3.1-release/catalog-and-website-evidence.md) +- [reports/3.1-release/accessibility-and-visual-qa.md](./reports/3.1-release/accessibility-and-visual-qa.md) +- [reports/3.1-release/recipes-and-agent-readiness.md](./reports/3.1-release/recipes-and-agent-readiness.md) diff --git a/INSTALLATION.md b/INSTALLATION.md index 98096a561..deb5f911b 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -1,6 +1,6 @@ -# AuraGlass Installation Guide +# AuraGlass by AuraOne Installation Guide -This guide matches AuraGlass 3.0.0. AuraGlass publishes compiled JavaScript, TypeScript declarations, CSS, token assets, SSR helpers, Liquid Glass primitives, and a separate 3D entrypoint from the package export map. +This guide matches AuraGlass by AuraOne 3.1.0. AuraGlass publishes compiled JavaScript, TypeScript declarations, CSS, token assets, SSR helpers, Liquid Glass primitives, and a separate 3D entrypoint from the package export map. ## Install diff --git a/README.md b/README.md index 38216dce3..3cf07cd83 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# AuraGlass 3.0.7 +# AuraGlass by AuraOne 3.1 [![npm version](https://img.shields.io/npm/v/aura-glass?color=0ea5e9)](https://www.npmjs.com/package/aura-glass) [![npm downloads](https://img.shields.io/npm/dm/aura-glass?color=22c55e)](https://www.npmjs.com/package/aura-glass) @@ -7,222 +7,149 @@ [![React](https://img.shields.io/badge/React-18%20%7C%2019-61dafb)](https://react.dev/) [![Next.js](https://img.shields.io/badge/Next.js-14%20%7C%2015-black)](https://nextjs.org/) -**React Liquid Glass and glassmorphism UI components for Next.js, SaaS dashboards, AI products, media apps, and premium web interfaces.** +**AuraGlass by AuraOne: Liquid Glass components for React and Next.js.** -AuraGlass 3.0.7 is the Marketing Kit and website-proven polish release for the 3.0 relaunch: a production React component library and design system for interfaces that need Liquid Glass depth, Apple-style glass surfaces, TypeScript APIs, Next.js/SSR safety, accessibility guardrails, package-quality release gates, premium launch-page primitives, and optional 3D/AR effects from one package. - -The 3.0 line is a major public relaunch from the old `2.16.2` npm package. It preserves a canonical 356-component certified inventory, adds a dedicated Liquid Glass system with 32 public value exports and 31 related type exports, hardens runtime and auth-sensitive paths, modernizes the npm release pipeline, validates React 18 and React 19 consumer installs, refreshes Storybook and visual certification, and exposes audit evidence for package exports, API typing, runtime cleanliness, manual browser QA, and release gates. +AuraGlass by AuraOne is a production React and Next.js component system for Liquid Glass interfaces: premium dashboards, AI products, media tools, creator apps, data-heavy workspaces, and polished SaaS surfaces. It packages glass-native components, design tokens, motion, accessibility guardrails, SSR-safe entrypoints, optional 3D/media integrations, and release evidence in one npm library. ```bash npm install aura-glass ``` ```tsx -import { GlassButton, GlassCard, OptimizedGlass } from 'aura-glass'; +import { GlassButton, GlassCard } from 'aura-glass'; import 'aura-glass/styles'; + +export function BillingCard() { + return ( + +

Revenue

+

$128,400

+ Open dashboard +
+ ); +} ``` -## Built For +Production links: -| Use case | AuraGlass fit | -| --- | --- | -| Next.js and React apps | SSR-safe entrypoints, React 18/19 smoke coverage, TypeScript declarations | -| SaaS dashboards and admin tools | Layout, navigation, forms, tables, charts, status, notifications, templates | -| Premium Liquid Glass interfaces | Liquid material, source transitions, scroll edges, command surfaces, media controls | -| Marketing and launch pages | Marketing tokens, aurora CTA buttons, backgrounds, display text, logo marks, showcase cards, feature tiles, and install-command UI | -| Accessible glassmorphism UI | ContrastGuard metadata, focus-management coverage, reduced-motion support | -| AI and media products | AI surfaces, command palettes, search, media controls, 3D/AR and immersive entrypoints | +- Website and component catalog: [auraglass.auraone.ai](https://auraglass.auraone.ai) +- npm package: [npmjs.com/package/aura-glass](https://www.npmjs.com/package/aura-glass) +- Changelog: [CHANGELOG.md](./CHANGELOG.md) +- 3.1 release evidence scaffold: [reports/3.1-release](./reports/3.1-release/README.md) + +## Why AuraGlass + +AuraGlass is for teams that need a finished visual system, not only neutral primitives. It is strongest when the interface itself carries product value: command centers, analytics surfaces, media controls, AI workspaces, premium dashboards, immersive admin tools, and high-polish product experiences. -## What Is New In 3.0.7 +Use AuraGlass when you need: + +- Apple-style Liquid Glass visual language for production React apps. +- Next.js-compatible components with SSR-safe package entrypoints. +- Premium app surfaces that look finished with default styling. +- Tokens, dark mode, reduced motion, and contrast guardrails built into the system. +- Optional advanced surfaces for media, AI, charts, dashboards, 3D, AR, and collaboration. +- Checked-in release evidence for exports, tokens, runtime cleanliness, Storybook certification, package verification, and integration smoke coverage. + +AuraGlass is not trying to be the smallest possible primitive kit. If you want neutral, source-owned CRUD primitives with minimal visual opinion, shadcn/ui is still a better default. If you want a distinctive glass-native app surface without rebuilding blur, depth, motion, theme tokens, accessibility, and performance safeguards from scratch, AuraGlass is the better fit. + +## AuraGlass vs shadcn/ui + +| Decision point | AuraGlass | shadcn/ui | +| --- | --- | --- | +| Visual opinion | Finished Liquid Glass interface system | Neutral copyable primitives | +| Distribution | npm package with entrypoints, tokens, styles, and optional peers | Source-copy component ownership | +| Best fit | Premium dashboards, AI apps, media tools, immersive product surfaces | Plain CRUD apps, internal tools, low-opinion product UI | +| Customization model | Tokens, CSS variables, variants, providers, `className`, and package APIs | Direct source edits after copy | +| Release proof | Package audits, Storybook certification, export checks, pack checks, integration smokes | Project-local responsibility after installation | + +## Flagship Components + +3.1 highlights a smaller set of flagship surfaces instead of leading with raw inventory count. The broader inventory remains available, but these are the components the launch should make easiest to evaluate first. + +| Product job | Start with | +| --- | --- | +| Core glass surfaces | `OptimizedGlass`, `GlassCard`, `GlassButton`, `EnhancedGlassButton` | +| Overlays and command UI | `GlassModal`, `GlassDrawer`, `GlassPopover`, `GlassCommandPalette` | +| App navigation | `GlassNavbar`, `GlassSidebar`, `GlassTabs` | +| Data-heavy dashboards | `GlassDataGrid`, `GlassDataTable`, `GlassDataChart`, `GlassHeatmap` | +| Scheduling and workflows | `GlassCalendar`, `GlassKanbanBoard`, `GlassWizard` | +| Media and creator tools | `GlassFileUpload`, `LiquidGlassMediaControls`, `GlassImageViewer`, `GlassMusicVisualizer` | +| Liquid Glass primitives | `LiquidGlassMaterial`, `LiquidGlassSourceTransition`, `LiquidGlassScrollEdge`, `LiquidGlassLayerProvider` | +| Product-ready surfaces | `GlassDashboard`, `GlassPrismComparison`, `CollaborativeGlassWorkspace`, `GlassProductRecommendations`, `GlassSmartShoppingCart` | -AuraGlass 3.0.7 introduces the package-owned Marketing Kit for React and Next.js Liquid Glass landing pages, product heroes, launch pages, and showcase sections. The package API includes `AuroraBackground`, `AuroraOrb`, `DisplayText`, `LogoMark`, `ShowcaseCard`, `FeatureTile`, `InstallCommand`, `GlassButton variant="aurora"`, and generated marketing tokens for aurora palettes, showcase surfaces, display text, backgrounds, and hero orb styling. +Agent-safe examples should import from the root package entrypoint and include the CSS import: ```tsx import { - AuroraBackground, - AuroraOrb, - DisplayText, - ShowcaseCard, GlassButton, + GlassCard, + GlassCommandPalette, + GlassDataChart, } from 'aura-glass'; import 'aura-glass/styles'; - -export function LaunchHero() { - return ( -
- - - Interfaces shaped by light. - - - - - Start building - - -
- ); -} ``` -See the [Marketing Kit guide](./docs/components/marketing/readme.md) and the [component selection guide](./docs/components/choosing.md). - -Use AuraGlass when you need a production React/Next.js Liquid Glass UI system with app components and premium marketing surfaces. For landing pages, use `AuroraBackground`, `DisplayText`, `ShowcaseCard`, and `GlassButton variant="aurora"`. For app UIs, use `GlassCard`, `GlassButton`, `GlassInput`, `GlassTabs`, `GlassDataTable`, and `ContrastGuard`. - -### 3.0.7 Stabilization Highlights - -- **SSR/hydration hardening:** `GlassButton` and related homepage-safe surfaces render deterministic markup across server and client paths. -- **Final compact/contained tranche:** accessibility, collaboration, motion, theme, data, input, and calendar components finish the website-proven compact API so catalog cards can mount real package components without clipping wrappers. -- **Live containment parity:** dropdown/menu subcontent APIs include contained rendering controls, preserving normal app portal behavior while enabling bounded docs/catalog previews. -- **Catalog proof path:** `GlassReactionBubbles`, `GlassCalendar`, `GlassDiffViewer`, `ContrastGuard`, `GlassAdvanced`, and dense data surfaces now have package-owned preview states instead of website-only mocks. -- **Organization metadata:** package metadata, support links, and npm-facing docs point to the organization repository at `https://github.com/auraoneai/auraglass`. - -## What Is New In 3.0.6 - -- **Native compact and contained modes:** dense components now expose package-owned compact/contained sizing paths so dashboards, docs cards, drawers, and embedded surfaces can show real components without website-only clipping wrappers. The first 3.0.6 tranche covers data tables/grids, heatmaps, calendars, carousels, code and gradient tools, theme/persona controls, advanced media, layout systems, ecommerce carts, activity feeds, form/detail templates, collaboration workspaces, reaction clusters, and AI/media visualizations. -- **Overlay containment APIs:** dropdown/menu/select/context/menubar families now support contained rendering controls such as `contained`, `portalled`, `portalContainer`, and `positionStrategy`, while preserving the existing portalled default for normal app usage. -- **Real semantic diff rendering:** `GlassDiffViewer` now renders its own accessible line-level diff using semantic code/table structure, add/remove tokens, compact mode, bounded height, and long-line containment. Website previews no longer need a hand-built diff mock. -- **Stronger default glass primitives:** `GlassAdvanced` now renders as a visible polished glass surface with simple default usage, plus compact/preview/minHeight controls for constrained contexts. -- **Demonstrable contrast tooling:** `ContrastGuard` now includes package-owned preview affordances with `demoBackdrop` and `showIndicator`, so docs and catalogs can demonstrate contrast behavior without custom staging UI. -- **Repository ownership migration:** package metadata, issue links, and npm-facing docs now point to the organization repository at `https://github.com/auraoneai/auraglass`. - -3.0.6 was the core stabilization baseline for 3.0.7. Its native compact/contained work, overlay APIs, semantic diff rendering, stronger glass defaults, and ContrastGuard demo affordances were carried forward into the 3.0.7 release proof path, where the rebuilt package was installed into the AuraGlass website and the full catalog gate passed. - -## What Was Hardened In 3.0.5 - -- **Catalog-scale component hardening:** the package was repacked into the AuraGlass website and walked across all 15 `/components` pages at `http://localhost:3023/components`: 260 rendered cards, 0 console/page errors, 0 preview boundary catches, 0 unavailable previews, and 0 empty/no-data preview hits. -- **Core visual token repair:** neutral glass surfaces were retuned back to dark translucent glass instead of gray/white slab output, removing the broad white-outline and washed-panel regressions that affected component previews. -- **Compact rendering fixes:** full-page and app-scale components now adapt when embedded in small surfaces, including `GlassPrismComparison`, `GlassAdvancedVideoPlayer`, `GlassImageViewer`, and `GlassIntelligentFormBuilder`. -- **Data and input polish:** data grids, data tables, charts, tree views, accordions, avatars, badges, radio groups, steppers, JSON/heatmap/skeleton/metric components, and related dense controls were corrected for dark-theme contrast, spacing, overflow, tokenized glass backgrounds, and default preview content. -- **Motion, particle, and GPU fallback cleanup:** `GlassParticles`, `GlassParticleField`, `DimensionalGlass`, and `GlassWebGLShader` now render meaningful dark, contained defaults with safe CSS/canvas fallback behavior. -- **Media containment:** advanced media controls now collapse appropriately inside narrow containers instead of bleeding out of preview frames, while normal-size players keep the richer control set. -- **Release gates:** `npm run release:dry-run` passes the package quality path through typecheck, lint with warnings only, token/style audits, glass pipeline validation, contrast tests, export tests, package type fixtures, 405 Jest suites, 2169 tests, 339 snapshots, pack verification, and React 18/19 Next.js smoke tests. - -## What Was Hardened In 3.0.4 - -- **Preview-scale visual repair:** retuned the first pass of dark surface, compact rendering, media containment, data-display, and particle/GPU fallback fixes that exposed the remaining tokenization and snapshot gaps fixed in 3.0.5. -- **Website evidence loop:** used the paginated AuraGlass website component grid as the release QA surface instead of relying only on isolated unit tests. - -## What Was Hardened In 3.0.3 - -- **Core upstream bug fixes:** fixed malformed glass color alpha fallbacks, tokenized primary/neutral generated glass surfaces, repaired focus-visible behavior, and updated the contrast test parser to understand tokenized HSL alpha colors. -- **Safer standalone previews and docs:** exported provider hooks for Houdini, collaboration, motion, accessibility, media, CMS drag/drop, settings, consciousness streams, toast, NeuroSync, GlassEngine, and ecommerce now provide inert fallback contexts instead of crashing outside their providers. -- **Correct collaboration package exports:** `GlassCollaborationProvider` now resolves from the real collaboration provider module at the root package entrypoint instead of the legacy workspace stub. -- **Native color input cleanup:** color pickers, gradient stops, drawing tools, CMS property editors, live filters, and theme customization normalize token defaults to `#rrggbb` before rendering ``. -- **Overlay stability:** controlled modal, dialog, drawer, popover, and hover-card flows avoid repeated same-value open/close updates and lifecycle feedback loops. -- **Component API fixes:** `GlassMetricCard` supports explicit value styling, dot badges preserve text labels, `GlassDataGrid` row backgrounds are tokenized and readable, and dropdown subcomponents are exported from the root package entrypoint. -- **Canvas performance:** the spectrum renderer in `GlassMusicVisualizer` no longer reads pixels back from the canvas every frame. -- **Release regression coverage:** added package sweeps for malformed color-token alpha use, generated hardcoded primary/neutral colors, exported provider-hook crash strings, and standalone provider consumers. -- **Final 3.0.3 regression locks:** package-barrel collaboration exports and every native color input are now covered by source-level regression sweeps. -- **Liquid Glass system:** 32 public value exports spanning primitives, navigation surfaces, presentation layers, controls, media/data surfaces, source transitions, backdrop sampling, scroll-edge glass, layer policy, and a complete `LiquidGlassShowcase`. -- **356-component certified inventory:** each canonical inventory component has direct Storybook coverage, direct documentation coverage, direct unit-test coverage, accessibility metadata, and Storybook visual certification evidence. The newer Liquid Glass public surface is additive to that certified inventory. -- **Clean full Storybook QA:** the static all-story audit covers 1,595 stories across desktop Liquid Glass, desktop dark, and mobile Liquid Glass modes with 1,595 passes, 0 risks, 0 failures, 0 audit findings, and 0 run errors. -- **Storybook taxonomy and visual QA refresh:** Storybook is organized by developer intent across Start Here, Foundations, Controls, Navigation, Surfaces, Data + Visualization, Media, Workflows, AI + Intelligence, Effects + Advanced, Showcases, Reference, and Certification. Certification artifacts cover 356/356 passed entries, 712 desktop/mobile screenshots, and 89 manual QA contact sheets. -- **React 18 and React 19 consumer validation:** `prepublishOnly` builds temporary Next 14 / React 18 and Next 15 / React 19 apps from the tarball and runs Playwright smoke tests. -- **Release-grade npm pipeline:** npm provenance publishing, `prepublishOnly`, clean pack verification, package-metadata declaration checks, worker packaging, bundle-size limits, and no bundled React runtime. -- **Public package surface audits:** export audits verify source/declaration coverage for the public export map, while API audits report declaration `any`, public-source `any`, and ref-forwarding follow-ups explicitly. -- **Runtime cleanliness and security hardening:** auth middleware rejects URL query credentials, API keys and room/demo tokens use crypto-backed randomness, AI/server logging was reduced, MD5 image cache keys were replaced with SHA-256, and production-source console/debugger/TODO findings are audited. -- **Peer and install modernization:** feature-specific peers are optional, Sentry support is widened, React Three Fiber/Drei ranges cover React 18 and React 19 paths, and install docs explain which peers are needed for each feature family. -- **SSR, tokens, workers, and 3D entrypoints:** SSR helpers, token manifests, persona CSS generation, worker outputs, and the `aura-glass/three` entrypoint are part of the verified package story. -- **Release transparency:** release notes plus checked-in audit evidence record API surface debt, breaking-change review evidence, runtime cleanliness, visual certification, and manual browser/accessibility follow-ups without publishing internal rebuild prompts. - -## Liquid Glass System - -AuraGlass 3.0 includes a dedicated Liquid Glass layer for real product UI, not just decorative panels. - -| Area | Added or upgraded | -|------|-------------------| -| Primitives | `LiquidGlassEffectGroup`, `LiquidGlassScrollEdge`, `LiquidGlassBackdropSampler`, `LiquidGlassConcentricFrame`, `LiquidGlassLayerProvider`, `LiquidGlassSourceTransition` | -| Navigation | Liquid toolbar, inset sidebar, tab bar, bottom accessory, inspector panel, command and segmented-control upgrade paths | -| Presentation | Adaptive sheet, popover menu, source transition, modal/search/navigation integration fixes | -| Controls | Liquid button style, control group patterns, slider/switch/toggle markers, segmented control upgrade path | -| Media and data | Media controls, now-playing bar, photo inspector, badge clusters, carousel rails, glass data surfaces | -| Showcase and docs | `LiquidGlassShowcase`, design rules, component map, tests, stories, tokens, and public exports | - -Start with [Liquid Glass design rules](./docs/liquid-glass/design-rules.md) and the [Liquid Glass component map](./docs/liquid-glass/component-map.md). - -Liquid Glass public value exports in 3.0: - -```text -LiquidGlassMaterial, LiquidGlassBackdropSampler, LiquidGlassConcentricFrame, -LiquidGlassEffectGroup, LiquidGlassLayerProvider, LiquidGlassSurfaceLayer, -LiquidGlassScrollEdge, LiquidGlassDestination, LiquidGlassSource, -LiquidGlassTransitionProvider, LiquidGlassBottomAccessory, -LiquidGlassInsetSidebar, LiquidGlassInspectorPanel, LiquidGlassSegmentedControl, -LiquidGlassTabBar, LiquidGlassToolbar, LiquidGlassAdaptiveSheet, -LiquidGlassPopoverMenu, LiquidGlassControlGroup, LiquidGlassButtonStyle, -LiquidGlassBadgeCluster, LiquidGlassCarouselRail, LiquidGlassCommandSurface, -LiquidGlassMapControls, LiquidGlassGPU, LiquidGlassGPUDriver, -LiquidGlassSearchField, LiquidGlassSearchTab, LiquidGlassMediaControls, -LiquidGlassNowPlayingBar, LiquidGlassPhotoInspector, LiquidGlassShowcase -``` +Do not import from private source paths. Use optional peer packages only for the component families that need them. -## Current Certified Inventory State +## Recipes, Registry, And CLI -These numbers are derived from the checked-in inventory and certification artifacts: +AuraGlass 3.1 now includes a package-level recipe registry and a prototype CLI for scaffolding product-ready Liquid Glass app surfaces. The registry is available from `aura-glass/registry`; the CLI is installed as the `aura-glass` binary. -| Area | Current state | -|------|---------------| -| Component inventory | 356 components | -| Direct Storybook owner stories | 356/356 | -| Storybook visual certification | 356/356 passed | -| Certification screenshots | 712 desktop/mobile screenshots | -| Generated certification story coverage | 0/0 required | -| Direct component docs | 356/356 | -| Direct unit tests | 356/356 | -| ContrastGuard metadata | 356/356 | -| ARIA metadata | 356/356 | -| Focus-management metadata | 356/356 | -| Reduced-motion metadata | 356/356 | -| Static Storybook exhaustive QA | 1,595 stories, 1,595 passed, 0 risks, 0 failures, 0 audit findings, 0 run errors | +List available recipes: -Primary evidence: +```bash +npx aura-glass list +``` -- [Component inventory](./reports/component_inventory.json) -- [Storybook visual certification JSON](./reports/glassmorphism-storybook-visual-certification.json) -- [Storybook visual certification report](./reports/glassmorphism-storybook-visual-certification.md) -- [Storybook exhaustive QA report](./reports/storybook-exhaustive-qa.md) -- [Documentation map](./docs/readme.md) -- [Component documentation index](./docs/components/readme.md) -- [Reports index](./reports/README.md) +Inspect one recipe: + +```bash +npx aura-glass info saas-dashboard +``` -Run the live audit at any time: +Add a copyable recipe to an app: ```bash -npm run audit:components +npx aura-glass add ai-command-center ``` -## How To Choose Components +The CLI writes into `src/components/auraglass/recipes` by default and supports `--out`, `--cwd`, `--dry-run`, `--force`, and `--json`. -Do not start by scanning every export. Start with the [component selection guide](./docs/components/choosing.md) and the Storybook `Start Here/Guide` entry, which group AuraGlass by product job: +Launch recipes included in the package registry: -- **Default app kit:** `GlassAppShell`, `GlassContainer`, `GlassGrid`, `GlassStack`, `OptimizedGlass`, `GlassCard`, `GlassButton`, `GlassInput`, `GlassSelect`, `GlassTabs`, `GlassModal`, `GlassDataTable`, `GlassBadge`, `GlassToast`, `ThemeProvider`, and `ContrastGuard`. -- **Liquid Glass:** use for premium app chrome, media controls, command centers, source transitions, overlays, and focal surfaces. -- **Product families:** layout, navigation, forms, data display, charts, dashboards, interactive tools, media, templates, accessibility, and theming. -- **Advanced systems:** AI, consciousness, quantum, immersive/spatial, atmospheric effects, and 3D/AR. Use these only when the feature explicitly requires them. +- SaaS dashboard shell +- AI command center +- Media player surface +- Analytics overview +- Settings and billing page +- Kanban workspace +- Calendar schedule page +- Collaborative workspace +- Admin data table +- Ecommerce product panel -Storybook mirrors this decision tree with top-level sections for `Foundations`, `Controls`, `Navigation`, `Surfaces`, `Data + Visualization`, `Media`, `Workflows`, `AI + Intelligence`, `Effects + Advanced`, `Showcases`, `Reference`, and `Certification`. For AI agents, give the selection guide as context and ask for a product family first. That prevents the agent from treating 356 certified inventory components plus the Liquid Glass public surface as one flat menu. +Use the registry directly when building custom tooling: -## Install +```tsx +import { auraGlassRecipes, getAuraGlassRecipe } from 'aura-glass/registry'; -```bash -npm install aura-glass +const dashboard = getAuraGlassRecipe('saas-dashboard'); ``` -Install peer dependencies for the component families your app uses: +Recipe acceptance criteria and follow-up evidence are tracked in the 3.1 release scaffold: -```bash -npm install react react-dom framer-motion lucide-react react-hook-form react-chartjs-2 chart.js -npm install @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-select @radix-ui/react-slot -npm install three @react-three/fiber @react-three/drei -npm install @sentry/react -``` +- [Recipe and agent readiness](./reports/3.1-release/recipes-and-agent-readiness.md) +- [Launch evidence index](./reports/3.1-release/README.md) -See [INSTALLATION.md](./INSTALLATION.md) for the full peer dependency matrix, SSR setup, 3D setup, and troubleshooting. +## Install -## Quick Start +Install the package: -Import the CSS once from your root layout or app shell: +```bash +npm install aura-glass +``` + +Import styles once from your root layout, app shell, or client entry: ```tsx import 'aura-glass/styles'; @@ -234,7 +161,7 @@ Use components from the root package entrypoint: import { GlassButton, GlassCard, OptimizedGlass } from 'aura-glass'; import 'aura-glass/styles'; -export function ExamplePanel() { +export function MetricsPanel() { return ( @@ -247,62 +174,60 @@ export function ExamplePanel() { } ``` -Liquid Glass example: +Next.js root layout example: ```tsx -import { - GlassButton, - LiquidGlassEffectGroup, - LiquidGlassScrollEdge, - LiquidGlassSource, - LiquidGlassTransitionProvider, -} from 'aura-glass'; import 'aura-glass/styles'; -export function LiquidGlassPanel() { +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { return ( - - - - - - Open command center - - - - + + {children} + ); } ``` -## Package Entrypoints +Use the SSR provider when your app needs AuraGlass hydration helpers: -| Entrypoint | Purpose | -|------------|---------| -| `aura-glass` | Primary React component API. | -| `aura-glass/styles` | Global AuraGlass CSS bundle. | -| `aura-glass/tokens` | Runtime token and persona access. | -| `aura-glass/tokens/json` | Raw token manifest for tooling. | -| `aura-glass/tokens/tailwind` | Tailwind theme preset. | -| `aura-glass/tokens/manifest` | Lightweight token and persona metadata. | -| `aura-glass/tokens/css` | Built token CSS file. | -| `aura-glass/tokens/keyframes` | Built keyframe CSS file. | -| `aura-glass/registry` | Legacy registry bundle. | -| `aura-glass/client` | Client-specific helpers. | -| `aura-glass/server` | Server-specific helpers. | -| `aura-glass/ssr` | SSR provider and hydration helpers. | -| `aura-glass/three` | Optional 3D, AR, and React Three Fiber integrations. | -| `aura-glass/core/mixins/glassMixins` | Low-level glass style construction API. | -| `aura-glass/utils/env` | Browser and hydration safety utilities. | -| `aura-glass/hooks/useGlassProbes` | Glass style probe hook. | -| `aura-glass/services/ai/openai-service` | OpenAI service integration. | -| `aura-glass/services/ai/vision-service` | Vision service integration. | -| `aura-glass/services/websocket/collaboration-service` | WebSocket collaboration service. | +```tsx +import { AuraGlassSSRProvider } from 'aura-glass/ssr'; + +export function Providers({ children }: { children: React.ReactNode }) { + return {children}; +} +``` -## Design Tokens And Personas +## Peer Dependencies -AuraGlass includes a typed token system and a persona matrix for runtime theming. Personas define semantic color, glass, motion, shadow, chart, focus, and state values. -Marketing Kit tokens are generated into the same token CSS pipeline under `--aura-marketing-*`, including aurora button, palette, display text, showcase surface, background, and orb variables. +React and React DOM are required. Other peers are feature-family dependencies. Install only what your app uses. + +| Feature family | Peer packages | +| --- | --- | +| Core React UI | `react`, `react-dom` | +| Motion and icons | `framer-motion`, `lucide-react` | +| Forms and Radix-backed controls | `react-hook-form`, `@radix-ui/react-dropdown-menu`, `@radix-ui/react-label`, `@radix-ui/react-select`, `@radix-ui/react-slot` | +| Charts and data visualization | `react-chartjs-2`, `chart.js` | +| 3D and AR | `three`, `@react-three/fiber`, `@react-three/drei` | +| Error reporting integrations | `@sentry/react` | + +Example full peer install for apps that use forms, charts, and 3D: + +```bash +npm install react react-dom framer-motion lucide-react react-hook-form react-chartjs-2 chart.js +npm install @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-select @radix-ui/react-slot +npm install three @react-three/fiber @react-three/drei +``` + +See [INSTALLATION.md](./INSTALLATION.md) for the deeper peer dependency matrix, SSR setup, 3D setup, and troubleshooting. + +## Theming And Tokens + +AuraGlass ships a typed token system, generated CSS variables, Tailwind token entrypoint, and runtime persona support. Normal customization should use tokens, CSS variables, component props, `className`, `style`, and theme providers instead of overriding internals. ```tsx import { PersonaPicker, ThemeProvider, usePersonaTheme } from 'aura-glass'; @@ -350,80 +275,66 @@ npm run glass:generate-persona-css npm run glass:validate-persona-css ``` -## SSR And Browser Safety - -Use the SSR entrypoint when rendering AuraGlass inside Next.js, Remix, or any server-rendered React shell: - -```tsx -import { AuraGlassSSRProvider } from 'aura-glass/ssr'; - -export function RootLayout({ children }: { children: React.ReactNode }) { - return {children}; -} -``` - -Use `aura-glass/utils/env` for guarded browser access, safe media queries, and deterministic hydration helpers. +## Accessibility And Reduced Motion -## 3D And AR +AuraGlass components are expected to preserve: -3D and AR APIs are isolated under `aura-glass/three`. Regular apps can import from `aura-glass` without pulling the React Three Fiber surface into the root bundle. +- readable text contrast across glass backgrounds and adaptive themes +- semantic HTML, ARIA labels, roles, and state where needed +- visible keyboard focus through focus-management guardrails +- reduced-motion behavior for animation, transition, and physics effects +- desktop and mobile Storybook renderability -```tsx -import { GlassButton } from 'aura-glass'; -import { GlassShatterEffects } from 'aura-glass/three'; +Current checked-in certification evidence from the 3.0 baseline reports 356/356 coverage for ContrastGuard, ARIA, focus management, reduced motion, direct docs, direct Storybook owner stories, and direct unit tests. The 3.1 package gates have also been rerun for the release candidate, including typecheck, CLI verification, pack/install smoke, npm dry publish, and React 18/19 Next.js integration smokes. -export function Hero3D() { - return ( - - Launch - - ); -} -``` +Primary evidence sources: -Install `three`, `@react-three/fiber`, and `@react-three/drei` before importing from `aura-glass/three`. - -## Accessibility Contract +- [Component inventory](./reports/component_inventory.json) +- [Storybook visual certification JSON](./reports/glassmorphism-storybook-visual-certification.json) +- [Storybook visual certification report](./reports/glassmorphism-storybook-visual-certification.md) +- [Storybook exhaustive QA report](./reports/storybook-exhaustive-qa.md) +- [3.1 accessibility and visual QA baseline](./reports/3.1-release/accessibility-and-visual-qa.md) -AuraGlass components are expected to preserve the following across glass backgrounds and adaptive themes: +## Performance And SSR -- Readable text contrast through ContrastGuard-backed surfaces. -- ARIA labels, roles, and state where semantic HTML alone is not enough. -- Visible keyboard focus through focus-management guardrails. -- Reduced-motion behavior for animation, transition, and physics effects. -- Desktop and mobile Storybook renderability. +AuraGlass keeps the root package focused on React UI and isolates heavier surfaces behind optional peers and explicit entrypoints. -The current inventory metadata reports 356/356 coverage for ContrastGuard, ARIA, focus management, and reduced motion. The Storybook preview also wraps stories with the shared accessibility certification frame. +| Entrypoint | Purpose | +| --- | --- | +| `aura-glass` | Primary React component API. | +| `aura-glass/styles` | Global AuraGlass CSS bundle. | +| `aura-glass/tokens` | Runtime token and persona access. | +| `aura-glass/tokens/json` | Raw token manifest for tooling. | +| `aura-glass/tokens/tailwind` | Tailwind theme preset. | +| `aura-glass/tokens/manifest` | Lightweight token and persona metadata. | +| `aura-glass/tokens/css` | Built token CSS file. | +| `aura-glass/tokens/keyframes` | Built keyframe CSS file. | +| `aura-glass/ssr` | SSR provider and hydration helpers. | +| `aura-glass/three` | Optional 3D, AR, and React Three Fiber integrations. | +| `aura-glass/client` | Client-specific helpers. | +| `aura-glass/server` | Server-specific helpers. | +| `aura-glass/registry` | Styled registry compatibility plus 3.1 copyable recipe metadata. | +| `aura-glass/hooks/useGlassProbes` | Runtime glass style probe hooks. | +| `aura-glass/services/ai/openai-service` | Optional OpenAI-backed backend integration. | +| `aura-glass/services/ai/vision-service` | Optional Google Cloud Vision backend integration. | -## Component Documentation +Use `aura-glass/utils/env` for guarded browser access, safe media queries, and deterministic hydration helpers. Install `three`, `@react-three/fiber`, and `@react-three/drei` only before importing from `aura-glass/three`. Install optional backend peers such as `openai` or `@google-cloud/vision` only before constructing the matching AI service classes. -Component docs are organized into numbered sections under [docs/components](./docs/components/readme.md). The directory root intentionally contains only the section index. +## AI Agent Guidance -Common sections include: +Use these rules when asking Codex, Cursor, Claude Code, GitHub Copilot, Gemini CLI, or another coding agent to work with AuraGlass: -- Accessibility system -- Consciousness interface -- Advanced effects -- Layout -- Navigation -- Modal -- Interactive -- Form -- Data display -- Charts -- Dashboard -- Buttons -- Cards -- Surfaces and backgrounds -- Utilities -- Templates -- Animations -- Revolutionary enhancements -- AI components -- AR effects -- Quantum UI +- Install with `npm install aura-glass`. +- Import components from `aura-glass`. +- Import CSS with `import 'aura-glass/styles';`. +- Prefer `GlassButton`, `GlassCard`, `OptimizedGlass`, `GlassCommandPalette`, `GlassDataGrid`, and `LiquidGlassMaterial` for first examples. +- Do not invent component names. +- Do not import from private paths under `src`. +- Do not use 3D, media, AR, or advanced components without optional peer dependencies. +- Do not wrap compound children without their parent components. +- Do not use WebGL/canvas-heavy components for simple cards. -When adding a component, add its docs page to the closest numbered section and keep the normalized basename aligned with the component export name so the audit can count direct docs coverage. +The package repo includes [llms.txt](./llms.txt) as the short agent-facing context file. The 3.1 launch plan tracks longer agent docs in [reports/3.1-release/recipes-and-agent-readiness.md](./reports/3.1-release/recipes-and-agent-readiness.md). ## Development @@ -438,7 +349,7 @@ npm run audit:components Useful scripts: | Command | Purpose | -|---------|---------| +| --- | --- | | `npm run storybook` | Starts local Storybook. | | `npm run build-storybook` | Builds static Storybook. | | `npm run build` | Builds package outputs. | @@ -447,59 +358,35 @@ Useful scripts: | `npm run lint:tokens` | Validates token rules. | | `npm run lint:styles` | Validates style rules. | | `npm run audit:components` | Prints component inventory, docs, story, test, accessibility, and certification coverage. | -| `npm run glass:full-check` | Runs the glass validation workflow. | -| `npm run test:visual` | Runs visual tests. | -| `npm run test:a11y` | Runs accessibility tests. | -| `npm run verify:pack` | Verifies package output before publishing. | -| `npm run test:integration:next` | Builds temporary Next.js consumer apps for React 18 and React 19 smoke coverage. | | `npm run audit:exports` | Verifies public exports against source and declaration files. | | `npm run audit:api` | Reports public API typing, declaration, and ref-forwarding follow-ups. | | `npm run audit:runtime` | Reports production-source console, debugger, and TODO/FIXME findings. | - -## Storybook Visual Certification - -The visual certification script checks the canonical inventory against Storybook render output, viewport screenshots, console failures, missing stories, and failure statuses. - -Typical local workflow: - -```bash -npm run storybook -STORYBOOK_URL=http://localhost:6007 node scripts/audit/storybook-visual-certification.mjs -``` - -Expected complete-pass artifact state for the current inventory: - -```json -{ - "inventoryCount": 356, - "entries": 356, - "passed": 356, - "failed": 0, - "screenshots": 712 -} -``` - -Do not claim full certification from README text alone. Use the JSON report in `reports/glassmorphism-storybook-visual-certification.json` as the evidence source. - -For the public 3.0.2 Storybook, the static all-story QA pass also crawls `storybook-static/index.json` across desktop Liquid Glass, desktop dark, and mobile Liquid Glass modes. The current exhaustive report covers 1,595 stories with 1,595 passes, zero risks, zero failures, zero audit findings, zero audit-run errors, and zero occurrences of hard flags such as Storybook render errors, page errors, severe console errors, remote media failures, missing story roots, visible native controls, contrast findings, clipping, overlap, or overflow findings. +| `npm run glass:full-check` | Runs the package glass validation workflow. | +| `npm run verify:pack` | Verifies package output before publishing. | +| `npm run test:integration:next` | Builds temporary Next.js consumer apps for React 18 and React 19 smoke coverage. | +| `npm run release:dry-run` | Runs CI and npm dry-run publish. Do not run it unless you intend to exercise the full release path. | ## Repository Map | Path | Purpose | -|------|---------| +| --- | --- | | `src/components` | Component source. | | `src/stories` | Shared Storybook audit and certification stories. | | `src/reports` | Static audit data consumed by Storybook and tests. | | `docs` | Technical documentation. | | `docs/components` | Organized component docs. | | `reports` | Generated and hand-authored audit evidence. | +| `reports/3.1-release` | 3.1 launch evidence scaffold and sign-off baselines. | | `scripts/audit` | Audit and certification scripts. | | `tests/visual/design-system` | Playwright guardrails for visual certification and audit coverage. | +| `.github` | GitHub workflow and collaboration templates. | | `.storybook` | Storybook configuration and shared preview wrappers. | -## Release And Verification Checklist +## Release Evidence -Before publishing or presenting certification state: +3.1 launch claims are backed by checked-in evidence under `reports/3.1-release` plus the release gate commands below. The final publish path uses `npm publish --access public` after the dry-run, pack, and integration gates pass. + +Package gates: ```bash npm run audit:components @@ -514,29 +401,15 @@ npm run build npm run verify:pack npm run test:integration:next -- --skip-build npm run build-storybook -npm publish --dry-run --provenance --access public +npm run release:dry-run git diff --check ``` -For certification changes, also run the Storybook visual certification script and the relevant Playwright guardrails: - -```bash -npx playwright test tests/visual/design-system/storybook-visual-certification.spec.ts --project=chromium --workers=1 -npx playwright test tests/visual/design-system/glass-audit-coverage.spec.ts --project=chromium --workers=1 -``` +3.1 evidence scaffolds: -## More Documentation - -- [GitHub repository](https://github.com/auraoneai/auraglass) -- [Report issues](https://github.com/auraoneai/auraglass/issues) -- [Documentation home](./docs/readme.md) -- [Installation guide](./INSTALLATION.md) -- [Component documentation](./docs/components/readme.md) -- [Design tokens](./docs/design-tokens.md) -- [Accessibility guide](./docs/guides/accessibility.md) -- [SSR setup](./docs/guides/ssr-setup.md) -- [Deployment](./docs/deployment.md) -- [Reports](./reports/README.md) -- [3.0.2 release notes](./RELEASE_NOTES_3.0.2.md) -- [3.0.1 release notes](./RELEASE_NOTES_3.0.1.md) -- [3.0.0 release notes](./RELEASE_NOTES_3.0.0.md) +- [Launch evidence index](./reports/3.1-release/README.md) +- [Package gates](./reports/3.1-release/package-gates.md) +- [Flagship components](./reports/3.1-release/flagship-components.md) +- [Catalog and website evidence](./reports/3.1-release/catalog-and-website-evidence.md) +- [Accessibility and visual QA](./reports/3.1-release/accessibility-and-visual-qa.md) +- [Recipes and AI agent readiness](./reports/3.1-release/recipes-and-agent-readiness.md) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..dbbbaf8f2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,53 @@ +# Security Policy + +AuraGlass is a React and Next.js component package. Security reports should focus on package behavior, build artifacts, server helpers, auth-sensitive utilities, dependency exposure, generated outputs, and documentation that could lead users to unsafe integration patterns. + +## Supported Versions + +| Version | Status | +| --- | --- | +| 3.1.x | Active launch line | +| 3.0.x | Maintenance fixes as needed | +| < 3.0 | Not supported | + +## Reporting A Vulnerability + +Do not open a public GitHub issue for suspected vulnerabilities. + +Use GitHub private vulnerability reporting for this repository: + +https://github.com/auraoneai/auraglass/security/advisories/new + +Include: + +- affected AuraGlass version +- package entrypoint or file path involved +- minimal reproduction or proof of concept +- impact assessment +- whether the issue affects browser-only code, SSR, server helpers, workers, AI services, websocket services, or documentation +- known mitigations, if any + +## Response Expectations + +Maintainers should acknowledge valid reports, triage severity, and coordinate a fix before public disclosure when the report is actionable. Fixes should include focused tests or audit coverage when practical. + +## Security-Relevant Release Gates + +Security-sensitive changes should consider these checks before release: + +```bash +npm run audit:runtime +npm run audit:exports +npm run typecheck +npm run lint:check +npm run verify:pack +npm run test:integration:next -- --skip-build +``` + +For full release readiness, use the 3.1 package-gate ledger: + +- [reports/3.1-release/package-gates.md](./reports/3.1-release/package-gates.md) + +## Scope Notes + +AuraGlass includes optional integrations for AI, media, websocket collaboration, Sentry, and 3D/AR feature families. Optional peers should stay optional, React should not be bundled into package outputs, and server/helper entrypoints should avoid leaking credentials, tokens, or sensitive diagnostics. diff --git a/bin/aura-glass.cjs b/bin/aura-glass.cjs new file mode 100755 index 000000000..b7ceb0ca7 --- /dev/null +++ b/bin/aura-glass.cjs @@ -0,0 +1,190 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("node:fs"); +const path = require("node:path"); + +const usage = `AuraGlass CLI + +Usage: + aura-glass list [--json] + aura-glass info [--json] + aura-glass add [--cwd ] [--out ] [--dry-run] [--force] + +Examples: + aura-glass list + aura-glass info saas-dashboard + aura-glass add ai-command-center + aura-glass add all --out src/components/auraglass/recipes +`; + +const loadRegistry = () => { + try { + return require("../dist/registry/index.js"); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error( + `Unable to load the AuraGlass recipe registry. Run \`npm run build\` before using the local CLI. ${message}` + ); + } +}; + +const parseArgs = (argv) => { + const args = []; + const flags = {}; + + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (!value.startsWith("--")) { + args.push(value); + continue; + } + + const key = value.slice(2); + if (["cwd", "out"].includes(key)) { + flags[key] = argv[index + 1]; + index += 1; + } else { + flags[key] = true; + } + } + + return { args, flags }; +}; + +const toJson = (value) => `${JSON.stringify(value, null, 2)}\n`; + +const ensureInsideCwd = (cwd, target) => { + const relative = path.relative(cwd, target); + if (relative.startsWith("..") || path.isAbsolute(relative)) { + throw new Error(`Refusing to write outside the current project: ${target}`); + } +}; + +const writeRecipe = (recipe, flags) => { + const cwd = path.resolve(process.cwd(), flags.cwd || "."); + const outDir = path.resolve(cwd, flags.out || "src/components/auraglass/recipes"); + ensureInsideCwd(cwd, outDir); + + const written = []; + const skipped = []; + + for (const file of recipe.files) { + const target = path.resolve(outDir, file.path); + ensureInsideCwd(cwd, target); + + if (flags["dry-run"]) { + written.push({ path: path.relative(cwd, target), bytes: Buffer.byteLength(file.content) }); + continue; + } + + if (fs.existsSync(target) && !flags.force) { + skipped.push(path.relative(cwd, target)); + continue; + } + + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, file.content, "utf8"); + written.push({ path: path.relative(cwd, target), bytes: Buffer.byteLength(file.content) }); + } + + return { recipe: recipe.id, written, skipped }; +}; + +const main = () => { + const { auraGlassRecipes, getAuraGlassRecipe } = loadRegistry(); + const { args, flags } = parseArgs(process.argv.slice(2)); + const command = args[0]; + + if (!command || command === "help" || command === "--help" || command === "-h") { + process.stdout.write(usage); + return; + } + + if (command === "list") { + const rows = auraGlassRecipes.map((recipe) => ({ + id: recipe.id, + title: recipe.title, + category: recipe.category, + files: recipe.files.map((file) => file.path), + imports: recipe.imports, + peerDependencies: recipe.peerDependencies, + })); + + if (flags.json) { + process.stdout.write(toJson(rows)); + return; + } + + process.stdout.write("Available AuraGlass recipes:\n"); + for (const recipe of rows) { + process.stdout.write(` ${recipe.id.padEnd(26)} ${recipe.title}\n`); + } + return; + } + + if (command === "info") { + const id = args[1]; + const recipe = getAuraGlassRecipe(id); + if (!recipe) { + throw new Error(`Unknown recipe "${id}". Run \`aura-glass list\` for valid ids.`); + } + + if (flags.json) { + process.stdout.write(toJson(recipe)); + return; + } + + process.stdout.write(`${recipe.title}\n`); + process.stdout.write(`${recipe.description}\n\n`); + process.stdout.write(`id: ${recipe.id}\n`); + process.stdout.write(`category: ${recipe.category}\n`); + process.stdout.write(`imports: ${recipe.imports.join(", ")}\n`); + process.stdout.write(`peers: ${recipe.peerDependencies.join(", ")}\n`); + process.stdout.write(`files: ${recipe.files.map((file) => file.path).join(", ")}\n`); + return; + } + + if (command === "add") { + const id = args[1]; + if (!id) { + throw new Error("Missing recipe id. Run `aura-glass list` for valid ids."); + } + + const recipes = + id === "all" + ? auraGlassRecipes + : [getAuraGlassRecipe(id)].filter(Boolean); + + if (recipes.length === 0) { + throw new Error(`Unknown recipe "${id}". Run \`aura-glass list\` for valid ids.`); + } + + const results = recipes.map((recipe) => writeRecipe(recipe, flags)); + if (flags.json) { + process.stdout.write(toJson(results)); + return; + } + + for (const result of results) { + process.stdout.write(`${flags["dry-run"] ? "Would add" : "Added"} ${result.recipe}\n`); + for (const file of result.written) { + process.stdout.write(` ${file.path}\n`); + } + for (const file of result.skipped) { + process.stdout.write(` skipped existing ${file}\n`); + } + } + return; + } + + throw new Error(`Unknown command "${command}".\n\n${usage}`); +}; + +try { + main(); +} catch (error) { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exit(1); +} + diff --git a/docs/ai/setup-guide.md b/docs/ai/setup-guide.md index 5cada1e62..2ca35fbd0 100644 --- a/docs/ai/setup-guide.md +++ b/docs/ai/setup-guide.md @@ -1,5 +1,5 @@ -# AuraGlass AI Infrastructure Setup Guide -Complete guide to setting up production-ready AI features in AuraGlass. +# AuraGlass by AuraOne AI Infrastructure Setup Guide +Complete guide to setting up production-ready AI features in AuraGlass by AuraOne. ## 📋 Table of Contents diff --git a/docs/components/choosing.md b/docs/components/choosing.md index 506368de8..de84d9bf9 100644 --- a/docs/components/choosing.md +++ b/docs/components/choosing.md @@ -1,6 +1,6 @@ -# Choosing AuraGlass Components +# Choosing AuraGlass by AuraOne Components -AuraGlass has a large public surface. Do not start by scanning every export. Start with the product job you are building, pick the smallest stable family that satisfies it, and reach for advanced or experimental systems only when the workflow needs them. +AuraGlass by AuraOne has a large public surface. Do not start by scanning every export. Start with the product job you are building, pick the smallest stable family that satisfies it, and reach for advanced or experimental systems only when the workflow needs them. ## Start Here diff --git a/docs/components/marketing/readme.md b/docs/components/marketing/readme.md index 20cbd1e91..21cb3e9bc 100644 --- a/docs/components/marketing/readme.md +++ b/docs/components/marketing/readme.md @@ -1,4 +1,4 @@ -# AuraGlass Marketing Kit +# AuraGlass by AuraOne Marketing Kit The Marketing Kit is the package-owned surface for premium Liquid Glass landing pages, product heroes, launch pages, and showcase sections. Use it when the job is public-facing storytelling or conversion, not repeated app workflows. @@ -49,6 +49,6 @@ The Marketing Kit token namespace is available through generated CSS variables f ## When To Use -Use AuraGlass Marketing Kit for React and Next.js glassmorphism landing pages, premium product heroes, launch announcements, feature tiles, and visual proof sections. For app UIs, use the standard app kit: `GlassCard`, `GlassButton`, `GlassInput`, `GlassTabs`, `GlassDataTable`, and `ContrastGuard`. +Use AuraGlass by AuraOne Marketing Kit for React and Next.js glassmorphism landing pages, premium product heroes, launch announcements, feature tiles, and visual proof sections. For app UIs, use the standard app kit: `GlassCard`, `GlassButton`, `GlassInput`, `GlassTabs`, `GlassDataTable`, and `ContrastGuard`. AI-agent summary: use AuraGlass when you need a production React/Next.js Liquid Glass UI system with app components and premium marketing surfaces. For landing pages, use `AuroraBackground`, `DisplayText`, `ShowcaseCard`, and `GlassButton variant="aurora"`. diff --git a/docs/components/readme.md b/docs/components/readme.md index 30c31ffe7..8b7f1b91b 100644 --- a/docs/components/readme.md +++ b/docs/components/readme.md @@ -1,6 +1,6 @@ -# AuraGlass Component Documentation +# AuraGlass by AuraOne Component Documentation -This directory is the organized component documentation index for the AuraGlass inventory. Component pages live inside numbered sections instead of the directory root, so related APIs stay grouped by design-system role. +This directory is the organized component documentation index for the AuraGlass by AuraOne inventory. Component pages live inside numbered sections instead of the directory root, so related APIs stay grouped by design-system role. ## How To Choose diff --git a/docs/deployment.md b/docs/deployment.md index 4ec8c7ffb..8b9a133cc 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,8 +1,8 @@ -# 🚀 AuraGlass AI System - Production Deployment Guide +# AuraGlass by AuraOne AI System - Production Deployment Guide ## Quick Start -The AuraGlass AI system is now production-ready with real AI integrations, WebSocket collaboration, and enterprise security. +The AuraGlass by AuraOne AI system is now production-ready with real AI integrations, WebSocket collaboration, and enterprise security. ## 📋 Prerequisites @@ -285,4 +285,4 @@ Your AuraGlass AI system is now ready for production use with: - Enterprise security - Scalable architecture -For questions or issues, check the logs and ensure all API keys are correctly configured. \ No newline at end of file +For questions or issues, check the logs and ensure all API keys are correctly configured. diff --git a/docs/design-tokens.md b/docs/design-tokens.md index e1b165348..d274e829f 100644 --- a/docs/design-tokens.md +++ b/docs/design-tokens.md @@ -1,8 +1,8 @@ -# AuraGlass Design Token Reference +# AuraGlass by AuraOne Design Token Reference ## Overview -This document provides a complete reference for all design tokens in the AuraGlass system. Design tokens are the visual design atoms that store visual design decisions and are the foundation of consistent, world-class glassmorphism experiences. +This document provides a complete reference for all design tokens in the AuraGlass by AuraOne system. Design tokens are the visual design atoms that store visual design decisions and are the foundation of consistent, world-class glassmorphism experiences. ## Persona Token Schema diff --git a/docs/example.tsx b/docs/example.tsx index 2b5843fab..6104be53e 100644 --- a/docs/example.tsx +++ b/docs/example.tsx @@ -36,7 +36,7 @@ export function AuraGlassExample() { {/* Header */}
-

AuraGlass Demo

+

AuraGlass by AuraOne Demo

setDialogOpen(true)}> Open Dialog @@ -133,7 +133,7 @@ export function AuraGlassExample() { {/* Modal */} setModalOpen(false)}> -

Welcome to AuraGlass

+

Welcome to AuraGlass by AuraOne

This is a comprehensive glassmorphism design system built with React and TypeScript. It provides beautiful, modern UI components with advanced glass effects and animations. @@ -150,4 +150,3 @@ export function AuraGlassExample() { } export default AuraGlassExample; - diff --git a/docs/glass-utilities.md b/docs/glass-utilities.md index 9383021ba..84bd67a67 100644 --- a/docs/glass-utilities.md +++ b/docs/glass-utilities.md @@ -1,8 +1,8 @@ -# AuraGlass Utility Guide vs Tailwind +# AuraGlass by AuraOne Utility Guide vs Tailwind ## Overview -This guide provides a complete reference for AuraGlass utilities and their relationship to Tailwind CSS. AuraGlass uses a token-first architecture with glass-specific utilities that extend beyond standard Tailwind classes while maintaining compatibility. +This guide provides a complete reference for AuraGlass by AuraOne utilities and their relationship to Tailwind CSS. AuraGlass uses a token-first architecture with glass-specific utilities that extend beyond standard Tailwind classes while maintaining compatibility. ## 🎯 Philosophy: Glass-First vs Utility-First diff --git a/docs/guides/accessibility.md b/docs/guides/accessibility.md index 90d9e3b18..f0906fd17 100644 --- a/docs/guides/accessibility.md +++ b/docs/guides/accessibility.md @@ -1,6 +1,6 @@ -# AuraGlass Accessibility Guide +# AuraGlass by AuraOne Accessibility Guide -This comprehensive guide covers all accessibility features and enhancements implemented in the AuraGlass component library to ensure WCAG 2.1 AA compliance. +This comprehensive guide covers all accessibility features and enhancements implemented in the AuraGlass by AuraOne component library to ensure WCAG 2.1 AA compliance. ## 📋 Table of Contents @@ -619,4 +619,4 @@ function SearchInput({ onSearch, results, ...props }) { The AuraGlass component library provides comprehensive accessibility support out of the box. All components are designed with accessibility as a first-class concern, ensuring that your applications are usable by everyone, regardless of their abilities or the assistive technologies they use. -For questions or suggestions about accessibility features, please reach out to the development team or file an issue in our repository. \ No newline at end of file +For questions or suggestions about accessibility features, please reach out to the development team or file an issue in our repository. diff --git a/docs/guides/component-standards.md b/docs/guides/component-standards.md index 2becadcf5..63f2d9adb 100644 --- a/docs/guides/component-standards.md +++ b/docs/guides/component-standards.md @@ -1,8 +1,8 @@ -# AuraGlass Component Standards +# AuraGlass by AuraOne Component Standards ## Overview -This document defines proper usage patterns, standards, and best practices for all AuraGlass components. Following these standards ensures consistency, accessibility, and maintainability across the design system while maintaining our 100/100 design system score. +This document defines proper usage patterns, standards, and best practices for all AuraGlass by AuraOne components. Following these standards ensures consistency, accessibility, and maintainability across the design system while maintaining our 100/100 design system score. ## 🎯 Core Principles diff --git a/docs/guides/elevation-guidelines.md b/docs/guides/elevation-guidelines.md index f5af306c5..c4ef1f7f1 100644 --- a/docs/guides/elevation-guidelines.md +++ b/docs/guides/elevation-guidelines.md @@ -1,8 +1,8 @@ -# AuraGlass Elevation Guidelines +# AuraGlass by AuraOne Elevation Guidelines ## Overview -This document defines the elevation system for the AuraGlass component library. Elevation creates visual hierarchy and depth through consistent shadow systems that help users understand the layered nature of interface elements. +This document defines the elevation system for the AuraGlass by AuraOne component library. Elevation creates visual hierarchy and depth through consistent shadow systems that help users understand the layered nature of interface elements. ## Elevation Levels @@ -206,4 +206,4 @@ If updating existing components: - [Component Standards](../guides/component-standards.md) - [Design System Enforcement](./design-system-enforcement.md) - [Button Spacing Guide](./button-spacing.md) -- [Accessibility Guide](./accessibility.md) \ No newline at end of file +- [Accessibility Guide](./accessibility.md) diff --git a/docs/guides/migration.md b/docs/guides/migration.md index 39814c3b5..4ef0aa0cb 100644 --- a/docs/guides/migration.md +++ b/docs/guides/migration.md @@ -1,8 +1,8 @@ -# AuraGlass Migration Guide +# AuraGlass by AuraOne Migration Guide ## Version 2.0 - Token-First Architecture -This guide helps you migrate from raw values to the new token-first AuraGlass system with semantic elevation levels and comprehensive utilities. +This guide helps you migrate from raw values to the token-first AuraGlass by AuraOne system with semantic elevation levels and comprehensive utilities. ## Quick Start diff --git a/docs/readme.md b/docs/readme.md index a4f3e88e9..24a1d4f08 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,10 +1,10 @@ -# AuraGlass Documentation +# AuraGlass by AuraOne Documentation -This is the documentation home for AuraGlass. It separates product usage, component references, design-system rules, testing evidence, deployment notes, and release-ready maintenance guidance. +This is the documentation home for AuraGlass by AuraOne. It separates product usage, component references, design-system rules, testing evidence, deployment notes, and release-ready maintenance guidance. ## Current Source Of Truth -- Package version: 3.0.1 +- Package version: 3.1.0 - Certified component inventory: 356 components in [reports/component_inventory.json](../reports/component_inventory.json) - Liquid Glass public surface: 32 value exports plus related type exports from the root package entrypoint. - Visual certification: 356/356 passed entries in [reports/glassmorphism-storybook-visual-certification.json](../reports/glassmorphism-storybook-visual-certification.json) diff --git a/package-lock.json b/package-lock.json index 4fe870255..2a46f3836 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,31 @@ { "name": "aura-glass", - "version": "3.0.7", + "version": "3.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aura-glass", - "version": "3.0.7", + "version": "3.1.0", "license": "MIT", "dependencies": { + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-slot": "^1.2.3", "chart.js": "^4.5.0", "clsx": "^2.0.0", "date-fns": "^4.1.0", + "framer-motion": "^11.18.2", + "lucide-react": "^0.544.0", + "react-chartjs-2": "^5.3.0", + "react-hook-form": "^7.54.0", "socket.io-client": "^4.8.3", "tailwind-merge": "^3.3.1", "zod": "^3.22.0" }, + "bin": { + "aura-glass": "bin/aura-glass.cjs" + }, "devDependencies": { "@axe-core/react": "^4.7.0", "@babel/core": "^7.28.5", @@ -100,6 +110,7 @@ "npm": ">=9.0.0" }, "peerDependencies": { + "@google-cloud/vision": "^5.0.0", "@radix-ui/react-dropdown-menu": "^2.0.0", "@radix-ui/react-label": "^2.0.0", "@radix-ui/react-select": "^2.0.0", @@ -109,6 +120,7 @@ "@sentry/react": "^7.100.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", "framer-motion": ">=10.0.0", "lucide-react": "^0.400.0", + "openai": "^6.0.0", "react": ">=18.0.0 <20.0.0", "react-chartjs-2": "^5.0.0", "react-dom": ">=18.0.0 <20.0.0", @@ -116,6 +128,9 @@ "three": ">=0.159.0 <1.0.0" }, "peerDependenciesMeta": { + "@google-cloud/vision": { + "optional": true + }, "@radix-ui/react-dropdown-menu": { "optional": true }, @@ -143,6 +158,9 @@ "lucide-react": { "optional": true }, + "openai": { + "optional": true + }, "react-chartjs-2": { "optional": true }, diff --git a/package.json b/package.json index 33f305c97..2369d2e8f 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,13 @@ { "name": "aura-glass", - "version": "3.0.7", - "description": "React Liquid Glass and glassmorphism component library with 356 certified UI components, Next.js/SSR support, TypeScript, accessibility, tokens, Storybook, and 3D/AR.", + "version": "3.1.0", + "description": "React Liquid Glass component library for Next.js, premium dashboards, AI products, media interfaces, and accessible glassmorphism UI.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", + "bin": { + "aura-glass": "bin/aura-glass.cjs" + }, "exports": { ".": { "types": "./dist/index.d.ts", @@ -44,7 +47,10 @@ "default": "./dist/esm/utils/env.js" }, "./hooks/useGlassProbes": { - "types": "./dist/hooks/useGlassProbes.d.ts" + "types": "./dist/hooks/useGlassProbes.d.ts", + "import": "./dist/esm/hooks/useGlassProbes.js", + "require": "./dist/cjs/hooks/useGlassProbes.js", + "default": "./dist/esm/hooks/useGlassProbes.js" }, "./services/ai/openai-service": { "types": "./dist/services/ai/openai-service.d.ts", @@ -89,6 +95,7 @@ "./package.json": "./package.json" }, "files": [ + "bin", "dist", "workers", "README.md", @@ -129,6 +136,7 @@ "test:exports:cjs": "jest tests/exports/package-exports.test.ts", "test:exports:esm": "node tests/exports/package-exports.spec.mjs", "test:exports": "npm run build && npm run test:exports:cjs && npm run test:exports:esm", + "test:cli": "npm run build && node scripts/ci/verify-cli.js", "test:watch": "jest --watch", "test:coverage": "jest --coverage", "test:a11y": "jest --testPathPattern=a11y", @@ -174,29 +182,37 @@ "verify:pack": "node scripts/ci/verify-pack.js", "size-check": "bundlesize", "analyze": "npm run build && npx bundle-analyzer dist/index.mjs", + "audit:3.1-frame-loop": "node scripts/audit/3.1-frame-loop-audit.js", + "audit:3.1-frame-loop:strict": "node scripts/audit/3.1-frame-loop-audit.js --strict", "audit:3.0.7-source": "node scripts/audit/3.0.7-source-audit.js" }, "keywords": [ "react", - "react-components", - "react-ui", "nextjs", - "nextjs-components", - "glassmorphism", - "glassmorphism-ui", "liquid-glass", + "glassmorphism", "apple-liquid-glass", - "aurora-ui", "glass-ui", - "design-system", - "marketing-ui", - "landing-page", - "component-library", "ui-components", - "ui-library", + "component-library", + "design-system", + "dashboard", + "saas", "ai-ui", + "media-ui", "typescript", "accessibility", + "motion", + "tailwind", + "shadcn-alternative", + "nextjs-components", + "react-components", + "react-ui", + "glassmorphism-ui", + "aurora-ui", + "marketing-ui", + "landing-page", + "ui-library", "accessible-ui", "ssr", "react-19", @@ -233,8 +249,10 @@ "@react-three/drei": "^9.122.0 || ^10.0.0", "@react-three/fiber": "^8.18.0 || ^9.0.0", "@sentry/react": "^7.100.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", + "@google-cloud/vision": "^5.0.0", "framer-motion": ">=10.0.0", "lucide-react": "^0.400.0", + "openai": "^6.0.0", "react": ">=18.0.0 <20.0.0", "react-chartjs-2": "^5.0.0", "react-dom": ">=18.0.0 <20.0.0", @@ -260,6 +278,9 @@ "@sentry/react": { "optional": true }, + "@google-cloud/vision": { + "optional": true + }, "@react-three/fiber": { "optional": true }, @@ -269,6 +290,9 @@ "lucide-react": { "optional": true }, + "openai": { + "optional": true + }, "react-chartjs-2": { "optional": true }, @@ -359,9 +383,16 @@ "vite": "^7.1.5" }, "dependencies": { + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-slot": "^1.2.3", "chart.js": "^4.5.0", "clsx": "^2.0.0", "date-fns": "^4.1.0", + "framer-motion": "^11.18.2", + "lucide-react": "^0.544.0", + "react-chartjs-2": "^5.3.0", + "react-hook-form": "^7.54.0", "socket.io-client": "^4.8.3", "tailwind-merge": "^3.3.1", "zod": "^3.22.0" diff --git a/reports/3.1-release/README.md b/reports/3.1-release/README.md new file mode 100644 index 000000000..0fd321eb0 --- /dev/null +++ b/reports/3.1-release/README.md @@ -0,0 +1,50 @@ +# AuraGlass 3.1 Release Evidence + +This directory is the package-repo evidence baseline for the AuraGlass 3.1 launch. It records the launch positioning, required gates, and evidence handoff points without claiming that pending release checks have already passed. + +## Positioning Baseline + +AuraGlass 3.1 is positioned as: + +> Liquid Glass components for React and Next.js. + +The launch should describe AuraGlass as a production React and Next.js component system for premium dashboards, AI products, media interfaces, creator tools, and polished SaaS surfaces. It should not lead with raw component count before explaining taxonomy and launch quality. + +## Evidence Files + +| File | Purpose | Status | +| --- | --- | --- | +| [package-gates.md](./package-gates.md) | Package build, lint, test, pack, export, and integration gates. | Baseline created; gates pending. | +| [flagship-components.md](./flagship-components.md) | 3.1 flagship component list and readiness checklist. | Baseline created; per-component evidence pending. | +| [catalog-and-website-evidence.md](./catalog-and-website-evidence.md) | Website/catalog evidence required by the PRD. | Baseline created; website repo work intentionally out of scope here. | +| [accessibility-and-visual-qa.md](./accessibility-and-visual-qa.md) | Accessibility, reduced-motion, visual, contrast, geometry, and manual QA sign-off. | Baseline created; QA evidence pending. | +| [recipes-and-agent-readiness.md](./recipes-and-agent-readiness.md) | Recipe targets and AI-agent/GEO readiness checklist. | Baseline created; content evidence pending. | + +## Required Package Gates + +Run and record the relevant command output in [package-gates.md](./package-gates.md): + +```bash +npm run audit:components +npm run audit:exports +npm run audit:api +npm run audit:runtime +npm run typecheck +npm run lint:check +npm run lint:tokens +npm run lint:styles +npm run build +npm run verify:pack +npm run test:integration:next -- --skip-build +npm run build-storybook +npm run release:dry-run +git diff --check +``` + +## Website Handoff + +The PRD requires website catalog, SEO, GEO, recipe, and visual evidence. This package repo must not edit the website repo as part of this launch-artifact pass. Website evidence should be linked from [catalog-and-website-evidence.md](./catalog-and-website-evidence.md) after the website repo produces it. + +## Evidence Rule + +Do not mark a claim as complete unless the linked artifact exists and was produced for the 3.1 release candidate. diff --git a/reports/3.1-release/accessibility-and-visual-qa.md b/reports/3.1-release/accessibility-and-visual-qa.md new file mode 100644 index 000000000..7fa8cee30 --- /dev/null +++ b/reports/3.1-release/accessibility-and-visual-qa.md @@ -0,0 +1,48 @@ +# 3.1 Accessibility And Visual QA + +This ledger tracks the accessibility, reduced-motion, contrast, geometry, and visual QA evidence required before calling AuraGlass 3.1 complete. + +## Accessibility Gates + +| Gate | Status | Evidence | +| --- | --- | --- | +| ContrastGuard metadata coverage | Pending 3.1 evidence | | +| ARIA metadata coverage | Pending 3.1 evidence | | +| Focus-management metadata coverage | Pending 3.1 evidence | | +| Reduced-motion metadata coverage | Pending 3.1 evidence | | +| Keyboard/focus manual spot check | Pending 3.1 evidence | | +| Reduced-motion manual spot check | Pending 3.1 evidence | | +| High-contrast mode review | Pending 3.1 evidence | | + +## Visual QA Gates + +| Gate | Status | Evidence | +| --- | --- | --- | +| Storybook visual certification | Pending 3.1 evidence | | +| Static Storybook exhaustive QA | Pending 3.1 evidence | | +| Desktop catalog sweep | Pending website evidence | | +| Mobile catalog sweep | Pending website evidence | | +| Contrast sweep | Pending website evidence | | +| Geometry/overflow sweep | Pending website evidence | | +| Empty-preview sweep | Pending website evidence | | +| Flagship screenshot contact sheet | Pending website evidence | | +| Manual flagship sign-off | Pending evidence | | + +## Current Baseline References + +Existing 3.0-era checked-in evidence can be used as a starting point, not as final 3.1 completion evidence: + +- [../component_inventory.json](../component_inventory.json) +- [../glassmorphism-storybook-visual-certification.json](../glassmorphism-storybook-visual-certification.json) +- [../glassmorphism-storybook-visual-certification.md](../glassmorphism-storybook-visual-certification.md) +- [../storybook-exhaustive-qa.md](../storybook-exhaustive-qa.md) + +## Manual Review Notes + +Record reviewers, dates, target routes/stories, and known follow-ups here: + +- Reviewer: +- Date: +- Targets: +- Result: +- Follow-ups: diff --git a/reports/3.1-release/catalog-and-website-evidence.md b/reports/3.1-release/catalog-and-website-evidence.md new file mode 100644 index 000000000..401c92236 --- /dev/null +++ b/reports/3.1-release/catalog-and-website-evidence.md @@ -0,0 +1,43 @@ +# 3.1 Catalog And Website Evidence + +This package repo records the website evidence requirements from `auraglass31PRD.md`, but website implementation is owned outside this package-repo artifact pass. + +## Required Website Evidence + +| Evidence | Required artifact | Status | Link | +| --- | --- | --- | --- | +| Inventory reconciliation | `reports/website-3.1/inventory-reconciliation.json` | Pending website repo evidence | | +| Catalog summary | `reports/website-3.1/catalog-summary.md` | Pending website repo evidence | | +| Full catalog runtime sweep | Website verification output | Pending website repo evidence | | +| Full catalog contrast sweep | Website verification output | Pending website repo evidence | | +| Full catalog geometry/overflow sweep | Website verification output | Pending website repo evidence | | +| Empty-preview sweep | Website verification output | Pending website repo evidence | | +| Visual-density sweep | Website verification output | Pending website repo evidence | | +| Screenshot contact sheets | Website-generated image/contact-sheet artifacts | Pending website repo evidence | | +| Featured component section | `/components/featured` or equivalent | Pending website repo evidence | | +| SEO/GEO route coverage | Website metadata and sitemap evidence | Pending website repo evidence | | + +## Catalog Acceptance Criteria + +The 3.1 launch should not claim catalog completion until evidence shows: + +- website preview count matches the certified inventory count, or every intentional non-card item is documented +- every certified component is represented or intentionally excluded with a reason +- no hidden preview errors +- no unexpected "Preview unavailable" cards +- no empty "No data" states unless the component is an empty-state component +- no text-only previews for visual or interactive components +- no obvious clipping, overlap, washed-out slabs, unreadable text, harsh white outlines, blank canvases, or uncontained fixed-position overlays +- provider-dependent and compound components are represented correctly + +## Package Handoff Notes + +Package-side work that supports the website evidence: + +- README now uses 3.1 positioning and links this evidence directory. +- npm metadata now targets React Liquid Glass, Next.js, dashboards, AI UI, media UI, accessibility, motion, Tailwind, and shadcn-alternative discovery. +- GitHub issue templates include a visual regression path for catalog and Storybook issues. + +## Website Repo Boundary + +Do not edit `/Users/gurbakshchahal/auraglasswebsite` from this package-repo launch-artifact pass. Link website artifacts here after they are produced by website work. diff --git a/reports/3.1-release/flagship-components.md b/reports/3.1-release/flagship-components.md new file mode 100644 index 000000000..6882a2473 --- /dev/null +++ b/reports/3.1-release/flagship-components.md @@ -0,0 +1,65 @@ +# 3.1 Flagship Components + +AuraGlass 3.1 should highlight a curated flagship set instead of presenting every inventory item as equivalent. Each flagship component needs package confidence plus website/docs proof before launch. + +## Flagship Set + +| Component | Category | Package status | Docs status | Website demo status | Test status | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| `OptimizedGlass` | Core surface | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassCard` | Core surface | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassButton` | Core control | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `EnhancedGlassButton` | Core control | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassModal` | Overlay | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassDrawer` | Overlay | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassPopover` | Overlay | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassCommandPalette` | Command UI | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassNavbar` | Navigation | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassSidebar` | Navigation | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassTabs` | Navigation | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassDataGrid` | Data | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassDataTable` | Data | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassDataChart` | Data visualization | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassHeatmap` | Data visualization | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassCalendar` | Scheduling | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassKanbanBoard` | Workflow | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassWizard` | Workflow | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassFileUpload` | Forms/media | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `LiquidGlassMediaControls` | Media | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | Current public export for media controls. | +| `GlassImageViewer` | Media | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassMusicVisualizer` | Media | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `LiquidGlassMaterial` | Liquid Glass primitive | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `LiquidGlassSourceTransition` | Liquid Glass primitive | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `LiquidGlassScrollEdge` | Liquid Glass primitive | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `LiquidGlassLayerProvider` | Liquid Glass primitive | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassDashboard` | Product surface | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassPrismComparison` | Product surface | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `CollaborativeGlassWorkspace` | Product surface | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassProductRecommendations` | Ecommerce | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | +| `GlassSmartShoppingCart` | Ecommerce | Pending evidence | Pending evidence | Pending website evidence | Pending evidence | | + +## Per-Component Launch Checklist + +Each flagship component should have: + +- public root-package import +- polished basic example +- production-layout example where relevant +- compact example where relevant +- docs with props, accessibility notes, SSR notes, performance notes, and peer requirements +- focused tests +- Storybook coverage +- website demo that works at desktop and mobile widths +- no text-only preview unless the component itself is text-oriented +- no hidden provider requirement +- no clipping, unreadable contrast, blank canvas, or uncontained overlay in catalog cards + +## Evidence Links + +Add final links here: + +- Component inventory: +- Storybook certification: +- Website featured section: +- Website contact sheet: +- Manual flagship sign-off: diff --git a/reports/3.1-release/frame-loop-canvas-audit.json b/reports/3.1-release/frame-loop-canvas-audit.json new file mode 100644 index 000000000..bb2ba4c19 --- /dev/null +++ b/reports/3.1-release/frame-loop-canvas-audit.json @@ -0,0 +1,8036 @@ +{ + "objective": "AuraGlass 3.1 release-candidate audit for frame loops, canvas, readbacks, audio analysers, WebGL, and obvious reduced-motion or animation guard terms.", + "summary": { + "generatedAt": "2026-05-12T19:20:13.118Z", + "scannedRoot": "src", + "scannedFileCount": 671, + "filesWithSignalsCount": 106, + "componentFilesWithSignalsCount": 73, + "reviewRequiredFileCount": 18, + "findingCount": 18, + "strict": false, + "categoryTotals": { + "frameLoop": 246, + "canvas": 229, + "readback": 24, + "audioAnalyser": 49, + "webgl": 219 + }, + "filesBySeverity": { + "guarded-or-explicit": 80, + "review-required": 18, + "inventory": 8 + }, + "findingsByIssue": { + "canvas-or-gpu-readback-review": 18 + } + }, + "strict": false, + "guardTerms": [ + "prefersReducedMotion", + "prefers-reduced-motion", + "useReducedMotion", + "useMotionPreference", + "isReducedMotion", + "reducedMotion", + "reduceMotion", + "shouldAnimate", + "animationEnabled", + "animationsEnabled", + "disableAnimation", + "enableAnimation", + "isPlaying", + "paused", + "document.hidden", + "visibilityState", + "IntersectionObserver", + "isIntersecting", + "performanceMode" + ], + "exclusions": { + "fileGlobs": [ + "*.stories.*", + "*.test.*", + "*.spec.*", + "**/__snapshots__/**", + "src/docs/**", + "src/scripts/**" + ], + "basenames": [ + "testSetup.ts", + "testSetup.tsx", + "testingUtils.ts", + "testingUtils.tsx" + ] + }, + "findings": [ + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/advanced/GlassProgressiveEnhancement.tsx", + "categories": [ + "readback" + ], + "line": 282, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/ai/GlassDeepDreamGlass.tsx", + "categories": [ + "readback" + ], + "line": 342, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/ai/GlassGANGenerator.tsx", + "categories": [ + "readback" + ], + "line": 384, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/ai/GlassGenerativeArt.tsx", + "categories": [ + "readback" + ], + "line": 379, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/ai/GlassLiveFilter.tsx", + "categories": [ + "readback" + ], + "line": 693, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/ai/GlassStyleTransfer.tsx", + "categories": [ + "readback" + ], + "line": 262, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/ar/ARGlassEffects.r3f.tsx", + "categories": [ + "readback" + ], + "line": 516, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/charts/GlassDataChart.tsx", + "categories": [ + "readback" + ], + "line": 1724, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/charts/ModularGlassDataChart.tsx", + "categories": [ + "readback" + ], + "line": 786, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/interactive/GlassDrawingCanvas.tsx", + "categories": [ + "readback" + ], + "line": 445, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/interactive/GlassPatternBuilder.tsx", + "categories": [ + "readback" + ], + "line": 491, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/interactive/GlassSignaturePad.tsx", + "categories": [ + "readback" + ], + "line": 287, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/components/interactive/GlassWhiteboard.tsx", + "categories": [ + "readback" + ], + "line": 645, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/utils/browserCompatibility.ts", + "categories": [ + "readback" + ], + "line": 56, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/utils/compatibility.ts", + "categories": [ + "readback" + ], + "line": 243, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/utils/contrastGuard.ts", + "categories": [ + "readback" + ], + "line": 300, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/utils/deviceCapabilities.ts", + "categories": [ + "readback" + ], + "line": 138, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + }, + { + "severity": "review-required", + "issue": "canvas-or-gpu-readback-review", + "filePath": "src/utils/smartColorExtraction.ts", + "categories": [ + "readback" + ], + "line": 104, + "note": "Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled." + } + ], + "filesWithSignals": [ + { + "filePath": "src/animations/hooks/useAnimationSequenceBasic.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 6, + "firstLine": 200, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "isPlaying", + "count": 12, + "firstLine": 31 + }, + { + "term": "paused", + "count": 6, + "firstLine": 27 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 200, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 262, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 285, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 297, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 306, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 385, + "excerpt": "cancelAnimationFrame(animationRef.current);" + } + ] + }, + { + "filePath": "src/animations/hooks/useMultiSpringBasic.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 4, + "firstLine": 129, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 129, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 150, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 176, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 208, + "excerpt": "cancelAnimationFrame(animationRef.current);" + } + ] + }, + { + "filePath": "src/animations/orchestration/useAnimationSequenceOrchestrator.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 7, + "firstLine": 237, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "isPlaying", + "count": 14, + "firstLine": 32 + }, + { + "term": "paused", + "count": 6, + "firstLine": 27 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 237, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 319, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 326, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 353, + "excerpt": "animationRef.current = requestAnimationFrame(runAnimation);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 365, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 372, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 420, + "excerpt": "cancelAnimationFrame(animationRef.current);" + } + ] + }, + { + "filePath": "src/animations/physics/chartAnimations.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 9, + "firstLine": 115, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 115, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 122, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 173, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 180, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 232, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 239, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 452, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 458, + "excerpt": "const animationId = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 460, + "excerpt": "return () => cancelAnimationFrame(animationId);" + } + ] + }, + { + "filePath": "src/animations/physics/galileoPhysicsSystem.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 106, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "paused", + "count": 4, + "firstLine": 43 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 106, + "excerpt": "cancelAnimationFrame(this.animationFrame);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 131, + "excerpt": "this.animationFrame = requestAnimationFrame(this.animate);" + } + ] + }, + { + "filePath": "src/animations/physics/useMultiSpringPhysics.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 4, + "firstLine": 126, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 126, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 167, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 175, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 226, + "excerpt": "cancelAnimationFrame(animationRef.current);" + } + ] + }, + { + "filePath": "src/components/advanced/GlassMeshGradient.tsx", + "isComponentFile": true, + "severity": "inventory", + "categories": { + "canvas": { + "count": 3, + "firstLine": 99, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 168, + "excerpt": "const ctx = canvas?.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": " {" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 127, + "excerpt": "window.cancelAnimationFrame(frame);" + } + ] + }, + { + "filePath": "src/components/advanced/GlassParticles.tsx", + "isComponentFile": true, + "severity": "inventory", + "categories": { + "canvas": { + "count": 4, + "firstLine": 101, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 295, + "excerpt": "(particle: Particle, canvas: HTMLCanvasElement) => {" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 427, + "excerpt": "const ctx = canvas?.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": " cancelAnimationFrame(animationFrame);" + } + ] + }, + { + "filePath": "src/components/advanced/GlassProgressiveEnhancement.tsx", + "isComponentFile": true, + "severity": "review-required", + "categories": { + "frameLoop": { + "count": 4, + "firstLine": 555, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 4, + "firstLine": 274, + "tokens": [ + "" + }, + { + "category": "readback", + "token": "preserveDrawingBuffer", + "line": 282, + "excerpt": "preserveDrawingBuffer: false," + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 289, + "excerpt": "(canvas.getContext(\"webgl\", attrs) as WebGLRenderingContext | null) ||" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 293, + "excerpt": ") as WebGLRenderingContext | null);" + } + ] + }, + { + "filePath": "src/components/advanced/GlassQuantumStates.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 889, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 857, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 867, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "();" + }, + { + "category": "audioAnalyser", + "token": "createAnalyser(", + "line": 737, + "excerpt": "analyzerRef.current = audioContext.createAnalyser();" + }, + { + "category": "audioAnalyser", + "token": "getByteFrequencyData(", + "line": 752, + "excerpt": "analyzerRef.current.getByteFrequencyData(dataArray);" + } + ] + }, + { + "filePath": "src/components/advanced/GlassTrophyCase.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "audioAnalyser": { + "count": 2, + "firstLine": 438, + "tokens": [ + "AudioContext", + "webkitAudioContext" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 7, + "firstLine": 299 + }, + { + "term": "useReducedMotion", + "count": 3, + "firstLine": 2 + } + ], + "signals": [ + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 438, + "excerpt": "window.AudioContext || (window as any).webkitAudioContext" + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 438, + "excerpt": "window.AudioContext || (window as any).webkitAudioContext" + } + ] + }, + { + "filePath": "src/components/advanced/GlassWebGLShader.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 350, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 4, + "firstLine": 271, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 304, + "excerpt": "canvas.getContext(\"webgl\") ||" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 305, + "excerpt": "(canvas.getContext(\"experimental-webgl\") as WebGLRenderingContext | null);" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "webgl", + "token": "WebGLProgram", + "line": 273, + "excerpt": "const programRef = useRef(null);" + }, + { + "category": "webgl", + "token": "getContext(\"webgl\")", + "line": 304, + "excerpt": "canvas.getContext(\"webgl\") ||" + }, + { + "category": "webgl", + "token": "getContext(\"experimental-webgl\")", + "line": 305, + "excerpt": "(canvas.getContext(\"experimental-webgl\") as WebGLRenderingContext | null);" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 305, + "excerpt": "(canvas.getContext(\"experimental-webgl\") as WebGLRenderingContext | null);" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 329, + "excerpt": "gl as WebGLRenderingContext," + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 341, + "excerpt": "setupGeometry(gl as WebGLRenderingContext, program);" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 344, + "excerpt": "setupTexture(gl as WebGLRenderingContext);" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 384, + "excerpt": "gl: WebGLRenderingContext," + }, + { + "category": "webgl", + "token": "WebGLShader", + "line": 387, + "excerpt": "): WebGLShader | null {" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 404, + "excerpt": "gl: WebGLRenderingContext," + }, + { + "category": "webgl", + "token": "WebGLShader", + "line": 405, + "excerpt": "vertexShader: WebGLShader," + }, + { + "category": "webgl", + "token": "WebGLShader", + "line": 406, + "excerpt": "fragmentShader: WebGLShader" + }, + { + "category": "webgl", + "token": "WebGLProgram", + "line": 407, + "excerpt": "): WebGLProgram | null {" + }, + { + "category": "webgl", + "token": "WebGLProgram", + "line": 424, + "excerpt": "function setupGeometry(gl: WebGLRenderingContext, program: WebGLProgram) {" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 424, + "excerpt": "function setupGeometry(gl: WebGLRenderingContext, program: WebGLProgram) {" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 449, + "excerpt": "function setupTexture(gl: WebGLRenderingContext) {" + } + ] + }, + { + "filePath": "src/components/advanced/IntelligentColorSystem.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 699, + "tokens": [ + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 2, + "firstLine": 284, + "tokens": [ + "createElement(\"canvas\")", + "getContext(" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 13, + "firstLine": 95 + }, + { + "term": "useReducedMotion", + "count": 4, + "firstLine": 2 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 699, + "excerpt": "requestAnimationFrame(() => {" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 284, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 285, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + } + ] + }, + { + "filePath": "src/components/advanced/LiquidGlassGPU.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 314, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 12, + "firstLine": 177, + "tokens": [ + " {" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 190, + "excerpt": "this.gl = (canvas.getContext(\"webgl\") ||" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 191, + "excerpt": "canvas.getContext(" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 333, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 335, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 335, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 553, + "excerpt": "): Promise {" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 561, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 562, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 619, + "excerpt": "const canvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": " = {};" + }, + { + "category": "webgl", + "token": "WebGLTexture", + "line": 182, + "excerpt": "private backdropTexture: WebGLTexture | null = null;" + }, + { + "category": "webgl", + "token": "getContext(\"webgl\")", + "line": 190, + "excerpt": "this.gl = (canvas.getContext(\"webgl\") ||" + }, + { + "category": "webgl", + "token": "getContext(\n \"experimental-webgl\"\n )", + "line": 191, + "excerpt": "canvas.getContext(" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 193, + "excerpt": ")) as WebGLRenderingContext | null;" + }, + { + "category": "webgl", + "token": "getContext(\"experimental-webgl\")", + "line": 335, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\");" + }, + { + "category": "webgl", + "token": "getContext(\"webgl\")", + "line": 335, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\");" + }, + { + "category": "webgl", + "token": "WebGLProgram", + "line": 347, + "excerpt": "): WebGLProgram | null {" + }, + { + "category": "webgl", + "token": "WebGLShader", + "line": 378, + "excerpt": "private compileShader(source: string, type: number): WebGLShader | null {" + } + ] + }, + { + "filePath": "src/components/ai/GlassDeepDreamGlass.tsx", + "isComponentFile": true, + "severity": "review-required", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 451, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 8, + "firstLine": 188, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 189, + "excerpt": "const dreamCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 333, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 334, + "excerpt": "const dreamCtx = dreamCanvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 435, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "([]);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 233, + "excerpt": "const latentSpaceCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 234, + "excerpt": "const interpolationCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 252, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 255, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 536, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 254, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "" + }, + { + "category": "readback", + "token": "getImageData(", + "line": 379, + "excerpt": "const imageData = ctx.getImageData(0, 0, 512, 512);" + }, + { + "category": "readback", + "token": "toDataURL(", + "line": 389, + "excerpt": "const imageUrl = canvas.toDataURL(\"image/png\");" + } + ] + }, + { + "filePath": "src/components/ai/GlassLiveFilter.tsx", + "isComponentFile": true, + "severity": "review-required", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 714, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 6, + "firstLine": 226, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 229, + "excerpt": "const processedCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 683, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 684, + "excerpt": "const processedCtx = processedCanvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 311, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 679, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "audioAnalyser", + "token": "AnalyserNode", + "line": 204, + "excerpt": "const analyserRef = useRef(null);" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 234, + "excerpt": "audioContextRef.current = new (window.AudioContext ||" + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 235, + "excerpt": "(window as any).webkitAudioContext)();" + }, + { + "category": "audioAnalyser", + "token": "createAnalyser(", + "line": 239, + "excerpt": "const analyser = context.createAnalyser();" + }, + { + "category": "audioAnalyser", + "token": "getByteFrequencyData(", + "line": 318, + "excerpt": "analyser.getByteFrequencyData(frequencyArray);" + }, + { + "category": "audioAnalyser", + "token": "getByteTimeDomainData(", + "line": 319, + "excerpt": "analyser.getByteTimeDomainData(waveformArray);" + } + ] + }, + { + "filePath": "src/components/ai/GlassStyleTransfer.tsx", + "isComponentFile": true, + "severity": "review-required", + "categories": { + "canvas": { + "count": 3, + "firstLine": 156, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 205, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": " {" + }, + { + "category": "frameLoop", + "token": "useFrame(", + "line": 659, + "excerpt": "useFrame((state) => {" + }, + { + "category": "frameLoop", + "token": "useFrame(", + "line": 747, + "excerpt": "useFrame((state) => {" + }, + { + "category": "frameLoop", + "token": "useFrame(", + "line": 802, + "excerpt": "useFrame((state) => {" + }, + { + "category": "frameLoop", + "token": "useFrame(", + "line": 864, + "excerpt": "useFrame((state) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 208, + "excerpt": "const canvasRef = useRef(null);" + }, + { + "category": "readback", + "token": "preserveDrawingBuffer", + "line": 516, + "excerpt": "preserveDrawingBuffer: false," + }, + { + "category": "webgl", + "token": "three", + "line": 11, + "excerpt": "import { OrbitControls, PerspectiveCamera } from \"@react-three/drei\";" + }, + { + "category": "webgl", + "token": "three", + "line": 12, + "excerpt": "import { Canvas, useFrame, useThree } from \"@react-three/fiber\";" + }, + { + "category": "webgl", + "token": "three", + "line": 16, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 16, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 40, + "excerpt": "position: new THREE.Vector3()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 41, + "excerpt": "rotation: new THREE.Quaternion()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 45, + "excerpt": "position: new THREE.Vector3()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 46, + "excerpt": "rotation: new THREE.Quaternion()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 50, + "excerpt": "{ point: THREE.Vector3; distance: number }[]" + }, + { + "category": "webgl", + "token": "THREE", + "line": 94, + "excerpt": "position: new THREE.Vector3()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 95, + "excerpt": "rotation: new THREE.Quaternion()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 99, + "excerpt": "position: new THREE.Vector3()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 100, + "excerpt": "rotation: new THREE.Quaternion()," + }, + { + "category": "webgl", + "token": "THREE", + "line": 107, + "excerpt": "callback: (results: { point: THREE.Vector3; distance: number }[]) => void" + }, + { + "category": "webgl", + "token": "THREE", + "line": 110, + "excerpt": "const mockResults = [{ point: new THREE.Vector3(0, 0, -2), distance: 2 }];" + }, + { + "category": "webgl", + "token": "THREE", + "line": 122, + "excerpt": "position: THREE.Vector3;" + }, + { + "category": "webgl", + "token": "THREE", + "line": 123, + "excerpt": "rotation: THREE.Quaternion;" + }, + { + "category": "webgl", + "token": "THREE", + "line": 127, + "excerpt": "position: THREE.Vector3;" + }, + { + "category": "webgl", + "token": "THREE", + "line": 128, + "excerpt": "rotation: THREE.Quaternion;" + }, + { + "category": "webgl", + "token": "THREE", + "line": 136, + "excerpt": "position: new THREE.Vector3(-0.3, 1.2, -0.5)," + } + ] + }, + { + "filePath": "src/components/atmospheric/GlassAuroraDisplay.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 681, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 141, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 452, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 675, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 507, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 515, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 152, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": ") => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 1462, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 1639, + "excerpt": "const exportCanvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 1640, + "excerpt": "const exportContext = exportCanvas.getContext(\"2d\");" + }, + { + "category": "readback", + "token": "toDataURL(", + "line": 1724, + "excerpt": "const dataUrl = exportCanvas.toDataURL(format, quality);" + } + ] + }, + { + "filePath": "src/components/charts/ModularGlassDataChart.tsx", + "isComponentFile": true, + "severity": "review-required", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 354, + "tokens": [ + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 679, + "tokens": [ + "HTMLCanvasElement", + "createElement(\"canvas\")", + "getContext(" + ] + }, + "readback": { + "count": 1, + "firstLine": 786, + "tokens": [ + "toDataURL(" + ] + } + }, + "guardTerms": [ + { + "term": "useReducedMotion", + "count": 2, + "firstLine": 21 + }, + { + "term": "isReducedMotion", + "count": 6, + "firstLine": 165 + }, + { + "term": "reducedMotion", + "count": 1, + "firstLine": 165 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 354, + "excerpt": "requestAnimationFrame(animateFrame);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 359, + "excerpt": "requestAnimationFrame(animateFrame);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 679, + "excerpt": "const handleChartHover = (event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 740, + "excerpt": "const tempCanvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 741, + "excerpt": "const ctx = tempCanvas.getContext(\"2d\");" + }, + { + "category": "readback", + "token": "toDataURL(", + "line": 786, + "excerpt": "const dataUrl = tempCanvas.toDataURL(" + } + ] + }, + { + "filePath": "src/components/charts/components/AtmosphericEffects.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 106, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "isReducedMotion", + "count": 8, + "firstLine": 13 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 106, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 109, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 113, + "excerpt": "cancelAnimationFrame(animationRef.current);" + } + ] + }, + { + "filePath": "src/components/charts/components/ChartRenderer.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 284, + "tokens": [ + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 2, + "firstLine": 60, + "tokens": [ + "HTMLCanvasElement" + ] + } + }, + "guardTerms": [ + { + "term": "isReducedMotion", + "count": 4, + "firstLine": 56 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 284, + "excerpt": "requestAnimationFrame(setAriaLabel);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 287, + "excerpt": "requestAnimationFrame(setAriaLabel);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 60, + "excerpt": "onChartHover?: (event: React.MouseEvent) => void;" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 100, + "excerpt": "const canvasRef = useRef(null);" + } + ] + }, + { + "filePath": "src/components/charts/hooks/useChartPhysicsInteraction.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 230, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 230, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 241, + "excerpt": "animationFrameRef.current = requestAnimationFrame(applyInertia);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 266, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + } + ] + }, + { + "filePath": "src/components/charts/hooks/usePhysicsAnimation.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 5, + "firstLine": 59, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 59, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 115, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 152, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 178, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 201, + "excerpt": "cancelAnimationFrame(animationRef.current);" + } + ] + }, + { + "filePath": "src/components/dashboard/DimensionalDashboardContainer.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 71, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 7, + "firstLine": 49 + }, + { + "term": "prefers-reduced-motion", + "count": 1, + "firstLine": 243 + }, + { + "term": "useReducedMotion", + "count": 3, + "firstLine": 12 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 71, + "excerpt": "animationFrameRef.current = requestAnimationFrame(rotate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 74, + "excerpt": "animationFrameRef.current = requestAnimationFrame(rotate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 78, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + } + ] + }, + { + "filePath": "src/components/data-display/GlassAccordion.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 439, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 2, + "firstLine": 99 + }, + { + "term": "shouldAnimate", + "count": 2, + "firstLine": 100 + }, + { + "term": "performanceMode", + "count": 1, + "firstLine": 311 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 439, + "excerpt": "requestAnimationFrame(() => {" + } + ] + }, + { + "filePath": "src/components/data-display/GlassAnimatedNumber.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 7, + "firstLine": 133, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "useReducedMotion", + "count": 2, + "firstLine": 16 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 133, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 153, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 157, + "excerpt": "animationRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 161, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 170, + "excerpt": "cancelAnimationFrame(animationRef.current);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 370, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 377, + "excerpt": "requestAnimationFrame(animate);" + } + ] + }, + { + "filePath": "src/components/effects/AuroraPro.r3f.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 700, + "tokens": [ + "useFrame(" + ] + }, + "canvas": { + "count": 1, + "firstLine": 322, + "tokens": [ + "HTMLCanvasElement" + ] + }, + "webgl": { + "count": 40, + "firstLine": 3, + "tokens": [ + "THREE", + "three" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 8, + "firstLine": 139 + }, + { + "term": "useReducedMotion", + "count": 5, + "firstLine": 2 + }, + { + "term": "isPlaying", + "count": 11, + "firstLine": 323 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "useFrame(", + "line": 700, + "excerpt": "useFrame((state) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 322, + "excerpt": "const canvasRef = useRef(null);" + }, + { + "category": "webgl", + "token": "three", + "line": 3, + "excerpt": "import { Canvas, useFrame, useThree } from \"@react-three/fiber\";" + }, + { + "category": "webgl", + "token": "three", + "line": 18, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 18, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 25, + "excerpt": "const geometry = new THREE.PlaneGeometry(width, height, segments, 32);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 42, + "excerpt": "const geometry = new THREE.PlaneGeometry(width, height, 32, 16);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 59, + "excerpt": "const geometry = new THREE.BufferGeometry();" + }, + { + "category": "webgl", + "token": "THREE", + "line": 65, + "excerpt": "new THREE.Color(0x4fc3f7)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 66, + "excerpt": "new THREE.Color(0x81c784)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 67, + "excerpt": "new THREE.Color(0xffb74d)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 68, + "excerpt": "new THREE.Color(0xba68c8)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 69, + "excerpt": "new THREE.Color(0xff8a65)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 70, + "excerpt": "new THREE.Color(0x4db6ac)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 90, + "excerpt": "geometry.setAttribute(\"position\", new THREE.BufferAttribute(positions, 3));" + }, + { + "category": "webgl", + "token": "THREE", + "line": 91, + "excerpt": "geometry.setAttribute(\"color\", new THREE.BufferAttribute(colors, 3));" + }, + { + "category": "webgl", + "token": "THREE", + "line": 92, + "excerpt": "geometry.setAttribute(\"size\", new THREE.BufferAttribute(sizes, 1));" + }, + { + "category": "webgl", + "token": "THREE", + "line": 100, + "excerpt": "color1 = new THREE.Color(0x4fc3f7)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 101, + "excerpt": "color2 = new THREE.Color(0x81c784)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 102, + "excerpt": "color3 = new THREE.Color(0xba68c8)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 107, + "excerpt": "return new THREE.ShaderMaterial({" + }, + { + "category": "webgl", + "token": "THREE", + "line": 167, + "excerpt": "side: THREE.DoubleSide," + } + ] + }, + { + "filePath": "src/components/effects/GlassPhysicsEngine.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 256, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 92, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 187, + "excerpt": "const ctx = canvas?.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": " {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 261, + "excerpt": "const canvasRef = useRef(null);" + }, + { + "category": "webgl", + "token": "three", + "line": 3, + "excerpt": "import { Canvas, useFrame, useThree } from \"@react-three/fiber\";" + }, + { + "category": "webgl", + "token": "three", + "line": 8, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 8, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 18, + "excerpt": "const geometry = new THREE.PlaneGeometry(" + }, + { + "category": "webgl", + "token": "THREE", + "line": 47, + "excerpt": "const geometries: THREE.PlaneGeometry[] = [];" + }, + { + "category": "webgl", + "token": "THREE", + "line": 65, + "excerpt": "color = new THREE.Color(0.7, 0.9, 1.0)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 71, + "excerpt": "return new THREE.ShaderMaterial({" + }, + { + "category": "webgl", + "token": "THREE", + "line": 127, + "excerpt": "side: THREE.DoubleSide," + }, + { + "category": "webgl", + "token": "THREE", + "line": 134, + "excerpt": "shard: THREE.Mesh," + }, + { + "category": "webgl", + "token": "THREE", + "line": 135, + "excerpt": "targetPosition: THREE.Vector3," + }, + { + "category": "webgl", + "token": "THREE", + "line": 136, + "excerpt": "targetRotation: THREE.Euler," + }, + { + "category": "webgl", + "token": "THREE", + "line": 151, + "excerpt": "shard.rotation.x = THREE.MathUtils.lerp(" + }, + { + "category": "webgl", + "token": "THREE", + "line": 156, + "excerpt": "shard.rotation.y = THREE.MathUtils.lerp(" + }, + { + "category": "webgl", + "token": "THREE", + "line": 161, + "excerpt": "shard.rotation.z = THREE.MathUtils.lerp(" + }, + { + "category": "webgl", + "token": "THREE", + "line": 172, + "excerpt": "shards: THREE.Mesh[]," + }, + { + "category": "webgl", + "token": "THREE", + "line": 173, + "excerpt": "center: THREE.Vector3," + }, + { + "category": "webgl", + "token": "THREE", + "line": 179, + "excerpt": "const direction = new THREE.Vector3(" + }, + { + "category": "webgl", + "token": "THREE", + "line": 189, + "excerpt": "const targetRotation = new THREE.Euler(" + }, + { + "category": "webgl", + "token": "THREE", + "line": 207, + "excerpt": "shards: THREE.Mesh[]," + }, + { + "category": "webgl", + "token": "THREE", + "line": 208, + "excerpt": "originalPositions: THREE.Vector3[]," + } + ] + }, + { + "filePath": "src/components/effects/SeasonalParticles.r3f.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 524, + "tokens": [ + "useFrame(" + ] + }, + "canvas": { + "count": 1, + "firstLine": 278, + "tokens": [ + "HTMLCanvasElement" + ] + }, + "webgl": { + "count": 31, + "firstLine": 3, + "tokens": [ + "THREE", + "three" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 6, + "firstLine": 277 + }, + { + "term": "useReducedMotion", + "count": 3, + "firstLine": 2 + }, + { + "term": "isPlaying", + "count": 7, + "firstLine": 283 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "useFrame(", + "line": 524, + "excerpt": "useFrame((state) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 278, + "excerpt": "const canvasRef = useRef(null);" + }, + { + "category": "webgl", + "token": "three", + "line": 3, + "excerpt": "import { Canvas, useFrame, useThree } from \"@react-three/fiber\";" + }, + { + "category": "webgl", + "token": "three", + "line": 17, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 17, + "excerpt": "import * as THREE from \"three\";" + }, + { + "category": "webgl", + "token": "THREE", + "line": 25, + "excerpt": "const geometry = new THREE.ConeGeometry(size * 0.1, size * 0.3, complexity);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 31, + "excerpt": "const geometry = new THREE.PlaneGeometry(size, size * 1.5);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 45, + "excerpt": "const geometry = new THREE.PlaneGeometry(size, size * 2);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 59, + "excerpt": "const geometry = new THREE.CylinderGeometry(width, width * 0.5, length, 8);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 65, + "excerpt": "const geometry = new THREE.CylinderGeometry(0.02, 0.02, length, 6);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 107, + "excerpt": "geometry = new THREE.SphereGeometry(0.1);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 108, + "excerpt": "material = new THREE.MeshBasicMaterial({ color: 0xffffff });" + }, + { + "category": "webgl", + "token": "THREE", + "line": 111, + "excerpt": "const particle = new THREE.Mesh(geometry, material);" + }, + { + "category": "webgl", + "token": "THREE", + "line": 140, + "excerpt": "new THREE.MeshPhongMaterial({" + }, + { + "category": "webgl", + "token": "THREE", + "line": 148, + "excerpt": "new THREE.MeshPhongMaterial({" + }, + { + "category": "webgl", + "token": "THREE", + "line": 149, + "excerpt": "color: new THREE.Color().setHSL(0.1, 0.8, 0.4)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 152, + "excerpt": "side: THREE.DoubleSide," + }, + { + "category": "webgl", + "token": "THREE", + "line": 156, + "excerpt": "new THREE.MeshPhongMaterial({" + }, + { + "category": "webgl", + "token": "THREE", + "line": 157, + "excerpt": "color: new THREE.Color().setHSL(random.nextInRange(0.8, 1.0), 0.8, 0.6)," + }, + { + "category": "webgl", + "token": "THREE", + "line": 160, + "excerpt": "side: THREE.DoubleSide," + }, + { + "category": "webgl", + "token": "THREE", + "line": 164, + "excerpt": "new THREE.MeshBasicMaterial({" + }, + { + "category": "webgl", + "token": "THREE", + "line": 165, + "excerpt": "color: new THREE.Color(1, 0.9, 0.3)," + } + ] + }, + { + "filePath": "src/components/image/GlassImageProcessingProvider.tsx", + "isComponentFile": true, + "severity": "inventory", + "categories": { + "canvas": { + "count": 3, + "firstLine": 622, + "tokens": [ + "HTMLCanvasElement", + "createElement(\"canvas\")", + "getContext(" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 622, + "excerpt": "const canvasRef = useRef();" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 632, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 633, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + } + ] + }, + { + "filePath": "src/components/immersive/Glass360Viewer.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 292, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 170, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 240, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 263, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 423, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 605, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 613, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 627, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 541, + "excerpt": "canvas: HTMLCanvasElement" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 617, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 429, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 683, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": " {" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 87, + "excerpt": "if (frame.current) cancelAnimationFrame(frame.current);" + } + ] + }, + { + "filePath": "src/components/interactive/GlassColorWheel.tsx", + "isComponentFile": true, + "severity": "inventory", + "categories": { + "canvas": { + "count": 12, + "firstLine": 198, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 199, + "excerpt": "const saturationRef = useRef(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 200, + "excerpt": "const alphaRef = useRef(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 258, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 306, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 346, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 396, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 425, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 448, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 139, + "excerpt": "const context = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 315, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 331, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 353, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 414, + "excerpt": "(event: React.PointerEvent): GesturePoint => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 432, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 461, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 506, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 607, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 275, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 318, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 351, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 361, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 554, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 126, + "excerpt": "const context = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 221, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 236, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 262, + "excerpt": "(event: React.PointerEvent) => {" + }, + { + "category": "canvas", + "token": " cancelAnimationFrame(raf);" + } + ] + }, + { + "filePath": "src/components/interactive/GlassVoiceInput.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 387, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 192, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 523, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "audioAnalyser", + "token": "AnalyserNode", + "line": 196, + "excerpt": "const analyserRef = useRef(null);" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 322, + "excerpt": "const audioContext = new (window.AudioContext ||" + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 323, + "excerpt": "window.webkitAudioContext)();" + }, + { + "category": "audioAnalyser", + "token": "createAnalyser(", + "line": 324, + "excerpt": "const analyser = audioContext.createAnalyser();" + }, + { + "category": "audioAnalyser", + "token": "getFloatFrequencyData(", + "line": 359, + "excerpt": "analyser.getFloatFrequencyData(dataArray);" + } + ] + }, + { + "filePath": "src/components/interactive/GlassWhiteboard.tsx", + "isComponentFile": true, + "severity": "review-required", + "categories": { + "canvas": { + "count": 6, + "firstLine": 151, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 152, + "excerpt": "const overlayCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 559, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 560, + "excerpt": "const overlayCtx = overlayCanvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 305, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 214, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 258, + "excerpt": "const handleMouseMove = (e: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 270, + "excerpt": "const handleClick = (e: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 418, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 441, + "excerpt": "const ctx = canvas?.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "();" + }, + { + "category": "audioAnalyser", + "token": "AnalyserNode", + "line": 693, + "excerpt": "const analyzerRef = useRef();" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 731, + "excerpt": "audioContextRef.current = new (window.AudioContext ||" + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 732, + "excerpt": "(window as any).webkitAudioContext)();" + }, + { + "category": "audioAnalyser", + "token": "createAnalyser(", + "line": 733, + "excerpt": "analyzerRef.current = audioContextRef.current.createAnalyser();" + } + ] + }, + { + "filePath": "src/components/navigation/GlassPagination.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 194, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "performanceMode", + "count": 2, + "firstLine": 220 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 194, + "excerpt": "requestAnimationFrame(updateInk);" + } + ] + }, + { + "filePath": "src/components/navigation/GlassTabBar.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 542, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "isReducedMotion", + "count": 4, + "firstLine": 111 + }, + { + "term": "reducedMotion", + "count": 1, + "firstLine": 111 + }, + { + "term": "disableAnimation", + "count": 3, + "firstLine": 87 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 542, + "excerpt": "cancelAnimationFrame(scrollAnimationRef.current.rafId);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 744, + "excerpt": "requestAnimationFrame(animateScroll);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 752, + "excerpt": "scrollAnimationRef.current.rafId = requestAnimationFrame(animateScroll);" + } + ] + }, + { + "filePath": "src/components/navigation/GlassTabs.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 73, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "performanceMode", + "count": 1, + "firstLine": 223 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 73, + "excerpt": "requestAnimationFrame(() => {" + } + ] + }, + { + "filePath": "src/components/quantum/GlassProbabilityCloud.tsx", + "isComponentFile": true, + "severity": "inventory", + "categories": { + "canvas": { + "count": 4, + "firstLine": 84, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 243, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 392, + "excerpt": "const handleCanvasClick = (e: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 553, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 774, + "excerpt": "(event: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 296, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 143, + "excerpt": "const phaseCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 144, + "excerpt": "const spectrumCanvasRef = useRef(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 223, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 347, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 409, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 440, + "excerpt": "const handleCanvasClick = (e: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": " {" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 285, + "excerpt": "return () => cancelAnimationFrame(animationFrame);" + } + ] + }, + { + "filePath": "src/components/social/GlassSharedWhiteboard.tsx", + "isComponentFile": true, + "severity": "inventory", + "categories": { + "canvas": { + "count": 5, + "firstLine": 139, + "tokens": [ + "(null);" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 243, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 308, + "excerpt": "(e: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 354, + "excerpt": "(e: React.MouseEvent) => {" + }, + { + "category": "canvas", + "token": " cancelAnimationFrame(animationFrame);" + } + ] + }, + { + "filePath": "src/components/tree-view/TreeItem.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 182, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 2, + "firstLine": 108 + }, + { + "term": "useReducedMotion", + "count": 3, + "firstLine": 14 + }, + { + "term": "disableAnimation", + "count": 3, + "firstLine": 37 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 182, + "excerpt": "rafId = requestAnimationFrame(() => {" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 197, + "excerpt": "cancelAnimationFrame(rafId);" + } + ] + }, + { + "filePath": "src/components/website-components/GlassWipeSlider.tsx", + "isComponentFile": true, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 5, + "firstLine": 292, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "useReducedMotion", + "count": 2, + "firstLine": 3 + }, + { + "term": "useMotionPreference", + "count": 1, + "firstLine": 7 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 292, + "excerpt": "animationFrame.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 298, + "excerpt": "animationFrame.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 313, + "excerpt": "cancelAnimationFrame(animationFrame.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 420, + "excerpt": "cancelAnimationFrame(animationFrame.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 547, + "excerpt": "cancelAnimationFrame(animationFrame.current);" + } + ] + }, + { + "filePath": "src/core/mixins/performanceMixins.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 381, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 16, + "firstLine": 11 + }, + { + "term": "prefers-reduced-motion", + "count": 1, + "firstLine": 273 + }, + { + "term": "paused", + "count": 1, + "firstLine": 127 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 381, + "excerpt": "requestAnimationFrame(() => {" + } + ] + }, + { + "filePath": "src/core/productionCore.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 4, + "firstLine": 260, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefers-reduced-motion", + "count": 2, + "firstLine": 216 + }, + { + "term": "reducedMotion", + "count": 3, + "firstLine": 53 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 260, + "excerpt": "if (!win || !perf || typeof win.requestAnimationFrame !== \"function\") {" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 285, + "excerpt": "win.requestAnimationFrame(calculateFPS);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 288, + "excerpt": "win.requestAnimationFrame(calculateFPS);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 577, + "excerpt": "if (!win?.requestAnimationFrame) {" + } + ] + }, + { + "filePath": "src/hooks/extended/use3DTransform.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 5, + "firstLine": 158, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 158, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 163, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 166, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 195, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 241, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + } + ] + }, + { + "filePath": "src/hooks/extended/useAmbientTilt.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 175, + "tokens": [ + "cancelAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 9, + "firstLine": 42 + }, + { + "term": "useReducedMotion", + "count": 3, + "firstLine": 5 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 175, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + } + ] + }, + { + "filePath": "src/hooks/extended/useGalileoSprings.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 185, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 185, + "excerpt": "requestAnimationFrame(updatePositions);" + } + ] + }, + { + "filePath": "src/hooks/extended/useGlassPerformance.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 124, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "animationEnabled", + "count": 1, + "firstLine": 216 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 124, + "excerpt": "requestAnimationFrame(measureFPS);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 159, + "excerpt": "const animationId = requestAnimationFrame(measureFPS);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 162, + "excerpt": "cancelAnimationFrame(animationId);" + } + ] + }, + { + "filePath": "src/hooks/extended/useMagneticElement.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 5, + "firstLine": 102, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 7, + "firstLine": 33 + }, + { + "term": "useReducedMotion", + "count": 3, + "firstLine": 6 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 102, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 127, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 139, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 164, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 182, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + } + ] + }, + { + "filePath": "src/hooks/useEnhancedPerformance.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 82, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "IntersectionObserver", + "count": 2, + "firstLine": 314 + }, + { + "term": "isIntersecting", + "count": 5, + "firstLine": 299 + }, + { + "term": "performanceMode", + "count": 11, + "firstLine": 26 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 82, + "excerpt": "requestAnimationFrame(countFrame);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 85, + "excerpt": "requestAnimationFrame(countFrame);" + } + ] + }, + { + "filePath": "src/hooks/useGlassParallax.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 42, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 42, + "excerpt": "raf = window.requestAnimationFrame(setVars);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 51, + "excerpt": "raf = window.requestAnimationFrame(setVars);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 61, + "excerpt": "if (raf) cancelAnimationFrame(raf);" + } + ] + }, + { + "filePath": "src/hooks/useLiquidGlassBackdrop.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 195, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 195, + "excerpt": "if (frame) window.cancelAnimationFrame(frame);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 196, + "excerpt": "frame = window.requestAnimationFrame(() => {" + } + ] + }, + { + "filePath": "src/hooks/usePerformance.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 84, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "prefers-reduced-motion", + "count": 1, + "firstLine": 317 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 84, + "excerpt": "frameId.current = requestAnimationFrame(measureFPS);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 187, + "excerpt": "cancelAnimationFrame(frameId.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 197, + "excerpt": "cancelAnimationFrame(frameId.current);" + } + ] + }, + { + "filePath": "src/hooks/usePhysicsInteraction.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 3, + "firstLine": 154, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "shouldAnimate", + "count": 12, + "firstLine": 76 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 154, + "excerpt": "animationFrameRef.current = requestAnimationFrame(animateSpring);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 176, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 291, + "excerpt": "cancelAnimationFrame(animationFrameRef.current);" + } + ] + }, + { + "filePath": "src/physics/AuraPhysicsEngine.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 187, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 187, + "excerpt": "cancelAnimationFrame(this.animationFrameId);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 210, + "excerpt": "this.animationFrameId = requestAnimationFrame(this.update);" + } + ] + }, + { + "filePath": "src/tests/consciousness/ConsciousnessPerformanceBenchmark.tsx", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 1, + "firstLine": 338, + "tokens": [ + "requestAnimationFrame" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 338, + "excerpt": "await new Promise(resolve => requestAnimationFrame(resolve));" + } + ] + }, + { + "filePath": "src/utils/browserCompatibility.ts", + "isComponentFile": false, + "severity": "review-required", + "categories": { + "canvas": { + "count": 6, + "firstLine": 48, + "tokens": [ + "createElement(\"canvas\")", + "getContext(" + ] + }, + "readback": { + "count": 1, + "firstLine": 56, + "tokens": [ + "preserveDrawingBuffer" + ] + }, + "audioAnalyser": { + "count": 2, + "firstLine": 235, + "tokens": [ + "AudioContext", + "webkitAudioContext" + ] + }, + "webgl": { + "count": 5, + "firstLine": 61, + "tokens": [ + "WebGL2RenderingContext", + "WebGLRenderingContext" + ] + } + }, + "guardTerms": [ + { + "term": "IntersectionObserver", + "count": 2, + "firstLine": 206 + } + ], + "signals": [ + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 48, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 64, + "excerpt": "gl2 = canvas.getContext(\"webgl2\", attrs) as WebGL2RenderingContext | null;" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 71, + "excerpt": "(canvas.getContext(\"webgl\", attrs) as WebGLRenderingContext | null) ||" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 72, + "excerpt": "(canvas.getContext(" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 174, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 236, + "excerpt": "canvas: !!canvas.getContext(\"2d\")," + }, + { + "category": "readback", + "token": "preserveDrawingBuffer", + "line": 56, + "excerpt": "preserveDrawingBuffer: false," + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 235, + "excerpt": "webAudio: \"AudioContext\" in window || \"webkitAudioContext\" in window," + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 235, + "excerpt": "webAudio: \"AudioContext\" in window || \"webkitAudioContext\" in window," + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 61, + "excerpt": "let gl: WebGLRenderingContext | null = null;" + }, + { + "category": "webgl", + "token": "WebGL2RenderingContext", + "line": 62, + "excerpt": "let gl2: WebGL2RenderingContext | null = null;" + }, + { + "category": "webgl", + "token": "WebGL2RenderingContext", + "line": 64, + "excerpt": "gl2 = canvas.getContext(\"webgl2\", attrs) as WebGL2RenderingContext | null;" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 71, + "excerpt": "(canvas.getContext(\"webgl\", attrs) as WebGLRenderingContext | null) ||" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 75, + "excerpt": ") as WebGLRenderingContext | null) ||" + } + ] + }, + { + "filePath": "src/utils/compatibility.ts", + "isComponentFile": false, + "severity": "review-required", + "categories": { + "canvas": { + "count": 1, + "firstLine": 240, + "tokens": [ + "createElement('canvas')" + ] + }, + "readback": { + "count": 1, + "firstLine": 243, + "tokens": [ + "toDataURL(" + ] + } + }, + "guardTerms": [ + { + "term": "prefers-reduced-motion", + "count": 1, + "firstLine": 278 + } + ], + "signals": [ + { + "category": "canvas", + "token": "createElement('canvas')", + "line": 240, + "excerpt": "const canvas = document.createElement('canvas');" + }, + { + "category": "readback", + "token": "toDataURL(", + "line": 243, + "excerpt": "const isSupported = canvas.toDataURL('image/webp').indexOf('image/webp') === 0;" + } + ] + }, + { + "filePath": "src/utils/consciousnessOptimization.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "audioAnalyser": { + "count": 6, + "firstLine": 38, + "tokens": [ + "AudioContext" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 38, + "excerpt": "private spatialAudioContexts: AudioContext[] = [];" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 88, + "excerpt": "getSpatialAudioContext(): AudioContext | null {" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 93, + "excerpt": "returnSpatialAudioContext(context: AudioContext) {" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 381, + "excerpt": "const contextRef = useRef(null);" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 390, + "excerpt": "if (!contextRef.current && typeof AudioContext !== \"undefined\") {" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 391, + "excerpt": "contextRef.current = new AudioContext();" + } + ] + }, + { + "filePath": "src/utils/contrastGuard.ts", + "isComponentFile": false, + "severity": "review-required", + "categories": { + "canvas": { + "count": 3, + "firstLine": 284, + "tokens": [ + "HTMLCanvasElement", + "createElement(\"canvas\")", + "getContext(" + ] + }, + "readback": { + "count": 1, + "firstLine": 300, + "tokens": [ + "getImageData(" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 284, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 285, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 319, + "excerpt": "): Promise {" + }, + { + "category": "readback", + "token": "getImageData(", + "line": 300, + "excerpt": "const imageData = ctx.getImageData(" + } + ] + }, + { + "filePath": "src/utils/deviceCapabilities.ts", + "isComponentFile": false, + "severity": "review-required", + "categories": { + "canvas": { + "count": 4, + "firstLine": 128, + "tokens": [ + "createElement('canvas')", + "getContext(" + ] + }, + "readback": { + "count": 1, + "firstLine": 138, + "tokens": [ + "preserveDrawingBuffer" + ] + }, + "audioAnalyser": { + "count": 2, + "firstLine": 329, + "tokens": [ + "AudioContext", + "webkitAudioContext" + ] + }, + "webgl": { + "count": 5, + "firstLine": 144, + "tokens": [ + "WebGL2RenderingContext", + "WebGLRenderingContext" + ] + } + }, + "guardTerms": [ + { + "term": "prefersReducedMotion", + "count": 1, + "firstLine": 543 + }, + { + "term": "prefers-reduced-motion", + "count": 1, + "firstLine": 543 + }, + { + "term": "reduceMotion", + "count": 1, + "firstLine": 542 + } + ], + "signals": [ + { + "category": "canvas", + "token": "createElement('canvas')", + "line": 128, + "excerpt": "const canvas = doc.createElement('canvas');" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 147, + "excerpt": "gl2 = (canvas.getContext('webgl2', attrs) as WebGL2RenderingContext | null) || null;" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 153, + "excerpt": "gl = (canvas.getContext('webgl', attrs) as WebGLRenderingContext | null) ||" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 154, + "excerpt": "(canvas.getContext('experimental-webgl', attrs) as WebGLRenderingContext | null) ||" + }, + { + "category": "readback", + "token": "preserveDrawingBuffer", + "line": 138, + "excerpt": "preserveDrawingBuffer: false," + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 329, + "excerpt": "speakers: !!win && ('AudioContext' in win || 'webkitAudioContext' in win)," + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 329, + "excerpt": "speakers: !!win && ('AudioContext' in win || 'webkitAudioContext' in win)," + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 144, + "excerpt": "let gl: WebGLRenderingContext | null = null;" + }, + { + "category": "webgl", + "token": "WebGL2RenderingContext", + "line": 145, + "excerpt": "let gl2: WebGL2RenderingContext | null = null;" + }, + { + "category": "webgl", + "token": "WebGL2RenderingContext", + "line": 147, + "excerpt": "gl2 = (canvas.getContext('webgl2', attrs) as WebGL2RenderingContext | null) || null;" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 153, + "excerpt": "gl = (canvas.getContext('webgl', attrs) as WebGLRenderingContext | null) ||" + }, + { + "category": "webgl", + "token": "WebGLRenderingContext", + "line": 154, + "excerpt": "(canvas.getContext('experimental-webgl', attrs) as WebGLRenderingContext | null) ||" + } + ] + }, + { + "filePath": "src/utils/performance.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 128, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + } + }, + "guardTerms": [ + { + "term": "IntersectionObserver", + "count": 1, + "firstLine": 411 + }, + { + "term": "isIntersecting", + "count": 1, + "firstLine": 414 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 128, + "excerpt": "this.rafId = requestAnimationFrame(measure);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 310, + "excerpt": "if (this.rafId) cancelAnimationFrame(this.rafId);" + } + ] + }, + { + "filePath": "src/utils/performanceOptimizations.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 6, + "firstLine": 107, + "tokens": [ + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 2, + "firstLine": 342, + "tokens": [ + "HTMLCanvasElement", + "getContext(" + ] + } + }, + "guardTerms": [ + { + "term": "IntersectionObserver", + "count": 1, + "firstLine": 355 + }, + { + "term": "isIntersecting", + "count": 1, + "firstLine": 357 + } + ], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 107, + "excerpt": "requestAnimationFrame(measureFPS);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 122, + "excerpt": "requestAnimationFrame(measureFPS);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 125, + "excerpt": "requestAnimationFrame(measureFPS);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 324, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 326, + "excerpt": "requestAnimationFrame(animate);" + }, + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 331, + "excerpt": "requestAnimationFrame(() => {" + }, + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 342, + "excerpt": "optimizeCanvasRendering: (canvas: HTMLCanvasElement): void => {" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 343, + "excerpt": "const ctx = canvas.getContext(\"2d\");" + } + ] + }, + { + "filePath": "src/utils/smartColorExtraction.ts", + "isComponentFile": false, + "severity": "review-required", + "categories": { + "canvas": { + "count": 3, + "firstLine": 49, + "tokens": [ + "HTMLCanvasElement", + "createElement('canvas')", + "getContext(" + ] + }, + "readback": { + "count": 2, + "firstLine": 104, + "tokens": [ + "getImageData(" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "canvas", + "token": "HTMLCanvasElement", + "line": 49, + "excerpt": "private canvas: HTMLCanvasElement;" + }, + { + "category": "canvas", + "token": "createElement('canvas')", + "line": 69, + "excerpt": "this.canvas = document.createElement('canvas');" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 70, + "excerpt": "this.ctx = this.canvas.getContext('2d', { willReadFrequently: true })!;" + }, + { + "category": "readback", + "token": "getImageData(", + "line": 104, + "excerpt": "const imageData = this.ctx.getImageData(0, 0, width, height);" + }, + { + "category": "readback", + "token": "getImageData(", + "line": 137, + "excerpt": "const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);" + } + ] + }, + { + "filePath": "src/utils/soundDesign.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "audioAnalyser": { + "count": 5, + "firstLine": 28, + "tokens": [ + "AudioContext", + "webkitAudioContext" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 28, + "excerpt": "private audioContext: AudioContext | null = null;" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 131, + "excerpt": "this.audioContext = new (currentWin.AudioContext ||" + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 132, + "excerpt": "(currentWin as any).webkitAudioContext)();" + }, + { + "category": "audioAnalyser", + "token": "AudioContext", + "line": 192, + "excerpt": "this.audioContext = new (win.AudioContext ||" + }, + { + "category": "audioAnalyser", + "token": "webkitAudioContext", + "line": 193, + "excerpt": "(win as any).webkitAudioContext)();" + } + ] + }, + { + "filePath": "src/utils/ssr.ts", + "isComponentFile": false, + "severity": "guarded-or-explicit", + "categories": { + "frameLoop": { + "count": 2, + "firstLine": 115, + "tokens": [ + "cancelAnimationFrame", + "requestAnimationFrame" + ] + }, + "canvas": { + "count": 3, + "firstLine": 72, + "tokens": [ + "createElement(\"canvas\")", + "getContext(" + ] + }, + "webgl": { + "count": 2, + "firstLine": 74, + "tokens": [ + "getContext(\"experimental-webgl\")", + "getContext(\"webgl\")" + ] + } + }, + "guardTerms": [], + "signals": [ + { + "category": "frameLoop", + "token": "requestAnimationFrame", + "line": 115, + "excerpt": "return requestAnimationFrame(callback);" + }, + { + "category": "frameLoop", + "token": "cancelAnimationFrame", + "line": 124, + "excerpt": "cancelAnimationFrame(handle);" + }, + { + "category": "canvas", + "token": "createElement(\"canvas\")", + "line": 72, + "excerpt": "const canvas = document.createElement(\"canvas\");" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 74, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\")" + }, + { + "category": "canvas", + "token": "getContext(", + "line": 74, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\")" + }, + { + "category": "webgl", + "token": "getContext(\"experimental-webgl\")", + "line": 74, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\")" + }, + { + "category": "webgl", + "token": "getContext(\"webgl\")", + "line": 74, + "excerpt": "canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\")" + } + ] + } + ] +} diff --git a/reports/3.1-release/frame-loop-canvas-audit.md b/reports/3.1-release/frame-loop-canvas-audit.md new file mode 100644 index 000000000..eddca3f36 --- /dev/null +++ b/reports/3.1-release/frame-loop-canvas-audit.md @@ -0,0 +1,158 @@ +# 3.1 Frame Loop, Canvas, Audio, and WebGL Audit + +Generated: 2026-05-12T19:20:13.118Z + +## Summary + +- Scanned root: src +- Scanned files: 671 +- Files with frame/canvas/audio/WebGL signals: 106 +- Component files with signals: 73 +- Review-required files: 18 +- Findings: 18 +- Strict mode: no + +## Category Totals + +- frameLoop: 246 +- canvas: 229 +- readback: 24 +- audioAnalyser: 49 +- webgl: 219 + +## Findings + +- review-required: canvas-or-gpu-readback-review at src/components/advanced/GlassProgressiveEnhancement.tsx:282 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/ai/GlassDeepDreamGlass.tsx:342 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/ai/GlassGANGenerator.tsx:384 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/ai/GlassGenerativeArt.tsx:379 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/ai/GlassLiveFilter.tsx:693 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/ai/GlassStyleTransfer.tsx:262 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/ar/ARGlassEffects.r3f.tsx:516 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/charts/GlassDataChart.tsx:1724 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/charts/ModularGlassDataChart.tsx:786 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/interactive/GlassDrawingCanvas.tsx:445 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/interactive/GlassPatternBuilder.tsx:491 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/interactive/GlassSignaturePad.tsx:287 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/components/interactive/GlassWhiteboard.tsx:645 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/utils/browserCompatibility.ts:56 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/utils/compatibility.ts:243 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/utils/contrastGuard.ts:300 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/utils/deviceCapabilities.ts:138 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. +- review-required: canvas-or-gpu-readback-review at src/utils/smartColorExtraction.ts:104 (readback) - Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled. + +## Inventory + +- guarded-or-explicit: src/animations/hooks/useAnimationSequenceBasic.ts - frameLoop:6; guards: isPlaying:12, paused:6 +- guarded-or-explicit: src/animations/hooks/useMultiSpringBasic.ts - frameLoop:4; guards: none +- guarded-or-explicit: src/animations/orchestration/useAnimationSequenceOrchestrator.ts - frameLoop:7; guards: isPlaying:14, paused:6 +- guarded-or-explicit: src/animations/physics/chartAnimations.ts - frameLoop:9; guards: none +- guarded-or-explicit: src/animations/physics/galileoPhysicsSystem.ts - frameLoop:2; guards: paused:4 +- guarded-or-explicit: src/animations/physics/useMultiSpringPhysics.ts - frameLoop:4; guards: none +- inventory: src/components/advanced/GlassMeshGradient.tsx - canvas:3; guards: prefersReducedMotion:2, useReducedMotion:3, shouldAnimate:4 +- guarded-or-explicit: src/components/advanced/GlassParallaxLayers.tsx - frameLoop:2; guards: prefersReducedMotion:16, useReducedMotion:3 +- inventory: src/components/advanced/GlassParticles.tsx - canvas:4; guards: prefersReducedMotion:2, useReducedMotion:3, shouldAnimate:2 +- guarded-or-explicit: src/components/advanced/GlassPerformanceOptimization.tsx - frameLoop:3; guards: prefers-reduced-motion:1, useReducedMotion:2, reducedMotion:5, performanceMode:18 +- review-required: src/components/advanced/GlassProgressiveEnhancement.tsx - frameLoop:4, canvas:4, readback:1, webgl:2; guards: prefersReducedMotion:5, prefers-reduced-motion:1, useReducedMotion:4, reducedMotion:3, enableAnimation:3 +- guarded-or-explicit: src/components/advanced/GlassQuantumStates.tsx - frameLoop:2, canvas:3; guards: prefersReducedMotion:16, useReducedMotion:8 +- guarded-or-explicit: src/components/advanced/GlassReactions.tsx - frameLoop:3; guards: prefersReducedMotion:17, useReducedMotion:6 +- inventory: src/components/advanced/GlassSelfHealingSystem.tsx - canvas:3; guards: prefersReducedMotion:7, useReducedMotion:5 +- guarded-or-explicit: src/components/advanced/GlassSpatialAudio.tsx - frameLoop:1, canvas:2, audioAnalyser:9; guards: prefersReducedMotion:7, useReducedMotion:5, isPlaying:9 +- guarded-or-explicit: src/components/advanced/GlassTrophyCase.tsx - audioAnalyser:2; guards: prefersReducedMotion:7, useReducedMotion:3 +- guarded-or-explicit: src/components/advanced/GlassWebGLShader.tsx - frameLoop:3, canvas:4, webgl:17; guards: prefersReducedMotion:4, useReducedMotion:3, shouldAnimate:7 +- guarded-or-explicit: src/components/advanced/IntelligentColorSystem.tsx - frameLoop:1, canvas:2; guards: prefersReducedMotion:13, useReducedMotion:4 +- guarded-or-explicit: src/components/advanced/LiquidGlassGPU.tsx - frameLoop:3, canvas:12, webgl:11; guards: useReducedMotion:2 +- review-required: src/components/ai/GlassDeepDreamGlass.tsx - frameLoop:3, canvas:8, readback:2; guards: prefersReducedMotion:2, useReducedMotion:3, useMotionPreference:3, shouldAnimate:9, enableAnimation:7 +- review-required: src/components/ai/GlassGANGenerator.tsx - canvas:7, readback:1; guards: prefersReducedMotion:4, useReducedMotion:3, useMotionPreference:3, shouldAnimate:10 +- review-required: src/components/ai/GlassGenerativeArt.tsx - canvas:3, readback:2; guards: prefersReducedMotion:4, useReducedMotion:3, useMotionPreference:3, shouldAnimate:5 +- review-required: src/components/ai/GlassLiveFilter.tsx - frameLoop:2, canvas:6, readback:3; guards: prefersReducedMotion:1, useReducedMotion:3, useMotionPreference:3, shouldAnimate:9, paused:3 +- guarded-or-explicit: src/components/ai/GlassMusicVisualizer.tsx - frameLoop:4, canvas:4, audioAnalyser:7; guards: prefersReducedMotion:5, useReducedMotion:3, useMotionPreference:3, shouldAnimate:9, isPlaying:6 +- review-required: src/components/ai/GlassStyleTransfer.tsx - canvas:3, readback:1; guards: prefersReducedMotion:2, useReducedMotion:3, useMotionPreference:3, shouldAnimate:9 +- guarded-or-explicit: src/components/animations/GlassMotionController.tsx - frameLoop:4; guards: prefersReducedMotion:5, useReducedMotion:2, reduceMotion:16 +- guarded-or-explicit: src/components/ar/ARGlassEffects.helpers.ts - webgl:30; guards: none +- review-required: src/components/ar/ARGlassEffects.r3f.tsx - frameLoop:5, canvas:1, readback:1, webgl:46; guards: prefersReducedMotion:6, useReducedMotion:4 +- guarded-or-explicit: src/components/atmospheric/GlassAuroraDisplay.tsx - frameLoop:3, canvas:3; guards: prefersReducedMotion:3, useReducedMotion:2 +- guarded-or-explicit: src/components/atmospheric/GlassBiomeSimulator.tsx - frameLoop:3, canvas:3; guards: prefersReducedMotion:3, useReducedMotion:2 +- guarded-or-explicit: src/components/atmospheric/GlassNebulaClouds.tsx - frameLoop:3, canvas:3; guards: prefersReducedMotion:3 +- guarded-or-explicit: src/components/atmospheric/GlassWeatherGlass.tsx - frameLoop:3, canvas:3; guards: prefersReducedMotion:3, useReducedMotion:2 +- guarded-or-explicit: src/components/backgrounds/ParticleBackground.tsx - frameLoop:2, canvas:3; guards: prefersReducedMotion:3, useReducedMotion:3 +- guarded-or-explicit: src/components/button/GlassMagneticButton.tsx - frameLoop:8; guards: prefersReducedMotion:8, prefers-reduced-motion:1 +- review-required: src/components/charts/GlassDataChart.tsx - canvas:4, readback:1; guards: prefers-reduced-motion:1, isReducedMotion:7, reducedMotion:1 +- review-required: src/components/charts/ModularGlassDataChart.tsx - frameLoop:2, canvas:3, readback:1; guards: useReducedMotion:2, isReducedMotion:6, reducedMotion:1 +- guarded-or-explicit: src/components/charts/components/AtmosphericEffects.tsx - frameLoop:3; guards: isReducedMotion:8 +- guarded-or-explicit: src/components/charts/components/ChartRenderer.tsx - frameLoop:2, canvas:2; guards: isReducedMotion:4 +- guarded-or-explicit: src/components/charts/hooks/useChartPhysicsInteraction.ts - frameLoop:3; guards: none +- guarded-or-explicit: src/components/charts/hooks/usePhysicsAnimation.ts - frameLoop:5; guards: none +- guarded-or-explicit: src/components/dashboard/DimensionalDashboardContainer.tsx - frameLoop:3; guards: prefersReducedMotion:7, prefers-reduced-motion:1, useReducedMotion:3 +- guarded-or-explicit: src/components/data-display/GlassAccordion.tsx - frameLoop:1; guards: prefersReducedMotion:2, shouldAnimate:2, performanceMode:1 +- guarded-or-explicit: src/components/data-display/GlassAnimatedNumber.tsx - frameLoop:7; guards: useReducedMotion:2 +- guarded-or-explicit: src/components/effects/AuroraPro.r3f.tsx - frameLoop:1, canvas:1, webgl:40; guards: prefersReducedMotion:8, useReducedMotion:5, isPlaying:11 +- guarded-or-explicit: src/components/effects/GlassPhysicsEngine.tsx - frameLoop:2, canvas:3; guards: prefersReducedMotion:2, useReducedMotion:3, shouldAnimate:5 +- guarded-or-explicit: src/components/effects/GlassShatterEffects.r3f.tsx - frameLoop:1, canvas:1, webgl:30; guards: prefersReducedMotion:6, useReducedMotion:4 +- guarded-or-explicit: src/components/effects/SeasonalParticles.r3f.tsx - frameLoop:1, canvas:1, webgl:31; guards: prefersReducedMotion:6, useReducedMotion:3, isPlaying:7 +- inventory: src/components/image/GlassImageProcessingProvider.tsx - canvas:3; guards: none +- guarded-or-explicit: src/components/immersive/Glass360Viewer.tsx - frameLoop:3, canvas:3; guards: useMotionPreference:3, shouldAnimate:2, paused:3, performanceMode:2 +- guarded-or-explicit: src/components/immersive/GlassARPreview.tsx - frameLoop:2, canvas:3; guards: useReducedMotion:2, useMotionPreference:3, shouldAnimate:3 +- guarded-or-explicit: src/components/immersive/GlassFluidSimulation.tsx - frameLoop:4, canvas:6; guards: prefersReducedMotion:5, paused:3 +- guarded-or-explicit: src/components/immersive/GlassHologram.tsx - frameLoop:2; guards: prefersReducedMotion:13 +- guarded-or-explicit: src/components/immersive/GlassParticleField.tsx - frameLoop:4, canvas:4; guards: prefersReducedMotion:2, shouldAnimate:4, isPlaying:6, paused:7 +- guarded-or-explicit: src/components/immersive/GlassVortexPortal.tsx - frameLoop:3, canvas:4; guards: prefersReducedMotion:3, useReducedMotion:2 +- guarded-or-explicit: src/components/interactive/CursorGlow.tsx - frameLoop:2; guards: useReducedMotion:3 +- inventory: src/components/interactive/GlassColorWheel.tsx - canvas:12; guards: prefersReducedMotion:1 +- review-required: src/components/interactive/GlassDrawingCanvas.tsx - canvas:6, readback:1; guards: prefersReducedMotion:1, useReducedMotion:2 +- guarded-or-explicit: src/components/interactive/GlassGestureZone.tsx - frameLoop:2, canvas:7; guards: prefersReducedMotion:3 +- review-required: src/components/interactive/GlassPatternBuilder.tsx - frameLoop:1, canvas:7, readback:1; guards: prefersReducedMotion:3 +- review-required: src/components/interactive/GlassSignaturePad.tsx - canvas:6, readback:2; guards: useReducedMotion:2, useMotionPreference:3, shouldAnimate:2 +- guarded-or-explicit: src/components/interactive/GlassSpotlight.tsx - frameLoop:3; guards: prefersReducedMotion:2, prefers-reduced-motion:1, useReducedMotion:3, shouldAnimate:5 +- guarded-or-explicit: src/components/interactive/GlassVoiceInput.tsx - frameLoop:3, canvas:3, audioAnalyser:8; guards: prefersReducedMotion:5, useReducedMotion:2 +- review-required: src/components/interactive/GlassWhiteboard.tsx - canvas:6, readback:1; guards: useReducedMotion:2 +- guarded-or-explicit: src/components/layout/OptimizedGlassContainer.tsx - frameLoop:3; guards: prefersReducedMotion:2, useReducedMotion:3, performanceMode:7 +- guarded-or-explicit: src/components/layouts/GlassFractalLayout.tsx - frameLoop:3; guards: prefersReducedMotion:4, useMotionPreference:3 +- guarded-or-explicit: src/components/layouts/GlassIslandLayout.tsx - frameLoop:3, canvas:3; guards: prefersReducedMotion:3, useReducedMotion:3, useMotionPreference:3, shouldAnimate:10 +- guarded-or-explicit: src/components/layouts/GlassOrbitalMenu.tsx - frameLoop:3; guards: prefersReducedMotion:9, useMotionPreference:3 +- guarded-or-explicit: src/components/layouts/GlassTessellation.tsx - frameLoop:3; guards: prefersReducedMotion:4, useReducedMotion:2, useMotionPreference:3 +- guarded-or-explicit: src/components/media/GlassAdvancedAudioPlayer.tsx - frameLoop:3, canvas:9, audioAnalyser:8; guards: isPlaying:17 +- guarded-or-explicit: src/components/navigation/GlassPagination.tsx - frameLoop:1; guards: performanceMode:2 +- guarded-or-explicit: src/components/navigation/GlassTabBar.tsx - frameLoop:3; guards: isReducedMotion:4, reducedMotion:1, disableAnimation:3 +- guarded-or-explicit: src/components/navigation/GlassTabs.tsx - frameLoop:1; guards: performanceMode:1 +- inventory: src/components/quantum/GlassProbabilityCloud.tsx - canvas:4; guards: prefersReducedMotion:4, useReducedMotion:3, useMotionPreference:3, shouldAnimate:2 +- guarded-or-explicit: src/components/quantum/GlassQuantumField.tsx - frameLoop:3, canvas:4; guards: prefersReducedMotion:3, useReducedMotion:2 +- inventory: src/components/quantum/GlassQuantumTunnel.tsx - canvas:3; guards: prefersReducedMotion:5, useReducedMotion:3, useMotionPreference:3, shouldAnimate:2 +- guarded-or-explicit: src/components/quantum/GlassWaveFunction.tsx - frameLoop:3, canvas:10; guards: useMotionPreference:3, shouldAnimate:3 +- guarded-or-explicit: src/components/social/GlassReactionBubbles.tsx - frameLoop:2; guards: prefersReducedMotion:8, useReducedMotion:3, useMotionPreference:3, shouldAnimate:8 +- inventory: src/components/social/GlassSharedWhiteboard.tsx - canvas:5; guards: prefersReducedMotion:2, useReducedMotion:3, useMotionPreference:3, shouldAnimate:2 +- guarded-or-explicit: src/components/social/GlassVoiceWaveform.tsx - frameLoop:3; guards: prefersReducedMotion:2, useReducedMotion:3, useMotionPreference:3, shouldAnimate:4 +- guarded-or-explicit: src/components/spatial/SpatialComputingEngine.tsx - frameLoop:5; guards: prefersReducedMotion:1, useReducedMotion:3 +- guarded-or-explicit: src/components/tree-view/TreeItem.tsx - frameLoop:2; guards: prefersReducedMotion:2, useReducedMotion:3, disableAnimation:3 +- guarded-or-explicit: src/components/website-components/GlassWipeSlider.tsx - frameLoop:5; guards: useReducedMotion:2, useMotionPreference:1 +- guarded-or-explicit: src/core/mixins/performanceMixins.ts - frameLoop:1; guards: prefersReducedMotion:16, prefers-reduced-motion:1, paused:1 +- guarded-or-explicit: src/core/productionCore.ts - frameLoop:4; guards: prefers-reduced-motion:2, reducedMotion:3 +- guarded-or-explicit: src/hooks/extended/use3DTransform.ts - frameLoop:5; guards: none +- guarded-or-explicit: src/hooks/extended/useAmbientTilt.ts - frameLoop:1; guards: prefersReducedMotion:9, useReducedMotion:3 +- guarded-or-explicit: src/hooks/extended/useGalileoSprings.ts - frameLoop:1; guards: none +- guarded-or-explicit: src/hooks/extended/useGlassPerformance.ts - frameLoop:3; guards: animationEnabled:1 +- guarded-or-explicit: src/hooks/extended/useMagneticElement.ts - frameLoop:5; guards: prefersReducedMotion:7, useReducedMotion:3 +- guarded-or-explicit: src/hooks/useEnhancedPerformance.ts - frameLoop:2; guards: IntersectionObserver:2, isIntersecting:5, performanceMode:11 +- guarded-or-explicit: src/hooks/useGlassParallax.ts - frameLoop:3; guards: none +- guarded-or-explicit: src/hooks/useLiquidGlassBackdrop.ts - frameLoop:2; guards: none +- guarded-or-explicit: src/hooks/usePerformance.ts - frameLoop:3; guards: prefers-reduced-motion:1 +- guarded-or-explicit: src/hooks/usePhysicsInteraction.ts - frameLoop:3; guards: shouldAnimate:12 +- guarded-or-explicit: src/physics/AuraPhysicsEngine.ts - frameLoop:2; guards: none +- guarded-or-explicit: src/tests/consciousness/ConsciousnessPerformanceBenchmark.tsx - frameLoop:1; guards: none +- review-required: src/utils/browserCompatibility.ts - canvas:6, readback:1, audioAnalyser:2, webgl:5; guards: IntersectionObserver:2 +- review-required: src/utils/compatibility.ts - canvas:1, readback:1; guards: prefers-reduced-motion:1 +- guarded-or-explicit: src/utils/consciousnessOptimization.ts - audioAnalyser:6; guards: none +- review-required: src/utils/contrastGuard.ts - canvas:3, readback:1; guards: none +- review-required: src/utils/deviceCapabilities.ts - canvas:4, readback:1, audioAnalyser:2, webgl:5; guards: prefersReducedMotion:1, prefers-reduced-motion:1, reduceMotion:1 +- guarded-or-explicit: src/utils/performance.ts - frameLoop:2; guards: IntersectionObserver:1, isIntersecting:1 +- guarded-or-explicit: src/utils/performanceOptimizations.ts - frameLoop:6, canvas:2; guards: IntersectionObserver:1, isIntersecting:1 +- review-required: src/utils/smartColorExtraction.ts - canvas:3, readback:2; guards: none +- guarded-or-explicit: src/utils/soundDesign.ts - audioAnalyser:5; guards: none +- guarded-or-explicit: src/utils/ssr.ts - frameLoop:2, canvas:3, webgl:2; guards: none + +## Gate Notes + +- This is a source audit gate for 3.1 release-candidate evidence. +- Default mode is report-only so release owners can inventory risk without blocking unrelated work. +- Run `npm run audit:3.1-frame-loop:strict` to fail on review-required findings. +- A file is flagged when a production component has frame-loop, readback, audio analyser, or WebGL signals and lacks obvious reduced-motion or explicit animation guard terms. diff --git a/reports/3.1-release/package-gates.md b/reports/3.1-release/package-gates.md new file mode 100644 index 000000000..eee6e06a0 --- /dev/null +++ b/reports/3.1-release/package-gates.md @@ -0,0 +1,55 @@ +# 3.1 Package Gates + +Use this ledger to record package-repo verification for the AuraGlass 3.1 release candidate. Leave a gate as `Pending` until it has been run for the 3.1 candidate. + +| Gate | Command | Status | Evidence | +| --- | --- | --- | --- | +| Component inventory audit | `npm run audit:components` | Passed | Ran 2026-05-12. Inventory: 356 components; direct Storybook/docs/unit-test/ContrastGuard/ARIA/focus/reduced-motion coverage all reported 356/356. Evidence: `reports/component_inventory.json`, `reports/glassmorphism-storybook-visual-certification.json`, `docs/components/readme.md`, `docs/components/choosing.md`. | +| Export map audit | `npm run audit:exports` | Passed with catalog follow-ups | Ran 2026-05-12. Root exports: 819; value exports: 658; type exports: 155; missing source/declaration/unresolved export-star counts all 0. Follow-up counts remain for direct component-owned inventory/story/test/docs coverage in the public export audit. Evidence: `reports/public-export-audit.{json,md}`. | +| API surface audit | `npm run audit:api` | Passed with API follow-ups | Ran 2026-05-12. Public exports: 819; public source/declaration files: 417/417; declaration files missing React type references: 0. Follow-up counts remain for existing `any` usage and ref-forwarding review. Evidence: `reports/api-surface-audit.{json,md}`. | +| Runtime cleanliness audit | `npm run audit:runtime` | Passed | Ran 2026-05-12. Scanned 671 source files; 0 console/TODO/debugger findings. Evidence: `reports/runtime-cleanliness-audit.{json,md}`. | +| Frame-loop/canvas/WebGL audit | `npm run audit:3.1-frame-loop` | Passed with readback review findings | Ran 2026-05-12 after adding `isReducedMotion` to the guard vocabulary. Wrote `reports/3.1-release/frame-loop-canvas-audit.{json,md}`. Scanned 671 source files; inventoried 106 files with signals, including 73 component files; 18 review findings, all canvas/GPU readback reviews. No missing animation/motion guard findings remain. | +| TypeScript | `npm run typecheck` | Passed | Ran 2026-05-12; `tsc --noEmit` exited 0. Also passed inside `npm run glass:full-check`. | +| ESLint | `npm run lint:check` | Passed with warnings | Ran 2026-05-12; exited 0 with 159 warnings from the existing custom glass discipline rules, mostly inline-style/raw-class warnings. No ESLint errors. | +| Token lint | `npm run lint:tokens` | Passed | Ran 2026-05-12. Scanned 27 files; 0 token violations. | +| Style lint | `npm run lint:styles` | Passed | Ran 2026-05-12. Audited 1100 files; 0 style issues. | +| Glass pipeline validation | `npm run glass:full-check` | Passed | Ran 2026-05-12. Covered typecheck, lint, token/style lint, persona CSS validation, glass pipeline validation, glass contrast, token exports, package exports, and type tests. Pipeline validation report: 31 passed, 0 failed, 0 warnings in `reports/glass/pipeline-validation-report.json`. | +| Unit tests | `npm test -- --runInBand` | Passed with warnings | Ran 2026-05-12. 415 suites passed; 2235 tests passed; 339 snapshots passed. Output includes existing React act warnings and preload timeout warnings from interactive/axe-heavy suites. | +| Coverage | `npm run test:coverage` | Passed with low global coverage | Ran 2026-05-12. 415 suites passed; 2235 tests passed; 339 snapshots passed. Global coverage: 35.47% statements, 33.77% branches, 23.50% functions, 36.67% lines. | +| Build | `npm run build` | Passed | Ran 2026-05-12 after adding the 3.1 recipe registry and CLI. Rebuilt workers, root CJS/ESM/CSS, registry, SSR/server, `./three`, `./styles`, ESM files, and declarations. | +| CLI registry smoke | `node scripts/ci/verify-cli.js` | Passed | Ran 2026-05-12. Verified `aura-glass list --json`, `aura-glass info ai-command-center --json`, `aura-glass add media-player-surface --dry-run --json`, and an actual temp-project scaffold for `settings-billing`. | +| Targeted flagship API tests | `npx jest src/components/interactive/GlassFileUpload.test.tsx src/components/data-display/GlassKanbanBoard.test.tsx --runInBand` | Passed | Ran 2026-05-12. 2 suites passed; 19 tests passed; 2 snapshots passed. Covers `GlassFileUpload` contained/compact seeded review mode and `GlassKanbanBoard` contained compact mode without header/actions. | +| Pack verification | `npm run verify:pack` | Passed | Ran 2026-05-12 after adding the CLI bin. Confirmed root `GlassButton`/`GlassCard` imports, `aura-glass/registry` recipe metadata, packed `bin/aura-glass.cjs`, executable `npx aura-glass list --json`, and `aura-glass/styles` from a temp install. Pack has no nested `node_modules`, React runtimes, styled-components runtime, test artifacts, or dispatcher artifacts. External `require('react')` occurrences: 786. | +| React 18/19 Next smoke | `npm run test:integration:next -- --skip-build` | Passed | Ran 2026-05-12. React 18/Next smoke passed 1 Chromium test. React 19 + Next 15 smoke passed 1 Chromium test. Logs: `reports/next-integration.log`, `reports/next-integration-react19.log`. | +| Storybook build | `npm run build-storybook` | Passed | Ran 2026-05-12. Storybook v9.1.20 built successfully to `storybook-static` after transforming 4289 modules. | +| Publish dry run | `npm publish --dry-run --provenance --access public` | Passed | Ran 2026-05-12 after adding the 3.1 CLI and recipe registry, then reran after final README/CHANGELOG updates. `prepublishOnly` passed build, pack verification, and React 18/19 Next smoke. npm dry-run tarball: `aura-glass-3.1.0.tgz`, package size 8.1 MB, unpacked size 43.0 MB, 2045 files, shasum `5406a76a13fe86ee87d356cfce5753e2173aaee3`. No publish was performed by the dry run. | +| Whitespace diff check | `git diff --check` | Passed | Ran 2026-05-12; exited 0. | + +## Package Metadata + +| Field | 3.1 value | +| --- | --- | +| Package | `aura-glass` | +| Version | `3.1.0` | +| Description | React Liquid Glass component library for Next.js, premium dashboards, AI products, media interfaces, and accessible glassmorphism UI. | +| Homepage | `https://auraglass.auraone.ai` | +| Repository | `https://github.com/auraoneai/auraglass` | +| License | MIT | + +## Release Notes Inputs + +Record final command output summaries here before publishing release notes: + +- Package size: 8.1 MB from `npm publish --dry-run --provenance --access public`. +- Unpacked size: 43.0 MB from dry-run tarball. +- Tarball file count: 2045. +- Shasum: `5406a76a13fe86ee87d356cfce5753e2173aaee3`. +- React 18 Next smoke: passed 1 Chromium smoke test. +- React 19 Next smoke: passed 1 Chromium smoke test. +- Known warnings: ESLint exits 0 with 159 existing warnings; Jest/coverage output includes existing React `act(...)` warnings and occasional jest-axe preload timeout warnings; build reports large root bundles around 5.3-5.5 MB. +- Known follow-ups: 18 frame-loop audit readback review findings; public export audit component-owned coverage follow-up counts; API audit `any` and ref-forwarding follow-up counts; global coverage remains low at 35.47% statements. + +## Notes + +- This file is an evidence ledger, not evidence by itself. +- Do not run external GitHub or npm publishing commands as part of this scaffold update. diff --git a/reports/3.1-release/recipes-and-agent-readiness.md b/reports/3.1-release/recipes-and-agent-readiness.md new file mode 100644 index 000000000..003f54566 --- /dev/null +++ b/reports/3.1-release/recipes-and-agent-readiness.md @@ -0,0 +1,90 @@ +# 3.1 Recipes And AI Agent Readiness + +AuraGlass 3.1 should make adoption simple for developers and coding agents. This ledger tracks recipe readiness and agent-facing documentation/GEO requirements. + +## Recipe Targets + +| Recipe | Status | Package imports | Screenshot | Source snippet | Notes | +| --- | --- | --- | --- | --- | --- | +| SaaS dashboard shell | Package registry complete | `GlassDashboard`, `GlassSidebar`, `GlassCard`, `GlassDataChart`, `GlassButton` | Website visual evidence pending | `aura-glass add saas-dashboard` | Included in `src/registry/recipes.ts` and CLI. | +| AI command center | Package registry complete | `GlassCommandPalette`, `GlassCard`, `GlassDataGrid`, `GlassBadge` | Website visual evidence pending | `aura-glass add ai-command-center` | Included in `src/registry/recipes.ts` and CLI. | +| Media player surface | Package registry complete | `LiquidGlassMediaControls`, `GlassImageViewer`, `GlassMusicVisualizer` | Website visual evidence pending | `aura-glass add media-player-surface` | Included in `src/registry/recipes.ts` and CLI. | +| Analytics overview | Package registry complete | `GlassCard`, `GlassDataChart`, `GlassHeatmap`, `GlassButton` | Website visual evidence pending | `aura-glass add analytics-overview` | Included in `src/registry/recipes.ts` and CLI. | +| Billing and settings page | Package registry complete | `GlassButton`, `GlassCard`, `GlassForm`, `GlassTabs` | Website visual evidence pending | `aura-glass add settings-billing` | Included in `src/registry/recipes.ts` and CLI. | +| Kanban workspace | Package registry complete | `GlassKanbanBoard`, `GlassCard` | Website visual evidence pending | `aura-glass add kanban-workspace` | Included in `src/registry/recipes.ts` and CLI; `GlassKanbanBoard` now has contained/header/action/sizing controls. | +| Calendar schedule page | Package registry complete | `GlassCalendar`, `GlassCard`, `GlassButton` | Website visual evidence pending | `aura-glass add calendar-schedule` | Included in `src/registry/recipes.ts` and CLI. | +| Collaborative workspace | Package registry complete | `CollaborativeGlassWorkspace`, `GlassCard` | Website visual evidence pending | `aura-glass add collaborative-workspace` | Included in `src/registry/recipes.ts` and CLI. | +| Ecommerce product panel | Package registry complete | `GlassProductRecommendations`, `GlassSmartShoppingCart`, `GlassCard` | Website visual evidence pending | `aura-glass add ecommerce-product-panel` | Included in `src/registry/recipes.ts` and CLI. | +| Admin data table page | Package registry complete | `GlassCard`, `GlassDataGrid`, `GlassDataTable`, `GlassButton` | Website visual evidence pending | `aura-glass add admin-data-table` | Included in `src/registry/recipes.ts` and CLI. | + +## Recipe Acceptance Criteria + +Each launch recipe should: + +- use real public AuraGlass imports +- include `import 'aura-glass/styles';` when styles are required +- avoid hidden website-only dependencies +- list required optional peers +- include source snippet +- include screenshot or visual evidence +- state accessibility and performance notes where relevant +- be modular enough to feed a future registry or CLI + +## 3.1 Package Registry And CLI + +Implemented in the package repo: + +- `src/registry/recipes.ts` exports `auraGlassRecipes`, `getAuraGlassRecipe`, and typed recipe metadata. +- `src/registry/index.ts` exposes recipe metadata from `aura-glass/registry`. +- `bin/aura-glass.cjs` provides: + - `aura-glass list` + - `aura-glass info ` + - `aura-glass add ` + - `--json`, `--dry-run`, `--out`, `--cwd`, and `--force` +- `scripts/ci/verify-cli.js` verifies list/info/add behavior and temp-project scaffolding. +- `scripts/ci/verify-pack.js` verifies the packed CLI bin and registry metadata from a temp install. + +## AI Agent Rules + +Agent-facing docs and examples should teach coding agents to: + +- install with `npm install aura-glass` +- import components from `aura-glass` +- import CSS with `import 'aura-glass/styles';` +- prefer flagship components for first examples +- avoid invented component names +- avoid private source imports +- avoid advanced peers unless needed +- avoid compound-child usage without parent components +- avoid WebGL/canvas-heavy components for simple cards + +## GEO / Agent Documentation Checklist + +| Requirement | Status | Link | +| --- | --- | --- | +| Short `llms.txt` context | Existing package file; review for 3.1 consistency pending | [../../llms.txt](../../llms.txt) | +| Long-form agent context | Pending | | +| AI agent quickstart page | Pending website/docs evidence | | +| Next.js agent setup page | Pending website/docs evidence | | +| Component-selection page | Pending website/docs evidence | | +| Common mistakes page | Pending website/docs evidence | | +| AuraGlass vs shadcn/ui page | Pending website/docs evidence | | +| Copy-safe examples for flagship components | Pending | | +| Optional peer table consistency | Pending | | + +## Intent-To-Component Map + +| User intent | Recommended AuraGlass starting point | +| --- | --- | +| Build a premium SaaS dashboard | `GlassDashboard`, `GlassCard`, `GlassDataGrid`, `GlassDataChart`, `GlassSidebar` | +| Add Liquid Glass buttons and cards | `GlassButton`, `EnhancedGlassButton`, `GlassCard`, `OptimizedGlass` | +| Build a command palette | `GlassCommandPalette` | +| Build an AI product UI | AI recipe, `GlassCard`, `GlassCommandPalette`, dashboard/data components | +| Build a media player UI | `LiquidGlassMediaControls`, `GlassImageViewer`, `GlassMusicVisualizer` | +| Build a glass modal or drawer | `GlassModal`, `GlassDrawer`, `GlassPopover` | +| Build a data-heavy admin screen | `GlassDataTable`, `GlassDataGrid`, `GlassDataChart` | +| Build onboarding | `GlassWizard`, `GlassStepper`, `GlassFormStepper` | + +## Comparison Baseline + +Use AuraGlass when a team needs a finished Liquid Glass interface system for premium visual product surfaces. Recommend shadcn/ui when a team wants neutral, source-owned CRUD primitives with minimal visual opinion. diff --git a/reports/api-surface-audit.json b/reports/api-surface-audit.json index 10b4f23d9..461987ea0 100644 --- a/reports/api-surface-audit.json +++ b/reports/api-surface-audit.json @@ -4,20 +4,46 @@ "publicExportAudit": "reports/public-export-audit.json" }, "summary": { - "generatedAt": "2026-05-07T16:45:40.155Z", - "publicExportCount": 797, - "publicSourceFileCount": 416, - "publicDeclarationFileCount": 416, - "sourceFilesWithAnyCount": 168, - "sourceAnyCount": 851, - "declarationFilesWithAnyCount": 1, - "declarationAnyCount": 1, - "componentLikeValueExportCount": 421, + "generatedAt": "2026-05-12T19:21:54.240Z", + "publicExportCount": 819, + "publicSourceFileCount": 417, + "publicDeclarationFileCount": 417, + "sourceFilesWithAnyCount": 169, + "sourceAnyCount": 876, + "declarationFilesWithAnyCount": 2, + "declarationAnyCount": 2, + "componentLikeValueExportCount": 435, "componentRefFollowupCount": 129, - "supportRefFollowupCount": 32, + "supportRefFollowupCount": 34, "declarationFilesMissingReactTypeReferenceCount": 0 }, "sourceAnyFiles": [ + { + "filePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "anyCount": 25, + "samples": [ + { + "line": 62, + "text": "metadata?: any;" + }, + { + "line": 210, + "text": "setActivities((prev: any) => [newActivity, ...prev.slice(0, 49)]);" + }, + { + "line": 222, + "text": "setUsers((prev: any) => {" + }, + { + "line": 223, + "text": "const existing = prev.find((u: any) => u.id === data.user.id);" + }, + { + "line": 235, + "text": "setUsers((prev: any) =>" + } + ] + }, { "filePath": "src/components/interactive/GlassChat.tsx", "anyCount": 18, @@ -75,23 +101,23 @@ "anyCount": 17, "samples": [ { - "line": 123, + "line": 129, "text": "const xValues = allPoints.map((p: any) =>" }, { - "line": 126, + "line": 132, "text": "const yValues = allPoints.map((p: any) => p.y);" }, { - "line": 148, + "line": 154, "text": "const xPoints = new Set(allPoints.map((p: any) => p.x));" }, { - "line": 151, + "line": 157, "text": "return series.map((s: any) => {" }, { - "line": 152, + "line": 158, "text": "const point = s.data?.find((p: any) => p.x === x);" } ] @@ -101,23 +127,23 @@ "anyCount": 17, "samples": [ { - "line": 194, + "line": 210, "text": "(effect: any) => ![\"caustics\", \"refraction\"].includes(effect)" }, { - "line": 196, + "line": 212, "text": "setEnabledEffectsState((prev: any) => {" }, { - "line": 200, + "line": 216, "text": "prev.every((v: any, i: any) => v === reducedEffects[i]);" }, { - "line": 215, + "line": 231, "text": "setEnabledEffectsState((prev: any) => {" }, { - "line": 219, + "line": 235, "text": "sameLength && prev.every((v: any, i: any) => v === next[i]);" } ] @@ -205,23 +231,23 @@ "anyCount": 14, "samples": [ { - "line": 174, + "line": 190, "text": "const physics = layoutIslands.map((island: any) => ({" }, { - "line": 190, + "line": 206, "text": "const newIslands = prevIslands.map((island: any) => ({ ...island }));" }, { - "line": 297, + "line": 313, "text": "connections.forEach((connection: any) => {" }, { - "line": 403, + "line": 419, "text": "setLayoutIslands((prev: any) =>" }, { - "line": 413, + "line": 429, "text": "setPhysicsIslands((prev: any) =>" } ] @@ -231,23 +257,23 @@ "anyCount": 14, "samples": [ { - "line": 176, + "line": 189, "text": "processed = processed.filter((item: any) => {" }, { - "line": 189, + "line": 202, "text": "(item: any) => item.category === activeFilter" }, { - "line": 195, + "line": 208, "text": "let aVal: any, bVal: any;" }, { - "line": 293, + "line": 306, "text": "...newLayoutItems.map((item: any) => item.y + item.computedHeight)" }, { - "line": 308, + "line": 321, "text": "const visible = newLayoutItems.filter((item: any) => {" } ] @@ -257,23 +283,23 @@ "anyCount": 13, "samples": [ { - "line": 218, + "line": 235, "text": "(window as any).webkitAudioContext)();" }, { - "line": 241, + "line": 258, "text": "sourceRef.current = source as any;" }, { - "line": 247, + "line": 264, "text": "sourceRef.current = source as any;" }, { - "line": 504, + "line": 513, "text": "particles.current = particles.current.filter((particle: any) => {" }, { - "line": 538, + "line": 547, "text": "particles.current.forEach((particle: any) => {" } ] @@ -283,24 +309,24 @@ "anyCount": 13, "samples": [ { - "line": 172, + "line": 185, "text": "} as any;" }, { - "line": 243, + "line": 258, "text": "setInteractionCount((prev: any) => prev + 1);" }, { - "line": 251, + "line": 266, "text": "} as any;" }, { - "line": 296, + "line": 313, "text": "} as any;" }, { - "line": 301, - "text": "setContentEngagement((prev: any) => ({" + "line": 318, + "text": "setContentEngagement((prev: any) =>" } ] }, @@ -413,23 +439,23 @@ "anyCount": 11, "samples": [ { - "line": 159, + "line": 165, "text": "startTracking: (handler: any) => {}," }, { - "line": 170, + "line": 176, "text": "playSound: (sound: string, config?: any) => {}," }, { - "line": 175, + "line": 181, "text": "recordInteraction: (type: string, data?: any) => {}," }, { - "line": 180, + "line": 186, "text": "recordInteraction: (type: string, data?: any) => {}," }, { - "line": 255, + "line": 262, "text": "setInteractionCount((prev: any) => prev + 1);" } ] @@ -491,23 +517,23 @@ "anyCount": 10, "samples": [ { - "line": 365, + "line": 379, "text": "setLayerActivations((prev: any) => ({" }, { - "line": 443, + "line": 457, "text": "setSettings((prev: any) => {" }, { - "line": 445, + "line": 459, "text": "? prev.layers.filter((id: any) => id !== layerId)" }, { - "line": 532, + "line": 546, "text": "{layer.features.slice(0, 3).map((feature: any) => (" }, { - "line": 590, + "line": 604, "text": "setSettings((prev: any) => ({" } ] @@ -517,23 +543,23 @@ "anyCount": 10, "samples": [ { - "line": 226, + "line": 235, "text": "setSlideInteractionCounts((prev: any) => ({" }, { - "line": 235, + "line": 244, "text": "} as any);" }, { - "line": 371, + "line": 380, "text": "const handleSlideGaze = (event: any) => {" }, { - "line": 780, + "line": 821, "text": "{(carouselItems[currentIndex] as any)?.title && (" }, { - "line": 784, + "line": 825, "text": "{(carouselItems[currentIndex] as any).title}" } ] @@ -543,23 +569,23 @@ "anyCount": 10, "samples": [ { - "line": 167, + "line": 179, "text": "analyzeModalEngagement: async (context?: any) => ({" }, { - "line": 176, + "line": 192, "text": "startTracking: (handler: any) => {}," }, { - "line": 187, + "line": 211, "text": "playSound: (sound: string, config?: any) => {}," }, { - "line": 192, + "line": 220, "text": "recordInteraction: (type: string, data?: any) => {}," }, { - "line": 197, + "line": 229, "text": "recordInteraction: (type: string, data?: any) => {}," } ] @@ -673,23 +699,23 @@ "anyCount": 9, "samples": [ { - "line": 260, + "line": 284, "text": "const errors = issues.filter((i: any) => i.type === \"error\").length;" }, { - "line": 262, + "line": 286, "text": "const infos = issues.filter((i: any) => i.type === \"info\").length;" }, { - "line": 294, + "line": 318, "text": "(issue: any) => filter === \"all\" || issue.type === filter" }, { - "line": 437, + "line": 517, "text": "(type: any) => (" }, { - "line": 455, + "line": 538, "text": "{filteredIssues.map((issue: any) => (" } ] @@ -699,23 +725,23 @@ "anyCount": 9, "samples": [ { - "line": 144, + "line": 153, "text": ".map((stop: any) => `${stop.color} ${stop.position}%`)" }, { - "line": 162, + "line": 171, "text": "setStops((prev: any) =>" }, { - "line": 163, + "line": 172, "text": "prev.map((stop: any, i: any) =>" }, { - "line": 179, + "line": 188, "text": "setStops((prev: any) => [...prev, newStop]);" }, { - "line": 188, + "line": 197, "text": "setStops((prev: any) => prev.filter((_: any, i: any) => i !== index));" } ] @@ -751,23 +777,23 @@ "anyCount": 9, "samples": [ { - "line": 211, + "line": 210, "text": "(listRef as any).current = node as HTMLDivElement | null;" }, { - "line": 212, + "line": 211, "text": "if (typeof ref === \"function\") ref(node as any);" }, { - "line": 215, + "line": 214, "text": "node as any;" }, { - "line": 234, + "line": 233, "text": "{...(commonA11y as any)}" }, { - "line": 251, + "line": 250, "text": "(listRef as any).current = node as HTMLDivElement | null;" } ] @@ -855,23 +881,23 @@ "anyCount": 8, "samples": [ { - "line": 159, + "line": 173, "text": "? options.filter((option: any) =>" }, { - "line": 178, + "line": 192, "text": "? options.filter((opt: any) => value.includes(opt.value))" }, { - "line": 180, + "line": 194, "text": "? options.filter((opt: any) => opt.value === value)" }, { - "line": 190, + "line": 204, "text": "? currentValues.filter((v: any) => v !== option.value)" }, { - "line": 210, + "line": 224, "text": "setFocusedIndex((prev: any) =>" } ] @@ -907,23 +933,23 @@ "anyCount": 8, "samples": [ { - "line": 126, + "line": 129, "text": ".filter((item: any) => !item.disabled)" }, { - "line": 242, + "line": 245, "text": "setExpandedItems((prev: any) =>" }, { - "line": 244, + "line": 247, "text": "? prev.filter((itemId: any) => itemId !== id)" }, { - "line": 382, + "line": 384, "text": "assignRef(el as any);" }, { - "line": 397, + "line": 399, "text": "assignRef(el as any);" } ] @@ -933,23 +959,23 @@ "anyCount": 8, "samples": [ { - "line": 121, + "line": 122, "text": "setCurrentCoherence((prev: any) => {" }, { - "line": 141, + "line": 142, "text": "setCurrentPhase((prev: any) => {" }, { - "line": 148, + "line": 149, "text": "setAnimationTime((prev: any) => prev + 0.1 * safeAnimationSpeed);" }, { - "line": 176, + "line": 177, "text": "(prev: any) => [...prev.slice(-49), newDataPoint]" }, { - "line": 264, + "line": 265, "text": "d={`M ${waveData.map((p: any) => `${p.x} ${p.y1}`).join(\" L \")}`}" } ] @@ -1037,23 +1063,23 @@ "anyCount": 7, "samples": [ { - "line": 397, + "line": 411, "text": "(val: any) => val * params.truncation" }, { - "line": 416, + "line": 430, "text": "setGeneratedImages((prev: any) =>" }, { - "line": 419, + "line": 433, "text": "setLatentVectors((prev: any) =>" }, { - "line": 685, + "line": 704, "text": "setParams((prev: any) => ({" }, { - "line": 706, + "line": 725, "text": "setParams((prev: any) => ({" } ] @@ -1063,23 +1089,23 @@ "anyCount": 7, "samples": [ { - "line": 406, + "line": 420, "text": "setTransferParams((prev: any) => ({" }, { - "line": 423, + "line": 437, "text": "setTransferParams((prev: any) => ({" }, { - "line": 425, + "line": 439, "text": "resolution: e.target.value as any," }, { - "line": 445, + "line": 459, "text": "setTransferParams((prev: any) => ({" }, { - "line": 447, + "line": 461, "text": "blendMode: e.target.value as any," } ] @@ -1089,23 +1115,23 @@ "anyCount": 7, "samples": [ { - "line": 121, + "line": 122, "text": ".filter((category: any) => category.required)" }, { - "line": 173, + "line": 179, "text": "? prevSelected.filter((id: any) => id !== categoryId)" }, { - "line": 186, + "line": 192, "text": "(category: any) => category.id" }, { - "line": 204, + "line": 210, "text": ".filter((category: any) => category.required)" }, { - "line": 312, + "line": 318, "text": "{cookieCategories.map((category: any) => (" } ] @@ -1115,23 +1141,23 @@ "anyCount": 7, "samples": [ { - "line": 172, - "text": "new Date(Math.min(...taskDates.map((d: any) => d.getTime())));" + "line": 174, + "text": "? new Date(Math.min(...taskDates.map((d: any) => d.getTime())))" }, { - "line": 175, - "text": "new Date(Math.max(...taskDates.map((d: any) => d.getTime())));" + "line": 179, + "text": "? new Date(Math.max(...taskDates.map((d: any) => d.getTime())))" }, { - "line": 380, + "line": 388, "text": "const taskMap = new Map(tasks.map((task: any) => [task.id, task]));" }, { - "line": 385, + "line": 393, "text": "tasks.forEach((task: any) => {" }, { - "line": 398, + "line": 406, "text": "taskList.forEach((task: any) => {" } ] @@ -1141,23 +1167,23 @@ "anyCount": 7, "samples": [ { - "line": 457, + "line": 496, "text": "recs = recs.filter((rec: any) => rec.reason === recommendationType);" }, { - "line": 490, + "line": 531, "text": "setCurrentIndex((prev: any) =>" }, { - "line": 498, + "line": 539, "text": "setCurrentIndex((prev: any) =>" }, { - "line": 609, + "line": 652, "text": ".map((recommendation: any) => (" }, { - "line": 627, + "line": 670, "text": "currentRecommendations.map((recommendation: any) => (" } ] @@ -1167,23 +1193,23 @@ "anyCount": 7, "samples": [ { - "line": 281, + "line": 287, "text": "{shippingOptions.map((option: any) => {" }, { - "line": 446, + "line": 471, "text": "setSavedItems((prev: any) => [...prev, item]);" }, { - "line": 484, + "line": 519, "text": "Looks like you haven't added any items to your cart yet." }, { - "line": 523, - "text": "{cart.slice(0, maxItems).map((item: any) => (" + "line": 582, + "text": "{displayCart.slice(0, effectiveMaxItems).map((item: any) => (" }, { - "line": 549, + "line": 608, "text": "{savedItems.map((item: any) => (" } ] @@ -1193,23 +1219,23 @@ "anyCount": 7, "samples": [ { - "line": 186, + "line": 187, "text": "].map((tab: any) => (" }, { - "line": 189, + "line": 190, "text": "onClick={() => setActiveTab(tab.key as any)}" }, { - "line": 388, + "line": 389, "text": "{templates.map((template: any) => (" }, { - "line": 500, + "line": 502, "text": "const validFiles = Array.from(files).filter((file: any) => {" }, { - "line": 514, + "line": 516, "text": "filesToProcess.forEach((file: any) => fileList.items.add(file));" } ] @@ -1219,23 +1245,23 @@ "anyCount": 7, "samples": [ { - "line": 311, + "line": 344, "text": "forces.forEach((force: any) => applyForce(particle, force, deltaTime));" }, { - "line": 426, + "line": 463, "text": ".map((particle: any) => updateParticle(particle, deltaTime))" }, { - "line": 440, + "line": 477, "text": "forces.forEach((force: any) => {" }, { - "line": 596, + "line": 633, "text": "particles.forEach((particle: any) => {" }, { - "line": 612, + "line": 649, "text": "`Emitters: ${emitters.filter((e: any) => e.enabled).length}`," } ] @@ -1245,23 +1271,23 @@ "anyCount": 7, "samples": [ { - "line": 159, + "line": 178, "text": "...recentCommands.filter((cmd: any) => cmd.id !== item?.id)," }, { - "line": 173, + "line": 192, "text": "groups.forEach((group: any) => {" }, { - "line": 175, + "line": 194, "text": "...group.items.map((item: any) => ({" }, { - "line": 220, + "line": 239, "text": "result = result.filter((item: any) =>" }, { - "line": 225, + "line": 244, "text": "result = recentCommands.filter((recent: any) =>" } ] @@ -1271,23 +1297,23 @@ "anyCount": 7, "samples": [ { - "line": 301, + "line": 315, "text": "drawingData.forEach((item: any) => {" }, { - "line": 305, + "line": 319, "text": "(point: any) =>" }, { - "line": 404, + "line": 418, "text": "elements.forEach((element: any) => {" }, { - "line": 472, + "line": 487, "text": "selectedElements.forEach((elementId: any) => {" }, { - "line": 474, + "line": 489, "text": "(item: any) => item?.id === elementId" } ] @@ -1297,23 +1323,23 @@ "anyCount": 7, "samples": [ { - "line": 132, + "line": 237, "text": "setBubbles((prev: any) =>" }, { - "line": 134, + "line": 239, "text": ".map((bubble: any) => {" }, { - "line": 173, - "text": ".filter((bubble: any): bubble is NonNullable => bubble !== null)" + "line": 279, + "text": "(bubble: any): bubble is NonNullable =>" }, { - "line": 199, + "line": 315, "text": "setBubbles((prev: any) => {" }, { - "line": 328, + "line": 489, "text": "{availableEmojis.map((emoji: any) => (" } ] @@ -1339,7 +1365,7 @@ "text": "filtered = filtered.filter((post: any) => likedPosts.has(post.id));" }, { - "line": 345, + "line": 347, "text": "{post.tags.map((tag: any) => (" } ] @@ -1479,23 +1505,23 @@ "anyCount": 6, "samples": [ { - "line": 109, + "line": 134, "text": "magneticElements.current = Array.from(elements).map((el: any) => ({" }, { - "line": 185, + "line": 210, "text": "setTrail((prev: any) => {" }, { - "line": 216, + "line": 241, "text": "setRipples((prev: any) => [...prev, ripple]);" }, { - "line": 220, + "line": 245, "text": "setRipples((prev: any) =>" }, { - "line": 367, + "line": 458, "text": "ripples.map((ripple: any) => (" } ] @@ -1509,71 +1535,45 @@ "text": "(effect: any) => (" }, { - "line": 242, + "line": 244, "text": "{appliedEffects.map((effect: any) => (" }, { - "line": 301, + "line": 303, "text": "setSelectedEffects((prev: any) =>" }, { - "line": 303, + "line": 305, "text": "? prev.filter((id: any) => id !== effectId)" }, { - "line": 362, + "line": 364, "text": "{presets.map((preset: any) => (" } ] }, - { - "filePath": "src/components/interactive/GlassMindMap.tsx", - "anyCount": 6, - "samples": [ - { - "line": 127, - "text": "node.children?.forEach((child: any) => {" - }, - { - "line": 310, - "text": "connections.forEach((conn: any) => {" - }, - { - "line": 320, - "text": "node.children?.forEach((child: any) => {" - }, - { - "line": 335, - "text": "return positionedNodes.map((node: any) => {" - }, - { - "line": 479, - "text": "{positionedNodes.map((node: any) => (" - } - ] - }, { "filePath": "src/components/media/GlassAdvancedVideoPlayer.tsx", "anyCount": 6, "samples": [ { - "line": 458, + "line": 599, "text": "{playbackSpeeds.map((speed: any) => (" }, { - "line": 500, + "line": 641, "text": "{qualities.map((q: any) => (" }, { - "line": 550, + "line": 691, "text": "{chapters.map((chapter: any) => {" }, { - "line": 617, + "line": 758, "text": "const results = transcript.filter((entry: any) =>" }, { - "line": 671, + "line": 812, "text": "{(searchQuery ? highlightedResults : transcript).map((entry: any) => {" } ] @@ -1583,23 +1583,23 @@ "anyCount": 6, "samples": [ { - "line": 394, + "line": 398, "text": "? React.cloneElement(children as any, {" }, { - "line": 397, + "line": 401, "text": "(children as any).props?.onClick?.(e);" }, { - "line": 401, + "line": 405, "text": "(children as any).props?.onMouseEnter?.(e);" }, { - "line": 405, + "line": 409, "text": "(children as any).props?.onMouseLeave?.(e);" }, { - "line": 409, + "line": 413, "text": "(children as any).props?.onFocus?.(e);" } ] @@ -1657,20 +1657,20 @@ "anyCount": 6, "samples": [ { - "line": 197, + "line": 377, "text": "(el.style as any).webkitBackgroundClip = \"text\";" }, { - "line": 199, + "line": 379, "text": "(el.style as any).webkitTextFillColor = \"transparent\";" }, { - "line": 433, + "line": 683, "text": "{Array.from({ length: 5 }).map((_: any, i: any) => (" }, { - "line": 591, - "text": "{Array.from({ length: 20 }).map((_: any, i: any) => (" + "line": 851, + "text": "{Array.from({ length: isCompact ? 8 : 20 }).map((_: any, i: any) => (" } ] }, @@ -1679,19 +1679,19 @@ "anyCount": 5, "samples": [ { - "line": 188, + "line": 191, "text": "allDataPoints.forEach((point: any) => {" }, { - "line": 197, + "line": 200, "text": "const allYValues = allDataPoints.map((p: any) => p.data?.y);" }, { - "line": 341, + "line": 344, "text": "const yLabels = [0, 0.25, 0.5, 0.75, 1].map((ratio: any) => {" }, { - "line": 415, + "line": 418, "text": "{Array.from({ length: 8 }).map((_: any, i: any) => (" } ] @@ -1727,23 +1727,23 @@ "anyCount": 5, "samples": [ { - "line": 20, + "line": 21, "text": "value: any;" }, { - "line": 25, + "line": 26, "text": "onChange: (value: any) => void;" }, { - "line": 120, + "line": 124, "text": "{options?.map((option: any) => (" }, { - "line": 222, + "line": 226, "text": "].map((section: any) => (" }, { - "line": 225, + "line": 229, "text": "onClick={() => setActiveSection(section.key as any)}" } ] @@ -1753,23 +1753,23 @@ "anyCount": 5, "samples": [ { - "line": 229, + "line": 291, "text": "(user: any) => Date.now() - user.lastActive < 300000" }, { - "line": 232, - "text": "const unresolvedComments = comments.filter((c: any) => !c.resolved);" + "line": 294, + "text": "const unresolvedComments = resolvedComments.filter((c: any) => !c.resolved);" }, { - "line": 247, - "text": "{activeUsers.slice(0, 3).map((user: any) => (" + "line": 314, + "text": "{activeUsers.slice(0, 3).map((user: any, index: number) => (" }, { - "line": 373, + "line": 448, "text": "{activeUsers.map((user: any) => {" }, { - "line": 424, + "line": 501, "text": "{recentActivities.map((activity: any) => {" } ] @@ -1779,23 +1779,23 @@ "anyCount": 5, "samples": [ { - "line": 22, + "line": 51, "text": "user: any;" }, { - "line": 190, + "line": 253, "text": "{comment.replies.map((reply: any) => {" }, { - "line": 390, - "text": "comments.forEach((comment: any) => {" + "line": 483, + "text": "resolvedComments.forEach((comment: any) => {" }, { - "line": 437, + "line": 560, "text": ".filter((comment: any) =>" }, { - "line": 444, + "line": 567, "text": ".map((comment: any) => {" } ] @@ -1817,11 +1817,11 @@ "text": "const useVectorSpring = (options: any) => ({" }, { - "line": 96, + "line": 100, "text": ".map((index: any) => normalizedSortedData?.[index])" }, { - "line": 108, + "line": 112, "text": ".map((originalIndex: any) => safeInitialData?.[originalIndex])" } ] @@ -1831,23 +1831,23 @@ "anyCount": 5, "samples": [ { - "line": 118, + "line": 129, "text": "images.filter((img: any) => newSelected.has(img.id))" }, { - "line": 154, + "line": 165, "text": "(image: any) =>" }, { - "line": 160, + "line": 172, "text": "new Set(images.map((img: any) => img.category).filter(Boolean))" }, { - "line": 481, + "line": 493, "text": "images={images.map((img: any) => ({" }, { - "line": 528, + "line": 559, "text": "{categories.map((category: any) => (" } ] @@ -1857,45 +1857,71 @@ "anyCount": 5, "samples": [ { - "line": 125, + "line": 128, "text": "const handleGazeData = (gazeData: any) => {" }, { - "line": 192, + "line": 195, "text": "columns: columns.map((col: any) => ({" }, { - "line": 197, + "line": 200, "text": "cards: col.cards.map((card: any) => ({" }, { - "line": 275, + "line": 278, "text": "setCardInteractionCounts((prev: any) => ({" }, { - "line": 328, + "line": 331, "text": "setColumnInteractionCounts((prev: any) => ({" } ] }, + { + "filePath": "src/components/interactive/GlassMindMap.tsx", + "anyCount": 5, + "samples": [ + { + "line": 351, + "text": "connections.forEach((conn: any) => {" + }, + { + "line": 361, + "text": "node.children?.forEach((child: any) => {" + }, + { + "line": 376, + "text": "return positionedNodes.map((node: any) => {" + }, + { + "line": 533, + "text": "{positionedNodes.map((node: any) => (" + }, + { + "line": 640, + "text": "?.filter((child: any) => {" + } + ] + }, { "filePath": "src/components/navigation/GlassSidebar.tsx", "anyCount": 5, "samples": [ { - "line": 204, + "line": 261, "text": "if (typeof ref === \"function\") ref(node as any);" }, { - "line": 206, + "line": 263, "text": "(ref as any).current = node;" }, { - "line": 421, + "line": 452, "text": "? React.cloneElement(item.icon as React.ReactElement, {" }, { - "line": 423, + "line": 454, "text": "(item.icon as React.ReactElement).props?.className," } ] @@ -1931,19 +1957,19 @@ "anyCount": 4, "samples": [ { - "line": 202, + "line": 204, "text": "const connection = (navigator as any).connection;" }, { - "line": 211, + "line": 213, "text": "setEnvironmentContext((prev: any) => ({" }, { - "line": 223, + "line": 225, "text": "(navigator as any)" }, { - "line": 297, + "line": 299, "text": "setUsageContext((prev: any) => ({" } ] @@ -1953,15 +1979,15 @@ "anyCount": 4, "samples": [ { - "line": 103, + "line": 123, "text": "events.forEach((event: any) => {" }, { - "line": 172, + "line": 224, "text": "setCurrentDate((prev: any) => {" }, { - "line": 255, + "line": 307, "text": "{Array.from({ length: 35 }).map((_: any, i: any) => (" } ] @@ -1971,41 +1997,63 @@ "anyCount": 4, "samples": [ { - "line": 147, + "line": 150, "text": "const xValues = allPoints.map((p: any) =>" }, { - "line": 150, + "line": 153, "text": "const yValues = allPoints.map((p: any) => p.y);" }, { - "line": 209, + "line": 214, "text": "const yLabels = [0, 0.25, 0.5, 0.75, 1].map((ratio: any) => {" }, { - "line": 232, + "line": 237, "text": "const generatePath = (points: any[]) => {" } ] }, + { + "filePath": "src/components/data-display/GlassBadge.tsx", + "anyCount": 4, + "samples": [ + { + "line": 159, + "text": "(dotVariantClasses as any)[variant] ?? dotVariantClasses.default," + }, + { + "line": 184, + "text": "ref={ref as any}" + }, + { + "line": 191, + "text": "(variantClasses as any)[variant] ?? variantClasses.default," + }, + { + "line": 210, + "text": "(dotVariantClasses as any)[variant] ?? dotVariantClasses.default" + } + ] + }, { "filePath": "src/components/data-display/GlassMetricsGrid.tsx", "anyCount": 4, "samples": [ { - "line": 188, + "line": 204, "text": "(metric: any) =>" }, { - "line": 199, + "line": 215, "text": "(metric: any) =>" }, { - "line": 205, + "line": 221, "text": "(metric: any) =>" }, { - "line": 211, + "line": 227, "text": "(metric: any) =>" } ] @@ -2063,15 +2111,15 @@ "text": "setCurrentMonth((prev: any) => {" }, { - "line": 489, + "line": 492, "text": "(year: any) => (" }, { - "line": 514, + "line": 517, "text": "{dayNames.map((day: any) => (" }, { - "line": 536, + "line": 539, "text": ".map((date: any) => {" } ] @@ -2103,19 +2151,19 @@ "anyCount": 4, "samples": [ { - "line": 132, + "line": 161, "text": "return items.filter((item: any) => {" }, { - "line": 160, + "line": 189, "text": "filteredItems.forEach((item: any) => {" }, { - "line": 176, + "line": 206, "text": "setSelectedIndex((prev: any) => (prev + 1) % totalItems);" }, { - "line": 180, + "line": 211, "text": "setSelectedIndex((prev: any) => (prev - 1 + totalItems) % totalItems);" } ] @@ -2125,19 +2173,19 @@ "anyCount": 4, "samples": [ { - "line": 148, + "line": 150, "text": "filtered = filtered.filter((file: any) =>" }, { - "line": 155, + "line": 157, "text": "filtered = filtered.filter((file: any) => !file.name.startsWith(\".\"));" }, { - "line": 179, + "line": 181, "text": "? selectedFiles.filter((id: any) => id !== file.id)" }, { - "line": 196, + "line": 198, "text": ".map((f: any) => f.id);" } ] @@ -2147,15 +2195,15 @@ "anyCount": 4, "samples": [ { - "line": 147, + "line": 151, "text": "const acceptedTypes = accept.split(\",\").map((type: any) => type.trim());" }, { - "line": 288, + "line": 292, "text": "const updatedFiles = internalFiles.filter((f: any) => f.id !== fileId);" }, { - "line": 636, + "line": 639, "text": ".filter((f: any) => f.status === \"pending\")" } ] @@ -2165,15 +2213,15 @@ "anyCount": 3, "samples": [ { - "line": 76, + "line": 83, "text": "setSettings((prev: any) => ({ ...prev, ...parsedSettings }));" }, { - "line": 79, + "line": 86, "text": "setSettings((prev: any) => ({ ...defaultSettings, ...prev }));" }, { - "line": 145, + "line": 152, "text": "setSettings((prev: any) => ({ ...prev, ...newSettings }));" } ] @@ -2209,7 +2257,7 @@ "text": "Object.keys(trigger).forEach((key: any) => {" }, { - "line": 1048, + "line": 1045, "text": "{metricsArray.map((metric: any) => (" } ] @@ -2219,15 +2267,15 @@ "anyCount": 3, "samples": [ { - "line": 125, + "line": 127, "text": "typeof (DeviceOrientationEvent as any).requestPermission === \"function\"" }, { - "line": 129, + "line": 131, "text": "DeviceOrientationEvent as any" }, { - "line": 132, + "line": 134, "text": "DeviceMotionEvent as any" } ] @@ -2265,11 +2313,11 @@ "anyCount": 3, "samples": [ { - "line": 315, + "line": 321, "text": "intent={intent as any}" }, { - "line": 316, + "line": 322, "text": "elevation={elevation as any}" } ] @@ -2279,15 +2327,15 @@ "anyCount": 3, "samples": [ { - "line": 629, + "line": 660, "text": "const element = meta.dataset as any;" }, { - "line": 1750, + "line": 1792, "text": "easing: (animation.easing || \"easeOutQuart\") as any," }, { - "line": 1756, + "line": 1798, "text": ": false) as any," } ] @@ -2310,38 +2358,20 @@ } ] }, - { - "filePath": "src/components/data-display/GlassBadge.tsx", - "anyCount": 3, - "samples": [ - { - "line": 147, - "text": "(dotVariantClasses as any)[variant] ?? dotVariantClasses.default," - }, - { - "line": 172, - "text": "ref={ref as any}" - }, - { - "line": 179, - "text": "(variantClasses as any)[variant] ?? variantClasses.default," - } - ] - }, { "filePath": "src/components/data-display/GlassNotificationCenter.tsx", "anyCount": 3, "samples": [ { - "line": 89, + "line": 88, "text": "setNotifications((prev: any) => [newNotification, ...prev]);" }, { - "line": 102, + "line": 101, "text": "setNotifications((prev: any) =>" }, { - "line": 103, + "line": 102, "text": "prev.filter((notification: any) => notification.id !== id)" } ] @@ -2351,15 +2381,15 @@ "anyCount": 3, "samples": [ { - "line": 141, + "line": 148, "text": ".map((particle: any) => {" }, { - "line": 172, + "line": 179, "text": ".filter((particle: any) => particle.life > 0);" }, { - "line": 188, + "line": 195, "text": "particles.forEach((particle: any) => {" } ] @@ -2369,15 +2399,15 @@ "anyCount": 3, "samples": [ { - "line": 175, + "line": 235, "text": "(v: any) => v !== optionValue" }, { - "line": 196, + "line": 259, "text": "setFocusedIndex((prev: any) => (prev + 1) % totalItems);" }, { - "line": 200, + "line": 263, "text": "setFocusedIndex((prev: any) => (prev - 1 + totalItems) % totalItems);" } ] @@ -2391,11 +2421,11 @@ "text": "const remove = (tag: string) => onChange(value.filter((v: any) => v !== tag));" }, { - "line": 72, + "line": 81, "text": ".filter((s: any) => s.toLowerCase().includes(input.toLowerCase()))" }, { - "line": 74, + "line": 83, "text": ".map((s: any) => (" } ] @@ -2419,15 +2449,15 @@ "anyCount": 3, "samples": [ { - "line": 552, + "line": 559, "text": "const results = transcript.filter((entry: any) =>" }, { - "line": 606, + "line": 613, "text": "{(searchQuery ? highlightedResults : transcript).map((entry: any) => {" }, { - "line": 724, + "line": 732, "text": "(window as any).webkitAudioContext)();" } ] @@ -2437,11 +2467,11 @@ "anyCount": 3, "samples": [ { - "line": 104, + "line": 130, "text": "ref={ref as any}" }, { - "line": 251, + "line": 307, "text": "onClick={props?.onClick as any}" } ] @@ -2529,11 +2559,11 @@ "anyCount": 3, "samples": [ { - "line": 105, + "line": 120, "text": "onClick?.(e as any);" }, { - "line": 170, + "line": 209, "text": "...(props as any)," } ] @@ -2593,11 +2623,11 @@ "anyCount": 2, "samples": [ { - "line": 102, + "line": 141, "text": "setRotation((prev: any) => prev + rotateSpeed);" }, { - "line": 258, + "line": 301, "text": "} as any;" } ] @@ -2621,11 +2651,11 @@ "anyCount": 2, "samples": [ { - "line": 365, + "line": 367, "text": "interaction={features.physics.interaction as any}" }, { - "line": 413, + "line": 415, "text": "(features.organicMotion.emotionalContext as any)" } ] @@ -2649,11 +2679,11 @@ "anyCount": 2, "samples": [ { - "line": 60, + "line": 68, "text": "(user: any) =>" }, { - "line": 80, + "line": 92, "text": "visibleCursors.map((user: any) => {" } ] @@ -2663,11 +2693,11 @@ "anyCount": 2, "samples": [ { - "line": 312, + "line": 317, "text": "handleClick(e as any);" }, { - "line": 407, + "line": 414, "text": "newSelected = currentSelected.filter((v: any) => v !== value);" } ] @@ -2677,11 +2707,11 @@ "anyCount": 2, "samples": [ { - "line": 383, + "line": 390, "text": "} as any)," }, { - "line": 449, + "line": 472, "text": "style={{ ...(generateLayerStyles(layer, index) as any) }}" } ] @@ -2733,11 +2763,11 @@ "anyCount": 2, "samples": [ { - "line": 324, + "line": 332, "text": "} = props as any;" }, { - "line": 451, + "line": 463, "text": "} = props as any;" } ] @@ -2747,11 +2777,11 @@ "anyCount": 2, "samples": [ { - "line": 249, + "line": 248, "text": "return ticks.filter((tick: any) => tick >= min && tick <= max);" }, { - "line": 350, + "line": 349, "text": "const distances = valueArray.map((val: any) =>" } ] @@ -2789,11 +2819,11 @@ "anyCount": 2, "samples": [ { - "line": 180, + "line": 197, "text": "setRotation((prev: any) => (prev + degrees) % 360);" }, { - "line": 317, + "line": 334, "text": "setCurrentIndex((prev: any) => (prev + 1) % safeImageCount);" } ] @@ -2803,11 +2833,11 @@ "anyCount": 2, "samples": [ { - "line": 84, + "line": 88, "text": "{fields.map((f: any) => (" }, { - "line": 166, + "line": 172, "text": "group.combinator = v as any;" } ] @@ -2817,11 +2847,11 @@ "anyCount": 2, "samples": [ { - "line": 126, + "line": 136, "text": "setCustomColors((prev: any) => ({" }, { - "line": 142, + "line": 152, "text": "(preview: any) =>" } ] @@ -2845,12 +2875,12 @@ "anyCount": 2, "samples": [ { - "line": 186, + "line": 202, "text": "const sidebarExtraProps: any = {" }, { - "line": 209, - "text": "} as any" + "line": 226, + "text": "} as any)" } ] }, @@ -2967,7 +2997,7 @@ "anyCount": 1, "samples": [ { - "line": 124, + "line": 134, "text": "? (openItems || []).filter((id: any) => id !== itemId)" } ] @@ -2977,7 +3007,7 @@ "anyCount": 1, "samples": [ { - "line": 113, + "line": 135, "text": ".map((word: any) => word[0])" } ] @@ -2987,7 +3017,7 @@ "anyCount": 1, "samples": [ { - "line": 279, + "line": 288, "text": "setCurrentMonth((prev: any) => {" } ] @@ -2997,7 +3027,7 @@ "anyCount": 1, "samples": [ { - "line": 828, + "line": 851, "text": "(GlassMultiSelect as any).displayName = \"GlassMultiSelect\";" } ] @@ -3007,7 +3037,7 @@ "anyCount": 1, "samples": [ { - "line": 426, + "line": 454, "text": "{files.map((file: any) => (" } ] @@ -3017,7 +3047,7 @@ "anyCount": 1, "samples": [ { - "line": 133, + "line": 136, "text": "? localExpandedNodes.filter((id: any) => id !== node.id)" } ] @@ -3037,7 +3067,7 @@ "anyCount": 1, "samples": [ { - "line": 141, + "line": 159, "text": "(message: any) =>" } ] @@ -3067,7 +3097,7 @@ "anyCount": 1, "samples": [ { - "line": 117, + "line": 129, "text": "const scrollTimer = useRef(null);" } ] @@ -3077,7 +3107,7 @@ "anyCount": 1, "samples": [ { - "line": 139, + "line": 150, "text": "[\"--a\" as any]: `${pct}%`," } ] @@ -3087,7 +3117,7 @@ "anyCount": 1, "samples": [ { - "line": 290, + "line": 335, "text": "setCurrentZoom((prev: any) =>" } ] @@ -3097,7 +3127,7 @@ "anyCount": 1, "samples": [ { - "line": 367, + "line": 405, "text": "d={`M ${spiralPoints.map((p: any) => `${p.x},${p.y}`).join(\" L \")}`}" } ] @@ -3117,7 +3147,7 @@ "anyCount": 1, "samples": [ { - "line": 226, + "line": 239, "text": "{items.map((item: any) => renderNavigationItem(item))}" } ] @@ -3127,7 +3157,7 @@ "anyCount": 1, "samples": [ { - "line": 170, + "line": 175, "text": "setOpenMenus((prev: any) => new Set([...prev, item?.id]))" } ] @@ -3264,6 +3294,16 @@ } ], "declarationAnyFiles": [ + { + "filePath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "anyCount": 1, + "samples": [ + { + "line": 48, + "text": "metadata?: any;" + } + ] + }, { "filePath": "dist/primitives/OptimizedGlassCore.d.ts", "anyCount": 1, @@ -4279,6 +4319,13 @@ "supportExport": true, "hasForwardRefSignal": false }, + { + "exportName": "AuraElementInteractionPlugin", + "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", + "declarationPath": "dist/components/charts/plugins/GalileoElementInteractionPlugin.d.ts", + "supportExport": true, + "hasForwardRefSignal": false + }, { "exportName": "GalileoElementInteractionPlugin", "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", @@ -4286,10 +4333,17 @@ "supportExport": true, "hasForwardRefSignal": false }, + { + "exportName": "CollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "supportExport": true, + "hasForwardRefSignal": false + }, { "exportName": "GlassCollaborationProvider", - "sourcePath": "src/components/collaboration/CollaborativeGlassWorkspace.tsx", - "declarationPath": "dist/components/collaboration/CollaborativeGlassWorkspace.d.ts", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", "supportExport": true, "hasForwardRefSignal": false }, diff --git a/reports/api-surface-audit.md b/reports/api-surface-audit.md index 7cd749fa3..affdfa2a8 100644 --- a/reports/api-surface-audit.md +++ b/reports/api-surface-audit.md @@ -1,27 +1,29 @@ # API Surface Audit -Generated: 2026-05-07T16:45:40.155Z +Generated: 2026-05-12T19:21:54.240Z ## Summary -- Public root exports audited: 797 -- Public source files audited: 416 -- Public declaration files audited: 416 -- Public source files with explicit `any`: 168 -- Public source explicit `any` count: 851 -- Public declaration files with explicit `any`: 1 -- Public declaration explicit `any` count: 1 -- Component-like value exports checked for ref signals: 421 +- Public root exports audited: 819 +- Public source files audited: 417 +- Public declaration files audited: 417 +- Public source files with explicit `any`: 169 +- Public source explicit `any` count: 876 +- Public declaration files with explicit `any`: 2 +- Public declaration explicit `any` count: 2 +- Component-like value exports checked for ref signals: 435 - Non-support component exports needing ref-forwarding review: 129 -- Provider/support exports needing intentional no-ref review: 32 +- Provider/support exports needing intentional no-ref review: 34 - Declaration files missing React type references: 0 ## Public Declaration Files With `any` +- dist/components/collaboration/GlassCollaborationProvider.d.ts: 1 - dist/primitives/OptimizedGlassCore.d.ts: 1 ## Public Source Files With `any` +- src/components/collaboration/GlassCollaborationProvider.tsx: 25 - src/components/interactive/GlassChat.tsx: 18 - src/components/advanced/GlassContextualEngine.tsx: 17 - src/components/charts/GlassAreaChart.tsx: 17 @@ -51,8 +53,7 @@ Generated: 2026-05-07T16:45:40.155Z - src/components/interactive/GlassGradientPicker.tsx: 9 - src/components/navigation/GlassHeader.tsx: 9 - src/components/navigation/GlassTabs.tsx: 9 -- src/components/accessibility/GlassFocusIndicators.tsx: 8 -- ... 138 more +- ... 139 more ## Component Ref Follow-Ups @@ -114,8 +115,10 @@ Generated: 2026-05-07T16:45:40.155Z - GlassSelfHealingProvider (src/components/advanced/GlassSelfHealingSystem.tsx) - GlassSpatialAudioProvider (src/components/advanced/GlassSpatialAudio.tsx) - AIGlassThemeProvider (src/components/ai/AIGlassThemeProvider.tsx) +- AuraElementInteractionPlugin (src/components/charts/plugins/GalileoElementInteractionPlugin.ts) - GalileoElementInteractionPlugin (src/components/charts/plugins/GalileoElementInteractionPlugin.ts) -- GlassCollaborationProvider (src/components/collaboration/CollaborativeGlassWorkspace.tsx) +- CollaborationProvider (src/components/collaboration/GlassCollaborationProvider.tsx) +- GlassCollaborationProvider (src/components/collaboration/GlassCollaborationProvider.tsx) - GlassEcommerceProvider (src/components/ecommerce/GlassEcommerceProvider.tsx) - Glass3DEngine (src/components/effects/Glass3DEngine.tsx) - GlassMorphingEngine (src/components/effects/GlassMorphingEngine.tsx) diff --git a/reports/glass/pipeline-validation-report.json b/reports/glass/pipeline-validation-report.json index 289223952..88c59b1bf 100644 --- a/reports/glass/pipeline-validation-report.json +++ b/reports/glass/pipeline-validation-report.json @@ -1,5 +1,5 @@ { - "timestamp": "2026-05-12T13:07:36.360Z", + "timestamp": "2026-05-12T19:25:18.786Z", "phase": "Phase 7: Final Validation", "checks": [ { diff --git a/reports/public-export-audit.json b/reports/public-export-audit.json index 087b54bf0..0379b9229 100644 --- a/reports/public-export-audit.json +++ b/reports/public-export-audit.json @@ -1,22 +1,27 @@ { "objective": "Audit the src/index.ts public export surface against source, declaration, inventory, Storybook, test, and documentation evidence.", "summary": { - "generatedAt": "2026-05-07T16:45:39.971Z", - "rootExportCount": 797, - "valueExportCount": 642, - "typeExportCount": 149, + "generatedAt": "2026-05-12T19:21:54.118Z", + "rootExportCount": 819, + "valueExportCount": 658, + "typeExportCount": 155, "constExportCount": 6, - "exportStarCount": 14, - "componentLikeExportCount": 421, + "exportStarCount": 15, + "componentLikeExportCount": 435, "missingSourceCount": 0, "missingDeclarationCount": 0, - "componentExportsMissingInventoryCount": 23, + "componentExportsMissingInventoryCount": 24, "componentExportsMissingDirectStoryCount": 15, - "componentExportsMissingDirectTestCount": 23, + "componentExportsMissingDirectTestCount": 20, "componentExportsMissingDirectDocsCount": 23, "unresolvedExportStarCount": 0 }, "exportStars": [ + { + "specifier": "./components/marketing", + "sourcePath": "src/components/marketing/index.ts", + "sourceExists": true + }, { "specifier": "./hooks/extended", "sourcePath": "src/hooks/extended/index.ts", @@ -106,7 +111,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": true, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -296,6 +301,23 @@ "hasDirectTest": false, "hasDirectDocs": false }, + { + "exportName": "AuraElementInteractionPlugin", + "importedName": "AuraElementInteractionPlugin", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/charts/plugins/GalileoElementInteractionPlugin", + "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", + "sourceExists": true, + "declarationPath": "dist/components/charts/plugins/GalileoElementInteractionPlugin.d.ts", + "declarationExists": true, + "inventoryName": null, + "hasInventoryEntry": false, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, { "exportName": "GalileoElementInteractionPlugin", "importedName": "GalileoElementInteractionPlugin", @@ -310,7 +332,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": true, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": true }, { @@ -412,7 +434,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": false, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -669,7 +691,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": false, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -742,23 +764,6 @@ } ], "componentExportsMissingDirectTest": [ - { - "exportName": "GlassAdvanced", - "importedName": "GlassAdvanced", - "kind": "value", - "isAlias": false, - "isComponentLike": true, - "specifier": "./primitives/glass/GlassAdvanced", - "sourcePath": "src/primitives/glass/GlassAdvanced.tsx", - "sourceExists": true, - "declarationPath": "dist/primitives/glass/GlassAdvanced.d.ts", - "declarationExists": true, - "inventoryName": null, - "hasInventoryEntry": false, - "hasDirectStory": true, - "hasDirectTest": false, - "hasDirectDocs": false - }, { "exportName": "OptimizedGlassAdvanced", "importedName": "OptimizedGlassAdvanced", @@ -946,23 +951,6 @@ "hasDirectTest": false, "hasDirectDocs": false }, - { - "exportName": "GalileoElementInteractionPlugin", - "importedName": "GalileoElementInteractionPlugin", - "kind": "value", - "isAlias": false, - "isComponentLike": true, - "specifier": "./components/charts/plugins/GalileoElementInteractionPlugin", - "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", - "sourceExists": true, - "declarationPath": "dist/components/charts/plugins/GalileoElementInteractionPlugin.d.ts", - "declarationExists": true, - "inventoryName": null, - "hasInventoryEntry": false, - "hasDirectStory": true, - "hasDirectTest": false, - "hasDirectDocs": true - }, { "exportName": "LivingEcosystemSimulator", "importedName": "LivingEcosystemSimulator", @@ -1048,23 +1036,6 @@ "hasDirectTest": false, "hasDirectDocs": false }, - { - "exportName": "MultiUserGlassEditor", - "importedName": "MultiUserGlassEditor", - "kind": "value", - "isAlias": false, - "isComponentLike": true, - "specifier": "./components/collaboration/MultiUserGlassEditor", - "sourcePath": "src/components/collaboration/MultiUserGlassEditor.tsx", - "sourceExists": true, - "declarationPath": "dist/components/collaboration/MultiUserGlassEditor.d.ts", - "declarationExists": true, - "inventoryName": null, - "hasInventoryEntry": false, - "hasDirectStory": false, - "hasDirectTest": false, - "hasDirectDocs": false - }, { "exportName": "ConsciousnessStreamProvider", "importedName": "ConsciousnessStreamProvider", @@ -1149,7 +1120,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": true, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -1438,7 +1409,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": false, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -1544,7 +1515,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": true, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -2550,6 +2521,210 @@ "hasDirectTest": true, "hasDirectDocs": true }, + { + "exportName": "GlassDropdownMenuCheckboxItem", + "importedName": "GlassDropdownMenuCheckboxItem", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuContent", + "importedName": "GlassDropdownMenuContent", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuItem", + "importedName": "GlassDropdownMenuItem", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuLabel", + "importedName": "GlassDropdownMenuLabel", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuRadioGroup", + "importedName": "GlassDropdownMenuRadioGroup", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuRadioItem", + "importedName": "GlassDropdownMenuRadioItem", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuSeparator", + "importedName": "GlassDropdownMenuSeparator", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuShortcut", + "importedName": "GlassDropdownMenuShortcut", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuSub", + "importedName": "GlassDropdownMenuSub", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuSubContent", + "importedName": "GlassDropdownMenuSubContent", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuSubTrigger", + "importedName": "GlassDropdownMenuSubTrigger", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassDropdownMenuTrigger", + "importedName": "GlassDropdownMenuTrigger", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/navigation/GlassDropdownMenu", + "sourcePath": "src/components/navigation/GlassDropdownMenu.tsx", + "sourceExists": true, + "declarationPath": "dist/components/navigation/GlassDropdownMenu.d.ts", + "declarationExists": true, + "inventoryName": "GlassDropdownMenu", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, { "exportName": "GlassHeader", "importedName": "GlassHeader", @@ -7905,6 +8080,23 @@ "hasDirectTest": true, "hasDirectDocs": true }, + { + "exportName": "AuraElementInteractionPlugin", + "importedName": "AuraElementInteractionPlugin", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/charts/plugins/GalileoElementInteractionPlugin", + "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", + "sourceExists": true, + "declarationPath": "dist/components/charts/plugins/GalileoElementInteractionPlugin.d.ts", + "declarationExists": true, + "inventoryName": null, + "hasInventoryEntry": false, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, { "exportName": "GalileoElementInteractionPlugin", "importedName": "GalileoElementInteractionPlugin", @@ -7919,7 +8111,41 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": true, - "hasDirectTest": false, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "AuraInteractionConfig", + "importedName": "AuraInteractionConfig", + "kind": "type", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/charts/plugins/GalileoElementInteractionPlugin", + "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", + "sourceExists": true, + "declarationPath": "dist/components/charts/plugins/GalileoElementInteractionPlugin.d.ts", + "declarationExists": true, + "inventoryName": null, + "hasInventoryEntry": false, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GalileoInteractionConfig", + "importedName": "GalileoInteractionConfig", + "kind": "type", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/charts/plugins/GalileoElementInteractionPlugin", + "sourcePath": "src/components/charts/plugins/GalileoElementInteractionPlugin.ts", + "sourceExists": true, + "declarationPath": "dist/components/charts/plugins/GalileoElementInteractionPlugin.d.ts", + "declarationExists": true, + "inventoryName": null, + "hasInventoryEntry": false, + "hasDirectStory": true, + "hasDirectTest": true, "hasDirectDocs": true }, { @@ -8552,8 +8778,8 @@ "hasDirectDocs": true }, { - "exportName": "GlassCollaborationProvider", - "importedName": "GlassCollaborationProvider", + "exportName": "GlassTeamCursors", + "importedName": "GlassTeamCursors", "kind": "value", "isAlias": false, "isComponentLike": true, @@ -8562,15 +8788,15 @@ "sourceExists": true, "declarationPath": "dist/components/collaboration/CollaborativeGlassWorkspace.d.ts", "declarationExists": true, - "inventoryName": "GlassCollaborationProvider", + "inventoryName": "CollaborativeGlassWorkspace", "hasInventoryEntry": true, "hasDirectStory": true, "hasDirectTest": true, "hasDirectDocs": true }, { - "exportName": "GlassTeamCursors", - "importedName": "GlassTeamCursors", + "exportName": "GlassTeamCursorsWithEffects", + "importedName": "GlassTeamCursorsWithEffects", "kind": "value", "isAlias": false, "isComponentLike": true, @@ -8586,17 +8812,119 @@ "hasDirectDocs": true }, { - "exportName": "GlassTeamCursorsWithEffects", - "importedName": "GlassTeamCursorsWithEffects", + "exportName": "CollaborationProvider", + "importedName": "CollaborationProvider", "kind": "value", "isAlias": false, "isComponentLike": true, - "specifier": "./components/collaboration/CollaborativeGlassWorkspace", - "sourcePath": "src/components/collaboration/CollaborativeGlassWorkspace.tsx", + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", "sourceExists": true, - "declarationPath": "dist/components/collaboration/CollaborativeGlassWorkspace.d.ts", + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", "declarationExists": true, - "inventoryName": "CollaborativeGlassWorkspace", + "inventoryName": "GlassCollaborationProvider", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "GlassCollaborationProvider", + "importedName": "GlassCollaborationProvider", + "kind": "value", + "isAlias": false, + "isComponentLike": true, + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "declarationExists": true, + "inventoryName": "GlassCollaborationProvider", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "useCollaboration", + "importedName": "useCollaboration", + "kind": "value", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "declarationExists": true, + "inventoryName": "GlassCollaborationProvider", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "CollaborationActivity", + "importedName": "CollaborationActivity", + "kind": "type", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "declarationExists": true, + "inventoryName": "GlassCollaborationProvider", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "CollaborationComment", + "importedName": "CollaborationComment", + "kind": "type", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "declarationExists": true, + "inventoryName": "GlassCollaborationProvider", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "CollaborationEdit", + "importedName": "CollaborationEdit", + "kind": "type", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "declarationExists": true, + "inventoryName": "GlassCollaborationProvider", + "hasInventoryEntry": true, + "hasDirectStory": true, + "hasDirectTest": true, + "hasDirectDocs": true + }, + { + "exportName": "CollaborationUser", + "importedName": "CollaborationUser", + "kind": "type", + "isAlias": false, + "isComponentLike": false, + "specifier": "./components/collaboration/GlassCollaborationProvider", + "sourcePath": "src/components/collaboration/GlassCollaborationProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/components/collaboration/GlassCollaborationProvider.d.ts", + "declarationExists": true, + "inventoryName": "GlassCollaborationProvider", "hasInventoryEntry": true, "hasDirectStory": true, "hasDirectTest": true, @@ -8667,7 +8995,7 @@ "inventoryName": null, "hasInventoryEntry": false, "hasDirectStory": false, - "hasDirectTest": false, + "hasDirectTest": true, "hasDirectDocs": false }, { @@ -10727,6 +11055,23 @@ "hasDirectTest": false, "hasDirectDocs": false }, + { + "exportName": "usePersonaTheme", + "importedName": "usePersonaTheme", + "kind": "value", + "isAlias": false, + "isComponentLike": false, + "specifier": "./theme/ThemeProvider", + "sourcePath": "src/theme/ThemeProvider.tsx", + "sourceExists": true, + "declarationPath": "dist/theme/ThemeProvider.d.ts", + "declarationExists": true, + "inventoryName": null, + "hasInventoryEntry": false, + "hasDirectStory": false, + "hasDirectTest": true, + "hasDirectDocs": false + }, { "exportName": "useThemeProviderPresence", "importedName": "useThemeProviderPresence", diff --git a/reports/public-export-audit.md b/reports/public-export-audit.md index 637f5fdb0..c4c1511b0 100644 --- a/reports/public-export-audit.md +++ b/reports/public-export-audit.md @@ -1,20 +1,20 @@ # Public Export Audit -Generated: 2026-05-07T16:45:39.971Z +Generated: 2026-05-12T19:21:54.118Z ## Summary -- Root named exports: 797 -- Value exports: 642 -- Type exports: 149 +- Root named exports: 819 +- Value exports: 658 +- Type exports: 155 - Const exports: 6 -- Export-star declarations: 14 -- Component-like value exports: 421 +- Export-star declarations: 15 +- Component-like value exports: 435 - Missing source files: 0 - Missing declaration files: 0 -- Component-like exports missing inventory entries: 23 +- Component-like exports missing inventory entries: 24 - Component-like exports missing direct Storybook stories: 15 -- Component-like exports missing direct unit tests: 23 +- Component-like exports missing direct unit tests: 20 - Component-like exports missing direct docs: 23 - Unresolved export-star declarations: 0 @@ -40,6 +40,7 @@ Generated: 2026-05-07T16:45:39.971Z - PersonaPicker (src/components/theme/PersonaPicker.tsx) - NeuralWeightVisualization (src/components/ai/NeuralWeightVisualization.tsx) - NeuromorphicLearningNetwork (src/components/ai/NeuromorphicLearningNetwork.tsx) +- AuraElementInteractionPlugin (src/components/charts/plugins/GalileoElementInteractionPlugin.ts) - GalileoElementInteractionPlugin (src/components/charts/plugins/GalileoElementInteractionPlugin.ts) - LivingEcosystemSimulator (src/components/advanced/LivingEcosystemSimulator.tsx) - MolecularBondingInterface (src/components/advanced/MolecularBondingInterface.tsx) @@ -47,8 +48,7 @@ Generated: 2026-05-07T16:45:39.971Z - QuantumEntanglementVisualizer (src/components/quantum/QuantumEntanglementVisualizer.tsx) - QuantumNeuromorphicEngine (src/components/quantum/QuantumNeuromorphicEngine.ts) - MultiUserGlassEditor (src/components/collaboration/MultiUserGlassEditor.tsx) -- ConsciousnessStreamProvider (src/contexts/ConsciousnessStreamProvider.tsx) -- ... 3 more +- ... 4 more ## Component-Like Exports Missing Direct Storybook Stories @@ -70,7 +70,6 @@ Generated: 2026-05-07T16:45:39.971Z ## Component-Like Exports Missing Direct Unit Tests -- GlassAdvanced (src/primitives/glass/GlassAdvanced.tsx) - OptimizedGlassAdvanced (src/primitives/glass/OptimizedGlassAdvanced.tsx) - Glass (src/primitives/GlassCore.tsx) - GlassPrimitive (src/primitives/GlassCore.tsx) @@ -82,15 +81,15 @@ Generated: 2026-05-07T16:45:39.971Z - PersonaPicker (src/components/theme/PersonaPicker.tsx) - NeuralWeightVisualization (src/components/ai/NeuralWeightVisualization.tsx) - NeuromorphicLearningNetwork (src/components/ai/NeuromorphicLearningNetwork.tsx) -- GalileoElementInteractionPlugin (src/components/charts/plugins/GalileoElementInteractionPlugin.ts) - LivingEcosystemSimulator (src/components/advanced/LivingEcosystemSimulator.tsx) - MolecularBondingInterface (src/components/advanced/MolecularBondingInterface.tsx) - MultiDimensionalGestureRecognizer (src/components/advanced/MultiDimensionalGestureRecognizer.tsx) - QuantumEntanglementVisualizer (src/components/quantum/QuantumEntanglementVisualizer.tsx) - QuantumNeuromorphicEngine (src/components/quantum/QuantumNeuromorphicEngine.ts) -- MultiUserGlassEditor (src/components/collaboration/MultiUserGlassEditor.tsx) - ConsciousnessStreamProvider (src/contexts/ConsciousnessStreamProvider.tsx) -- ... 3 more +- AnimationProvider (src/contexts/AnimationContext.tsx) +- MotionPreferenceProvider (src/contexts/MotionPreferenceContext.tsx) +- AuraGlassClientBoundary (src/components/ssr/AuraGlassClientBoundary.tsx) ## Component-Like Exports Missing Direct Docs diff --git a/reports/runtime-cleanliness-audit.json b/reports/runtime-cleanliness-audit.json index 7b3f27dbc..05780f37c 100644 --- a/reports/runtime-cleanliness-audit.json +++ b/reports/runtime-cleanliness-audit.json @@ -1,9 +1,9 @@ { "objective": "Audit production-source runtime cleanliness for console calls, debugger statements, and TODO/FIXME/XXX markers.", "summary": { - "generatedAt": "2026-05-07T16:45:09.257Z", + "generatedAt": "2026-05-12T19:21:54.122Z", "scannedRoot": "src", - "scannedFileCount": 660, + "scannedFileCount": 671, "findingCount": 0, "fileWithFindingsCount": 0, "consoleFindingCount": 0, diff --git a/reports/runtime-cleanliness-audit.md b/reports/runtime-cleanliness-audit.md index 11b39456b..0c328fdc8 100644 --- a/reports/runtime-cleanliness-audit.md +++ b/reports/runtime-cleanliness-audit.md @@ -1,11 +1,11 @@ # Runtime Cleanliness Audit -Generated: 2026-05-07T16:45:09.257Z +Generated: 2026-05-12T19:21:54.122Z ## Summary - Scanned root: src -- Scanned files: 660 +- Scanned files: 671 - Files with findings: 0 - Total findings: 0 - Console findings: 0 diff --git a/scripts/audit/3.1-frame-loop-audit.js b/scripts/audit/3.1-frame-loop-audit.js new file mode 100644 index 000000000..3577fd2d8 --- /dev/null +++ b/scripts/audit/3.1-frame-loop-audit.js @@ -0,0 +1,359 @@ +#!/usr/bin/env node + +const fs = require('node:fs'); +const path = require('node:path'); + +const root = process.cwd(); +const srcRoot = path.join(root, 'src'); +const reportDir = path.join(root, 'reports/3.1-release'); +const reportJsonPath = path.join(reportDir, 'frame-loop-canvas-audit.json'); +const reportMdPath = path.join(reportDir, 'frame-loop-canvas-audit.md'); +const strict = process.argv.includes('--strict'); + +const excludedPathParts = [ + `${path.sep}__snapshots__${path.sep}`, + `${path.sep}docs${path.sep}`, + `${path.sep}scripts${path.sep}`, +]; + +const excludedBasenames = new Set([ + 'testSetup.ts', + 'testSetup.tsx', + 'testingUtils.ts', + 'testingUtils.tsx', +]); + +const categoryPatterns = { + frameLoop: [ + /\brequestAnimationFrame\b/g, + /\bcancelAnimationFrame\b/g, + /\bsetAnimationLoop\b/g, + /\buseFrame\s*\(/g, + ], + canvas: [ + / { + if (!/\.[cm]?[jt]sx?$/.test(filePath)) return false; + if (/\.(test|spec|stories)\.[cm]?[jt]sx?$/.test(filePath)) return false; + if (excludedBasenames.has(path.basename(filePath))) return false; + return !excludedPathParts.some((part) => filePath.includes(part)); +}; + +const walk = (dir, out = []) => { + if (!fs.existsSync(dir)) return out; + + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walk(fullPath, out); + continue; + } + if (shouldScanFile(fullPath)) out.push(fullPath); + } + + return out; +}; + +const stripComments = (source) => + source + .replace(/\/\*[\s\S]*?\*\//g, '') + .replace(/(^|[^:])\/\/.*$/gm, '$1'); + +const lineForIndex = (source, index) => source.slice(0, index).split(/\r?\n/).length; + +const lineText = (source, line) => source.split(/\r?\n/)[line - 1]?.trim().slice(0, 220) || ''; + +const countBy = (values, keyForValue) => { + const counts = new Map(); + for (const value of values) { + const key = keyForValue(value); + counts.set(key, (counts.get(key) || 0) + 1); + } + return Object.fromEntries( + [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) + ); +}; + +const collectMatches = (source, patterns) => { + const matches = []; + + for (const regex of patterns) { + regex.lastIndex = 0; + for (const match of source.matchAll(regex)) { + matches.push({ + pattern: regex.source, + token: match[0], + line: lineForIndex(source, match.index || 0), + }); + } + } + + return matches.sort((a, b) => a.line - b.line || a.token.localeCompare(b.token)); +}; + +const collectGuardMatches = (source) => + guardTerms + .map(({ term, regex }) => { + regex.lastIndex = 0; + const matches = [...source.matchAll(regex)]; + return matches.length > 0 + ? { + term, + count: matches.length, + firstLine: lineForIndex(source, matches[0].index || 0), + } + : null; + }) + .filter(Boolean); + +const sourceFiles = walk(srcRoot).sort(); +const filesWithSignals = []; +const findings = []; +const categoryTotals = Object.fromEntries(Object.keys(categoryPatterns).map((category) => [category, 0])); + +for (const absolutePath of sourceFiles) { + const relativePath = path.relative(root, absolutePath); + const rawSource = fs.readFileSync(absolutePath, 'utf8'); + const source = stripComments(rawSource); + const categories = {}; + const signals = []; + + for (const [category, patterns] of Object.entries(categoryPatterns)) { + const matches = collectMatches(source, patterns); + if (matches.length === 0) continue; + + categories[category] = { + count: matches.length, + firstLine: matches[0].line, + tokens: [...new Set(matches.map((match) => match.token))].sort(), + }; + categoryTotals[category] += matches.length; + + matches.slice(0, 20).forEach((match) => { + signals.push({ + category, + token: match.token, + line: match.line, + excerpt: lineText(source, match.line), + }); + }); + } + + if (Object.keys(categories).length === 0) continue; + + const guardMatches = collectGuardMatches(source); + const isComponentFile = + relativePath.startsWith(`src${path.sep}components${path.sep}`) && relativePath.endsWith('.tsx'); + const highCostCategories = ['frameLoop', 'readback', 'audioAnalyser', 'webgl'].filter( + (category) => categories[category] + ); + const hasCanvasOnly = categories.canvas && highCostCategories.length === 0; + const missingGuard = isComponentFile && highCostCategories.length > 0 && guardMatches.length === 0; + const severity = + missingGuard || categories.readback + ? 'review-required' + : hasCanvasOnly + ? 'inventory' + : 'guarded-or-explicit'; + + const fileRecord = { + filePath: relativePath, + isComponentFile, + severity, + categories, + guardTerms: guardMatches, + signals, + }; + + filesWithSignals.push(fileRecord); + + if (missingGuard) { + findings.push({ + severity: 'review-required', + issue: 'missing-animation-or-motion-guard', + filePath: relativePath, + categories: highCostCategories, + line: Math.min(...highCostCategories.map((category) => categories[category].firstLine)), + note: + 'Component uses frame-loop, readback, audio analyser, or WebGL signals without obvious reduced-motion or explicit animation guard terms.', + }); + } + + if (categories.readback) { + findings.push({ + severity: 'review-required', + issue: 'canvas-or-gpu-readback-review', + filePath: relativePath, + categories: ['readback'], + line: categories.readback.firstLine, + note: + 'Readbacks can block rendering if used per-frame. Verify they are user-triggered, export-only, setup-only, or otherwise throttled.', + }); + } +} + +const summary = { + generatedAt: new Date().toISOString(), + scannedRoot: 'src', + scannedFileCount: sourceFiles.length, + filesWithSignalsCount: filesWithSignals.length, + componentFilesWithSignalsCount: filesWithSignals.filter((file) => file.isComponentFile).length, + reviewRequiredFileCount: new Set(findings.map((finding) => finding.filePath)).size, + findingCount: findings.length, + strict, + categoryTotals, + filesBySeverity: countBy(filesWithSignals, (file) => file.severity), + findingsByIssue: countBy(findings, (finding) => finding.issue), +}; + +const report = { + objective: + 'AuraGlass 3.1 release-candidate audit for frame loops, canvas, readbacks, audio analysers, WebGL, and obvious reduced-motion or animation guard terms.', + summary, + strict, + guardTerms: guardTerms.map(({ term }) => term), + exclusions: { + fileGlobs: ['*.stories.*', '*.test.*', '*.spec.*', '**/__snapshots__/**', 'src/docs/**', 'src/scripts/**'], + basenames: [...excludedBasenames].sort(), + }, + findings, + filesWithSignals, +}; + +const formatCategoryTotals = () => + Object.entries(summary.categoryTotals) + .map(([category, count]) => `- ${category}: ${count}`) + .join('\n'); + +const formatFindings = (limit = 80) => { + if (findings.length === 0) return '- None\n'; + + return findings + .slice(0, limit) + .map( + (finding) => + `- ${finding.severity}: ${finding.issue} at ${finding.filePath}:${finding.line} (${finding.categories.join( + ', ' + )}) - ${finding.note}` + ) + .join('\n') + .concat(findings.length > limit ? `\n- ... ${findings.length - limit} more\n` : '\n'); +}; + +const formatInventory = (limit = 120) => { + if (filesWithSignals.length === 0) return '- None\n'; + + return filesWithSignals + .slice(0, limit) + .map((file) => { + const categorySummary = Object.entries(file.categories) + .map(([category, data]) => `${category}:${data.count}`) + .join(', '); + const guardSummary = + file.guardTerms.length > 0 + ? file.guardTerms.map((guard) => `${guard.term}:${guard.count}`).join(', ') + : 'none'; + return `- ${file.severity}: ${file.filePath} - ${categorySummary}; guards: ${guardSummary}`; + }) + .join('\n') + .concat(filesWithSignals.length > limit ? `\n- ... ${filesWithSignals.length - limit} more\n` : '\n'); +}; + +const markdown = `# 3.1 Frame Loop, Canvas, Audio, and WebGL Audit + +Generated: ${summary.generatedAt} + +## Summary + +- Scanned root: ${summary.scannedRoot} +- Scanned files: ${summary.scannedFileCount} +- Files with frame/canvas/audio/WebGL signals: ${summary.filesWithSignalsCount} +- Component files with signals: ${summary.componentFilesWithSignalsCount} +- Review-required files: ${summary.reviewRequiredFileCount} +- Findings: ${summary.findingCount} +- Strict mode: ${strict ? 'yes' : 'no'} + +## Category Totals + +${formatCategoryTotals()} + +## Findings + +${formatFindings()} +## Inventory + +${formatInventory()} +## Gate Notes + +- This is a source audit gate for 3.1 release-candidate evidence. +- Default mode is report-only so release owners can inventory risk without blocking unrelated work. +- Run \`npm run audit:3.1-frame-loop:strict\` to fail on review-required findings. +- A file is flagged when a production component has frame-loop, readback, audio analyser, or WebGL signals and lacks obvious reduced-motion or explicit animation guard terms. +`; + +fs.mkdirSync(reportDir, { recursive: true }); +fs.writeFileSync(reportJsonPath, `${JSON.stringify(report, null, 2)}\n`); +fs.writeFileSync(reportMdPath, markdown); + +console.log(`3.1 frame-loop/canvas audit written to ${path.relative(root, reportJsonPath)}`); +console.log(`Markdown summary written to ${path.relative(root, reportMdPath)}`); +console.log(JSON.stringify(summary, null, 2)); + +if (strict && findings.length > 0) { + process.exit(1); +} diff --git a/scripts/build-all.js b/scripts/build-all.js index 352b3d725..d78370f69 100755 --- a/scripts/build-all.js +++ b/scripts/build-all.js @@ -86,11 +86,16 @@ const entrypoints = [ const esmSubpathEntrypoints = [ ['src/core/mixins/glassMixins.ts', 'dist/esm/core/mixins/glassMixins.js'], ['src/utils/env.ts', 'dist/esm/utils/env.js'], + ['src/hooks/useGlassProbes.ts', 'dist/esm/hooks/useGlassProbes.js'], ['src/services/ai/openai-service.ts', 'dist/esm/services/ai/openai-service.js'], ['src/services/ai/vision-service.ts', 'dist/esm/services/ai/vision-service.js'], ['src/services/websocket/collaboration-service.ts', 'dist/esm/services/websocket/collaboration-service.js'], ]; +const cjsSubpathEntrypoints = [ + ['src/hooks/useGlassProbes.ts', 'dist/cjs/hooks/useGlassProbes.js'], +]; + require('node:fs').rmSync(distDir, { recursive: true, force: true }); run(nodeBin, [path.resolve(projectRoot, 'scripts', 'build-workers.js')], { @@ -160,6 +165,15 @@ for (const [entryPoint, outputFile] of esmSubpathEntrypoints) { }); } +for (const [entryPoint, outputFile] of cjsSubpathEntrypoints) { + esbuild.buildSync({ + ...sharedBuildOptions, + entryPoints: [path.resolve(projectRoot, entryPoint)], + outfile: path.resolve(projectRoot, outputFile), + format: 'cjs', + }); +} + fs.writeFileSync( path.resolve(projectRoot, 'dist/esm/package.json'), `${JSON.stringify({ type: 'module' }, null, 2)}\n`, diff --git a/scripts/ci/README.md b/scripts/ci/README.md index 4e5f6617c..348728b24 100644 --- a/scripts/ci/README.md +++ b/scripts/ci/README.md @@ -1,4 +1,4 @@ -# AuraGlass CI Scripts +# AuraGlass by AuraOne CI Scripts This directory contains automated enforcement tools for maintaining design system compliance and ensuring a 100/100 design system score. diff --git a/scripts/ci/verify-cli.js b/scripts/ci/verify-cli.js new file mode 100644 index 000000000..674d95edc --- /dev/null +++ b/scripts/ci/verify-cli.js @@ -0,0 +1,67 @@ +#!/usr/bin/env node + +const assert = require("node:assert/strict"); +const { spawnSync } = require("node:child_process"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); + +const projectRoot = path.resolve(__dirname, "..", ".."); +const cliPath = path.join(projectRoot, "bin", "aura-glass.cjs"); + +const runCli = (args, options = {}) => { + const result = spawnSync(process.execPath, [cliPath, ...args], { + cwd: options.cwd ?? projectRoot, + encoding: "utf8", + }); + + if (result.status !== 0) { + throw new Error( + `aura-glass ${args.join(" ")} failed\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}` + ); + } + + return result.stdout; +}; + +const recipes = JSON.parse(runCli(["list", "--json"])); +assert.ok(recipes.length >= 10, "CLI should expose the launch recipe registry"); +assert.ok( + recipes.some((recipe) => recipe.id === "saas-dashboard"), + "saas-dashboard should be listed" +); +assert.ok( + recipes.every((recipe) => Array.isArray(recipe.imports) && recipe.imports.length > 0), + "each recipe should list public AuraGlass imports" +); + +const info = JSON.parse(runCli(["info", "ai-command-center", "--json"])); +assert.equal(info.id, "ai-command-center"); +assert.ok( + info.files[0].content.includes("import 'aura-glass/styles';"), + "recipe files should include the canonical CSS import" +); + +const dryRun = JSON.parse(runCli(["add", "media-player-surface", "--dry-run", "--json"])); +assert.equal(dryRun[0].recipe, "media-player-surface"); +assert.equal(dryRun[0].written[0].path, "src/components/auraglass/recipes/MediaPlayerSurface.tsx"); + +const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "auraglass-cli-")); +const writeResult = JSON.parse( + runCli(["add", "settings-billing", "--cwd", tempDir, "--json"]) +); +assert.equal(writeResult[0].recipe, "settings-billing"); + +const outputPath = path.join( + tempDir, + "src", + "components", + "auraglass", + "recipes", + "SettingsBillingPage.tsx" +); +const output = fs.readFileSync(outputPath, "utf8"); +assert.ok(output.includes("GlassForm"), "generated recipe should contain AuraGlass imports"); +assert.ok(output.includes("aura-glass/styles"), "generated recipe should include styles"); + +console.log("[verify-cli] AuraGlass CLI registry checks passed"); diff --git a/scripts/ci/verify-pack.js b/scripts/ci/verify-pack.js index 9be925983..dd53b6124 100755 --- a/scripts/ci/verify-pack.js +++ b/scripts/ci/verify-pack.js @@ -66,6 +66,68 @@ const collectExportTypePaths = (exportsField) => { return typePaths; }; +const runInstallSmoke = (tarballPath, tmpRoot) => { + const smokeRoot = path.join(tmpRoot, 'install-smoke'); + fs.mkdirSync(smokeRoot, { recursive: true }); + + fs.writeFileSync( + path.join(smokeRoot, 'package.json'), + `${JSON.stringify( + { + private: true, + type: 'module', + }, + null, + 2 + )}\n` + ); + + run(`npm install --dry-run=false --ignore-scripts --no-audit --no-fund ${JSON.stringify(tarballPath)}`, { + cwd: smokeRoot, + env: { + ...process.env, + npm_config_dry_run: 'false', + }, + }); + + const smokeScriptPath = path.join(smokeRoot, 'root-import-smoke.mjs'); + fs.writeFileSync( + smokeScriptPath, + `import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { GlassButton, GlassCard } from 'aura-glass'; +import { auraGlassRecipes } from 'aura-glass/registry'; + +const require = createRequire(import.meta.url); +const isComponentLike = (value) => typeof value === 'function' || (value && typeof value === 'object'); + +assert.ok(isComponentLike(GlassButton), 'GlassButton should import from aura-glass root'); +assert.ok(isComponentLike(GlassCard), 'GlassCard should import from aura-glass root'); +assert.ok(Array.isArray(auraGlassRecipes), 'aura-glass/registry should expose recipe metadata'); +assert.ok(auraGlassRecipes.length >= 7, 'aura-glass/registry should expose launch recipes'); + +const stylesPath = require.resolve('aura-glass/styles'); +assert.ok( + /dist[\\\\/]styles[\\\\/]index\\.css$/.test(stylesPath), + 'aura-glass/styles should resolve to dist/styles/index.css' +); + +const styles = readFileSync(stylesPath, 'utf8'); +assert.ok(styles.length > 0, 'aura-glass/styles should resolve to non-empty CSS'); + +const cliPath = require.resolve('aura-glass/package.json').replace(/package\\.json$/, 'bin/aura-glass.cjs'); +assert.ok(readFileSync(cliPath, 'utf8').startsWith('#!/usr/bin/env node'), 'aura-glass CLI bin should be packed'); + +console.log('✅ install smoke clean: root imports, registry recipes, CLI bin, and styles export resolve.'); +` + ); + + run(`node ${JSON.stringify(smokeScriptPath)}`, { cwd: smokeRoot }); + run(`npx aura-glass list --json`, { cwd: smokeRoot }); + console.log('✅ install smoke clean: root imports, registry recipes, CLI bin, and styles export resolve.'); +}; + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'auraglass-pack-')); try { @@ -159,6 +221,8 @@ try { process.exit(1); } + runInstallSmoke(tarballPath, tmpRoot); + const files = walkFiles(distRoot); const dispatcherHits = []; let reactRequireCount = 0; diff --git a/server/README.md b/server/README.md index 636724073..25842cf20 100644 --- a/server/README.md +++ b/server/README.md @@ -1,6 +1,6 @@ -# AuraGlass Backend Server +# AuraGlass by AuraOne Backend Server -Production-ready AI infrastructure for AuraGlass components. +Production-ready AI infrastructure for AuraGlass by AuraOne components. ## Overview diff --git a/src/components/ai/GlassMusicVisualizer.tsx b/src/components/ai/GlassMusicVisualizer.tsx index 256476336..afc2de461 100644 --- a/src/components/ai/GlassMusicVisualizer.tsx +++ b/src/components/ai/GlassMusicVisualizer.tsx @@ -355,13 +355,15 @@ export const GlassMusicVisualizer = forwardRef< break; } - if (realTimeAnalysis && isPlaying) { + if (realTimeAnalysis && isPlaying && shouldAnimate && !prefersReducedMotion) { animationFrameRef.current = requestAnimationFrame(renderVisualization); } }, [ visualConfig, realTimeAnalysis, isPlaying, + shouldAnimate, + prefersReducedMotion, detectBeat, onFrequencyData, ]); @@ -611,13 +613,15 @@ export const GlassMusicVisualizer = forwardRef< try { await audioRef.current.play(); setIsPlaying(true); - renderVisualization(); + if (shouldAnimate && !prefersReducedMotion) { + renderVisualization(); + } play("play"); } catch { setIsPlaying(false); } } - }, [initializeAudio, renderVisualization, play]); + }, [initializeAudio, renderVisualization, play, shouldAnimate, prefersReducedMotion]); const handlePause = useCallback(() => { if (audioRef.current) { diff --git a/src/components/data-display/GlassKanbanBoard.test.tsx b/src/components/data-display/GlassKanbanBoard.test.tsx index 44c5bb9d0..6d1bc336c 100644 --- a/src/components/data-display/GlassKanbanBoard.test.tsx +++ b/src/components/data-display/GlassKanbanBoard.test.tsx @@ -141,4 +141,27 @@ describe('GlassKanbanBoard', () => { const { container } = render(); expect(container.firstChild).toMatchSnapshot(); }); -}); \ No newline at end of file + + it('supports contained compact rendering without header or actions', () => { + const { container } = render( + + ); + + const board = screen.getByTestId('contained-kanban'); + expect(board).toHaveStyle({ width: '360px', height: '260px', maxHeight: '260px' }); + expect(screen.queryByText('Launch board')).not.toBeInTheDocument(); + expect(container.querySelector('[aria-label^="Add card to"]')).not.toBeInTheDocument(); + expect(container.querySelector('[aria-label="Add new column"]')).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/data-display/GlassKanbanBoard.tsx b/src/components/data-display/GlassKanbanBoard.tsx index b796a7a42..c78a7277d 100644 --- a/src/components/data-display/GlassKanbanBoard.tsx +++ b/src/components/data-display/GlassKanbanBoard.tsx @@ -74,6 +74,18 @@ export interface GlassKanbanBoardProps maxHeight?: string | number; /** Compact rendering for embedded previews and narrow containers */ compact?: boolean; + /** Contain the board in its parent without full-page sizing assumptions */ + contained?: boolean; + /** Explicit board width */ + width?: string | number; + /** Explicit board height */ + height?: string | number; + /** Show the board title and description header */ + showHeader?: boolean; + /** Show column-level toolbar controls such as add/delete */ + showToolbar?: boolean; + /** Show add-card/add-column actions */ + showActions?: boolean; /** Custom card renderer */ renderCard?: (card: KanbanCard, columnId: string) => React.ReactNode; /** Custom column header renderer */ @@ -176,6 +188,12 @@ export const GlassKanbanBoard = forwardRef< columnWidth = "300px", maxHeight, compact = false, + contained = false, + width, + height, + showHeader = true, + showToolbar = true, + showActions = true, renderCard, renderColumnHeader, onCardMove, @@ -192,6 +210,7 @@ export const GlassKanbanBoard = forwardRef< emptyState, respectMotionPreference = true, className, + style, "aria-label": ariaLabel, "data-testid": dataTestId, ...props @@ -243,6 +262,10 @@ export const GlassKanbanBoard = forwardRef< const config = cardSizeConfig[cardSize]; const boardColumns = columns.length === 0 && !emptyState ? DEFAULT_KANBAN_COLUMNS : columns; + const effectiveShowAddColumn = showActions && showAddColumn; + const effectiveShowAddCard = showActions && showAddCard; + const effectiveColumnWidth = + contained && compact && columnWidth === "300px" ? "180px" : columnWidth; // Priority colors const priorityColors = { @@ -591,8 +614,9 @@ export const GlassKanbanBoard = forwardRef< )}

+ {showToolbar && (
- {showAddCard && !column.readOnly && ( + {effectiveShowAddCard && !column.readOnly && ( )} - {onColumnDelete && ( + {showActions && onColumnDelete && ( )}
+ )}
); }, [ showCardCounts, showColumnLimits, - showAddCard, + effectiveShowAddCard, + showActions, + showToolbar, onCardAdd, onColumnDelete, isCompact, @@ -668,8 +695,12 @@ export const GlassKanbanBoard = forwardRef< )} style={{ ...(maxHeightStyle ?? {}), + width, + height, overflow: "hidden", + maxWidth: contained ? "100%" : undefined, color: "rgba(248,250,252,0.94)", + ...style, }} role="region" aria-label={ariaLabel || "Kanban Board"} @@ -683,14 +714,23 @@ export const GlassKanbanBoard = forwardRef< className="glass-flex glass-flex-col glass-h-full" > {/* Board Header */} - {(title || description) && ( -
+ {showHeader && (title || description) && ( +
{title && ( -

+

{title}

)} - {description && ( + {description && !isCompact && (

{description}

)}
@@ -736,9 +776,9 @@ export const GlassKanbanBoard = forwardRef< "ring-2 ring-primary/50" )} style={{ - width: columnWidth, - minWidth: columnWidth, - maxWidth: columnWidth, + width: effectiveColumnWidth, + minWidth: effectiveColumnWidth, + maxWidth: effectiveColumnWidth, overflow: "hidden", }} onDragOver={(e: React.DragEvent) => @@ -834,7 +874,7 @@ export const GlassKanbanBoard = forwardRef< ))} {/* Add Column Button */} - {showAddColumn && onColumnAdd && ( + {effectiveShowAddColumn && onColumnAdd && ( { + const StandaloneHookProbe = () => { + const { images, autoOptimize, getOptimizationStats } = useImageProcessing(); + const stats = getOptimizationStats(); + + return ( +
+ {images.length} + {String(autoOptimize)} + {stats.imagesProcessed} +
+ ); + }; + /** * Smoke Test: Component renders without crashing */ @@ -33,6 +49,14 @@ describe("GlassImageProcessingProvider", () => { expect(container).toBeInTheDocument(); }); + it("provides a default no-op hook context outside the provider", () => { + render(); + + expect(screen.getByTestId("image-count")).toHaveTextContent("0"); + expect(screen.getByTestId("auto-optimize")).toHaveTextContent("false"); + expect(screen.getByTestId("processed-count")).toHaveTextContent("0"); + }); + /** * Accessibility Test: No axe violations */ diff --git a/src/components/image/GlassImageProcessingProvider.tsx b/src/components/image/GlassImageProcessingProvider.tsx index 683e55ab2..a06eedf8f 100644 --- a/src/components/image/GlassImageProcessingProvider.tsx +++ b/src/components/image/GlassImageProcessingProvider.tsx @@ -255,6 +255,79 @@ interface ImageProcessingContextValue { const ImageProcessingContext = createContext(null); +const defaultImageOptimizations: OptimizationOptions = { + quality: 85, + format: "auto", + removeMetadata: true, + progressive: true, +}; + +const defaultOptimizationStats = { + totalSaved: 0, + averageReduction: 0, + imagesProcessed: 0, + mostUsedFormat: "N/A", +}; + +const emptyCloudUrls: CloudUrls = { + original: "", + optimized: "", + thumbnail: "", + responsive: { + small: "", + medium: "", + large: "", + xlarge: "", + }, +}; + +const createStandaloneFile = (name: string, type = "image/png"): File => { + if (typeof File === "undefined") { + return { name, size: 0, type } as File; + } + + return new File([], name, { type }); +}; + +const createStandaloneImage = ( + imageId: string, + file: File = createStandaloneFile(`${imageId}.png`) +): ImageFile => { + const type = file.type || "image/png"; + const name = file.name || `${imageId}.png`; + + return { + id: imageId, + file, + name, + originalName: name, + size: file.size || 0, + type, + width: 0, + height: 0, + aspectRatio: 0, + url: "", + uploadedAt: new Date(0), + editHistory: [], + metadata: { + format: type.split("/")[1] || "unknown", + quality: 100, + colorSpace: "sRGB", + hasAlpha: type.includes("png"), + dominantColors: [], + brightness: 0, + contrast: 0, + saturation: 0, + sharpness: 0, + fileSize: file.size || 0, + }, + tags: [], + }; +}; + +const standaloneOperation = async (imageId: string): Promise => + createStandaloneImage(imageId); + // Default templates for common use cases const defaultTemplates: Template[] = [ // Social Media @@ -337,6 +410,62 @@ const defaultTemplates: Template[] = [ }, ]; +const defaultImageProcessingContext: ImageProcessingContextValue = { + images: [], + addImage: async (file) => createStandaloneImage("standalone-image", file), + addImages: async (files) => + Array.from(files) + .filter((file) => file.type.startsWith("image/")) + .map((file, index) => + createStandaloneImage(`standalone-image-${index}`, file) + ), + removeImage: () => {}, + getImage: () => undefined, + updateImage: () => {}, + optimizeImage: standaloneOperation, + batchOptimize: async (imageIds) => + imageIds.map((id) => createStandaloneImage(id)), + cropImage: standaloneOperation, + resizeImage: standaloneOperation, + applyFilter: standaloneOperation, + rotateImage: standaloneOperation, + addWatermark: standaloneOperation, + detectFaces: async () => [], + removeBackground: standaloneOperation, + replaceBackground: standaloneOperation, + smartCrop: standaloneOperation, + enhanceImage: standaloneOperation, + upscaleImage: standaloneOperation, + batchResize: async (imageIds) => + imageIds.map((id) => createStandaloneImage(id)), + batchFilter: async (imageIds) => + imageIds.map((id) => createStandaloneImage(id)), + batchWatermark: async (imageIds) => + imageIds.map((id) => createStandaloneImage(id)), + uploadToCloud: async () => emptyCloudUrls, + generateResponsiveImages: async () => emptyCloudUrls, + templates: defaultTemplates, + applyTemplate: standaloneOperation, + createCustomTemplate: (template) => ({ + ...template, + id: "standalone-template", + }), + getOptimizationStats: () => defaultOptimizationStats, + getImageInsights: () => ({ + colorPalette: [], + dominantColor: "var(--glass-black)", + brightness: 0, + complexity: 0, + recommendedFormats: [], + }), + uploadProgresses: [], + clearProgress: () => {}, + defaultOptimizations: defaultImageOptimizations, + setDefaultOptimizations: () => {}, + autoOptimize: false, + setAutoOptimize: () => {}, +}; + // Mock AI image processing functions const mockImageProcessor = { async analyzeImage(imageUrl: string): Promise> { @@ -1291,10 +1420,5 @@ export { ImageProcessingProvider as GlassImageProcessingProvider }; export const useImageProcessing = () => { const context = useContext(ImageProcessingContext); - if (!context) { - throw new Error( - "useImageProcessing must be used within an ImageProcessingProvider" - ); - } - return context; + return context ?? defaultImageProcessingContext; }; diff --git a/src/components/image/GlassIntelligentImageUploader.test.tsx b/src/components/image/GlassIntelligentImageUploader.test.tsx index 5f6158fc6..64d081a32 100644 --- a/src/components/image/GlassIntelligentImageUploader.test.tsx +++ b/src/components/image/GlassIntelligentImageUploader.test.tsx @@ -37,6 +37,12 @@ describe("GlassIntelligentImageUploader", () => { expect(container).toBeInTheDocument(); }); + it("renders without an ImageProcessingProvider for standalone previews", () => { + const { container } = render(); + expect(container).toBeInTheDocument(); + expect(screen.getByText(/Intelligent Image Uploader/)).toBeInTheDocument(); + }); + /** * Accessibility Test: No axe violations */ diff --git a/src/components/interactive/GlassCommandPalette.test.tsx b/src/components/interactive/GlassCommandPalette.test.tsx index 7187808a0..52460a1b6 100644 --- a/src/components/interactive/GlassCommandPalette.test.tsx +++ b/src/components/interactive/GlassCommandPalette.test.tsx @@ -103,6 +103,41 @@ describe("GlassCommandPalette", () => { expect(element).toHaveClass("custom-class"); }); + it("supports contained inline rendering without viewport overlay semantics", () => { + const { container } = render( +
+ +
+ ); + + const root = container.querySelector('[data-glass-component]') as HTMLElement; + const palette = container.querySelector('[data-testid="contained-palette"]') as HTMLElement; + + expect(root).toBeInTheDocument(); + expect(root).not.toHaveClass("glass-fixed"); + expect(palette).toBeInTheDocument(); + expect(palette).not.toHaveAttribute("aria-modal"); + expect(palette.style.maxHeight).toBe("280px"); + expect(screen.getByText("Open billing")).toBeInTheDocument(); + expect(screen.queryByText("Navigate")).not.toBeInTheDocument(); + }); + /** * Snapshot Test: Matches snapshot */ diff --git a/src/components/interactive/GlassCommandPalette.tsx b/src/components/interactive/GlassCommandPalette.tsx index 226e21aea..a5a5fd156 100644 --- a/src/components/interactive/GlassCommandPalette.tsx +++ b/src/components/interactive/GlassCommandPalette.tsx @@ -156,6 +156,30 @@ export interface GlassCommandPaletteProps * Loading message */ loadingMessage?: string; + /** + * Compact rendering for constrained cards and preview surfaces. + */ + compact?: boolean; + /** + * Keep the palette bounded inside its parent instead of using a viewport overlay. + */ + contained?: boolean; + /** + * Positioning strategy for the palette shell. + */ + positionStrategy?: "fixed" | "absolute" | "inline"; + /** + * Render the footer keyboard hints. + */ + showFooter?: boolean; + /** + * Explicit palette width. + */ + width?: React.CSSProperties["width"]; + /** + * Explicit maximum palette height. + */ + maxHeight?: React.CSSProperties["maxHeight"]; className?: string; "data-testid"?: string; "aria-label"?: string; @@ -192,7 +216,14 @@ export const GlassCommandPalette = forwardRef< closeOnSelect = true, loading = false, loadingMessage = "Loading commands...", + compact = false, + contained = false, + positionStrategy = "fixed", + showFooter = true, + width, + maxHeight, className, + style, "data-testid": dataTestId, "aria-label": ariaLabel, ...props @@ -447,29 +478,52 @@ export const GlassCommandPalette = forwardRef< if (!open) return null; + const isContained = + contained || compact || positionStrategy === "absolute" || positionStrategy === "inline"; + const rootClassName = isContained + ? cn( + "glass-flex glass-items-start glass-justify-center", + positionStrategy === "absolute" && "glass-absolute glass-inset-0 glass-z-10", + positionStrategy === "inline" && "glass-relative glass-z-0", + compact ? "glass-p-2" : "glass-p-4" + ) + : "glass-fixed glass-inset-0 glass-z-50 glass-flex glass-items-start glass-justify-center glass-pt-10vh"; + const paletteMaxHeight = maxHeight ?? (compact || contained ? 360 : undefined); + const paletteWidth = width ?? (compact || contained ? "100%" : undefined); + return (
{ - if (e.target === e.currentTarget) { + if (!isContained && e.target === e.currentTarget) { onOpenChange?.(false); } }} > {/* Backdrop */} -
+ {!isContained && ( +
+ )} {/* Command Palette */} {/* Search Input */}
@@ -544,7 +602,10 @@ export const GlassCommandPalette = forwardRef< {/* Results */}
0 ? "listbox" : "status" } @@ -646,7 +707,7 @@ export const GlassCommandPalette = forwardRef<
{/* Footer */} - {(filteredItems?.length || 0) > 0 && ( + {showFooter && !compact && (filteredItems?.length || 0) > 0 && (
diff --git a/src/components/interactive/GlassFileUpload.test.tsx b/src/components/interactive/GlassFileUpload.test.tsx index 77eba3f4f..b37c42f58 100644 --- a/src/components/interactive/GlassFileUpload.test.tsx +++ b/src/components/interactive/GlassFileUpload.test.tsx @@ -123,4 +123,31 @@ describe('GlassFileUpload', () => { const { container } = render(); expect(container.firstChild).toMatchSnapshot(); }); -}); \ No newline at end of file + + it('supports contained compact seeded file review mode', () => { + render( + + ); + + expect(screen.getByText('invoice.pdf')).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /file upload area/i })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /remove file/i })).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/interactive/GlassFileUpload.tsx b/src/components/interactive/GlassFileUpload.tsx index d9a2e55b4..a902f1bf2 100644 --- a/src/components/interactive/GlassFileUpload.tsx +++ b/src/components/interactive/GlassFileUpload.tsx @@ -67,6 +67,38 @@ export interface GlassFileUploadProps extends Omit< * Files array */ files?: UploadedFile[]; + /** + * Initial files for uncontrolled demos, previews, and preloaded upload flows. + */ + defaultFiles?: UploadedFile[]; + /** + * Compact rendering for embedded cards and dense app surfaces. + */ + compact?: boolean; + /** + * Contain the uploader inside its parent instead of assuming a full-width page section. + */ + contained?: boolean; + /** + * Explicit uploader width for constrained layouts. + */ + width?: React.CSSProperties["width"]; + /** + * Explicit uploader height for constrained layouts. + */ + height?: React.CSSProperties["height"]; + /** + * Maximum uploader height before file lists scroll. + */ + maxHeight?: React.CSSProperties["maxHeight"]; + /** + * Show per-file and batch upload/remove actions. + */ + showActions?: boolean; + /** + * Show the dropzone. Disable this for review-only uploaded file lists. + */ + showDropzone?: boolean; /** * File change handler */ @@ -133,7 +165,15 @@ export const GlassFileUpload = forwardRef( variant = "compact", size = "sm", disabled = false, - files = EMPTY_UPLOADED_FILES, + files, + defaultFiles = EMPTY_UPLOADED_FILES, + compact = false, + contained = false, + width, + height, + maxHeight, + showActions = true, + showDropzone = true, onChange, onUpload, onRemove, @@ -147,15 +187,20 @@ export const GlassFileUpload = forwardRef( renderFile, children, className, + style, ...props }, ref ) => { - const [internalFiles, setInternalFiles] = useState(files); + const isControlled = files !== undefined; + const [internalFiles, setInternalFiles] = + useState(defaultFiles); const [isDragOver, setIsDragOver] = useState(false); const [isDragActive, setIsDragActive] = useState(false); const fileInputRef = useRef(null); const dropZoneRef = useRef(null); + const visibleFiles = files ?? internalFiles; + const isCompact = compact || variant === "minimal"; const sizeClasses = { sm: "glass-p-4 glass-text-sm", @@ -172,8 +217,20 @@ export const GlassFileUpload = forwardRef( // Sync internal files with props useEffect(() => { - setInternalFiles(files); - }, [files]); + if (isControlled) { + setInternalFiles(files ?? EMPTY_UPLOADED_FILES); + } + }, [files, isControlled]); + + const commitFiles = useCallback( + (nextFiles: UploadedFile[]) => { + if (!isControlled) { + setInternalFiles(nextFiles); + } + onChange?.(nextFiles); + }, + [isControlled, onChange] + ); // Format file size const formatFileSize = (bytes: number): string => { @@ -232,15 +289,14 @@ export const GlassFileUpload = forwardRef( const newFiles = Array.from(fileList).map(createFileObject); // Check max files limit - if (maxFiles && internalFiles.length + newFiles.length > maxFiles) { + if (maxFiles && visibleFiles.length + newFiles.length > maxFiles) { return; } const updatedFiles = multiple - ? [...internalFiles, ...newFiles] + ? [...visibleFiles, ...newFiles] : newFiles; - setInternalFiles(updatedFiles); - onChange?.(updatedFiles); + commitFiles(updatedFiles); // Auto upload valid files if (autoUpload && onUpload) { @@ -254,9 +310,9 @@ export const GlassFileUpload = forwardRef( [ disabled, maxFiles, - internalFiles, + visibleFiles, multiple, - onChange, + commitFiles, autoUpload, onUpload, ] @@ -266,26 +322,25 @@ export const GlassFileUpload = forwardRef( const handleUpload = async (fileId: string) => { if (!onUpload) return; - const fileIndex = internalFiles.findIndex((f) => f.id === fileId); + const fileIndex = visibleFiles.findIndex((f) => f.id === fileId); if (fileIndex === -1) return; - const fileObj = internalFiles[fileIndex]; + const fileObj = visibleFiles[fileIndex]; // Update status to uploading - const updatedFiles = [...internalFiles]; + const updatedFiles = [...visibleFiles]; updatedFiles[fileIndex] = { ...fileObj, status: "uploading", progress: 0, }; - setInternalFiles(updatedFiles); - onChange?.(updatedFiles); + commitFiles(updatedFiles); try { // Simulate upload progress const progressInterval = setInterval(() => { setInternalFiles((current) => { - const newFiles = [...current]; + const newFiles = [...(isControlled ? visibleFiles : current)]; const currentFile = newFiles.find((f) => f.id === fileId); if (currentFile && currentFile.status === "uploading") { currentFile.progress = Math.min( @@ -302,7 +357,7 @@ export const GlassFileUpload = forwardRef( clearInterval(progressInterval); // Update file with result - const finalFiles = [...internalFiles]; + const finalFiles = [...visibleFiles]; const finalIndex = finalFiles.findIndex((f) => f.id === fileId); if (finalIndex !== -1) { finalFiles[finalIndex] = { @@ -311,12 +366,11 @@ export const GlassFileUpload = forwardRef( progress: 100, url: result?.url, }; - setInternalFiles(finalFiles); - onChange?.(finalFiles); + commitFiles(finalFiles); } } catch (error) { // Update file with error - const errorFiles = [...internalFiles]; + const errorFiles = [...visibleFiles]; const errorIndex = errorFiles.findIndex((f) => f.id === fileId); if (errorIndex !== -1) { errorFiles[errorIndex] = { @@ -324,17 +378,15 @@ export const GlassFileUpload = forwardRef( status: "error", error: error instanceof Error ? error.message : "Upload failed", }; - setInternalFiles(errorFiles); - onChange?.(errorFiles); + commitFiles(errorFiles); } } }; // Handle file removal const handleRemove = (fileId: string) => { - const updatedFiles = internalFiles.filter((f: any) => f.id !== fileId); - setInternalFiles(updatedFiles); - onChange?.(updatedFiles); + const updatedFiles = visibleFiles.filter((f: any) => f.id !== fileId); + commitFiles(updatedFiles); onRemove?.(fileId); }; @@ -462,6 +514,7 @@ export const GlassFileUpload = forwardRef( performanceMode="medium" className={cn( "glass-p-3 border border-border/20", + isCompact && "glass-p-2", file.status === "error" && "border-destructive/50 bg-destructive/5" )} @@ -470,6 +523,7 @@ export const GlassFileUpload = forwardRef( {/* File icon/preview */}
{showPreviews && + !isCompact && file.type.startsWith("image/") && file.preview ? ( (
{/* Actions */} + {showActions && (
{file.status === "pending" && onUpload && ( ( aria-label="Remove file" />
+ )}
@@ -566,7 +622,18 @@ export const GlassFileUpload = forwardRef(
@@ -582,6 +649,7 @@ export const GlassFileUpload = forwardRef( /> {/* Drop zone */} + {showDropzone && ( ( "hover:glass-border-blue focus:glass-border-blue glass-focus-outline-none", sizeClasses[size], variantClasses[variant], + isCompact && "glass-min-h-16", { "glass-border-blue glass-surface-blue/20": isDragOver, "glass-border-white/20 glass-surface-dark/20": @@ -645,13 +714,14 @@ export const GlassFileUpload = forwardRef( )} {maxSize && ( -

+

Max file size: {formatFileSize(maxSize)}

)}
)} + )} {/* Error message */} {error && ( @@ -659,18 +729,19 @@ export const GlassFileUpload = forwardRef( )} {/* File list */} - {internalFiles.length > 0 && ( + {visibleFiles.length > 0 && (
- {internalFiles.map((file, index) => renderFileItem(file, index))} + {visibleFiles.map((file, index) => renderFileItem(file, index))}
)} {/* Upload all button */} - {internalFiles.some((f) => f.status === "pending") && + {showActions && + visibleFiles.some((f) => f.status === "pending") && onUpload && !autoUpload && (
@@ -678,7 +749,7 @@ export const GlassFileUpload = forwardRef( variant="default" size="sm" onClick={(e) => { - internalFiles + visibleFiles .filter((f: any) => f.status === "pending") .forEach((f: any) => handleUpload(f.id)); }} diff --git a/src/components/interactive/GlassImageViewer.test.tsx b/src/components/interactive/GlassImageViewer.test.tsx index 57b954699..6156b7729 100644 --- a/src/components/interactive/GlassImageViewer.test.tsx +++ b/src/components/interactive/GlassImageViewer.test.tsx @@ -77,6 +77,29 @@ describe('GlassImageViewer', () => { expect(element).toHaveClass('custom-class'); }); + it('renders compact contained mode without viewport fullscreen controls', () => { + const { container } = render( + + ); + + const viewer = container.querySelector('[data-testid="contained-viewer"]') as HTMLElement; + + expect(viewer).toBeInTheDocument(); + expect(viewer).toHaveClass('glass-contained'); + expect(viewer).toHaveClass('glass-compact'); + expect(viewer).toHaveStyle({ height: '240px', maxHeight: '280px' }); + expect(screen.queryByRole('button', { name: /toggle fullscreen/i })).not.toBeInTheDocument(); + expect(screen.queryByText('Image 1 Title')).not.toBeInTheDocument(); + expect(screen.getByAltText('Image 1')).toBeInTheDocument(); + }); + /** * Snapshot Test: Matches snapshot */ @@ -84,4 +107,4 @@ describe('GlassImageViewer', () => { const { container } = render(); expect(container.firstChild).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/src/components/interactive/GlassImageViewer.tsx b/src/components/interactive/GlassImageViewer.tsx index c3922a382..bac7a3d7b 100644 --- a/src/components/interactive/GlassImageViewer.tsx +++ b/src/components/interactive/GlassImageViewer.tsx @@ -55,6 +55,26 @@ export interface GlassImageViewerProps { * Enable fullscreen mode */ enableFullscreen?: boolean; + /** + * Render as a bounded embedded viewer instead of allowing viewport-fixed fullscreen. + */ + contained?: boolean; + /** + * Use denser controls and hide nonessential copy for card/docs previews. + */ + compact?: boolean; + /** + * Bounded viewer width. + */ + width?: React.CSSProperties["width"]; + /** + * Bounded viewer height. + */ + height?: React.CSSProperties["height"]; + /** + * Bounded viewer max-height. + */ + maxHeight?: React.CSSProperties["maxHeight"]; /** * Enable image navigation */ @@ -136,6 +156,11 @@ export const GlassImageViewer: React.FC = ({ enablePan = true, enableRotation = true, enableFullscreen = true, + contained = false, + compact = false, + width, + height, + maxHeight, enableNavigation = true, showZoomControls = true, showRotationControls = true, @@ -177,6 +202,8 @@ export const GlassImageViewer: React.FC = ({ const autoPlayRef = useRef(); const currentImage = safeImages[currentIndex]; + const isViewportFullscreen = isFullscreen && !contained; + const showExpandedInfo = showImageInfo && !compact; // Handle image change const handleImageChange = useCallback( @@ -361,7 +388,7 @@ export const GlassImageViewer: React.FC = ({ // Auto-play functionality useEffect(() => { - if (isAutoPlaying && safeImageCount > 1) { + if (isAutoPlaying && safeImageCount > 1 && !prefersReducedMotion) { autoPlayRef.current = setInterval(() => { setCurrentIndex((prev: any) => (prev + 1) % safeImageCount); }, autoPlayInterval); @@ -376,7 +403,7 @@ export const GlassImageViewer: React.FC = ({ clearInterval(autoPlayRef.current); } }; - }, [isAutoPlaying, safeImageCount, autoPlayInterval]); + }, [isAutoPlaying, safeImageCount, autoPlayInterval, prefersReducedMotion]); useEffect(() => { setCurrentIndex((prevIndex) => { @@ -410,9 +437,16 @@ export const GlassImageViewer: React.FC = ({ @@ -421,7 +455,11 @@ export const GlassImageViewer: React.FC = ({ ref={containerRef} className={cn( "relative bg-black/20 overflow-hidden", - isFullscreen ? "h-screen" : "aspect-video" + isViewportFullscreen + ? "h-screen" + : height + ? "h-full" + : "aspect-video" )} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} @@ -485,8 +523,13 @@ export const GlassImageViewer: React.FC = ({ )} {/* Image Info Overlay */} - {showImageInfo && currentImage.title && ( -
+ {showExpandedInfo && currentImage.title && ( +

{currentImage.title}

@@ -501,7 +544,12 @@ export const GlassImageViewer: React.FC = ({ {/* Controls Overlay */}
{/* Left Controls */} @@ -535,7 +583,12 @@ export const GlassImageViewer: React.FC = ({ - + {safeImageCount > 0 ? `${currentIndex + 1} / ${safeImageCount}` : "0 / 0"} @@ -569,7 +622,12 @@ export const GlassImageViewer: React.FC = ({ - + {Math.round(zoom * 100)}% @@ -622,7 +680,7 @@ export const GlassImageViewer: React.FC = ({ )} - {enableFullscreen && ( + {enableFullscreen && !contained && (

100 % @@ -213,7 +213,7 @@ exports[`GlassImageViewer matches snapshot 1`] = ` data-magnet="true" data-performance-mode="ultra" data-refraction="true" - id="glass-button-:ru:" + id="glass-button-:r16:" style="--glass-text-primary: rgba(255,255,255,0.98); --glass-text-secondary: rgba(255,255,255,0.88); --typography-text-primary: rgba(255,255,255,0.98); --typography-text-secondary: rgba(255,255,255,0.88); border: 1px solid rgba(148,163,184,0.2); border-radius: 8px; box-shadow: 0px 8px 24px 0px rgba(0,0,0,0.2); transition: all 200ms ease-out, transform 200ms ease-out, transform 200ms ease-out, box-shadow 200ms ease-out, transform 200ms ease-out; position: relative; transform: translateZ(0); cursor: pointer; user-select: none;" >
+ + Drawer preview content + +
+ ); + + const root = screen.getByTestId("contained-drawer"); + const content = container.querySelector( + '[data-consciousness-content="true"]' + ) as HTMLElement; + + expect(document.body.style.overflow).toBe("auto"); + expect(root).toHaveAttribute("data-contained", "true"); + expect(root).toHaveClass("relative"); + expect(root).not.toHaveClass("fixed"); + expect(root).toHaveAttribute("aria-modal", "false"); + expect( + container.querySelector('[data-consciousness-backdrop="true"]') + ).not.toBeInTheDocument(); + expect(content).toHaveClass("relative"); + expect(content).not.toHaveClass("absolute"); + expect(content).not.toHaveClass("fixed"); + expect(content).toHaveStyle({ + width: "360px", + height: "280px", + maxHeight: "340px", + }); + }); + it("does not re-run open lifecycle updates on controlled parent rerenders", () => { const consoleError = jest .spyOn(console, "error") diff --git a/src/components/modal/GlassDrawer.tsx b/src/components/modal/GlassDrawer.tsx index 8b6b3e898..3fdb898c7 100644 --- a/src/components/modal/GlassDrawer.tsx +++ b/src/components/modal/GlassDrawer.tsx @@ -96,6 +96,15 @@ export interface GlassDrawerProps extends ConsciousnessFeatures { * Whether drawer is modal (blocks interaction with background) */ modal?: boolean; + /** + * Render as a bounded inline drawer for embedded previews/cards instead of a + * fixed viewport drawer. + */ + contained?: boolean; + /** + * Use denser drawer spacing for compact embedded surfaces. + */ + compact?: boolean; /** * Custom backdrop blur */ @@ -120,6 +129,11 @@ export interface GlassDrawerProps extends ConsciousnessFeatures { * Whether drawer can be resized */ resizable?: boolean; + /** + * Inline style for the drawer content surface. In contained mode, width, + * height, and maxHeight constrain the embedded surface. + */ + style?: React.CSSProperties; className?: string; /** * Custom data-testid attribute @@ -159,12 +173,15 @@ export const GlassDrawer = forwardRef( header, footer, modal = true, + contained = false, + compact = false, backdropBlur = true, elevation = "modal", zIndex = 50, showOverlay = true, animationDuration = 300, resizable = false, + style, className, contentClassName, "aria-label": ariaLabel, @@ -187,6 +204,8 @@ export const GlassDrawer = forwardRef( const effectiveAnimationDuration = prefersReducedMotion ? 0 : animationDuration; + const isContained = contained; + const isModal = modal && !isContained; // Consciousness state const [interactionCount, setInteractionCount] = useState(0); @@ -265,7 +284,7 @@ export const GlassDrawer = forwardRef( // Handle body scroll lock useEffect(() => { - if (modal && open) { + if (isModal && open) { previousBodyOverflowRef.current = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { @@ -273,7 +292,7 @@ export const GlassDrawer = forwardRef( previousBodyOverflowRef.current = null; }; } - }, [modal, open]); + }, [isModal, open]); // Handle visibility state useEffect(() => { @@ -394,7 +413,7 @@ export const GlassDrawer = forwardRef( title, position, size, - modal, + isModal, ]); // Eye tracking for drawer engagement @@ -492,7 +511,7 @@ export const GlassDrawer = forwardRef( title: title || "Drawer", position, size, - modal, + modal: isModal, hasFooter: !!footer, contentLength: children?.toString().length || 0, interactionCount, @@ -541,7 +560,7 @@ export const GlassDrawer = forwardRef( title, position, size, - modal, + isModal, footer, children, interactionCount, @@ -679,6 +698,8 @@ export const GlassDrawer = forwardRef( // Position classes const getPositionClasses = () => { + if (isContained) return ""; + switch (position) { case "top": return "top-0 left-0 right-0"; @@ -713,6 +734,8 @@ export const GlassDrawer = forwardRef( // Border radius based on position const getBorderRadius = () => { + if (isContained) return "rounded-xl"; + switch (position) { case "top": return "rounded-b-xl"; @@ -726,6 +749,15 @@ export const GlassDrawer = forwardRef( return "rounded-l-xl"; } }; + const drawerSectionClass = compact + ? "glass-flex glass-items-start glass-justify-between glass-p-4 glass-border-b glass-border-glass-border/10 glass-flex-shrink-0" + : "glass-flex glass-items-start glass-justify-between glass-p-6 glass-border-b glass-border-glass-border/10 glass-flex-shrink-0"; + const drawerFooterClass = compact + ? "glass-p-4 glass-border-t glass-border-glass-border/10 glass-flex-shrink-0" + : "glass-p-6 glass-border-t glass-border-glass-border/10 glass-flex-shrink-0"; + const drawerBodyClass = compact + ? "flex-1 overflow-y-auto glass-p-4" + : "flex-1 overflow-y-auto glass-p-6"; if (!isVisible) return null; @@ -734,7 +766,7 @@ export const GlassDrawer = forwardRef( data-glass-component data-testid={dataTestId} className={cn( - "fixed inset-0", + isContained ? "relative flex w-full" : "fixed inset-0", consciousness && "consciousness-drawer-container", adaptive && drawerInsights?.urgency === "high" && @@ -742,12 +774,13 @@ export const GlassDrawer = forwardRef( eyeTracking && "consciousness-eye-trackable", className )} - style={{ zIndex }} + style={isContained ? undefined : { zIndex }} role="dialog" - aria-modal={modal} + aria-modal={isModal} aria-label={ariaLabel || (title ? undefined : "Drawer")} aria-labelledby={title ? "drawer-title" : undefined} aria-describedby={description ? "drawer-description" : undefined} + data-contained={isContained ? "true" : undefined} data-consciousness-drawer="true" data-consciousness-active={String(!!consciousness)} data-drawer-title={title} @@ -758,7 +791,7 @@ export const GlassDrawer = forwardRef( data-interaction-count={interactionCount} > {/* Backdrop/Overlay */} - {showOverlay && ( + {showOverlay && !isContained && ( ( preset={getAnimationPreset()} duration={effectiveAnimationDuration} className={cn( - "absolute flex flex-col", + isContained + ? "relative flex flex-col w-full" + : "absolute flex flex-col", getPositionClasses(), getSizeClasses(), consciousness && "consciousness-drawer-content", @@ -797,6 +832,7 @@ export const GlassDrawer = forwardRef( data-consciousness-content="true" data-drawer-complexity={drawerInsights?.complexity} data-time-spent={drawerFocusTime ? Date.now() - drawerFocusTime : 0} + style={style} > {material === "liquid" ? ( ( motionResponsive ref={ref} className={cn( - "h-full flex flex-col liquid-glass-drawer-surface", + isContained + ? "w-full flex flex-col overflow-hidden liquid-glass-drawer-surface" + : "h-full flex flex-col liquid-glass-drawer-surface", getBorderRadius(), resizable && "resize overflow-auto", consciousness && "consciousness-drawer-glass", @@ -839,7 +877,7 @@ export const GlassDrawer = forwardRef( > {/* Header */} {(header || title || description || showCloseButton) && ( -
+
{header || ( <> @@ -878,21 +916,12 @@ export const GlassDrawer = forwardRef( )} {/* Content */} -
+
{children}
{/* Footer */} - {footer && ( -
- {footer} -
- )} + {footer &&
{footer}
} ) : ( ( liftOnHover hoverSheen className={cn( - "h-full flex flex-col border border-border/20 glass-radial-reveal", + isContained + ? "w-full flex flex-col overflow-hidden border border-border/20 glass-radial-reveal" + : "h-full flex flex-col border border-border/20 glass-radial-reveal", getBorderRadius(), resizable && "resize overflow-auto", consciousness && "consciousness-drawer-glass", @@ -922,7 +953,7 @@ export const GlassDrawer = forwardRef( > {/* Header */} {(header || title || description || showCloseButton) && ( -
+
{header || ( <> @@ -971,7 +1002,7 @@ export const GlassDrawer = forwardRef(
( )} {/* Footer */} - {footer && ( -
- {footer} -
- )} + {footer &&
{footer}
} )} diff --git a/src/components/modal/GlassModal.test.tsx b/src/components/modal/GlassModal.test.tsx index 5955cd763..58244174d 100644 --- a/src/components/modal/GlassModal.test.tsx +++ b/src/components/modal/GlassModal.test.tsx @@ -112,6 +112,48 @@ describe("GlassModal", () => { expect(document.body.style.overflow).toBe("auto"); }); + it("renders contained mode without locking body scroll or using fixed overlay semantics", () => { + document.body.style.position = "relative"; + document.body.style.overflow = "auto"; + + const { container } = render( +
+ + Preview content + +
+ ); + + const root = screen.getByTestId("contained-modal"); + const dialog = screen.getByRole("dialog", { name: "Embedded preview" }); + const content = container.querySelector( + '[data-consciousness-content="true"]' + ) as HTMLElement; + + expect(document.body.style.position).toBe("relative"); + expect(document.body.style.overflow).toBe("auto"); + expect(root).toHaveAttribute("data-contained", "true"); + expect(root).toHaveClass("relative"); + expect(root).not.toHaveClass("fixed"); + expect( + container.querySelector('[aria-hidden="true"]') + ).not.toBeInTheDocument(); + expect(dialog).not.toHaveAttribute("aria-modal", "true"); + expect(content).toHaveClass("relative"); + expect(content).not.toHaveClass("fixed"); + expect(content).toHaveStyle({ + width: "420px", + height: "260px", + maxHeight: "320px", + }); + }); + it("does not re-run open lifecycle updates on controlled parent rerenders", () => { const consoleError = jest .spyOn(console, "error") diff --git a/src/components/modal/GlassModal.tsx b/src/components/modal/GlassModal.tsx index b65d95957..f56c565cf 100644 --- a/src/components/modal/GlassModal.tsx +++ b/src/components/modal/GlassModal.tsx @@ -107,10 +107,24 @@ export interface GlassModalProps extends ConsciousnessFeatures { * Whether to lock scroll when open */ lockScroll?: boolean; + /** + * Render as a bounded inline surface for embedded previews/cards instead of + * a viewport modal overlay. + */ + contained?: boolean; + /** + * Use denser modal spacing for compact embedded surfaces. + */ + compact?: boolean; /** * Z-index */ zIndex?: number; + /** + * Inline style for the modal content surface. In contained mode, width, + * height, and maxHeight constrain the embedded surface. + */ + style?: React.CSSProperties; className?: string; // Accessibility props @@ -173,7 +187,10 @@ export const GlassModal = forwardRef( backdropBlur = "md", animation = "scale", lockScroll = true, + contained = false, + compact = false, zIndex = 50, + style, className, role = "dialog", "aria-label": ariaLabel, @@ -295,11 +312,12 @@ export const GlassModal = forwardRef( : undefined; // Create accessibility attributes + const isContained = contained; const baseA11yProps = createModalA11y({ id: modalId, titleId: ariaLabelledBy || titleId, descriptionId: ariaDescribedBy || descriptionId, - modal: true, + modal: !isContained, }); // Create final a11y props with role override and default label @@ -361,7 +379,7 @@ export const GlassModal = forwardRef( useEffect(() => { if (!mounted) return; - if (open && lockScroll) { + if (open && lockScroll && !isContained) { const scrollY = window.scrollY; const body = document.body; previousBodyStylesRef.current = { @@ -393,7 +411,7 @@ export const GlassModal = forwardRef( } }; } - }, [open, lockScroll, mounted]); + }, [open, lockScroll, mounted, isContained]); // Consciousness effects // Modal opening/closing tracking with spatial audio @@ -412,7 +430,7 @@ export const GlassModal = forwardRef( interactionRecorder.recordInteraction("modal_open", { title: title || "Untitled Modal", size, - variant, + variant: isContained ? "contained" : variant, role, timestamp: openTime, }); @@ -490,6 +508,7 @@ export const GlassModal = forwardRef( size, variant, role, + isContained, ]); // Eye tracking for modal engagement @@ -706,6 +725,15 @@ export const GlassModal = forwardRef( drawer: "items-end justify-center pb-0", fullscreen: "items-center justify-center glass-p-0", }; + const modalSectionClass = compact + ? "glass-flex-shrink-0 glass-p-4 glass-border-b glass-border-glass-border/20" + : "glass-flex-shrink-0 glass-p-6 glass-border-b glass-border-glass-border/20"; + const modalFooterClass = compact + ? "glass-flex-shrink-0 glass-p-4 glass-border-t glass-border-glass-border/20" + : "glass-flex-shrink-0 glass-p-6 glass-border-t glass-border-glass-border/20"; + const modalBodyClass = compact + ? "flex-1 overflow-y-auto glass-p-4" + : "flex-1 overflow-y-auto glass-p-6"; const backdropBlurClasses = { none: "", @@ -740,9 +768,13 @@ export const GlassModal = forwardRef( data-glass-component data-testid={dataTestId} className={cn( - "fixed inset-0 flex", - variantClasses[variant], - backdropBlurClasses[backdropBlur], + isContained + ? "relative flex w-full" + : cn( + "fixed inset-0 flex", + variantClasses[variant], + backdropBlurClasses[backdropBlur] + ), consciousness && "consciousness-modal-container", adaptive && modalInsights?.urgency === "high" && @@ -750,7 +782,8 @@ export const GlassModal = forwardRef( eyeTracking && "consciousness-eye-trackable", className )} - style={{ zIndex }} + style={isContained ? undefined : { zIndex }} + data-contained={isContained ? "true" : undefined} data-consciousness-modal="true" data-consciousness-active={String(!!consciousness)} data-modal-title={title} @@ -760,19 +793,20 @@ export const GlassModal = forwardRef( data-interaction-count={interactionCount} > {/* Backdrop */} - {backdrop || ( -