diff --git a/README.md b/README.md
index 2f9c983..d8ec94a 100644
--- a/README.md
+++ b/README.md
@@ -222,10 +222,9 @@ If you find OpenDSA useful, consider:
OpenDSA is [MIT licensed](LICENSE).
----
- Made with love by the OpenDSA community
+ Made with love by the Solo Shun for the OpenDSA community
diff --git a/apps/docs/app/_meta.js b/apps/docs/app/_meta.js
index fb3c43b..fc947e9 100644
--- a/apps/docs/app/_meta.js
+++ b/apps/docs/app/_meta.js
@@ -1,8 +1,8 @@
export default {
- index: 'Home',
- architecture: 'Architecture',
- roadmap: 'Roadmap',
- migration: 'Migration',
- tech_stack: 'Tech Stack'
+ index: 'Overview',
+ project: 'Project Overview',
+ technical: 'Technical Docs',
+ code_of_conduct: 'Code of Conduct',
+ contributing: 'Contributing',
+ sponsors: 'Support Us☕'
}
-
diff --git a/apps/docs/app/architecture/page.mdx b/apps/docs/app/architecture/page.mdx
deleted file mode 100644
index c0c5551..0000000
--- a/apps/docs/app/architecture/page.mdx
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Architecture
----
-
-This page will be migrated from `apps/docs/internal/OPENALGO_ARCHITECTURE.md`.
-
diff --git a/apps/docs/app/code_of_conduct/page.mdx b/apps/docs/app/code_of_conduct/page.mdx
new file mode 100644
index 0000000..c9908c8
--- /dev/null
+++ b/apps/docs/app/code_of_conduct/page.mdx
@@ -0,0 +1,134 @@
+---
+title: Code of Conduct
+description: Our pledge and standards for community participation.
+---
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+**conduct@opendsa.dev**.
+
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/apps/docs/app/contributing/page.mdx b/apps/docs/app/contributing/page.mdx
new file mode 100644
index 0000000..1985a28
--- /dev/null
+++ b/apps/docs/app/contributing/page.mdx
@@ -0,0 +1,1017 @@
+---
+title: Contributing
+description: Guidelines and instructions for contributing to the OpenDSA project.
+---
+
+# Contributing to OpenDSA
+
+Thank you for your interest in contributing to OpenDSA! This document provides guidelines and instructions for contributing to the project.
+
+## Table of Contents
+
+1. [Code of Conduct](#code-of-conduct)
+2. [Getting Started](#getting-started)
+3. [Development Setup](#development-setup)
+4. [Project Structure](#project-structure)
+5. [Making Contributions](#making-contributions)
+6. [Adding a New Visualizer](#adding-a-new-visualizer)
+7. [Code Style Guide](#code-style-guide)
+8. [Commit Guidelines](#commit-guidelines)
+9. [Pull Request Process](#pull-request-process)
+10. [Issue Guidelines](#issue-guidelines)
+11. [Community](#community)
+
+
+## Code of Conduct
+
+By participating in this project, you agree to abide by our [Code of Conduct](/code_of_conduct). Please read it before contributing.
+
+**Key Points**:
+- Be respectful and inclusive
+- Welcome newcomers
+- Accept constructive criticism
+- Focus on what's best for the community
+
+
+## Getting Started
+
+### Prerequisites
+
+Before you begin, ensure you have the following installed:
+
+- **Node.js**: v18.17 or higher ([Download](https://nodejs.org/))
+- **pnpm**: v8 or higher (`npm install -g pnpm`)
+- **Git**: Latest version ([Download](https://git-scm.com/))
+
+### Quick Start
+
+```bash
+# 1. Fork the repository on GitHub
+
+# 2. Clone your fork
+git clone https://github.com/soloshun/opendsa.git
+cd opendsa
+
+# 3. Add upstream remote
+git remote add upstream https://github.com/soloshun/opendsa.git
+
+# 4. Install dependencies
+pnpm install
+
+# 5. Start development server
+pnpm dev
+```
+
+
+## Development Setup
+
+### Installing Dependencies
+
+```bash
+# Install all dependencies for the monorepo
+pnpm install
+```
+
+### Running Development Servers
+
+```bash
+# Run all apps in development mode
+pnpm dev
+
+# Run specific app
+pnpm dev --filter=@opendsa/app
+pnpm dev --filter=@opendsa/web
+pnpm dev --filter=@opendsa/docs
+```
+
+### Building
+
+```bash
+# Build all packages and apps
+pnpm build
+
+# Build specific package
+pnpm build --filter=@opendsa/algorithms
+```
+
+### Testing
+
+```bash
+# Run all tests
+pnpm test
+
+# Run tests in watch mode
+pnpm test:watch
+
+# Run tests for specific package
+pnpm test --filter=@opendsa/algorithms
+
+# Run E2E tests
+pnpm test:e2e
+```
+
+### Linting and Formatting
+
+```bash
+# Run linter
+pnpm lint
+
+# Fix lint issues
+pnpm lint:fix
+
+# Format code
+pnpm format
+
+# Type check
+pnpm type-check
+```
+
+
+## Project Structure
+
+```
+opendsa/
+├── apps/
+│ ├── web/ # Marketing website
+│ ├── app/ # Main visualizer application
+│ └── docs/ # Documentation site
+│
+├── packages/
+│ ├── ui/ # Shared UI components
+│ ├── algorithms/ # Algorithm implementations
+│ ├── visualizers/ # Visualization components
+│ ├── types/ # Shared TypeScript types
+│ ├── utils/ # Shared utilities
+│ └── config/ # Shared configurations
+│
+├── .github/ # GitHub workflows and templates
+├── turbo.json # Turborepo configuration
+└── package.json # Root package.json
+```
+
+### Package Overview
+
+| Package | Description | Key Files |
+|---------|-------------|-----------|
+| `@opendsa/app` | Main visualizer app | `app/`, `components/` |
+| `@opendsa/web` | Marketing website | `app/`, `components/` |
+| `@opendsa/docs` | Documentation | `pages/` |
+| `@opendsa/ui` | UI components | `src/components/` |
+| `@opendsa/algorithms` | Pure algorithms | `src/sorting/`, `src/searching/` |
+| `@opendsa/visualizers` | Visualizer components | `src/engine/`, `src/sorting/` |
+| `@opendsa/types` | TypeScript types | `src/*.types.ts` |
+| `@opendsa/utils` | Utility functions | `src/` |
+
+
+## Making Contributions
+
+### Types of Contributions
+
+We welcome many types of contributions:
+
+- **Bug Fixes**: Fix issues in existing code
+- **New Features**: Add new functionality
+- **New Visualizers**: Add algorithm visualizations
+- **Documentation**: Improve or add documentation
+- **Tests**: Add or improve tests
+- **UI/UX**: Improve user interface and experience
+- **Performance**: Optimize existing code
+- **Accessibility**: Improve accessibility
+
+### Contribution Workflow
+
+```mermaid
+flowchart TB
+ A[Find or Create Issue] --> B[Fork Repository]
+ B --> C[Create Feature Branch]
+ C --> D[Make Changes]
+ D --> E[Write/Update Tests]
+ E --> F[Commit with Conventional Commits]
+ F --> G[Push to Your Fork]
+ G --> H[Create Pull Request]
+ H --> I{CI Passes?}
+ I -->|No| D
+ I -->|Yes| J[Code Review]
+ J --> K{Changes Requested?}
+ K -->|Yes| D
+ K -->|No| L[Merge]
+```
+
+### Branch Naming
+
+Use descriptive branch names:
+
+```
+feature/add-quicksort-visualizer
+fix/bubble-sort-animation-bug
+docs/improve-contributing-guide
+refactor/animation-engine
+test/add-merge-sort-tests
+```
+
+Format: `/`
+
+Types:
+- `feature/` - New features
+- `fix/` - Bug fixes
+- `docs/` - Documentation changes
+- `refactor/` - Code refactoring
+- `test/` - Test additions/changes
+- `chore/` - Maintenance tasks
+
+
+## Adding a New Visualizer
+
+This is the most common contribution. Follow this guide to add a new algorithm visualizer.
+
+### Step 1: Create the Algorithm Implementation
+
+Create the pure algorithm in `packages/algorithms`:
+
+```typescript
+// packages/algorithms/src/sorting/insertion-sort.ts
+
+import type { AnimationStep } from '@opendsa/types';
+
+/**
+ * Insertion Sort Algorithm
+ * Time: O(n^2) average, O(n) best | Space: O(1)
+ */
+export function insertionSort(array: number[]): number[] {
+ const arr = [...array];
+
+ for (let i = 1; i < arr.length; i++) {
+ const key = arr[i];
+ let j = i - 1;
+
+ while (j >= 0 && arr[j] > key) {
+ arr[j + 1] = arr[j];
+ j--;
+ }
+ arr[j + 1] = key;
+ }
+
+ return arr;
+}
+
+/**
+ * Generate animation steps for Insertion Sort
+ */
+export function insertionSortSteps(array: number[]): AnimationStep[] {
+ const steps: AnimationStep[] = [];
+ const arr = [...array];
+
+ // Initial state
+ steps.push({
+ id: `step-0`,
+ type: 'highlight',
+ indices: [],
+ description: 'Starting insertion sort',
+ codeLineNumbers: [1],
+ });
+
+ for (let i = 1; i < arr.length; i++) {
+ const key = arr[i];
+ let j = i - 1;
+
+ // Highlight current element
+ steps.push({
+ id: `step-${steps.length}`,
+ type: 'highlight',
+ indices: [i],
+ description: `Select element ${key} at index ${i}`,
+ codeLineNumbers: [4, 5],
+ });
+
+ while (j >= 0 && arr[j] > key) {
+ // Compare
+ steps.push({
+ id: `step-${steps.length}`,
+ type: 'compare',
+ indices: [j, j + 1],
+ description: `Compare ${arr[j]} with ${key}`,
+ codeLineNumbers: [7],
+ });
+
+ // Shift
+ arr[j + 1] = arr[j];
+ steps.push({
+ id: `step-${steps.length}`,
+ type: 'swap',
+ indices: [j, j + 1],
+ values: [...arr],
+ description: `Shift ${arr[j]} to the right`,
+ codeLineNumbers: [8],
+ });
+
+ j--;
+ }
+
+ // Insert
+ arr[j + 1] = key;
+ steps.push({
+ id: `step-${steps.length}`,
+ type: 'insert',
+ indices: [j + 1],
+ values: [...arr],
+ description: `Insert ${key} at index ${j + 1}`,
+ codeLineNumbers: [10],
+ });
+ }
+
+ // Mark all as sorted
+ steps.push({
+ id: `step-${steps.length}`,
+ type: 'mark-sorted',
+ indices: arr.map((_, i) => i),
+ description: 'Array is sorted!',
+ codeLineNumbers: [12],
+ });
+
+ return steps;
+}
+```
+
+### Step 2: Add Tests
+
+```typescript
+// packages/algorithms/src/sorting/__tests__/insertion-sort.test.ts
+
+import { describe, it, expect } from 'vitest';
+import { insertionSort, insertionSortSteps } from '../insertion-sort';
+
+describe('insertionSort', () => {
+ it('sorts an array correctly', () => {
+ expect(insertionSort([5, 3, 8, 1, 2])).toEqual([1, 2, 3, 5, 8]);
+ });
+
+ it('handles empty array', () => {
+ expect(insertionSort([])).toEqual([]);
+ });
+
+ it('handles single element', () => {
+ expect(insertionSort([1])).toEqual([1]);
+ });
+
+ it('handles already sorted array', () => {
+ expect(insertionSort([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
+ });
+
+ it('handles reverse sorted array', () => {
+ expect(insertionSort([5, 4, 3, 2, 1])).toEqual([1, 2, 3, 4, 5]);
+ });
+
+ it('handles duplicates', () => {
+ expect(insertionSort([3, 1, 3, 2, 1])).toEqual([1, 1, 2, 3, 3]);
+ });
+});
+
+describe('insertionSortSteps', () => {
+ it('generates correct number of steps', () => {
+ const steps = insertionSortSteps([3, 1, 2]);
+ expect(steps.length).toBeGreaterThan(0);
+ });
+
+ it('first step is highlight', () => {
+ const steps = insertionSortSteps([3, 1, 2]);
+ expect(steps[0].type).toBe('highlight');
+ });
+
+ it('last step marks all as sorted', () => {
+ const steps = insertionSortSteps([3, 1, 2]);
+ expect(steps[steps.length - 1].type).toBe('mark-sorted');
+ });
+});
+```
+
+### Step 3: Create the Visualizer Component
+
+```typescript
+// packages/visualizers/src/sorting/InsertionSortVisualizer.tsx
+
+'use client';
+
+import { useRef, useEffect, useMemo } from 'react';
+import { motion, AnimatePresence } from 'framer-motion';
+import type { VisualizerProps, AnimationStep } from '@opendsa/types';
+import { cn } from '@opendsa/utils';
+
+interface InsertionSortProps extends VisualizerProps {}
+
+export function InsertionSortVisualizer({
+ data,
+ currentStep,
+ steps,
+ isPlaying,
+ speed,
+}: InsertionSortProps) {
+ const containerRef = useRef(null);
+
+ const currentStepData = steps[currentStep];
+ const maxValue = useMemo(() => Math.max(...data, 1), [data]);
+
+ // Get the current state of the array at this step
+ const displayArray = useMemo(() => {
+ if (currentStepData?.values) {
+ return currentStepData.values as number[];
+ }
+ return data;
+ }, [currentStepData, data]);
+
+ const getBarColor = (index: number): string => {
+ if (!currentStepData) return 'bg-primary';
+
+ const { type, indices } = currentStepData;
+
+ if (type === 'mark-sorted' && indices.includes(index)) {
+ return 'bg-green-500';
+ }
+ if (type === 'compare' && indices.includes(index)) {
+ return 'bg-yellow-500';
+ }
+ if (type === 'swap' && indices.includes(index)) {
+ return 'bg-red-500';
+ }
+ if (type === 'highlight' && indices.includes(index)) {
+ return 'bg-blue-500';
+ }
+ if (type === 'insert' && indices.includes(index)) {
+ return 'bg-purple-500';
+ }
+
+ return 'bg-primary';
+ };
+
+ return (
+
+
+ {displayArray.map((value, index) => (
+
+ {displayArray.length <= 20 && (
+
+ {value}
+
+ )}
+
+ ))}
+
+
+ );
+}
+```
+
+### Step 4: Create the Controls Component
+
+```typescript
+// packages/visualizers/src/sorting/InsertionSortControls.tsx
+
+'use client';
+
+import { useState } from 'react';
+import {
+ Button,
+ Slider,
+ Input,
+ Card,
+ CardContent,
+} from '@opendsa/ui';
+import {
+ Play,
+ Pause,
+ RotateCcw,
+ SkipBack,
+ SkipForward,
+ Shuffle,
+} from 'lucide-react';
+import type { ControlsProps } from '@opendsa/types';
+
+export function InsertionSortControls({
+ onPlay,
+ onPause,
+ onReset,
+ onStepForward,
+ onStepBackward,
+ onSpeedChange,
+ onDataChange,
+ isPlaying,
+ currentStep,
+ totalSteps,
+ speed,
+}: ControlsProps) {
+ const [arraySize, setArraySize] = useState(10);
+
+ const generateRandomArray = () => {
+ const newArray = Array.from(
+ { length: arraySize },
+ () => Math.floor(Math.random() * 100) + 1
+ );
+ onDataChange(newArray);
+ };
+
+ return (
+
+
+ {/* Playback Controls */}
+
+
+
+
+
+
+ {isPlaying ? (
+
+ ) : (
+
+ )}
+
+
+
= totalSteps - 1}
+ >
+
+
+
+
+
+
+
+
+ {/* Progress */}
+
+ Step {currentStep + 1} of {totalSteps}
+
+
+ {/* Speed Control */}
+
+ Speed
+ onSpeedChange(value)}
+ min={1}
+ max={100}
+ step={1}
+ />
+
+
+ {/* Array Controls */}
+
+ setArraySize(Number(e.target.value))}
+ min={2}
+ max={50}
+ className="w-20"
+ />
+
+
+ Generate
+
+
+
+
+ );
+}
+```
+
+### Step 5: Register the Visualizer
+
+```typescript
+// packages/visualizers/src/sorting/insertion-sort-plugin.ts
+
+import type { VisualizerPlugin } from '@opendsa/types';
+import { insertionSortSteps } from '@opendsa/algorithms';
+import { InsertionSortVisualizer } from './InsertionSortVisualizer';
+import { InsertionSortControls } from './InsertionSortControls';
+
+export const insertionSortPlugin: VisualizerPlugin = {
+ meta: {
+ id: 'insertion-sort',
+ name: 'Insertion Sort',
+ category: 'sorting',
+ description: 'A simple sorting algorithm that builds the sorted array one element at a time.',
+ complexity: {
+ time: {
+ best: 'O(n)',
+ average: 'O(n²)',
+ worst: 'O(n²)',
+ },
+ space: 'O(1)',
+ },
+ tags: ['sorting', 'comparison', 'in-place', 'stable'],
+ difficulty: 'beginner',
+ },
+ component: InsertionSortVisualizer,
+ controls: InsertionSortControls,
+ generateSteps: insertionSortSteps,
+ defaultInput: [64, 34, 25, 12, 22, 11, 90],
+ defaultCode: `function insertionSort(arr) {
+ for (let i = 1; i < arr.length; i++) {
+ let key = arr[i];
+ let j = i - 1;
+
+ while (j >= 0 && arr[j] > key) {
+ arr[j + 1] = arr[j];
+ j--;
+ }
+ arr[j + 1] = key;
+ }
+ return arr;
+}`,
+};
+
+// Register in packages/visualizers/src/registry.ts
+import { registry } from './registry';
+import { insertionSortPlugin } from './sorting/insertion-sort-plugin';
+
+registry.register(insertionSortPlugin);
+```
+
+### Step 6: Export from Package
+
+```typescript
+// packages/visualizers/src/index.ts
+
+// ... existing exports
+export { InsertionSortVisualizer } from './sorting/InsertionSortVisualizer';
+export { InsertionSortControls } from './sorting/InsertionSortControls';
+export { insertionSortPlugin } from './sorting/insertion-sort-plugin';
+```
+
+### Step 7: Add Documentation
+
+Create a documentation page explaining the algorithm:
+
+```mdx
+// apps/docs/pages/algorithms/sorting/insertion-sort.mdx
+
+---
+title: Insertion Sort
+description: Learn how insertion sort works with interactive visualization
+---
+
+# Insertion Sort
+
+Insertion sort is a simple sorting algorithm that builds the final sorted array
+one item at a time.
+
+## How It Works
+
+1. Start from the second element (index 1)
+2. Compare it with elements before it
+3. Shift larger elements to the right
+4. Insert the element in its correct position
+5. Repeat for all elements
+
+## Complexity
+
+| Case | Time | Space |
+|------|------|-------|
+| Best | O(n) | O(1) |
+| Average | O(n²) | O(1) |
+| Worst | O(n²) | O(1) |
+
+## When to Use
+
+- Small datasets
+- Nearly sorted arrays
+- Online sorting (sorting as data arrives)
+- When simplicity is preferred over performance
+
+## Interactive Demo
+
+Visit the [Insertion Sort Visualizer](/visualize/sorting/insertion-sort) to see
+the algorithm in action.
+```
+
+
+## Code Style Guide
+
+### TypeScript
+
+- Use strict mode
+- Prefer `interface` over `type` for object shapes
+- Use descriptive variable names
+- Add JSDoc comments for public APIs
+
+```typescript
+// Good
+interface UserPreferences {
+ theme: 'light' | 'dark' | 'system';
+ fontSize: number;
+}
+
+/**
+ * Updates user preferences in storage
+ * @param preferences - The preferences to save
+ * @returns Promise that resolves when saved
+ */
+async function savePreferences(preferences: UserPreferences): Promise {
+ // Implementation
+}
+
+// Avoid
+type prefs = { t: string; fs: number };
+const save = async (p: any) => { /* ... */ };
+```
+
+### React Components
+
+- Use functional components with hooks
+- Prefer named exports
+- Use TypeScript for props
+- Extract complex logic to custom hooks
+
+```typescript
+// Good
+interface ButtonProps {
+ variant?: 'primary' | 'secondary';
+ children: React.ReactNode;
+ onClick?: () => void;
+}
+
+export function Button({ variant = 'primary', children, onClick }: ButtonProps) {
+ return (
+
+ {children}
+
+ );
+}
+```
+
+### File Organization
+
+```
+ComponentName/
+├── ComponentName.tsx # Main component
+├── ComponentName.test.tsx # Tests
+├── use-component-name.ts # Custom hook (if needed)
+├── types.ts # Types (if complex)
+└── index.ts # Exports
+```
+
+
+## Commit Guidelines
+
+We use [Conventional Commits](https://www.conventionalcommits.org/) for clear, automated changelogs.
+
+### Format
+
+```
+():
+
+[optional body]
+
+[optional footer]
+```
+
+### Types
+
+| Type | Description |
+|------|-------------|
+| `feat` | New feature |
+| `fix` | Bug fix |
+| `docs` | Documentation changes |
+| `style` | Code style changes (formatting) |
+| `refactor` | Code refactoring |
+| `perf` | Performance improvements |
+| `test` | Adding or updating tests |
+| `chore` | Maintenance tasks |
+| `ci` | CI/CD changes |
+
+### Examples
+
+```bash
+# Feature
+feat(visualizers): add insertion sort visualizer
+
+# Bug fix
+fix(animation): resolve timing issue in bubble sort
+
+# Documentation
+docs(contributing): add visualizer creation guide
+
+# Multiple scopes
+feat(algorithms,visualizers): add binary search
+```
+
+### Commit Message Guidelines
+
+- Use imperative mood ("add" not "added")
+- First line max 72 characters
+- Reference issues in footer: `Closes #123`
+
+
+## Pull Request Process
+
+### Before Creating a PR
+
+1. **Sync with upstream**
+ ```bash
+ git fetch upstream
+ git rebase upstream/dev
+ ```
+
+2. **Run all checks**
+ ```bash
+ pnpm lint
+ pnpm type-check
+ pnpm test
+ pnpm build
+ ```
+
+3. **Update documentation** if needed
+
+### PR Template
+
+When you create a PR, fill out the template:
+
+```markdown
+## Description
+Brief description of changes
+
+## Type of Change
+- [ ] Bug fix
+- [ ] New feature
+- [ ] Documentation
+- [ ] Refactoring
+
+## Related Issues
+Closes #123
+
+## Checklist
+- [ ] My code follows the code style
+- [ ] I have added tests
+- [ ] All tests pass
+- [ ] I have updated documentation
+- [ ] I have added a changeset (if applicable)
+
+## Screenshots (if applicable)
+```
+
+### Review Process
+
+1. **CI Checks**: All automated checks must pass
+2. **Code Review**: At least 1 maintainer approval
+3. **Discussion**: Address all comments
+4. **Merge**: Maintainer merges when ready
+
+### After Merge
+
+- Delete your feature branch
+- Pull latest changes
+- Celebrate your contribution!
+
+
+## Issue Guidelines
+
+### Bug Reports
+
+Use the bug report template:
+
+```markdown
+**Describe the bug**
+Clear description of the bug
+
+**To Reproduce**
+1. Go to '...'
+2. Click on '....'
+3. See error
+
+**Expected behavior**
+What should happen
+
+**Screenshots**
+If applicable
+
+**Environment**
+- OS: [e.g. Windows 11]
+- Browser: [e.g. Chrome 120]
+- Version: [e.g. 1.0.0]
+```
+
+### Feature Requests
+
+Use the feature request template:
+
+```markdown
+**Is your feature request related to a problem?**
+Clear description of the problem
+
+**Describe the solution you'd like**
+What you want to happen
+
+**Describe alternatives you've considered**
+Other solutions you've thought about
+
+**Additional context**
+Any other information
+```
+
+### Visualizer Requests
+
+Use the new visualizer template:
+
+```markdown
+**Algorithm/Data Structure**
+Name of the algorithm
+
+**Category**
+- [ ] Sorting
+- [ ] Searching
+- [ ] Graph
+- [ ] Tree
+- [ ] Dynamic Programming
+- [ ] Data Structure
+
+**Description**
+Brief description of the algorithm
+
+**Complexity**
+- Time: O(?)
+- Space: O(?)
+
+**Resources**
+Links to explanations, Wikipedia, etc.
+
+**Would you like to implement this?**
+- [ ] Yes, I'd like to work on this
+- [ ] No, just suggesting
+```
+
+
+## Community
+
+### Discord
+
+Join our Discord server for:
+- Real-time help
+- Feature discussions
+- Showing off your contributions
+- Connecting with other contributors
+
+[Join Discord⛓️💥❌](https://discord.gg/opendsa)
+
+### Getting Help
+
+- **Discord**: Quick questions, discussions
+- **GitHub Issues**: Bugs, features, documentation
+- **GitHub Discussions**: General questions, ideas
+
+### Recognition
+
+We appreciate all contributions! Contributors are:
+- Listed in our README
+- Mentioned in release notes
+- Eligible for contributor badges
+
+
+## License
+
+By contributing to OpenDSA, you agree that your contributions will be licensed under the MIT License.
+
+
+*Thank you for contributing to OpenDSA! Your efforts help make algorithm learning more accessible to everyone.*
diff --git a/apps/docs/app/globals.css b/apps/docs/app/globals.css
new file mode 100644
index 0000000..e89ab1d
--- /dev/null
+++ b/apps/docs/app/globals.css
@@ -0,0 +1,33 @@
+/* apps/docs/app/globals.css */
+
+/* Base text: Inter for everything */
+body {
+ font-family: var(--font-inter), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
+ font-size: 0.9rem;
+ font-weight: 400;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+/* Code blocks: JetBrains Mono */
+code,
+kbd,
+samp,
+pre,
+code[class*="language-"],
+pre[class*="language-"] {
+ font-family: var(--font-jetbrains-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;
+}
+
+/* Nextra code block overrides */
+.nextra-code,
+.nextra-code code,
+[data-rehype-pretty-code-fragment] code,
+[data-rehype-pretty-code-fragment] pre {
+ font-family: var(--font-jetbrains-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace !important;
+}
+
+/* Inline code */
+:not(pre)>code {
+ font-family: var(--font-jetbrains-mono), ui-monospace, monospace !important;
+}
\ No newline at end of file
diff --git a/apps/docs/app/layout.jsx b/apps/docs/app/layout.jsx
index dfb8774..b30f140 100644
--- a/apps/docs/app/layout.jsx
+++ b/apps/docs/app/layout.jsx
@@ -2,13 +2,32 @@ import { Footer, Layout, Navbar } from 'nextra-theme-docs'
import { Head } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import 'nextra-theme-docs/style.css'
+import './globals.css'
+import 'katex/dist/katex.min.css'
+import { JetBrains_Mono, Inter } from "next/font/google";
+// import Image from 'next/image'
+
+const jetbrainsMono = JetBrains_Mono({
+ variable: "--font-jetbrains-mono",
+ subsets: ["latin"],
+ display: "swap",
+ weight: ["100", "200", "300", "400", "500", "600", "700"],
+});
+
+const inter = Inter({
+ variable: "--font-inter",
+ subsets: ["latin"],
+ display: "swap",
+ weight: ["100", "200", "300", "400", "500", "600", "700"],
+});
export const metadata = {
title: {
default: 'OpenDSA Docs',
template: '%s | OpenDSA Docs'
},
- description: 'OpenDSA documentation'
+ description: 'OpenDSA documentation',
+ authors: [{ name: "Solomon Eshun" }],
}
const navbar = (
@@ -17,18 +36,20 @@ const navbar = (
/>
)
-const footer = {new Date().getFullYear()} © OpenDSA.
+const footer =
+ {new Date().getFullYear()} © OpenDSA by {" "} Solo Shun .
+
export default async function RootLayout({ children }) {
return (
-
+
{children}
diff --git a/apps/docs/app/migration/page.mdx b/apps/docs/app/migration/page.mdx
deleted file mode 100644
index 24fc5c5..0000000
--- a/apps/docs/app/migration/page.mdx
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Migration
----
-
-This page will be migrated from `apps/docs/internal/OPENALGO_MIGRATION.md`.
-
diff --git a/apps/docs/app/page.mdx b/apps/docs/app/page.mdx
index b0ec8dc..631ce11 100644
--- a/apps/docs/app/page.mdx
+++ b/apps/docs/app/page.mdx
@@ -1,8 +1,109 @@
---
-title: OpenDSA Docs
+title: Introduction
+description: Welcome to the OpenDSA documentation.
---
-Welcome to the OpenDSA documentation.
+# Introduction to OpenDSA
-Use the sidebar to navigate.
+> **See algorithms come to life**
+OpenDSA is an interactive visualization platform that helps you understand how algorithms and data structures work through step-by-step animations. Whether you're:
+
+- **Learning** algorithms for the first time
+- **Teaching** computer science concepts
+- **Preparing** for technical interviews
+- **Building** educational content
+
+OpenDSA makes complex algorithms visual and intuitive.
+
+## Features
+
+- **Interactive Visualizations** - Watch algorithms execute step-by-step with full control
+- **Multiple Categories** - Sorting, searching, graphs, trees, and more
+- **Code Highlighting** - See which line of code corresponds to each step
+- **Speed Control** - Slow down or speed up animations
+- **Shareable URLs** - Share specific visualization states with others
+- **Dark/Light Mode** - Easy on the eyes, day or night
+- **Keyboard Shortcuts** - Power-user friendly controls
+- **Open Source** - Free forever, community-driven
+
+## Visualizers
+
+### Sorting Algorithms
+- Bubble Sort
+- Selection Sort
+- Insertion Sort
+- Quick Sort
+- Merge Sort
+- *More coming soon...*
+
+### Searching Algorithms
+- Linear Search
+- Binary Search
+- *More coming soon...*
+
+### Data Structures
+- Arrays
+- *Linked Lists, Trees, Graphs coming soon...*
+
+## Quick Start
+
+### Try Online
+
+Visit [app.opendsa.dev](https://app.opendsa.dev.vercel.app) to start visualizing algorithms immediately - no installation required.
+
+### Run Locally
+
+```bash
+# Clone the repository
+git clone https://github.com/soloshun/opendsa.git
+cd opendsa
+
+# Install dependencies
+pnpm install
+
+# Start development server
+pnpm dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) in your browser.
+
+## Tech Stack
+
+| Layer | Technology |
+|-------|------------|
+| Framework | [Next.js 14](https://nextjs.org/) (App Router) |
+| Language | [TypeScript](https://www.typescriptlang.org/) |
+| Styling | [TailwindCSS](https://tailwindcss.com/) + [shadcn/ui](https://ui.shadcn.com/) |
+| Animations | [Framer Motion](https://www.framer.com/motion/) + [D3.js](https://d3js.org/) |
+| State | [Zustand](https://zustand-demo.pmnd.rs/) |
+| Monorepo | [Turborepo](https://turbo.build/) |
+| Package Manager | [pnpm](https://pnpm.io/) |
+| Deployment | [Vercel](https://vercel.com/) |
+
+## Contributing
+
+We welcome contributions from everyone! Whether it's:
+
+- Adding new algorithm visualizers
+- Fixing bugs
+- Improving documentation
+- Suggesting features
+
+See our [Contributing Guide](/contributing) to get started.
+
+## Community
+
+- **Discord**: [Join our community ⛓️💥❌](https://discord.gg/opendsa)
+- **Twitter**: [@self.solo_shun⛓️💥❌](https://twitter.com/opendsa)
+- **GitHub Discussions**: [Ask questions](https://github.com/soloshun/opendsa/discussions)
+
+
+
+Made with ❤️ by the Solo Shun for the OpenDSA community
+
+
\ No newline at end of file
diff --git a/apps/docs/app/project/_meta.js b/apps/docs/app/project/_meta.js
new file mode 100644
index 0000000..c0413b5
--- /dev/null
+++ b/apps/docs/app/project/_meta.js
@@ -0,0 +1,6 @@
+export default {
+ architecture: 'Architecture',
+ roadmap: 'Roadmap',
+ migration: 'Migration',
+ tech_stack: 'Tech Stack'
+}
diff --git a/apps/docs/app/project/architecture/page.mdx b/apps/docs/app/project/architecture/page.mdx
new file mode 100644
index 0000000..35f4149
--- /dev/null
+++ b/apps/docs/app/project/architecture/page.mdx
@@ -0,0 +1,948 @@
+title: Architecture
+description: Comprehensive architecture documentation for the OpenDSA algorithm visualization platform.
+
+# OpenDSA - System Architecture
+
+> Comprehensive architecture documentation for the OpenDSA algorithm visualization platform.
+
+## Table of Contents
+
+1. [Overview](#overview)
+2. [High-Level Architecture](#high-level-architecture)
+3. [Monorepo Structure](#monorepo-structure)
+4. [Application Architecture](#application-architecture)
+5. [Data Flow](#data-flow)
+6. [Visualizer Plugin System](#visualizer-plugin-system)
+7. [Animation Engine](#animation-engine)
+8. [State Management](#state-management)
+9. [Component Architecture](#component-architecture)
+10. [API Design](#api-design)
+
+
+## Overview
+
+OpenDSA is built as a **Turborepo monorepo** containing multiple applications and shared packages. This architecture enables:
+
+- **Code reuse** across applications (website, app, docs)
+- **Independent deployments** for each application
+- **Shared packages** for algorithms, UI components, and utilities
+- **Scalable contributor experience** with clear boundaries
+
+
+## High-Level Architecture
+
+```mermaid
+flowchart TB;
+ subgraph Users [Users];
+ Learner[Learner];
+ Contributor[Contributor];
+ Educator[Educator];
+ end
+
+ subgraph Apps [Applications];
+ Web[Web - Landing Page];
+ App[App - Visualizer];
+ Docs[Docs - Documentation];
+ end
+
+ subgraph Packages [Shared Packages];
+ UI[UI Components];
+ Algorithms[Algorithms];
+ Visualizers[Visualizers];
+ Types[Types];
+ Utils[Utils];
+ Config[Config];
+ end
+
+ subgraph Infrastructure [Infrastructure];
+ Vercel[Vercel Hosting];
+ GitHub[GitHub Repository];
+ Actions[GitHub Actions];
+ end
+
+ Users --> Apps;
+ Apps --> Packages;
+ Apps --> Infrastructure;
+ GitHub --> Actions;
+ Actions --> Vercel;
+```
+
+## Monorepo Structure
+
+```mermaid
+flowchart LR;
+ subgraph Root[opendsa/];
+ subgraph AppsDir[apps/];
+ WebApp[web/];
+ MainApp[app/];
+ DocsApp[docs/];
+ end
+
+ subgraph PackagesDir[packages/];
+ UIPackage[ui/];
+ AlgoPackage[algorithms/];
+ VizPackage[visualizers/];
+ TypesPackage[types/];
+ UtilsPackage[utils/];
+ ConfigPackage[config/];
+ end
+
+ TurboConfig[turbo.json];
+ RootPackage[package.json];
+ Workspace[pnpm-workspace.yaml];
+ end
+
+ WebApp --> UIPackage;
+ WebApp --> ConfigPackage;
+ MainApp --> UIPackage;
+ MainApp --> AlgoPackage;
+ MainApp --> VizPackage;
+ MainApp --> TypesPackage;
+ MainApp --> UtilsPackage;
+ DocsApp --> UIPackage;
+ DocsApp --> ConfigPackage;
+```
+
+### Directory Details
+
+```
+opendsa/
+├── apps/
+│ ├── web/ # Marketing website
+│ │ ├── app/ # Next.js App Router pages
+│ │ │ ├── page.tsx # Landing page
+│ │ │ ├── features/ # Features page
+│ │ │ ├── community/ # Community page
+│ │ │ ├── blog/ # Blog (MDX)
+│ │ │ └── layout.tsx # Root layout
+│ │ ├── components/ # Website-specific components
+│ │ ├── public/ # Static assets
+│ │ └── package.json
+│ │
+│ ├── app/ # Main visualizer application
+│ │ ├── app/ # Next.js App Router pages
+│ │ │ ├── page.tsx # Dashboard
+│ │ │ ├── visualize/ # Visualizer routes
+│ │ │ │ └── [category]/
+│ │ │ │ └── [algorithm]/
+│ │ │ │ └── page.tsx
+│ │ │ ├── playground/ # Playground mode
+│ │ │ ├── learn/ # Learning paths
+│ │ │ └── layout.tsx # App layout
+│ │ ├── components/ # App-specific components
+│ │ │ ├── visualizer/ # Visualizer wrappers
+│ │ │ ├── controls/ # Control panels
+│ │ │ ├── editor/ # Code editor
+│ │ │ └── sidebar/ # Navigation sidebar
+│ │ ├── lib/ # App utilities
+│ │ │ ├── store.ts # Zustand store
+│ │ │ └── hooks/ # Custom hooks
+│ │ └── package.json
+│ │
+│ └── docs/ # Documentation site
+│ ├── app/ # Nextjs app
+| │ ├── architecture/
+| | | └── page.mdx
+| | └── etc...
+│ ├── theme.config.tsx # Nextra config
+│ ├── next.config.mjs # Next config
+│ └── package.json
+│
+├── packages/
+│ ├── ui/ # Shared UI components
+│ │ ├── src/
+│ │ │ ├── components/ # shadcn/ui based components
+│ │ │ │ ├── button.tsx
+│ │ │ │ ├── card.tsx
+│ │ │ │ ├── slider.tsx
+│ │ │ │ └── ...
+│ │ │ └── index.ts # Public exports
+│ │ └── package.json
+│ │
+│ ├── algorithms/ # Pure algorithm implementations
+│ │ ├── src/
+│ │ │ ├── sorting/
+│ │ │ │ ├── bubble-sort.ts
+│ │ │ │ ├── quick-sort.ts
+│ │ │ │ ├── merge-sort.ts
+│ │ │ │ ├── insertion-sort.ts
+│ │ │ │ ├── selection-sort.ts
+│ │ │ │ └── index.ts
+│ │ │ ├── searching/
+│ │ │ │ ├── linear-search.ts
+│ │ │ │ ├── binary-search.ts
+│ │ │ │ ├── jump-search.ts
+│ │ │ │ └── index.ts
+│ │ │ ├── graph/
+│ │ │ │ ├── bfs.ts
+│ │ │ │ ├── dfs.ts
+│ │ │ │ ├── dijkstra.ts
+│ │ │ │ └── index.ts
+│ │ │ ├── tree/
+│ │ │ │ ├── bst.ts
+│ │ │ │ ├── traversals.ts
+│ │ │ │ └── index.ts
+│ │ │ └── index.ts
+│ │ ├── tests/
+│ │ └── package.json
+│ │
+│ ├── visualizers/ # Visualization components
+│ │ ├── src/
+│ │ │ ├── engine/ # Animation engine
+│ │ │ │ ├── types.ts
+│ │ │ │ ├── animation-engine.ts
+│ │ │ │ ├── use-animation.ts
+│ │ │ │ └── index.ts
+│ │ │ ├── sorting/
+│ │ │ │ ├── BubbleSortVisualizer.tsx
+│ │ │ │ ├── QuickSortVisualizer.tsx
+│ │ │ │ └── index.ts
+│ │ │ ├── searching/
+│ │ │ ├── graph/
+│ │ │ ├── tree/
+│ │ │ ├── registry.ts # Visualizer registry
+│ │ │ └── index.ts
+│ │ └── package.json
+│ │
+│ ├── types/ # Shared TypeScript types
+│ │ ├── src/
+│ │ │ ├── algorithm.types.ts
+│ │ │ ├── visualizer.types.ts
+│ │ │ ├── animation.types.ts
+│ │ │ └── index.ts
+│ │ └── package.json
+│ │
+│ ├── utils/ # Shared utilities
+│ │ ├── src/
+│ │ │ ├── array-utils.ts
+│ │ │ ├── graph-utils.ts
+│ │ │ ├── url-state.ts
+│ │ │ └── index.ts
+│ │ └── package.json
+│ │
+│ └── config/ # Shared configurations
+│ ├── eslint/
+│ ├── typescript/
+│ ├── tailwind/
+│ └── package.json
+│
+├── .github/
+│ ├── workflows/
+│ │ ├── ci.yml
+│ │ ├── release.yml
+│ │ └── dependency-update.yml
+│ ├── ISSUE_TEMPLATE/
+│ │ ├── bug_report.md
+│ │ ├── feature_request.md
+│ │ └── new_visualizer.md
+│ ├── PULL_REQUEST_TEMPLATE.md
+│ └── CODEOWNERS
+│
+├── turbo.json
+├── package.json
+├── pnpm-lock.yaml
+├── pnpm-workspace.yaml
+├── CONTRIBUTING.md
+├── CODE_OF_CONDUCT.md
+├── LICENSE
+└── README.md
+```
+
+
+## Application Architecture
+
+### apps/app - Main Visualizer Application
+
+```mermaid
+flowchart TB;
+ subgraph Pages[Pages - App Router];
+ Dashboard[Dashboard Page];
+ Visualize[Visualize Page];
+ Playground[Playground Page];
+ Learn[Learn Page];
+ end
+
+ subgraph Components[Components];
+ Sidebar[Sidebar Navigation];
+ VisualizerContainer[Visualizer Container];
+ ControlPanel[Control Panel];
+ CodeEditor[Code Editor];
+ StepInfo[Step Information];
+ end
+
+ subgraph State[State Layer];
+ ZustandStore[Zustand Store];
+ URLState[URL State];
+ LocalStorage[Local Storage];
+ end
+
+ subgraph Packages[External Packages];
+ VisualizersPackage[visualizers];
+ AlgorithmsPackage[algorithms];
+ UIPackage2[ui];
+ end
+
+ Dashboard --> Sidebar;
+ Visualize --> VisualizerContainer;
+ Visualize --> ControlPanel;
+ Visualize --> CodeEditor;
+ Playground --> VisualizerContainer;
+
+ VisualizerContainer --> VisualizersPackage;
+ ControlPanel --> UIPackage2;
+ CodeEditor --> Monaco[Monaco Editor];
+
+ Components --> State;
+ VisualizersPackage --> AlgorithmsPackage;
+```
+
+### Page Routing Structure
+
+```mermaid
+flowchart LR;
+ subgraph Routes[URL Routes];
+ Root["/"];
+ VisualizeRoot["/visualize"];
+ VisualizeCat["/visualize/sorting"];
+ VisualizeAlgo["/visualize/sorting/bubble-sort"];
+ PlaygroundRoute["/playground"];
+ LearnRoute["/learn"];
+ LearnPath["/learn/sorting-basics"];
+ end
+
+ Root --> Dashboard2[Dashboard];
+ VisualizeRoot --> CategoryList[Category List];
+ VisualizeCat --> AlgorithmList[Algorithm List];
+ VisualizeAlgo --> VisualizerPage[Visualizer Page];
+ PlaygroundRoute --> PlaygroundPage[Playground];
+ LearnRoute --> LearningPaths[Learning Paths];
+ LearnPath --> LessonPage[Lesson Page];
+```
+
+
+## Data Flow
+
+### Visualization Data Flow
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant UI as UI Controls
+ participant Store as Zustand Store
+ participant Engine as Animation Engine
+ participant Algo as Algorithm Package
+ participant Viz as Visualizer Component
+
+ User->>UI: Set array [5, 3, 8, 1, 2]
+ UI->>Store: updateArray([5, 3, 8, 1, 2])
+ User->>UI: Click "Play"
+ UI->>Store: play()
+ Store->>Algo: generateSteps(array)
+ Algo-->>Store: steps[]
+ Store->>Engine: startAnimation(steps)
+
+ loop Each Step
+ Engine->>Store: setCurrentStep(n)
+ Store->>Viz: render(currentState)
+ Viz-->>User: Visual update
+ Engine->>Engine: wait(speed)
+ end
+
+ Engine-->>Store: animationComplete()
+```
+
+### State Synchronization Flow
+
+```mermaid
+flowchart LR;
+ subgraph Sources[State Sources];
+ UserInput[User Input];
+ URLParams[URL Parameters];
+ Storage[Local Storage];
+ end
+
+ subgraph Store[Zustand Store];
+ ArrayState[Array State];
+ AnimationState[Animation State];
+ PreferencesState[Preferences];
+ end
+
+ subgraph Sync[Synchronization];
+ URLSync[URL Sync];
+ StorageSync[Storage Sync];
+ end
+
+ UserInput --> Store;
+ URLParams --> URLSync;
+ URLSync --> Store;
+ Storage --> StorageSync;
+ StorageSync --> Store;
+ Store --> URLSync;
+ Store --> StorageSync;
+```
+
+## Visualizer Plugin System
+
+### Plugin Interface
+
+```typescript
+// packages/types/src/visualizer.types.ts
+
+export type VisualizerCategory =
+ | 'sorting'
+ | 'searching'
+ | 'graph'
+ | 'tree'
+ | 'dp'
+ | 'data-structure';
+
+export interface TimeComplexity {
+ best: string;
+ average: string;
+ worst: string;
+}
+
+export interface Complexity {
+ time: TimeComplexity;
+ space: string;
+}
+
+export interface VisualizerMeta {
+ id: string;
+ name: string;
+ category: VisualizerCategory;
+ description: string;
+ complexity: Complexity;
+ tags: string[];
+ difficulty: 'beginner' | 'intermediate' | 'advanced';
+}
+
+export interface VisualizerProps {
+ data: T;
+ currentStep: number;
+ steps: AnimationStep[];
+ isPlaying: boolean;
+ speed: number;
+}
+
+export interface ControlsProps {
+ onPlay: () => void;
+ onPause: () => void;
+ onReset: () => void;
+ onStepForward: () => void;
+ onStepBackward: () => void;
+ onSpeedChange: (speed: number) => void;
+ onDataChange: (data: unknown) => void;
+ isPlaying: boolean;
+ currentStep: number;
+ totalSteps: number;
+ speed: number;
+}
+
+export interface VisualizerPlugin {
+ meta: VisualizerMeta;
+ component: React.ComponentType>;
+ controls: React.ComponentType;
+ generateSteps: (input: TInput, options?: TOptions) => AnimationStep[];
+ defaultInput: TInput;
+ defaultCode: string;
+ validateInput?: (input: unknown) => input is TInput;
+}
+```
+
+### Plugin Registration
+
+```mermaid
+flowchart TB;
+ subgraph Plugins[Visualizer Plugins];
+ BubbleSort[BubbleSortPlugin];
+ QuickSort[QuickSortPlugin];
+ MergeSort[MergeSortPlugin];
+ BinarySearch[BinarySearchPlugin];
+ BFS[BFSPlugin];
+ end
+
+ subgraph Registry[Visualizer Registry];
+ Register[register];
+ Get[get];
+ GetByCategory[getByCategory];
+ GetAll[getAll];
+ end
+
+ subgraph App[Application];
+ Router[Dynamic Router];
+ Renderer[Visualizer Renderer];
+ end
+
+ Plugins --> Register;
+ Register --> Registry;
+ Router --> Get;
+ Get --> Renderer;
+```
+
+### Registry Implementation
+
+```typescript
+// packages/visualizers/src/registry.ts
+
+import type { VisualizerPlugin, VisualizerCategory } from '@opendsa/types';
+
+class VisualizerRegistry {
+ private plugins: Map = new Map();
+
+ register(plugin: VisualizerPlugin): void {
+ if (this.plugins.has(plugin.meta.id)) {
+ console.warn(`Plugin ${plugin.meta.id} already registered. Overwriting.`);
+ }
+ this.plugins.set(plugin.meta.id, plugin);
+ }
+
+ get(id: string): VisualizerPlugin | undefined {
+ return this.plugins.get(id);
+ }
+
+ getByCategory(category: VisualizerCategory): VisualizerPlugin[] {
+ return Array.from(this.plugins.values())
+ .filter(plugin => plugin.meta.category === category);
+ }
+
+ getAll(): VisualizerPlugin[] {
+ return Array.from(this.plugins.values());
+ }
+
+ getCategories(): VisualizerCategory[] {
+ const categories = new Set(
+ Array.from(this.plugins.values()).map(p => p.meta.category)
+ );
+ return Array.from(categories);
+ }
+}
+
+export const registry = new VisualizerRegistry();
+```
+
+
+## Animation Engine
+
+### Animation Types
+
+```typescript
+// packages/types/src/animation.types.ts
+
+export type StepType =
+ | 'compare'
+ | 'swap'
+ | 'highlight'
+ | 'insert'
+ | 'delete'
+ | 'visit'
+ | 'mark-sorted'
+ | 'mark-found'
+ | 'pivot'
+ | 'partition';
+
+export interface AnimationStep {
+ id: string;
+ type: StepType;
+ indices: number[];
+ values?: unknown[];
+ description: string;
+ codeLineNumbers?: number[];
+ metadata?: Record;
+}
+
+export interface AnimationState {
+ steps: AnimationStep[];
+ currentStep: number;
+ isPlaying: boolean;
+ speed: number; // 1-100, percentage
+ direction: 'forward' | 'backward';
+}
+
+export interface AnimationControls {
+ play: () => void;
+ pause: () => void;
+ reset: () => void;
+ stepForward: () => void;
+ stepBackward: () => void;
+ goToStep: (step: number) => void;
+ setSpeed: (speed: number) => void;
+}
+```
+
+### Animation Engine Architecture
+
+```mermaid
+stateDiagram-v2
+ [*] --> Idle
+ Idle --> Playing: play()
+ Playing --> Paused: pause()
+ Paused --> Playing: play()
+ Playing --> Idle: reset()
+ Paused --> Idle: reset()
+ Playing --> Completed: lastStep
+ Completed --> Idle: reset()
+ Completed --> Playing: play() from start
+
+ Playing --> Playing: stepForward()
+ Paused --> Paused: stepForward()
+ Paused --> Paused: stepBackward()
+```
+
+### Animation Hook
+
+```typescript
+// packages/visualizers/src/engine/use-animation.ts
+
+import { useCallback, useEffect, useRef } from 'react';
+import { useStore } from 'zustand';
+import type { AnimationStep, AnimationControls } from '@opendsa/types';
+
+interface UseAnimationOptions {
+ steps: AnimationStep[];
+ onStepChange?: (step: number, stepData: AnimationStep) => void;
+ onComplete?: () => void;
+}
+
+export function useAnimation(options: UseAnimationOptions): AnimationControls {
+ const { steps, onStepChange, onComplete } = options;
+ const timerRef = useRef(null);
+
+ // Implementation details...
+
+ return {
+ play,
+ pause,
+ reset,
+ stepForward,
+ stepBackward,
+ goToStep,
+ setSpeed,
+ };
+}
+```
+
+
+## State Management
+
+### Zustand Store Structure
+
+```mermaid
+flowchart TB;
+ subgraph Store[Global Store];
+ subgraph VisualizerSlice[Visualizer Slice];
+ CurrentViz[currentVisualizer];
+ Data[data];
+ Steps[steps];
+ CurrentStep[currentStep];
+ end
+
+ subgraph AnimationSlice[Animation Slice];
+ IsPlaying[isPlaying];
+ Speed[speed];
+ Direction[direction];
+ end
+
+ subgraph PreferencesSlice[Preferences Slice];
+ Theme[theme];
+ EditorVisible[editorVisible];
+ SidebarOpen[sidebarOpen];
+ end
+ end
+
+ subgraph Middleware[Middleware];
+ Persist[persist];
+ DevTools[devtools];
+ URLSync2[url-sync];
+ end
+
+ Store --> Middleware;
+```
+
+### Store Implementation
+
+```typescript
+// apps/app/lib/store.ts
+
+import { create } from 'zustand';
+import { persist, devtools } from 'zustand/middleware';
+import type { AnimationStep } from '@opendsa/types';
+
+interface VisualizerState {
+ // Visualizer state
+ currentVisualizer: string | null;
+ data: unknown;
+ steps: AnimationStep[];
+ currentStep: number;
+
+ // Animation state
+ isPlaying: boolean;
+ speed: number;
+
+ // Actions
+ setVisualizer: (id: string) => void;
+ setData: (data: unknown) => void;
+ setSteps: (steps: AnimationStep[]) => void;
+ setCurrentStep: (step: number) => void;
+ play: () => void;
+ pause: () => void;
+ reset: () => void;
+ setSpeed: (speed: number) => void;
+}
+
+interface PreferencesState {
+ theme: 'light' | 'dark' | 'system';
+ editorVisible: boolean;
+ sidebarOpen: boolean;
+
+ setTheme: (theme: 'light' | 'dark' | 'system') => void;
+ toggleEditor: () => void;
+ toggleSidebar: () => void;
+}
+
+export const useVisualizerStore = create()(
+ devtools(
+ (set, get) => ({
+ currentVisualizer: null,
+ data: [],
+ steps: [],
+ currentStep: 0,
+ isPlaying: false,
+ speed: 50,
+
+ setVisualizer: (id) => set({ currentVisualizer: id }),
+ setData: (data) => set({ data }),
+ setSteps: (steps) => set({ steps, currentStep: 0 }),
+ setCurrentStep: (step) => set({ currentStep: step }),
+ play: () => set({ isPlaying: true }),
+ pause: () => set({ isPlaying: false }),
+ reset: () => set({ currentStep: 0, isPlaying: false }),
+ setSpeed: (speed) => set({ speed }),
+ }),
+ { name: 'visualizer-store' }
+ )
+);
+
+export const usePreferencesStore = create()(
+ persist(
+ (set) => ({
+ theme: 'system',
+ editorVisible: true,
+ sidebarOpen: true,
+
+ setTheme: (theme) => set({ theme }),
+ toggleEditor: () => set((state) => ({ editorVisible: !state.editorVisible })),
+ toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
+ }),
+ { name: 'opendsa-preferences' }
+ )
+);
+```
+
+
+## Component Architecture
+
+### Component Hierarchy
+
+```mermaid
+flowchart TB;
+ subgraph AppLayout[App Layout];
+ Header[Header];
+ Sidebar2[Sidebar];
+ MainContent[Main Content];
+ end
+
+ subgraph VisualizerPage[Visualizer Page];
+ VisualizerHeader[Visualizer Header];
+ VisualizerBody[Visualizer Body];
+ VisualizerFooter[Visualizer Footer];
+ end
+
+ subgraph VisualizerBodyContent[Visualizer Body Content];
+ VisualizerPanel[Visualizer Panel];
+ EditorPanel[Editor Panel];
+ end
+
+ subgraph VisualizerPanelContent[Visualizer Panel];
+ Canvas[Canvas/SVG];
+ StepIndicator[Step Indicator];
+ ControlBar[Control Bar];
+ end
+
+ subgraph EditorPanelContent[Editor Panel];
+ CodeEditor2[Code Editor];
+ Console[Console Output];
+ end
+
+ MainContent --> VisualizerPage;
+ VisualizerBody --> VisualizerBodyContent;
+ VisualizerBodyContent --> VisualizerPanelContent;
+ VisualizerBodyContent --> EditorPanelContent;
+```
+
+### Component Responsibilities
+
+| Component | Responsibility |
+|-----------|---------------|
+| `AppLayout` | Global layout, navigation, theme |
+| `Sidebar` | Algorithm/category navigation |
+| `VisualizerPage` | Page-level state, data fetching |
+| `VisualizerPanel` | Render visualization, handle resize |
+| `ControlBar` | Play/pause, speed, step controls |
+| `EditorPanel` | Code display, syntax highlighting |
+| `StepIndicator` | Current step info, progress |
+
+
+## API Design
+
+### Internal Package APIs
+
+```typescript
+// @opendsa/algorithms - Algorithm package exports
+export { bubbleSort, bubbleSortSteps } from './sorting/bubble-sort';
+export { quickSort, quickSortSteps } from './sorting/quick-sort';
+export { mergeSort, mergeSortSteps } from './sorting/merge-sort';
+export { linearSearch, linearSearchSteps } from './searching/linear-search';
+export { binarySearch, binarySearchSteps } from './searching/binary-search';
+export { bfs, bfsSteps } from './graph/bfs';
+export { dfs, dfsSteps } from './graph/dfs';
+
+// @opendsa/visualizers - Visualizer package exports
+export { registry } from './registry';
+export { useAnimation } from './engine/use-animation';
+export { BubbleSortVisualizer } from './sorting/BubbleSortVisualizer';
+export { QuickSortVisualizer } from './sorting/QuickSortVisualizer';
+// ... other visualizers
+
+// @opendsa/ui - UI component exports
+export { Button } from './components/button';
+export { Card } from './components/card';
+export { Slider } from './components/slider';
+export { Input } from './components/input';
+// ... other components
+
+// @opendsa/types - Type exports
+export type { AnimationStep, StepType } from './animation.types';
+export type { VisualizerPlugin, VisualizerMeta } from './visualizer.types';
+export type { AlgorithmResult } from './algorithm.types';
+```
+
+### URL State API
+
+```typescript
+// URL structure for sharing visualizations
+// https://app.opendsa.dev/visualize/sorting/bubble-sort?data=5,3,8,1,2&step=5&speed=50
+
+interface URLState {
+ data?: string; // Comma-separated values
+ step?: number; // Current step
+ speed?: number; // Animation speed (1-100)
+ playing?: boolean; // Auto-play on load
+}
+
+// Utility functions
+export function encodeURLState(state: Partial): string;
+export function decodeURLState(search: string): Partial;
+export function useURLState(): [URLState, (state: Partial) => void];
+```
+
+
+## Security Considerations
+
+### Code Execution
+
+- User code runs in a **sandboxed Web Worker**
+- No access to DOM, localStorage, or network
+- Execution timeout limits (5 seconds default)
+- Memory limits enforced
+
+### Input Validation
+
+- All user inputs validated before processing
+- Array size limits (max 100 elements for visualization)
+- Value range limits
+- Sanitization of any user-provided strings
+
+
+## Performance Optimizations
+
+### Rendering
+
+- **Canvas API** for large array visualizations (>50 elements)
+- **SVG** for smaller, more detailed visualizations
+- **React.memo** for static components
+- **useMemo/useCallback** for expensive computations
+
+### Animation
+
+- **RequestAnimationFrame** for smooth animations
+- **Web Workers** for step generation (large inputs)
+- **Virtualization** for step history (>1000 steps)
+
+### Bundle Size
+
+- **Tree shaking** enabled for all packages
+- **Dynamic imports** for visualizers (code split per visualizer)
+- **Lazy loading** for Monaco Editor
+
+
+## Accessibility
+
+### Requirements
+
+- **WCAG 2.1 AA** compliance target
+- **Keyboard navigation** for all controls
+- **Screen reader** announcements for step changes
+- **High contrast** mode support
+- **Reduced motion** preference respected
+
+### Implementation
+
+```typescript
+// Accessibility hook for visualizations
+export function useA11yAnnouncements() {
+ const announce = useCallback((message: string) => {
+ // Use aria-live region to announce changes
+ }, []);
+
+ return { announce };
+}
+```
+
+
+## Testing Strategy
+
+### Unit Tests (Vitest)
+
+- Algorithm correctness
+- Step generation accuracy
+- Utility functions
+- Store actions/selectors
+
+### Component Tests (Testing Library)
+
+- Component rendering
+- User interactions
+- State updates
+- Accessibility
+
+### E2E Tests (Playwright)
+
+- Full user flows
+- Cross-browser testing
+- Visual regression
+- Performance benchmarks
+
+
+## Conclusion
+
+This architecture provides:
+
+1. **Scalability** - Easy to add new algorithms and visualizers
+2. **Maintainability** - Clear separation of concerns
+3. **Contributor-friendly** - Well-defined plugin system
+4. **Performance** - Optimized rendering and animations
+5. **Accessibility** - Built-in from the start
+6. **Type safety** - Full TypeScript coverage
+
+The modular design ensures that OpenDSA can grow with its community while maintaining code quality and user experience.
diff --git a/apps/docs/app/project/migration/page.mdx b/apps/docs/app/project/migration/page.mdx
new file mode 100644
index 0000000..f5634a6
--- /dev/null
+++ b/apps/docs/app/project/migration/page.mdx
@@ -0,0 +1,42 @@
+---
+title: Migration
+description: Overview of the migration from the legacy project to OpenDSA.
+---
+
+# Migration to OpenDSA
+
+> A high-level overview of migrating from the legacy [ds-algo-deck](https://dsalgodeck.netlify.app/) project to the new OpenDSA platform.
+
+## Overview
+
+The OpenDSA project is a complete rewrite and modernization of the previous [`ds-algo-deck`](https://dsalgodeck.netlify.app/) visualization tool. This migration was driven by the need for better scalability, performance, and a more robust contributor experience.
+
+## Why Migrate?
+
+The legacy project was built with **React + Vite** and **Redux Toolkit**. While functional, as the project grew, we encountered limitations in:
+
+- **Scalability**: Managing a growing number of visualizers in a single repository without clear boundaries was becoming difficult.
+- **Performance**: Heavy visualizations started to impact UI responsiveness.
+- **Maintainability**: Mixed styling approaches (Tailwind + Styled Components) and lack of strict typing made contributions harder.
+
+## The New Stack
+
+OpenDSA introduces a modern, monorepo-based architecture:
+
+- **Next.js & Turborepo**: For efficient build pipelines and server-side capabilities.
+- **TypeScript**: Strict type safety across the entire codebase.
+- **Zustand**: Lightweight, performant state management.
+- **shadcn/ui**: a cohesive, accessible design system.
+
+| Aspect | Legacy (ds-algo-deck) | OpenDSA |
+|--------|------------------------|---------|
+| **Core** | React SPA | Next.js App Router |
+| **Repo** | Single Repo | Monorepo (Turborepo) |
+| **State** | Redux | Zustand |
+| **Styles** | Mixed | TailwindCSS + shadcn/ui |
+
+## Legacy Repository
+
+This documentation serves as the new home for the project. The old repository is kept for reference but development has moved here.
+
+For detailed internal migration steps used during the transition, please refer to the internal documentation or the project's commit history.
diff --git a/apps/docs/app/project/roadmap/page.mdx b/apps/docs/app/project/roadmap/page.mdx
new file mode 100644
index 0000000..2b5c5f3
--- /dev/null
+++ b/apps/docs/app/project/roadmap/page.mdx
@@ -0,0 +1,581 @@
+---
+title: Roadmap
+description: A phased approach to building the ultimate algorithm visualization platform.
+---
+
+# OpenDSA - Product Roadmap
+
+> A phased approach to building the ultimate algorithm visualization platform.
+
+## Table of Contents
+
+1. [Vision](#vision)
+2. [Roadmap Overview](#roadmap-overview)
+3. [Phase 1: Foundation](#phase-1-foundation-mvp)
+4. [Phase 2: Core Features](#phase-2-core-features)
+5. [Phase 3: Community and Learning](#phase-3-community-and-learning)
+6. [Phase 4: Advanced Features](#phase-4-advanced-features)
+7. [Future Considerations](#future-considerations)
+8. [Success Metrics](#success-metrics)
+
+
+## Vision
+
+**OpenDSA** aims to be the go-to open-source platform for visualizing and learning data structures and algorithms. Our goal is to make algorithm education:
+
+- **Visual**: See algorithms come to life
+- **Interactive**: Control and experiment with algorithms
+- **Accessible**: Free and open to everyone
+- **Community-driven**: Built by learners, for learners
+
+
+## Roadmap Overview
+
+```mermaid
+gantt
+ title OpenDSA Development Roadmap
+ dateFormat YYYY-MM
+
+ section Phase 1
+ Foundation/MVP :p1, 2026-01-24, 3M
+
+ section Phase 2
+ Core Features :p2, after p1, 3M
+
+ section Phase 3
+ Community/Learning :p3, after p2, 3M
+
+ section Phase 4
+ Advanced Features :p4, after p3, 3M
+```
+
+### Phase Summary
+
+| Phase | Focus | Duration | Status |
+|-------|-------|----------|--------|
+| Phase 1 | Foundation & MVP | ~3 months | Planned |
+| Phase 2 | Core Features | ~3 months | Planned |
+| Phase 3 | Community & Learning | ~3 months | Planned |
+| Phase 4 | Advanced Features | ~3 months | Planned |
+
+
+## Phase 1: Foundation (MVP)
+
+**Goal**: Establish the technical foundation and launch with essential features.
+
+### 1.1 Infrastructure Setup
+
+- [X] **Repository Setup**
+ - Initialize Turborepo monorepo
+ - Configure pnpm workspaces
+ - Set up TypeScript strict mode
+ - Configure ESLint + Prettier
+ - Set up Husky for git hooks
+
+- [ ] **CI/CD Pipeline**
+ - GitHub Actions for CI (lint, type-check, test, build)
+ - Vercel deployment configuration
+ - Preview deployments for PRs
+ - Automated dependency updates (Dependabot)
+
+- [ ] **Core Packages**
+ - `@opendsa/types` - Shared TypeScript types
+ - `@opendsa/config` - Shared configurations
+ - `@opendsa/utils` - Utility functions
+
+### 1.2 UI Component Library
+
+- [ ] **Base Components** (`@opendsa/ui`)
+ - Button, Input, Slider
+ - Card, Dialog, Popover
+ - Dropdown, Select, Tabs
+ - Toast notifications
+ - Theme provider (light/dark)
+
+- [ ] **Visualizer Components**
+ - Bar chart component (for sorting)
+ - Array visualization component
+ - Control panel component
+ - Step indicator component
+ - Speed slider component
+
+### 1.3 Animation Engine
+
+- [ ] **Core Engine** (`@opendsa/visualizers`)
+ - Step-based animation system
+ - Play/pause/reset controls
+ - Step forward/backward
+ - Speed control (1x - 10x)
+ - Animation state management
+
+- [ ] **Animation Hooks**
+ - `useAnimation` hook
+ - `useVisualizerStore` hook
+ - Keyboard shortcuts support
+
+### 1.4 Initial Algorithms
+
+- [ ] **Sorting Algorithms** (`@opendsa/algorithms`)
+ - Bubble Sort
+ - Selection Sort
+ - Insertion Sort
+ - Quick Sort
+ - Merge Sort
+
+- [ ] **Searching Algorithms**
+ - Linear Search
+ - Binary Search
+
+- [ ] **Data Structure Operations**
+ - Array: insert, delete, update, search
+
+### 1.5 Visualizer Application
+
+- [ ] **App Structure** (`apps/app`)
+ - Next.js App Router setup
+ - Layout with sidebar navigation
+ - Dynamic visualizer routes
+ - Responsive design (tablet+)
+
+- [ ] **Visualizer Pages**
+ - Sorting algorithm visualizers (5)
+ - Searching algorithm visualizers (2)
+ - Array operations visualizer
+
+- [ ] **Features**
+ - Play/pause animations
+ - Step-by-step mode
+ - Speed control
+ - Random array generation
+ - Custom array input
+
+### 1.6 Marketing Website
+
+- [X] **Landing Page** (`apps/web`)
+ - Hero section with demo
+ - Features overview
+ - Algorithm categories
+ - Call to action
+
+- [X] **Pages**
+ - Home (landing)
+ - Features
+ - About
+
+### 1.7 Documentation Site
+
+- [ ] **Initial Docs** (`apps/docs`)
+ - Getting started guide
+ - Installation instructions
+ - Quick start tutorial
+ - Contributing guide
+
+### 1.8 Launch Checklist
+
+- [ ] Domain setup (opendsa.dev)
+- [ ] SEO configuration
+- [ ] Analytics setup
+- [ ] Error tracking (Sentry)
+- [ ] README and LICENSE
+- [ ] Social media presence
+- [ ] Launch announcement
+
+
+## Phase 2: Core Features
+
+**Goal**: Expand algorithm coverage and enhance the visualization experience.
+
+### 2.1 Additional Sorting Algorithms
+
+- [ ] Heap Sort
+- [ ] Counting Sort
+- [ ] Radix Sort
+- [ ] Bucket Sort
+- [ ] Shell Sort
+- [ ] Tim Sort (simplified)
+
+### 2.2 Additional Searching Algorithms
+
+- [ ] Jump Search
+- [ ] Interpolation Search
+- [ ] Exponential Search
+- [ ] Ternary Search
+
+### 2.3 Graph Algorithms
+
+- [ ] **Graph Data Structure**
+ - Graph visualization component
+ - Node/edge creation UI
+ - Adjacency list/matrix views
+
+- [ ] **Traversal Algorithms**
+ - Breadth-First Search (BFS)
+ - Depth-First Search (DFS)
+
+- [ ] **Shortest Path**
+ - Dijkstra's Algorithm
+ - Bellman-Ford Algorithm
+ - Floyd-Warshall Algorithm
+
+- [ ] **Minimum Spanning Tree**
+ - Prim's Algorithm
+ - Kruskal's Algorithm
+
+### 2.4 Tree Algorithms
+
+- [ ] **Binary Search Tree**
+ - Insert, Delete, Search
+ - Tree visualization component
+ - Balance visualization
+
+- [ ] **Tree Traversals**
+ - Inorder
+ - Preorder
+ - Postorder
+ - Level order
+
+- [ ] **Advanced Trees** (simplified)
+ - AVL Tree rotations
+ - Red-Black Tree concepts
+
+### 2.5 Data Structure Visualizers
+
+- [ ] **Linked List**
+ - Singly linked list
+ - Doubly linked list
+ - Insert, delete, reverse
+
+- [ ] **Stack**
+ - Push, pop, peek
+ - Expression evaluation demo
+
+- [ ] **Queue**
+ - Enqueue, dequeue
+ - Circular queue
+ - Priority queue concepts
+
+- [ ] **Hash Table**
+ - Insert, search, delete
+ - Collision handling visualization
+
+### 2.6 Enhanced Features
+
+- [ ] **Code Editor Integration**
+ - Monaco Editor setup
+ - Syntax highlighting
+ - Code step highlighting
+ - Multiple language support (JS, Python, Java, C++)
+
+- [ ] **Shareable URLs**
+ - Encode state in URL
+ - Share specific visualization state
+ - Deep linking to steps
+
+- [ ] **User Preferences**
+ - Theme persistence
+ - Speed preferences
+ - Layout preferences
+ - Keyboard shortcuts customization
+
+### 2.7 Performance Optimizations
+
+- [ ] Canvas rendering for large arrays
+- [ ] Virtualization for step history
+- [ ] Web Worker for step generation
+- [ ] Bundle size optimization
+
+
+## Phase 3: Community and Learning
+
+**Goal**: Build educational content and community engagement features.
+
+### 3.1 Learning Paths
+
+- [ ] **Structured Courses**
+ - "Introduction to Sorting"
+ - "Mastering Searching"
+ - "Graph Algorithms 101"
+ - "Trees and Recursion"
+
+- [ ] **Path Features**
+ - Progress tracking
+ - Prerequisites
+ - Estimated duration
+ - Difficulty levels
+
+### 3.2 Interactive Tutorials
+
+- [ ] **Guided Walkthroughs**
+ - Step-by-step explanations
+ - Interactive quizzes
+ - "Try it yourself" sections
+ - Hints and solutions
+
+- [ ] **Concept Explanations**
+ - Time complexity visualizer
+ - Space complexity explanations
+ - Big O comparison charts
+ - Real-world applications
+
+### 3.3 Challenge Mode
+
+- [ ] **Algorithm Challenges**
+ - Predict the output
+ - Count the steps
+ - Identify the algorithm
+ - Fix the bug
+
+- [ ] **Gamification**
+ - Points/scoring system
+ - Streaks and achievements
+ - Leaderboard (optional)
+ - Progress badges
+
+### 3.4 Community Features
+
+- [ ] **Discord Integration**
+ - Discord server setup
+ - Role assignments
+ - Channel structure
+ - Bot for announcements
+
+- [ ] **Community Submissions**
+ - User-submitted visualizers
+ - Review process
+ - Attribution system
+
+- [ ] **Feedback System**
+ - In-app feedback
+ - Feature voting
+ - Bug reporting
+
+### 3.5 Blog
+
+- [ ] **Algorithm Deep Dives**
+ - Detailed explanations
+ - Use case examples
+ - Implementation tips
+
+- [ ] **Community Spotlights**
+ - Contributor features
+ - Project updates
+ - Release notes
+
+### 3.6 Documentation Expansion
+
+- [ ] **Algorithm Reference**
+ - Every algorithm documented
+ - Complexity analysis
+ - Code examples
+ - Related problems
+
+- [ ] **API Documentation**
+ - Package APIs
+ - Hook documentation
+ - Type definitions
+
+
+## Phase 4: Advanced Features
+
+**Goal**: Add power-user features and platform expansion capabilities.
+
+### 4.1 User Accounts (Optional)
+
+- [ ] **Authentication**
+ - GitHub OAuth
+ - Google OAuth
+ - Email/password (optional)
+
+- [ ] **User Features**
+ - Save favorite visualizations
+ - Track learning progress
+ - Custom settings sync
+ - Submission history
+
+### 4.2 Save and Load
+
+- [ ] **Visualization Saving**
+ - Save current state
+ - Name and organize
+ - Export/import JSON
+
+- [ ] **Collections**
+ - Create collections
+ - Share collections
+ - Public/private visibility
+
+### 4.3 Embed Widget
+
+- [ ] **Embeddable Component**
+ - iframe embed code
+ - Web component version
+ - Customization options
+
+- [ ] **Use Cases**
+ - Blog posts
+ - Documentation
+ - Educational platforms
+ - Coding bootcamps
+
+### 4.4 API
+
+- [ ] **Public API**
+ - Algorithm execution
+ - Step generation
+ - Embed configuration
+
+- [ ] **Integration Support**
+ - npm package for algorithms
+ - React component library
+ - Documentation
+
+### 4.5 Advanced Algorithms
+
+- [ ] **Dynamic Programming**
+ - Fibonacci visualization
+ - Longest Common Subsequence
+ - 0/1 Knapsack
+ - Matrix Chain Multiplication
+
+- [ ] **String Algorithms**
+ - Pattern matching (KMP)
+ - Rabin-Karp
+ - Trie operations
+
+- [ ] **Advanced Graph**
+ - Topological Sort
+ - Strongly Connected Components
+ - Network Flow concepts
+
+### 4.6 Mobile Experience
+
+- [ ] **Responsive Improvements**
+ - Mobile-optimized visualizations
+ - Touch gestures
+ - Portrait mode support
+
+- [ ] **PWA Features**
+ - Offline support
+ - Install prompt
+ - Push notifications (updates)
+
+### 4.7 Accessibility Audit
+
+- [ ] **WCAG 2.1 AA Compliance**
+ - Screen reader support
+ - Keyboard navigation
+ - High contrast mode
+ - Reduced motion support
+
+- [ ] **Documentation**
+ - Accessibility statement
+ - Known issues
+ - Alternative formats
+
+### 4.8 Internationalization
+
+- [ ] **i18n Setup**
+ - Translation framework
+ - Language selector
+ - RTL support
+
+- [ ] **Initial Languages**
+ - English (default)
+ - Spanish
+ - Chinese
+ - Hindi
+ - (Community contributions)
+
+
+## Future Considerations
+
+These are ideas for future exploration, not committed features:
+
+### Potential Features
+
+- **AI-Powered Explanations**: Use LLMs to generate custom explanations
+- **Collaborative Mode**: Real-time shared visualization sessions
+- **VR/AR Visualization**: 3D algorithm visualization
+- **Interview Prep Mode**: LeetCode-style practice integration
+- **Curriculum Builder**: Tools for educators to create courses
+- **Native Mobile Apps**: iOS/Android applications
+- **Desktop App**: Electron-based desktop application
+
+### Integration Ideas
+
+- **LeetCode/HackerRank**: Link to practice problems
+- **GitHub**: Import/export algorithm implementations
+- **Notion/Obsidian**: Embed widgets
+- **VS Code Extension**: In-editor visualization
+
+
+## Success Metrics
+
+### Phase 1 Metrics
+
+| Metric | Target |
+|--------|--------|
+| GitHub Stars | 100+ |
+| Monthly Active Users | 500+ |
+| Visualizers Available | 10+ |
+| Documentation Pages | 20+ |
+| Contributors | 5+ |
+
+### Phase 2 Metrics
+
+| Metric | Target |
+|--------|--------|
+| GitHub Stars | 500+ |
+| Monthly Active Users | 2,000+ |
+| Visualizers Available | 30+ |
+| Documentation Pages | 50+ |
+| Contributors | 15+ |
+
+### Phase 3 Metrics
+
+| Metric | Target |
+|--------|--------|
+| GitHub Stars | 2,000+ |
+| Monthly Active Users | 10,000+ |
+| Learning Paths | 5+ |
+| Discord Members | 500+ |
+| Blog Posts | 20+ |
+
+### Phase 4 Metrics
+
+| Metric | Target |
+|--------|--------|
+| GitHub Stars | 5,000+ |
+| Monthly Active Users | 50,000+ |
+| Embed Integrations | 100+ |
+| API Calls/Month | 10,000+ |
+| Languages Supported | 5+ |
+
+
+## How to Contribute to the Roadmap
+
+We welcome community input on our roadmap:
+
+1. **Feature Requests**: Open an issue with the "feature request" template
+2. **Voting**: React to issues to show support for features
+3. **Discussion**: Join our Discord to discuss roadmap items
+4. **Implementation**: Volunteer to implement roadmap items
+
+### Prioritization Criteria
+
+Features are prioritized based on:
+
+1. **Impact**: How many users will benefit
+2. **Effort**: Development complexity
+3. **Dependencies**: What needs to be built first
+4. **Community Interest**: Votes and feedback
+5. **Strategic Fit**: Alignment with project vision
+
+
+## Changelog
+
+| Date | Change |
+|------|--------|
+| 2026-01-24 | Initial roadmap created |
+
+*This roadmap is a living document and will be updated as the project evolves.*
diff --git a/apps/docs/app/project/tech_stack/page.mdx b/apps/docs/app/project/tech_stack/page.mdx
new file mode 100644
index 0000000..0fbc9ef
--- /dev/null
+++ b/apps/docs/app/project/tech_stack/page.mdx
@@ -0,0 +1,1049 @@
+---
+title: Tech Stack
+description: Comprehensive documentation of all technology choices and the rationale behind each decision.
+---
+
+# OpenDSA - Technology Stack
+
+> Comprehensive documentation of all technology choices and the rationale behind each decision.
+
+## Table of Contents
+
+1. [Overview](#overview)
+2. [Core Framework](#core-framework)
+3. [Build System](#build-system)
+4. [UI and Styling](#ui-and-styling)
+5. [Animations and Visualizations](#animations-and-visualizations)
+6. [State Management](#state-management)
+7. [Code Editor](#code-editor)
+8. [Testing](#testing)
+9. [Documentation](#documentation)
+10. [Deployment](#deployment)
+11. [Development Tools](#development-tools)
+12. [Comparison with Current Stack](#comparison-with-current-stack)
+
+
+## Overview
+
+The OpenDSA tech stack is chosen based on the following criteria:
+
+- **Industry Standard**: Widely adopted, well-documented technologies
+- **Developer Experience**: Fast iteration, good tooling, TypeScript support
+- **Performance**: Optimized for smooth animations and responsive UI
+- **Open Source Friendly**: Easy for contributors to understand and work with
+- **Scalability**: Can grow with the project's needs
+- **Maintainability**: Long-term support, active communities
+
+```mermaid
+flowchart TB;
+ subgraph Frontend[Frontend Layer];
+ NextJS[Next.js 14+];
+ React[React 18+];
+ TypeScript[TypeScript 5+];
+ end
+
+ subgraph Build[Build Layer];
+ Turborepo[Turborepo];
+ PNPM[pnpm];
+ end
+
+ subgraph UI[UI Layer];
+ ShadcnUI[shadcn/ui];
+ TailwindCSS[TailwindCSS];
+ RadixUI[Radix UI];
+ end
+
+ subgraph Animation[Animation Layer];
+ FramerMotion[Framer Motion];
+ D3JS[D3.js];
+ CanvasAPI[Canvas API];
+ end
+
+ subgraph State[State Layer];
+ Zustand[Zustand];
+ TanStackQuery[TanStack Query];
+ end
+
+ subgraph Testing2[Testing Layer];
+ Vitest[Vitest];
+ Playwright[Playwright];
+ TestingLibrary[Testing Library];
+ end
+
+ subgraph Deploy[Deployment];
+ Vercel[Vercel];
+ GitHubActions[GitHub Actions];
+ end
+
+ Frontend --> Build;
+ Frontend --> UI;
+ Frontend --> Animation;
+ Frontend --> State;
+ Frontend --> Testing2;
+ Build --> Deploy;
+```
+
+
+## Core Framework
+
+### Next.js 14+ (App Router)
+
+**Choice**: Next.js with App Router
+
+**Alternatives Considered**:
+- Vite + React (current stack)
+- Remix
+- Astro
+- Create React App
+
+**Rationale**:
+
+| Feature | Next.js | Vite + React | Remix |
+|---------|---------|--------------|-------|
+| SSR/SSG | Built-in | Manual | Built-in |
+| File-based routing | Yes | No | Yes |
+| API routes | Yes | No | Yes |
+| Image optimization | Built-in | Manual | Manual |
+| Vercel integration | Native | Good | Good |
+| App Router (RSC) | Yes | No | No |
+| Community/Ecosystem | Largest | Large | Growing |
+
+**Key Benefits**:
+1. **Server Components**: Reduce client bundle size
+2. **File-based Routing**: Intuitive, less boilerplate
+3. **Built-in Optimizations**: Images, fonts, scripts
+4. **Vercel Deployment**: Zero-config, preview deployments
+5. **SEO**: Better for marketing site
+6. **Ecosystem**: Vast plugin and tool support
+
+**Configuration**:
+```typescript
+// next.config.js
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ experimental: {
+ typedRoutes: true,
+ },
+ images: {
+ remotePatterns: [
+ { hostname: 'avatars.githubusercontent.com' },
+ ],
+ },
+ transpilePackages: [
+ '@opendsa/ui',
+ '@opendsa/visualizers',
+ '@opendsa/algorithms',
+ ],
+};
+
+export default nextConfig;
+```
+
+
+### TypeScript 5+
+
+**Choice**: TypeScript with strict mode
+
+**Alternatives Considered**:
+- JavaScript (current stack)
+- JSDoc type annotations
+
+**Rationale**:
+
+1. **Type Safety**: Catch errors at compile time
+2. **Better DX**: Autocomplete, refactoring support
+3. **Documentation**: Types serve as documentation
+4. **Contributor Experience**: Easier to understand codebase
+5. **Industry Standard**: Expected for serious projects
+
+**Configuration**:
+```json
+// tsconfig.json
+{
+ "compilerOptions": {
+ "strict": true,
+ "noUncheckedIndexedAccess": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "exactOptionalPropertyTypes": true,
+ "moduleResolution": "bundler",
+ "module": "ESNext",
+ "target": "ES2022",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "jsx": "preserve",
+ "incremental": true,
+ "paths": {
+ "@/*": ["./src/*"],
+ "@opendsa/ui": ["../../packages/ui/src"],
+ "@opendsa/algorithms": ["../../packages/algorithms/src"],
+ "@opendsa/visualizers": ["../../packages/visualizers/src"],
+ "@opendsa/types": ["../../packages/types/src"],
+ "@opendsa/utils": ["../../packages/utils/src"]
+ }
+ }
+}
+```
+
+
+### pnpm
+
+**Choice**: pnpm as package manager
+
+**Alternatives Considered**:
+- npm (current)
+- yarn
+- bun
+
+**Rationale**:
+
+| Feature | pnpm | npm | yarn | bun |
+|---------|------|-----|------|-----|
+| Disk space | Best | Worst | Medium | Best |
+| Install speed | Fast | Slow | Medium | Fastest |
+| Monorepo support | Native | Limited | Good | Growing |
+| Strict mode | Yes | No | No | No |
+| Stability | Excellent | Excellent | Good | Beta |
+
+**Key Benefits**:
+1. **Efficient Storage**: Content-addressable store, symlinks
+2. **Fast**: Up to 2x faster than npm
+3. **Strict**: Prevents phantom dependencies
+4. **Monorepo Native**: Built-in workspace support
+5. **Industry Adoption**: Used by Vue, Vite, Turborepo
+
+
+## Build System
+
+### Turborepo
+
+**Choice**: Turborepo for monorepo management
+
+**Alternatives Considered**:
+- Nx
+- Lerna
+- Rush
+- No monorepo (separate repos)
+
+**Rationale**:
+
+| Feature | Turborepo | Nx | Lerna |
+|---------|-----------|-----|-------|
+| Learning curve | Low | High | Medium |
+| Build caching | Excellent | Excellent | Limited |
+| Remote caching | Vercel | Nx Cloud | No |
+| Configuration | Minimal | Complex | Moderate |
+| Vercel integration | Native | Manual | Manual |
+
+**Key Benefits**:
+1. **Simple Configuration**: Single `turbo.json`
+2. **Intelligent Caching**: Local and remote caching
+3. **Parallel Execution**: Run tasks in parallel
+4. **Vercel Integration**: Free remote caching
+5. **Incremental Builds**: Only rebuild what changed
+
+**Configuration** (Turborepo 2.0+):
+```json
+// turbo.json
+{
+ "$schema": "https://turborepo.dev/schema.json",
+ "globalDependencies": ["**/.env.*local"],
+ "tasks": {
+ "build": {
+ "dependsOn": ["^build"],
+ "outputs": [".next/**", "!.next/cache/**", "dist/**"]
+ },
+ "lint": {},
+ "test": {
+ "dependsOn": ["^build"]
+ },
+ "dev": {
+ "cache": false,
+ "persistent": true
+ },
+ "type-check": {
+ "dependsOn": ["^type-check"]
+ }
+ }
+}
+```
+
+
+## UI and Styling
+
+### shadcn/ui
+
+**Choice**: shadcn/ui component library
+
+**Alternatives Considered**:
+- NextUI (current)
+- Radix UI (raw)
+- Chakra UI
+- MUI (Material UI)
+- Mantine
+
+**Rationale**:
+
+| Feature | shadcn/ui | NextUI | Chakra UI | MUI |
+|---------|-----------|--------|-----------|-----|
+| Own the code | Yes | No | No | No |
+| Bundle size | Minimal | Medium | Medium | Large |
+| Customization | Full | Medium | Good | Complex |
+| Accessibility | Excellent | Good | Excellent | Good |
+| Tailwind native | Yes | Yes | No | No |
+| Learning curve | Low | Low | Medium | High |
+
+**Key Benefits**:
+1. **Code Ownership**: Copy/paste, not a dependency
+2. **Full Customization**: Modify anything
+3. **Accessibility**: Built on Radix primitives
+4. **Tailwind Native**: Works seamlessly
+5. **Contributor Friendly**: Standard React components
+
+**Example Component**:
+```typescript
+// packages/ui/src/components/button.tsx
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
+import { cn } from "../lib/utils";
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+);
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean;
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button";
+ return (
+
+ );
+ }
+);
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
+```
+
+
+### TailwindCSS 3.4+
+
+**Choice**: TailwindCSS for styling
+
+**Alternatives Considered**:
+- Styled Components (partially used in current)
+- CSS Modules
+- Emotion
+- Vanilla CSS
+
+**Rationale**:
+
+| Feature | TailwindCSS | Styled Components | CSS Modules |
+|---------|-------------|-------------------|-------------|
+| Bundle size | Minimal (purged) | Runtime | Zero |
+| DX | Excellent | Good | Medium |
+| Design system | Built-in | Manual | Manual |
+| Dark mode | Built-in | Manual | Manual |
+| Responsiveness | Built-in | Manual | Manual |
+| Type safety | With plugins | Partial | No |
+
+**Key Benefits**:
+1. **Utility-First**: Fast iteration
+2. **Design Tokens**: Consistent spacing, colors
+3. **Dark Mode**: Built-in support
+4. **Responsive**: Mobile-first utilities
+5. **Purging**: Only ships used CSS
+6. **Industry Standard**: Widely known
+
+**Configuration**:
+```typescript
+// tailwind.config.ts
+import type { Config } from "tailwindcss";
+
+const config: Config = {
+ darkMode: "class",
+ content: [
+ "./app/**/*.{ts,tsx}",
+ "./components/**/*.{ts,tsx}",
+ "../../packages/ui/src/**/*.{ts,tsx}",
+ ],
+ theme: {
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ // Algorithm-specific colors
+ compare: "hsl(var(--compare))",
+ swap: "hsl(var(--swap))",
+ sorted: "hsl(var(--sorted))",
+ pivot: "hsl(var(--pivot))",
+ visited: "hsl(var(--visited))",
+ current: "hsl(var(--current))",
+ found: "hsl(var(--found))",
+ },
+ animation: {
+ "slide-in": "slideIn 0.3s ease-out",
+ "fade-in": "fadeIn 0.2s ease-out",
+ "scale-in": "scaleIn 0.2s ease-out",
+ "bar-swap": "barSwap 0.3s ease-in-out",
+ },
+ keyframes: {
+ slideIn: {
+ from: { transform: "translateY(-10px)", opacity: "0" },
+ to: { transform: "translateY(0)", opacity: "1" },
+ },
+ fadeIn: {
+ from: { opacity: "0" },
+ to: { opacity: "1" },
+ },
+ scaleIn: {
+ from: { transform: "scale(0.95)", opacity: "0" },
+ to: { transform: "scale(1)", opacity: "1" },
+ },
+ barSwap: {
+ "0%": { transform: "translateX(0)" },
+ "50%": { transform: "translateY(-10px)" },
+ "100%": { transform: "translateX(var(--swap-distance))" },
+ },
+ },
+ },
+ },
+ plugins: [require("tailwindcss-animate")],
+};
+
+export default config;
+```
+
+
+## Animations and Visualizations
+
+### Framer Motion
+
+**Choice**: Framer Motion for UI animations
+
+**Alternatives Considered**:
+- React Spring
+- GSAP
+- CSS animations only
+- Motion One
+
+**Rationale**:
+
+| Feature | Framer Motion | GSAP | React Spring | Motion One |
+|---------|---------------|------|--------------|------------|
+| React integration | Native | Wrapper | Native | Native |
+| Bundle size | Medium (20kb) | Large (60kb) | Medium | Small (3kb) |
+| Learning curve | Low | Medium | Medium | Low |
+| Layout animations | Excellent | Manual | Limited | No |
+| Gestures | Built-in | Plugin | Limited | No |
+| SSR | Yes | Manual | Yes | Yes |
+
+**Key Benefits**:
+1. **Declarative**: Animate with props
+2. **Layout Animations**: `layout` prop magic
+3. **Gestures**: Drag, tap, hover built-in
+4. **Exit Animations**: `AnimatePresence`
+5. **Spring Physics**: Natural motion
+
+**Use Cases in OpenDSA**:
+```typescript
+// Page transitions
+
+ {children}
+
+
+// Control panel animations
+
+ Play
+
+
+// Sidebar toggle
+
+ {/* Sidebar content */}
+
+```
+
+
+### D3.js
+
+**Choice**: D3.js for complex data visualizations
+
+**Alternatives Considered**:
+- Chart.js
+- Recharts
+- Visx
+- Pure SVG/Canvas
+
+**Rationale**:
+
+| Feature | D3.js | Recharts | Visx | Chart.js |
+|---------|-------|----------|------|----------|
+| Flexibility | Full | Limited | Full | Limited |
+| Learning curve | High | Low | Medium | Low |
+| Custom visualizations | Excellent | Poor | Good | Poor |
+| Animation control | Full | Limited | Good | Limited |
+| SVG manipulation | Native | Abstracted | Native | Canvas |
+
+**Key Benefits**:
+1. **Full Control**: Build any visualization
+2. **Data Binding**: Efficient updates
+3. **Transitions**: Smooth, customizable
+4. **Scales**: Map data to visual properties
+5. **Existing Knowledge**: Already used in current project
+
+**Use Cases in OpenDSA**:
+- Graph algorithms (BFS, DFS, Dijkstra)
+- Tree visualizations (BST, traversals)
+- Complex sorting visualizations (bars, with animations)
+- Linked list visualizations
+
+**Example**:
+```typescript
+// Graph visualization with D3
+import * as d3 from 'd3';
+
+function renderGraph(container: HTMLElement, nodes: Node[], edges: Edge[]) {
+ const svg = d3.select(container)
+ .append('svg')
+ .attr('width', '100%')
+ .attr('height', '100%');
+
+ const simulation = d3.forceSimulation(nodes)
+ .force('link', d3.forceLink(edges).id(d => d.id))
+ .force('charge', d3.forceManyBody().strength(-300))
+ .force('center', d3.forceCenter(width / 2, height / 2));
+
+ // Render edges
+ const link = svg.selectAll('.link')
+ .data(edges)
+ .join('line')
+ .attr('class', 'link')
+ .attr('stroke', '#999');
+
+ // Render nodes
+ const node = svg.selectAll('.node')
+ .data(nodes)
+ .join('circle')
+ .attr('class', 'node')
+ .attr('r', 20)
+ .attr('fill', d => d.visited ? 'var(--visited)' : 'var(--default)');
+
+ // Update positions on tick
+ simulation.on('tick', () => {
+ link
+ .attr('x1', d => d.source.x)
+ .attr('y1', d => d.source.y)
+ .attr('x2', d => d.target.x)
+ .attr('y2', d => d.target.y);
+
+ node
+ .attr('cx', d => d.x)
+ .attr('cy', d => d.y);
+ });
+}
+```
+
+
+### Canvas API
+
+**Choice**: Canvas API for high-performance array visualizations
+
+**Rationale**:
+- **Performance**: Handle 100+ elements at 60fps
+- **Control**: Pixel-level manipulation
+- **Memory**: Lower memory usage than SVG for many elements
+
+**Use Cases**:
+- Large array sorting visualizations (>50 elements)
+- Performance-critical animations
+- Real-time data updates
+
+**Example**:
+```typescript
+// High-performance array visualization
+function renderArray(
+ canvas: HTMLCanvasElement,
+ array: number[],
+ highlights: Map
+) {
+ const ctx = canvas.getContext('2d')!;
+ const { width, height } = canvas;
+ const barWidth = width / array.length;
+ const maxValue = Math.max(...array);
+
+ ctx.clearRect(0, 0, width, height);
+
+ array.forEach((value, index) => {
+ const barHeight = (value / maxValue) * (height - 20);
+ const x = index * barWidth;
+ const y = height - barHeight;
+
+ // Set color based on state
+ ctx.fillStyle = highlights.get(index) || 'hsl(var(--primary))';
+ ctx.fillRect(x + 1, y, barWidth - 2, barHeight);
+
+ // Draw value label for small arrays
+ if (array.length <= 30) {
+ ctx.fillStyle = 'hsl(var(--foreground))';
+ ctx.font = '12px sans-serif';
+ ctx.textAlign = 'center';
+ ctx.fillText(value.toString(), x + barWidth / 2, y - 5);
+ }
+ });
+}
+```
+
+
+## State Management
+
+### Zustand
+
+**Choice**: Zustand for global state
+
+**Alternatives Considered**:
+- Redux Toolkit (current)
+- Jotai
+- Recoil
+- React Context
+
+**Rationale**:
+
+| Feature | Zustand | Redux Toolkit | Jotai | Context |
+|---------|---------|---------------|-------|---------|
+| Bundle size | 1kb | 11kb | 2kb | 0kb |
+| Boilerplate | Minimal | Medium | Minimal | Medium |
+| Learning curve | Low | Medium | Low | Low |
+| DevTools | Yes | Excellent | Yes | Limited |
+| TypeScript | Excellent | Good | Excellent | Good |
+| Middleware | Yes | Yes | Limited | Manual |
+
+**Key Benefits**:
+1. **Simplicity**: Minimal boilerplate
+2. **Performance**: Selective re-renders out of box
+3. **TypeScript**: Great type inference
+4. **Flexibility**: No providers required
+5. **Size**: Tiny bundle impact
+
+**Store Structure**:
+```typescript
+// Visualization store
+interface VisualizerStore {
+ // State
+ visualizerId: string | null;
+ data: unknown;
+ steps: AnimationStep[];
+ currentStep: number;
+ isPlaying: boolean;
+ speed: number;
+
+ // Actions
+ setVisualizer: (id: string) => void;
+ setData: (data: unknown) => void;
+ generateSteps: () => void;
+ play: () => void;
+ pause: () => void;
+ reset: () => void;
+ stepForward: () => void;
+ stepBackward: () => void;
+ setSpeed: (speed: number) => void;
+}
+
+// Preferences store (persisted)
+interface PreferencesStore {
+ theme: 'light' | 'dark' | 'system';
+ editorVisible: boolean;
+ sidebarOpen: boolean;
+ keyboardShortcutsEnabled: boolean;
+
+ setTheme: (theme: 'light' | 'dark' | 'system') => void;
+ toggleEditor: () => void;
+ toggleSidebar: () => void;
+ toggleKeyboardShortcuts: () => void;
+}
+```
+
+
+## Code Editor
+
+### Monaco Editor
+
+**Choice**: Monaco Editor (same as VS Code)
+
+**Alternatives Considered**:
+- CodeMirror 6
+- Ace Editor
+- Prism.js (display only)
+
+**Rationale**:
+
+| Feature | Monaco | CodeMirror 6 | Ace |
+|---------|--------|--------------|-----|
+| IntelliSense | Full | Plugin | Limited |
+| Bundle size | Large (2MB) | Medium | Medium |
+| Features | Complete | Good | Good |
+| Familiarity | VS Code | Learning | Old |
+| TypeScript | Native | Plugin | Plugin |
+
+**Key Benefits**:
+1. **VS Code Experience**: Familiar to developers
+2. **IntelliSense**: Autocomplete, errors
+3. **TypeScript**: Native support
+4. **Themes**: VS Code themes work
+
+**Configuration**:
+```typescript
+// Monaco editor setup
+import { Editor, OnMount } from '@monaco-editor/react';
+
+interface CodeEditorProps {
+ code: string;
+ language: string;
+ highlightLines?: number[];
+ readOnly?: boolean;
+ onChange?: (value: string) => void;
+}
+
+export function CodeEditor({
+ code,
+ language,
+ highlightLines = [],
+ readOnly = false,
+ onChange,
+}: CodeEditorProps) {
+ const handleMount: OnMount = (editor, monaco) => {
+ // Configure editor
+ editor.updateOptions({
+ minimap: { enabled: false },
+ lineNumbers: 'on',
+ scrollBeyondLastLine: false,
+ readOnly,
+ fontSize: 14,
+ });
+
+ // Highlight lines
+ if (highlightLines.length > 0) {
+ editor.deltaDecorations([], highlightLines.map(line => ({
+ range: new monaco.Range(line, 1, line, 1),
+ options: {
+ isWholeLine: true,
+ className: 'highlighted-line',
+ glyphMarginClassName: 'highlighted-glyph',
+ },
+ })));
+ }
+ };
+
+ return (
+ onChange?.(value ?? '')}
+ theme="vs-dark"
+ />
+ );
+}
+```
+
+
+## Testing
+
+### Vitest
+
+**Choice**: Vitest for unit testing
+
+**Alternatives Considered**:
+- Jest
+- Node test runner
+- Mocha
+
+**Rationale**:
+
+| Feature | Vitest | Jest |
+|---------|--------|------|
+| Speed | Fast (native ESM) | Slower |
+| Vite integration | Native | Manual |
+| Watch mode | Excellent | Good |
+| API compatibility | Jest-compatible | - |
+| TypeScript | Native | Plugin |
+
+**Configuration**:
+```typescript
+// vitest.config.ts
+import { defineConfig } from 'vitest/config';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ environment: 'jsdom',
+ globals: true,
+ setupFiles: ['./test/setup.ts'],
+ coverage: {
+ provider: 'v8',
+ reporter: ['text', 'json', 'html'],
+ exclude: ['node_modules/', 'test/'],
+ },
+ },
+});
+```
+
+
+### Playwright
+
+**Choice**: Playwright for E2E testing
+
+**Alternatives Considered**:
+- Cypress
+- Puppeteer
+- TestCafe
+
+**Rationale**:
+
+| Feature | Playwright | Cypress |
+|---------|------------|---------|
+| Browsers | All | Chrome, Firefox, Edge |
+| Speed | Faster | Slower |
+| Auto-wait | Better | Good |
+| Parallelism | Built-in | Paid |
+| Cross-origin | Yes | Limited |
+
+**Configuration**:
+```typescript
+// playwright.config.ts
+import { defineConfig, devices } from '@playwright/test';
+
+export default defineConfig({
+ testDir: './e2e',
+ fullyParallel: true,
+ forbidOnly: !!process.env.CI,
+ retries: process.env.CI ? 2 : 0,
+ workers: process.env.CI ? 1 : undefined,
+ reporter: 'html',
+ use: {
+ baseURL: 'http://localhost:3000',
+ trace: 'on-first-retry',
+ },
+ projects: [
+ { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
+ { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
+ { name: 'webkit', use: { ...devices['Desktop Safari'] } },
+ ],
+ webServer: {
+ command: 'pnpm dev',
+ url: 'http://localhost:3000',
+ reuseExistingServer: !process.env.CI,
+ },
+});
+```
+
+
+## Documentation
+
+### Nextra
+
+**Choice**: Nextra for documentation site
+
+**Alternatives Considered**:
+- Docusaurus
+- Fumadocs
+- VitePress
+- GitBook
+
+**Rationale**:
+
+| Feature | Nextra | Docusaurus | Fumadocs |
+|---------|--------|------------|----------|
+| Framework | Next.js | React | Next.js |
+| Setup | Simple | Medium | Simple |
+| MDX | Native | Native | Native |
+| Search | Built-in | Plugin | Built-in |
+| Customization | Full | Good | Full |
+
+**Key Benefits**:
+1. **Next.js Native**: Same stack as apps
+2. **MDX**: React components in docs
+3. **Search**: Full-text search built-in
+4. **Theme**: Beautiful default theme
+5. **Simple**: Minimal configuration
+
+
+## Deployment
+
+### Vercel
+
+**Choice**: Vercel for hosting
+
+**Alternatives Considered**:
+- Netlify (current)
+- AWS Amplify
+- Cloudflare Pages
+- Self-hosted
+
+**Rationale**:
+
+| Feature | Vercel | Netlify | Cloudflare |
+|---------|--------|---------|------------|
+| Next.js support | Native | Good | Good |
+| Preview deployments | Yes | Yes | Yes |
+| Edge functions | Native | Beta | Native |
+| Turborepo caching | Native | No | No |
+| Pricing | Free tier | Free tier | Free tier |
+
+**Key Benefits**:
+1. **Next.js Creator**: Best Next.js support
+2. **Preview Deployments**: Per-PR previews
+3. **Turborepo Integration**: Remote caching
+4. **Zero Config**: Automatic detection
+5. **Free for OSS**: Open source program
+
+
+### GitHub Actions
+
+**Workflows**:
+
+1. **CI (ci.yml)**: Runs on every PR
+ - Lint
+ - Type check
+ - Unit tests
+ - Build verification
+
+2. **Release (release.yml)**: On merge to main
+ - Deploy to production
+ - Create release notes
+ - Update changelog
+
+3. **Dependency Update**: Weekly
+ - Dependabot PRs
+ - Security scanning
+
+
+## Development Tools
+
+### ESLint + Prettier
+
+**Configuration**:
+```javascript
+// eslint.config.js
+import eslint from '@eslint/js';
+import tseslint from 'typescript-eslint';
+import react from 'eslint-plugin-react';
+import reactHooks from 'eslint-plugin-react-hooks';
+
+export default tseslint.config(
+ eslint.configs.recommended,
+ ...tseslint.configs.strictTypeChecked,
+ {
+ plugins: {
+ react,
+ 'react-hooks': reactHooks,
+ },
+ rules: {
+ 'react-hooks/rules-of-hooks': 'error',
+ 'react-hooks/exhaustive-deps': 'warn',
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+ },
+ }
+);
+```
+
+
+## Comparison with Current Stack
+
+| Aspect | Current (ds-algo-deck) | New (OpenDSA) | Reason for Change |
+|--------|------------------------|----------------|-------------------|
+| **Framework** | React + Vite | Next.js 14 | SSR, SEO, file routing, Vercel integration |
+| **Language** | JavaScript | TypeScript | Type safety, better DX, documentation |
+| **Package Manager** | npm | pnpm | Speed, disk efficiency, strict mode |
+| **Build** | Single app | Turborepo | Code sharing, independent deployments |
+| **UI Library** | NextUI | shadcn/ui | Code ownership, customization, smaller bundle |
+| **State** | Redux Toolkit | Zustand | Simplicity, smaller bundle, less boilerplate |
+| **Styling** | Tailwind + Styled Components | Tailwind only | Consistency, simpler mental model |
+| **Animations** | Framer Motion + D3 | Same + Canvas | Add Canvas for performance |
+| **Testing** | None | Vitest + Playwright | Quality assurance, contributor confidence |
+| **Docs** | Markdown files | Nextra | Professional documentation site |
+| **Deploy** | Netlify | Vercel | Better Next.js support, Turborepo integration |
+| **CI/CD** | Manual | GitHub Actions | Automation, quality gates |
+
+
+## Summary
+
+The OpenDSA tech stack is carefully chosen to provide:
+
+1. **Modern Foundation**: Next.js + TypeScript + pnpm
+2. **Scalable Architecture**: Turborepo monorepo
+3. **Beautiful UI**: shadcn/ui + TailwindCSS
+4. **Smooth Animations**: Framer Motion + D3.js + Canvas
+5. **Simple State**: Zustand
+6. **Quality Assurance**: Vitest + Playwright
+7. **Great DX**: ESLint + Prettier + TypeScript
+8. **Easy Deployment**: Vercel + GitHub Actions
+
+This stack balances **developer experience**, **performance**, **maintainability**, and **contributor friendliness** - all essential for a successful open-source project.
diff --git a/apps/docs/app/roadmap/page.mdx b/apps/docs/app/roadmap/page.mdx
deleted file mode 100644
index 395d1c6..0000000
--- a/apps/docs/app/roadmap/page.mdx
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Roadmap
----
-
-This page will be migrated from `apps/docs/internal/OPENALGO_ROADMAP.md`.
-
diff --git a/apps/docs/app/sponsors/page.mdx b/apps/docs/app/sponsors/page.mdx
new file mode 100644
index 0000000..417b464
--- /dev/null
+++ b/apps/docs/app/sponsors/page.mdx
@@ -0,0 +1,117 @@
+# Support OpenDSA
+
+OpenDSA is 100% free and open source. We believe everyone should have access to quality algorithm visualizations for learning. No paywalls. No premium tiers. Just pure, open education.
+
+## Why Support Us?
+
+We're committed to keeping OpenDSA free forever. Your support helps us:
+
+- **Host reliable infrastructure** - Fast servers, CDN, and uptime
+- **Develop new features** - More algorithms, better visualizations
+- **Maintain the project** - Bug fixes, security updates, documentation
+- **Grow the community** - Events, educational content, outreach
+
+## Current Hosting
+
+OpenDSA is currently hosted on **Vercel's free tier**. As the project grows, we may need to scale to handle more traffic and features.
+
+
+## How to Support
+
+### GitHub Sponsors (Coming Soon)
+Support the maintainers directly through GitHub Sponsors. Every contribution helps keep the project alive.
+
+**Setup:** [github.com/sponsors](https://github.com/sponsors) - Account pending
+
+### Open Collective (Coming Soon)
+For transparent, community-managed funding. All expenses and contributions are public.
+
+**Setup:** [opencollective.com](https://opencollective.com) - Account pending
+
+### Buy Me a Coffee (Coming Soon)
+Quick one-time donations to fuel late-night coding sessions.
+
+**Setup:** [buymeacoffee.com](https://www.buymeacoffee.com) - Account pending
+
+### Ko-fi (Coming Soon)
+Another great platform for one-time or monthly support.
+
+**Setup:** [ko-fi.com](https://ko-fi.com) - Account pending
+
+### Patreon (Coming Soon)
+For those who want to support with monthly contributions.
+
+**Setup:** [patreon.com](https://www.patreon.com) - Account pending
+
+
+## Corporate Sponsors
+
+Are you a company that values open source education? We'd love to partner with you!
+
+### Sponsorship Tiers
+
+#### Bronze - $50/month
+- Logo on README
+- Shoutout on social media
+
+#### Silver - $100/month
+- Everything in Bronze
+- Logo on website footer
+- Monthly progress updates
+
+#### Gold - $250/month
+- Everything in Silver
+- Logo on homepage
+- Featured in release notes
+
+#### Platinum - $500+/month
+- Everything in Gold
+- Custom feature prioritization
+- Direct support channel
+
+**Interested?** Reach out at [GitHub Discussions](https://github.com/soloshun/opendsa/discussions) or email us at [solomoneshun373@gmail.com](mailto:solomoneshun373@gmail.com).
+
+
+## Current Sponsors
+
+*Be the first to support OpenDSA!*
+
+No sponsors yet. Your logo could be here.
+
+
+## Other Ways to Help
+
+Don't have the funds? No problem! You can still contribute:
+
+1. **Star the repo** - Helps with visibility
+2. **Share on social media** - Spread the word
+3. **Write a blog post** - Review or tutorial
+4. **Report bugs** - Help us improve
+5. **Submit PRs** - Code contributions welcome
+6. **Answer questions** - Help others in discussions
+
+
+## Transparency
+
+We believe in open finances. Once we set up Open Collective or similar platforms, all income and expenses will be publicly visible.
+
+**Current Monthly Costs:** \$0 (Vercel free tier)
+**Expected at Scale:** ~\$50-200/month (Pro hosting, domain, services)
+
+
+## FAQ
+
+### Will OpenDSA ever have paid features?
+No. OpenDSA will always be 100% free. Sponsorships help us maintain and improve the free platform.
+
+### Where does the money go?
+Hosting costs, domain registration, and development tools. Any surplus goes toward bounties for contributors.
+
+### Can I sponsor anonymously?
+Yes, most platforms support anonymous donations.
+
+### Is my donation tax-deductible?
+Depends on your country and the platform used. Open Collective offers fiscal hosting which may provide tax benefits in some jurisdictions.
+
+
+*Thank you for considering supporting OpenDSA. Every contribution, big or small, helps keep algorithm education free and accessible to everyone.*
diff --git a/apps/docs/app/tech_stack/page.mdx b/apps/docs/app/tech_stack/page.mdx
deleted file mode 100644
index a0c9fb5..0000000
--- a/apps/docs/app/tech_stack/page.mdx
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Tech Stack
----
-
-This page will be migrated from `apps/docs/internal/OPENALGO_TECH_STACK.md`.
-
diff --git a/apps/docs/app/technical/_meta.js b/apps/docs/app/technical/_meta.js
new file mode 100644
index 0000000..47a289f
--- /dev/null
+++ b/apps/docs/app/technical/_meta.js
@@ -0,0 +1,7 @@
+export default {
+ "implementation-status": 'Implementation Status',
+ "big-o": 'Big O Notation',
+ "data-structures": 'Data Structures',
+ algorithms: 'Algorithms',
+ visualizers: 'Visualizers'
+}
diff --git a/apps/docs/app/technical/algorithms/_meta.js b/apps/docs/app/technical/algorithms/_meta.js
new file mode 100644
index 0000000..5eff340
--- /dev/null
+++ b/apps/docs/app/technical/algorithms/_meta.js
@@ -0,0 +1,4 @@
+export default {
+ "bubble-sort": "Bubble Sort",
+ "quick-sort": "Quick Sort"
+}
diff --git a/apps/docs/app/technical/algorithms/bubble-sort/page.mdx b/apps/docs/app/technical/algorithms/bubble-sort/page.mdx
new file mode 100644
index 0000000..0743a73
--- /dev/null
+++ b/apps/docs/app/technical/algorithms/bubble-sort/page.mdx
@@ -0,0 +1,28 @@
+# Bubble Sort
+
+Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in the wrong order.
+
+## Complexity
+
+| Type | Complexity |
+| :--- | :--- |
+| **Time (Worst)** | $O(n^2)$ |
+| **Time (Average)** | $O(n^2)$ |
+| **Time (Best)** | $O(n)$ |
+| **Space** | $O(1)$ |
+
+## Implementation
+
+```typescript
+function bubbleSort(arr: number[]): number[] {
+ const n = arr.length;
+ for (let i = 0; i < n; i++) {
+ for (let j = 0; j < n - i - 1; j++) {
+ if (arr[j] > arr[j + 1]) {
+ [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
+ }
+ }
+ }
+ return arr;
+}
+```
diff --git a/apps/docs/app/technical/algorithms/page.mdx b/apps/docs/app/technical/algorithms/page.mdx
new file mode 100644
index 0000000..3f3af89
--- /dev/null
+++ b/apps/docs/app/technical/algorithms/page.mdx
@@ -0,0 +1,8 @@
+# Algorithms
+
+The current version of OpenDSA implements value-based algorithms to help users understand core computer science concepts.
+
+## Sorting Implementations
+
+- [Bubble Sort](/technical/algorithms/bubble-sort)
+- [Quick Sort](/technical/algorithms/quick-sort)
diff --git a/apps/docs/app/technical/algorithms/quick-sort/page.mdx b/apps/docs/app/technical/algorithms/quick-sort/page.mdx
new file mode 100644
index 0000000..e79c253
--- /dev/null
+++ b/apps/docs/app/technical/algorithms/quick-sort/page.mdx
@@ -0,0 +1,17 @@
+# Quick Sort
+
+Quick Sort is an efficient, divide-and-conquer sorting algorithm. It works by selecting a 'pivot' element and partitioning the other elements into two sub-arrays according to whether they are less than or greater than the pivot.
+
+## Complexity
+
+| Type | Complexity |
+| :--- | :--- |
+| **Time (Worst)** | $O(n^2)$ |
+| **Time (Average)** | $O(n \log n)$ |
+| **Time (Best)** | $O(n \log n)$ |
+| **Space** | $O(\log n)$ |
+
+## Concepts
+
+- **Pivot Selection**: Choosing the right pivot is crucial for performance.
+- **Partitioning**: Reordering the array so that elements < pivot come before elements > pivot.
diff --git a/apps/docs/app/technical/big-o/page.mdx b/apps/docs/app/technical/big-o/page.mdx
new file mode 100644
index 0000000..4c689f2
--- /dev/null
+++ b/apps/docs/app/technical/big-o/page.mdx
@@ -0,0 +1,51 @@
+# Big O Notation
+
+Big O notation is a mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity. In computer science, it is used to classify algorithms according to how their run time or space requirements grow as the input size grows.
+
+## Common Time Complexities
+
+| Notation | Name | Description | Example |
+| :--- | :--- | :--- | :--- |
+| **O(1)** | Constant | Execution time is independent of input size. | Accessing array index |
+| **O(log n)** | Logarithmic | Time grows logarithmically with input size. | Binary Search |
+| **O(n)** | Linear | Time grows linearly with input size. | Linear Search |
+| **O(n log n)** | Linearithmic | Faster than quadratic but slower than linear. | Merge Sort, Quick Sort |
+| **O(n²)** | Quadratic | Time grows with the square of the input size. | Bubble Sort |
+| **O(2ⁿ)** | Exponential | Time doubles with each addition to input. | Recursive Fibonacci |
+| **O(n!)** | Factorial | Growth is factorial based on input size. | Traveling Salesperson |
+
+## Why it Matters
+
+Understanding Big O helps developers:
+- Predict performance at scale.
+- Choose the right algorithm for the job.
+- Identify bottlenecks in code.
+
+### Visualizing Growth
+
+```mermaid
+graph LR
+ A["Input Size (n)"] --> B{Complexity}
+ B -->|O 1| C[Instant]
+ B -->|O log n| D[Fast]
+ B -->|O n| E[Manageable]
+ B -->|O n^2| F[Slow]
+ B -->|O 2^n| G["Unusable for large n"]
+```
+
+### Complexity Chart
+
+```mermaid
+xychart-beta
+ title "Time Complexity Growth"
+ x-axis "Input Size (n)" [1, 2, 4, 8, 16]
+ y-axis "Operations" 0 --> 300
+ line [1, 1, 1, 1, 1]
+ line [1, 2, 4, 8, 16]
+ line [1, 4, 16, 64, 256]
+```
+
diff --git a/apps/docs/app/technical/data-structures/_meta.js b/apps/docs/app/technical/data-structures/_meta.js
new file mode 100644
index 0000000..5bbe0bc
--- /dev/null
+++ b/apps/docs/app/technical/data-structures/_meta.js
@@ -0,0 +1,4 @@
+export default {
+ arrays: "Arrays",
+ trees: "Trees"
+}
diff --git a/apps/docs/app/technical/data-structures/arrays/page.mdx b/apps/docs/app/technical/data-structures/arrays/page.mdx
new file mode 100644
index 0000000..c6c9cb0
--- /dev/null
+++ b/apps/docs/app/technical/data-structures/arrays/page.mdx
@@ -0,0 +1,18 @@
+# Arrays
+
+An array is a collection of items stored at contiguous memory locations. It is one of the simplest and most widely used data structures.
+
+## Complexity
+
+| Operation | Complexity |
+| :--- | :--- |
+| **Access** | $O(1)$ |
+| **Search** | $O(n)$ |
+| **Insertion** | $O(n)$ |
+| **Deletion** | $O(n)$ |
+
+## Visualization
+
+In OpenDSA, arrays are visualized as a row of bars or boxes.
+- **Highlight**: Change color to indicate comparison or access.
+- **Swap**: Animate position exchange.
diff --git a/apps/docs/app/technical/data-structures/page.mdx b/apps/docs/app/technical/data-structures/page.mdx
new file mode 100644
index 0000000..1f92f3a
--- /dev/null
+++ b/apps/docs/app/technical/data-structures/page.mdx
@@ -0,0 +1,8 @@
+# Data Structures
+
+Core data structures implemented in OpenDSA with interactive visualizations.
+
+## Available Data Structures
+
+- [Arrays](/technical/data-structures/arrays) - Linear collection of elements
+- [Trees](/technical/data-structures/trees) - Hierarchical node-based structures
diff --git a/apps/docs/app/technical/data-structures/trees/page.mdx b/apps/docs/app/technical/data-structures/trees/page.mdx
new file mode 100644
index 0000000..7a1dc2a
--- /dev/null
+++ b/apps/docs/app/technical/data-structures/trees/page.mdx
@@ -0,0 +1,12 @@
+# Trees
+
+Trees are hierarchical data structures consisting of nodes connected by edges.
+
+## Binary Search Tree (BST)
+
+A binary tree where the key in each node is greater than all keys in the left subtree and less than all keys in the right subtree.
+
+### Properties
+- **Root**: Topmost node.
+- **Leaf**: Node with no children.
+- **Height**: Number of edges on the longest path from node to leaf.
diff --git a/apps/docs/app/technical/implementation-status/page.mdx b/apps/docs/app/technical/implementation-status/page.mdx
new file mode 100644
index 0000000..53b87c0
--- /dev/null
+++ b/apps/docs/app/technical/implementation-status/page.mdx
@@ -0,0 +1,185 @@
+# Implementation Status
+
+This page tracks the implementation progress of all algorithms and data structures in OpenDSA. Want to contribute? Pick any item marked with ○ and start building!
+
+## Progress Overview
+
+**Total Items:** 70+
+**Implemented:** 4
+**In Progress:** Community-driven development
+
+---
+
+## Data Structures
+
+### Arrays
+| Topic | Status |
+|-------|--------|
+| Basic Array Operations | ✅ Implemented |
+| Dynamic Arrays | ○ Pending |
+| Multi-dimensional Arrays | ○ Pending |
+
+### Linked Lists
+| Topic | Status |
+|-------|--------|
+| Singly Linked List | ○ Pending |
+| Doubly Linked List | ○ Pending |
+| Circular Linked List | ○ Pending |
+
+### Stacks
+| Topic | Status |
+|-------|--------|
+| Basic Stack Operations | ○ Pending |
+| Applications (Balancing Parentheses) | ○ Pending |
+
+### Queues
+| Topic | Status |
+|-------|--------|
+| Basic Queue | ○ Pending |
+| Circular Queue | ○ Pending |
+| Priority Queue | ○ Pending |
+| Deque (Double-Ended Queue) | ○ Pending |
+
+### Trees
+| Topic | Status |
+|-------|--------|
+| Binary Tree | ○ Pending |
+| Binary Search Tree (BST) | ○ Pending |
+| AVL Tree (Self-Balancing BST) | ○ Pending |
+| Red-Black Tree | ○ Pending |
+| Segment Tree | ○ Pending |
+| Trie | ○ Pending |
+| B-Tree and B+ Tree | ○ Pending |
+
+### Heaps
+| Topic | Status |
+|-------|--------|
+| Min Heap | ○ Pending |
+| Max Heap | ○ Pending |
+| Fibonacci Heap | ○ Pending |
+
+### Graphs
+| Topic | Status |
+|-------|--------|
+| Directed/Undirected Graphs | ○ Pending |
+| Weighted/Unweighted Graphs | ○ Pending |
+| Adjacency Matrix | ○ Pending |
+| Adjacency List | ○ Pending |
+| Edge List | ○ Pending |
+
+### Hashing
+| Topic | Status |
+|-------|--------|
+| Hash Tables | ○ Pending |
+| Hash Maps | ○ Pending |
+| Open Addressing | ○ Pending |
+| Separate Chaining | ○ Pending |
+
+---
+
+## Algorithms
+
+### Sorting (Easy)
+| Topic | Status |
+|-------|--------|
+| Bubble Sort | ✅ Implemented |
+| Selection Sort | ○ Pending |
+| Insertion Sort | ○ Pending |
+
+### Sorting (Intermediate)
+| Topic | Status |
+|-------|--------|
+| Merge Sort | ○ Pending |
+| Quick Sort | ○ Pending |
+
+### Sorting (Advanced)
+| Topic | Status |
+|-------|--------|
+| Heap Sort | ○ Pending |
+| Counting Sort | ○ Pending |
+| Radix Sort | ○ Pending |
+| Bucket Sort | ○ Pending |
+
+### Searching
+| Topic | Status |
+|-------|--------|
+| Linear Search | ✅ Implemented |
+| Binary Search | ○ Pending |
+| Jump Search | ○ Pending |
+| Exponential Search | ○ Pending |
+
+### Graph Algorithms
+| Topic | Status |
+|-------|--------|
+| Breadth-First Search (BFS) | ○ Pending |
+| Depth-First Search (DFS) | ○ Pending |
+| Dijkstra's Algorithm | ○ Pending |
+| Floyd-Warshall | ○ Pending |
+| Bellman-Ford | ○ Pending |
+| Prim's MST | ○ Pending |
+| Kruskal's MST | ○ Pending |
+| A* Search | ○ Pending |
+
+### Dynamic Programming
+| Topic | Status |
+|-------|--------|
+| Fibonacci | ○ Pending |
+| Coin Change (Minimum Coins) | ○ Pending |
+| Longest Common Subsequence (LCS) | ○ Pending |
+| Knapsack Problem | ○ Pending |
+| Matrix Chain Multiplication | ○ Pending |
+
+### Backtracking
+| Topic | Status |
+|-------|--------|
+| Rat in a Maze | ○ Pending |
+| N-Queens Problem | ○ Pending |
+| Knight's Tour | ○ Pending |
+| Sudoku Solver | ○ Pending |
+
+### Greedy Algorithms
+| Topic | Status |
+|-------|--------|
+| Activity Selection | ○ Pending |
+| Fractional Knapsack | ○ Pending |
+| Huffman Coding | ○ Pending |
+| Job Sequencing | ○ Pending |
+
+### Miscellaneous Algorithms
+| Topic | Status |
+|-------|--------|
+| Sieve of Eratosthenes (Prime Numbers) | ○ Pending |
+| Euclidean Algorithm (GCD) | ○ Pending |
+| KMP Pattern Matching | ○ Pending |
+| Rabin-Karp Algorithm | ○ Pending |
+| Bit Manipulation | ○ Pending |
+| Randomized Algorithms (QuickSelect) | ○ Pending |
+
+---
+
+## Future Plans
+
+### Machine Learning Visualizers (Coming Soon)
+- Linear Regression
+- Logistic Regression
+- Decision Trees
+- K-Means Clustering
+- Neural Network Forward/Backward Pass
+- Gradient Descent
+
+### Deep Learning Visualizers (Coming Soon)
+- Convolutional Neural Networks (CNN)
+- Recurrent Neural Networks (RNN)
+- Transformer Architecture
+- Attention Mechanisms
+
+---
+
+## How to Contribute
+
+1. **Pick an item** - Choose any pending (○) algorithm or data structure
+2. **Create an issue** - Let the community know you're working on it
+3. **Build the visualizer** - Follow our [architecture guide](/project/architecture)
+4. **Submit a PR** - Reference the issue in your pull request
+
+See our [Contributing Guide](/contributing) for detailed instructions.
diff --git a/apps/docs/app/technical/page.mdx b/apps/docs/app/technical/page.mdx
new file mode 100644
index 0000000..2c43071
--- /dev/null
+++ b/apps/docs/app/technical/page.mdx
@@ -0,0 +1,9 @@
+# Technical Documentation
+
+Detailed documentation of the internal implementation of OpenDSA.
+
+## Sections
+
+- [Data Structures](/technical/data-structures): Implementation details of core data structures.
+- [Algorithms](/technical/algorithms): Documentation of sorting, searching, graph, and tree algorithms.
+- [Visualizers](/technical/visualizers): Architecture of the visualization engine and plugin system.
diff --git a/apps/docs/app/technical/visualizers/_meta.js b/apps/docs/app/technical/visualizers/_meta.js
new file mode 100644
index 0000000..c814c72
--- /dev/null
+++ b/apps/docs/app/technical/visualizers/_meta.js
@@ -0,0 +1,4 @@
+export default {
+ architecture: "Architecture"
+}
+
diff --git a/apps/docs/app/technical/visualizers/architecture/page.mdx b/apps/docs/app/technical/visualizers/architecture/page.mdx
new file mode 100644
index 0000000..ef9d349
--- /dev/null
+++ b/apps/docs/app/technical/visualizers/architecture/page.mdx
@@ -0,0 +1,25 @@
+# Visualizer Architecture
+
+The core of OpenDSA is the extensible visualizer system.
+
+## Key Concepts
+
+### Plugin System
+Each algorithm visualization is a "Plugin" that provides:
+- **Meta**: Name, category, complexity.
+- **Component**: The React component rendering the visualization.
+- **Generator**: A function that generates animation steps.
+
+### Example: Bubble Sort
+```typescript
+export const BubbleSortPlugin: VisualizerPlugin = {
+ meta: {
+ id: "bubble-sort",
+ name: "Bubble Sort",
+ category: "sorting",
+ complexity: { time: { worst: "O(n²)", ... }, space: "O(1)" }
+ },
+ component: BubbleSortRenderer,
+ generateSteps: generateBubbleSortSteps
+};
+```
diff --git a/apps/docs/app/technical/visualizers/page.mdx b/apps/docs/app/technical/visualizers/page.mdx
new file mode 100644
index 0000000..4528e55
--- /dev/null
+++ b/apps/docs/app/technical/visualizers/page.mdx
@@ -0,0 +1,7 @@
+# Visualizers
+
+The OpenDSA visualizer system powers all algorithm and data structure animations.
+
+## Documentation
+
+- [Architecture](/technical/visualizers/architecture) - Core visualizer architecture and plugin system
diff --git a/apps/docs/internal/OPENALGO_ARCHITECTURE.md b/apps/docs/internal/OPENDSA_ARCHITECTURE.md
similarity index 100%
rename from apps/docs/internal/OPENALGO_ARCHITECTURE.md
rename to apps/docs/internal/OPENDSA_ARCHITECTURE.md
diff --git a/apps/docs/internal/OPENALGO_MIGRATION.md b/apps/docs/internal/OPENDSA_MIGRATION.md
similarity index 100%
rename from apps/docs/internal/OPENALGO_MIGRATION.md
rename to apps/docs/internal/OPENDSA_MIGRATION.md
diff --git a/apps/docs/internal/OPENALGO_ROADMAP.md b/apps/docs/internal/OPENDSA_ROADMAP.md
similarity index 100%
rename from apps/docs/internal/OPENALGO_ROADMAP.md
rename to apps/docs/internal/OPENDSA_ROADMAP.md
diff --git a/apps/docs/internal/OPENALGO_TECH_STACK.md b/apps/docs/internal/OPENDSA_TECH_STACK.md
similarity index 100%
rename from apps/docs/internal/OPENALGO_TECH_STACK.md
rename to apps/docs/internal/OPENDSA_TECH_STACK.md
diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs
index 54eff3a..17f832f 100644
--- a/apps/docs/next.config.mjs
+++ b/apps/docs/next.config.mjs
@@ -2,6 +2,9 @@ import nextra from 'nextra'
const withNextra = nextra({
// Nextra-specific options can go here.
+ latex: true,
+ // This helps with code block parsing
+ defaultShowCopyCode: true,
})
export default withNextra({
diff --git a/apps/docs/package.json b/apps/docs/package.json
index 8a4bdba..7526f03 100644
--- a/apps/docs/package.json
+++ b/apps/docs/package.json
@@ -8,10 +8,12 @@
"start": "next start"
},
"dependencies": {
+ "@theguild/remark-mermaid": "^0.3.0",
+ "katex": "^0.16.27",
"next": "16.1.4",
- "react": "19.2.3",
- "react-dom": "19.2.3",
"nextra": "^4.6.1",
- "nextra-theme-docs": "^4.6.1"
+ "nextra-theme-docs": "^4.6.1",
+ "react": "19.2.3",
+ "react-dom": "19.2.3"
}
}
diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts
index e9ffa30..2965787 100644
--- a/apps/web/next.config.ts
+++ b/apps/web/next.config.ts
@@ -1,7 +1,16 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
- /* config options here */
+ images: {
+ remotePatterns: [
+ {
+ protocol: "https",
+ hostname: "avatars.githubusercontent.com",
+ port: "",
+ pathname: "/**",
+ },
+ ],
+ },
};
export default nextConfig;
diff --git a/apps/web/package.json b/apps/web/package.json
index 99df217..b0edab0 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -9,9 +9,16 @@
"lint": "eslint"
},
"dependencies": {
+ "@tsparticles/engine": "^3.9.1",
+ "@tsparticles/react": "^3.0.0",
+ "@tsparticles/slim": "^3.9.1",
+ "clsx": "^2.1.1",
+ "framer-motion": "^12.29.0",
+ "lucide-react": "^0.563.0",
"next": "16.1.4",
"react": "19.2.3",
- "react-dom": "19.2.3"
+ "react-dom": "19.2.3",
+ "tailwind-merge": "^3.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css
index a2dc41e..1d7b03e 100644
--- a/apps/web/src/app/globals.css
+++ b/apps/web/src/app/globals.css
@@ -1,26 +1,211 @@
@import "tailwindcss";
:root {
- --background: #ffffff;
- --foreground: #171717;
+ --background: 0 0% 4%;
+ --foreground: 0 0% 98%;
+ --card: 0 0% 7%;
+ --card-foreground: 0 0% 98%;
+ --primary: 142 71% 45%;
+ --primary-foreground: 0 0% 4%;
+ --secondary: 0 0% 11%;
+ --secondary-foreground: 0 0% 98%;
+ --muted: 0 0% 15%;
+ --muted-foreground: 0 0% 64%;
+ --accent: 142 71% 45%;
+ --accent-foreground: 0 0% 4%;
+ --border: 0 0% 18%;
+ --ring: 142 71% 45%;
+ --radius: 0.75rem;
}
@theme inline {
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --font-sans: var(--font-geist-sans);
- --font-mono: var(--font-geist-mono);
+ --color-background: hsl(var(--background));
+ --color-foreground: hsl(var(--foreground));
+ --color-card: hsl(var(--card));
+ --color-card-foreground: hsl(var(--card-foreground));
+ --color-primary: hsl(var(--primary));
+ --color-primary-foreground: hsl(var(--primary-foreground));
+ --color-secondary: hsl(var(--secondary));
+ --color-secondary-foreground: hsl(var(--secondary-foreground));
+ --color-muted: hsl(var(--muted));
+ --color-muted-foreground: hsl(var(--muted-foreground));
+ --color-accent: hsl(var(--accent));
+ --color-accent-foreground: hsl(var(--accent-foreground));
+ --color-border: hsl(var(--border));
+ --color-ring: hsl(var(--ring));
+ --font-sans: var(--font-syne), system-ui, sans-serif;
+ --font-mono: var(--font-jetbrains-mono), ui-monospace, monospace;
}
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
- }
+* {
+ border-color: hsl(var(--border));
+}
+
+html {
+ scroll-behavior: smooth;
}
body {
- background: var(--background);
- color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
+ background-color: hsl(var(--background));
+ color: hsl(var(--foreground));
+ font-family: var(--font-syne), system-ui, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+/* Custom scrollbar */
+::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background: hsl(var(--background));
}
+
+::-webkit-scrollbar-thumb {
+ background: hsl(var(--border));
+ border-radius: 3px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: hsl(var(--muted-foreground));
+}
+
+/* Gradient text utility */
+.gradient-text {
+ background: linear-gradient(135deg, hsl(142 71% 45%) 0%, hsl(142 69% 58%) 50%, hsl(142 77% 73%) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+/* Glowing effect */
+.glow {
+ box-shadow: 0 0 20px hsla(142, 71%, 45%, 0.4),
+ 0 0 40px hsla(142, 71%, 45%, 0.2),
+ 0 0 60px hsla(142, 71%, 45%, 0.1);
+}
+
+.glow-sm {
+ box-shadow: 0 0 10px hsla(142, 71%, 45%, 0.3),
+ 0 0 20px hsla(142, 71%, 45%, 0.15);
+}
+
+.glow-text {
+ text-shadow: 0 0 30px hsla(142, 71%, 45%, 0.6),
+ 0 0 60px hsla(142, 71%, 45%, 0.4);
+}
+
+/* Shimmer animation */
+@keyframes shimmer {
+ 0% {
+ background-position: -200% 0;
+ }
+
+ 100% {
+ background-position: 200% 0;
+ }
+}
+
+.shimmer {
+ background: linear-gradient(90deg,
+ transparent 0%,
+ hsla(142, 71%, 45%, 0.08) 50%,
+ transparent 100%);
+ background-size: 200% 100%;
+ animation: shimmer 3s infinite;
+}
+
+/* Code block styling */
+.code-block {
+ background: linear-gradient(135deg, hsl(0 0% 5%) 0%, hsl(0 0% 9%) 100%);
+ border: 1px solid hsl(var(--border));
+ border-radius: var(--radius);
+}
+
+/* Grid pattern background */
+.grid-pattern {
+ background-image:
+ linear-gradient(hsla(142, 71%, 45%, 0.04) 1px, transparent 1px),
+ linear-gradient(90deg, hsla(142, 71%, 45%, 0.04) 1px, transparent 1px);
+ background-size: 60px 60px;
+}
+
+/* Noise texture overlay */
+.noise {
+ position: relative;
+}
+
+.noise::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
+ opacity: 0.03;
+ pointer-events: none;
+ z-index: 1;
+}
+
+/* Highlight box - like the yellow box in OpenReel */
+.highlight-box {
+ background: hsl(var(--primary));
+ color: hsl(var(--primary-foreground));
+ padding: 0.125rem 0.5rem;
+ display: inline-block;
+}
+
+/* Glass effect */
+.glass {
+ background: hsla(var(--background), 0.7);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+}
+
+/* Animated gradient border */
+@keyframes border-glow {
+
+ 0%,
+ 100% {
+ border-color: hsla(142, 71%, 45%, 0.3);
+ }
+
+ 50% {
+ border-color: hsla(142, 71%, 45%, 0.6);
+ }
+}
+
+.border-glow {
+ animation: border-glow 3s ease-in-out infinite;
+}
+
+/* Underline decoration like OpenReel */
+.underline-primary {
+ position: relative;
+ display: inline-block;
+}
+
+.underline-primary::after {
+ content: "";
+ position: absolute;
+ bottom: -4px;
+ left: 0;
+ right: 0;
+ height: 3px;
+ background: hsl(var(--primary));
+}
+
+/* Monospace label styling */
+.mono-label {
+ font-family: var(--font-mono);
+ font-size: 0.75rem;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: hsl(var(--primary));
+}
+
+/* Selection color */
+::selection {
+ background: hsla(142, 71%, 45%, 0.3);
+ color: hsl(var(--foreground));
+}
\ No newline at end of file
diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx
index f7fa87e..14c3663 100644
--- a/apps/web/src/app/layout.tsx
+++ b/apps/web/src/app/layout.tsx
@@ -1,20 +1,51 @@
import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
+import { Syne, JetBrains_Mono } from "next/font/google";
import "./globals.css";
-const geistSans = Geist({
- variable: "--font-geist-sans",
+const syne = Syne({
+ variable: "--font-syne",
subsets: ["latin"],
+ display: "swap",
+ weight: ["400", "500", "600", "700", "800"],
});
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
+const jetbrainsMono = JetBrains_Mono({
+ variable: "--font-jetbrains-mono",
subsets: ["latin"],
+ display: "swap",
+ weight: ["400", "500", "600", "700"],
});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "OpenDSA - Visualize Data Structures & Algorithms",
+ description:
+ "An open-source, interactive platform for visualizing data structures and algorithms. Learn through beautiful animations and step-by-step explanations.",
+ keywords: [
+ "algorithms",
+ "data structures",
+ "visualization",
+ "learning",
+ "open source",
+ "education",
+ "sorting",
+ "searching",
+ "graphs",
+ "trees",
+ ],
+ authors: [{ name: "Solomon Eshun" }],
+ openGraph: {
+ title: "OpenDSA - Visualize Data Structures & Algorithms",
+ description:
+ "An open-source, interactive platform for visualizing data structures and algorithms.",
+ type: "website",
+ locale: "en_US",
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: "OpenDSA - Visualize Data Structures & Algorithms",
+ description:
+ "An open-source, interactive platform for visualizing data structures and algorithms.",
+ },
};
export default function RootLayout({
@@ -23,10 +54,8 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
+
+
{children}
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
index 295f8fd..f2fac72 100644
--- a/apps/web/src/app/page.tsx
+++ b/apps/web/src/app/page.tsx
@@ -1,65 +1,35 @@
-import Image from "next/image";
+import { Header } from "@/components/sections/header";
+import { Hero } from "@/components/sections/hero";
+import { Features } from "@/components/sections/features";
+import { Architecture } from "@/components/sections/architecture";
+import { TechStack } from "@/components/sections/tech-stack";
+import { Roadmap } from "@/components/sections/roadmap";
+import { AlgorithmChecklist } from "@/components/sections/algorithm-checklist";
+import { FAQ } from "@/components/sections/faq";
+import { OpenSource } from "@/components/sections/open-source";
+import { Footer } from "@/components/sections/footer";
+import { ParticlesBackground } from "@/components/ui/particles-background";
export default function Home() {
return (
-
-
-
-
-
- To get started, edit the page.tsx file.
-
-
- Looking for a starting point or more instructions? Head over to{" "}
-
- Templates
- {" "}
- or the{" "}
-
- Learning
- {" "}
- center.
-
-
-
+
+ {/* Global particles network - covers entire page */}
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/apps/web/src/components/animations/ai-assistant.tsx b/apps/web/src/components/animations/ai-assistant.tsx
new file mode 100644
index 0000000..03125c0
--- /dev/null
+++ b/apps/web/src/components/animations/ai-assistant.tsx
@@ -0,0 +1,102 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+import { Sparkles } from "lucide-react";
+
+const steps = [
+ { prompt: "Explain bubble sort", response: "Bubble sort compares adjacent elements..." },
+ { prompt: "Optimize this code", response: "Use quick sort for O(n log n)..." },
+ { prompt: "Show me BFS", response: "Starting BFS from node A..." },
+];
+
+export function AIAssistant() {
+ const [currentStep, setCurrentStep] = useState(0);
+ const [displayText, setDisplayText] = useState("");
+
+ useEffect(() => {
+ const currentResponse = steps[currentStep].response;
+ let charIndex = 0;
+ setDisplayText("");
+
+ const typeInterval = setInterval(() => {
+ if (charIndex < currentResponse.length) {
+ setDisplayText(currentResponse.slice(0, charIndex + 1));
+ charIndex++;
+ } else {
+ clearInterval(typeInterval);
+ setTimeout(() => {
+ setCurrentStep((prev) => (prev + 1) % steps.length);
+ }, 2000);
+ }
+ }, 50);
+
+ return () => clearInterval(typeInterval);
+ }, [currentStep]);
+
+ return (
+
+ {/* AI Chat */}
+
+ {/* User prompt */}
+
+
+ U
+
+
+ {steps[currentStep].prompt}
+
+
+
+ {/* AI response */}
+
+
+
+ {/* Divider */}
+
+
+ {/* Mini Code Editor */}
+
+ {/* Editor tabs */}
+
+ {["JS", "PY", "C++", "JAVA"].map((lang, i) => (
+
+ {lang}
+
+ ))}
+
+ {/* Mini code */}
+
+
function sort (arr) {"{"}
+
{`//`} AI optimized
+
...
+
{"}"}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/animations/architecture-flow.tsx b/apps/web/src/components/animations/architecture-flow.tsx
new file mode 100644
index 0000000..e47421e
--- /dev/null
+++ b/apps/web/src/components/animations/architecture-flow.tsx
@@ -0,0 +1,233 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+
+// Plugin nodes
+const plugins = [
+ { id: "bubble", label: "BubbleSortPlugin", x: 50, y: 0 },
+ { id: "quick", label: "QuickSortPlugin", x: 50, y: 20 },
+ { id: "merge", label: "MergeSortPlugin", x: 50, y: 40 },
+ { id: "binary", label: "BinarySearchPlugin", x: 50, y: 60 },
+ { id: "bfs", label: "BFSPlugin", x: 50, y: 80 },
+];
+
+
+
+
+
+export function ArchitectureFlow() {
+ const [activePlugin, setActivePlugin] = useState(0);
+ const [flowStep, setFlowStep] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setFlowStep((prev) => {
+ if (prev >= 4) {
+ setActivePlugin((p) => (p + 1) % plugins.length);
+ return 0;
+ }
+ return prev + 1;
+ });
+ }, 800);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+
+ {/* Background sections */}
+ {/* Plugins Section */}
+
+
+ Visualizer Plugins
+
+
+ {/* Registry Section */}
+
+
+ Visualizer Registry
+
+
+ {/* App Section */}
+
+
+ Application
+
+
+ {/* Connection lines */}
+ {/* Plugin to Register */}
+ = 1 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth={flowStep >= 1 ? "0.8" : "0.4"}
+ fill="none"
+ markerEnd="url(#arrowhead)"
+ />
+
+ {/* Register to Get */}
+
+
+ {/* Router to Get */}
+ = 2 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth={flowStep >= 2 ? "0.8" : "0.4"}
+ fill="none"
+ markerEnd="url(#arrowhead)"
+ />
+
+ {/* Get to Renderer */}
+ = 3 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth={flowStep >= 3 ? "0.8" : "0.4"}
+ fill="none"
+ markerEnd="url(#arrowhead)"
+ />
+
+ {/* Arrow marker */}
+
+
+
+
+
+
+ {/* Flowing dot animation */}
+ {flowStep === 1 && (
+
+ )}
+ {flowStep === 2 && (
+
+ )}
+ {flowStep === 3 && (
+
+ )}
+
+ {/* Plugin nodes */}
+ {plugins.map((plugin, index) => (
+
+ = 0 ? "hsl(142 71% 45% / 0.2)" : "hsl(0 0% 8%)"}
+ stroke={activePlugin === index && flowStep >= 0 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth="0.4"
+ animate={{
+ fill: activePlugin === index && flowStep >= 0 ? "hsl(142 71% 45% / 0.2)" : "hsl(0 0% 8%)",
+ stroke: activePlugin === index && flowStep >= 0 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)",
+ }}
+ />
+ = 0 ? "hsl(142 71% 45%)" : "hsl(0 0% 60%)"}
+ fontSize="2.5"
+ fontFamily="monospace"
+ >
+ {plugin.label}
+
+
+ ))}
+
+ {/* Registry nodes */}
+
+ = 1 ? "hsl(142 71% 45% / 0.2)" : "hsl(0 0% 8%)"}
+ stroke={flowStep >= 1 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth="0.4"
+ />
+ = 1 ? "hsl(142 71% 45%)" : "hsl(0 0% 60%)"} fontSize="2.5" fontFamily="monospace">
+ register
+
+
+
+
+ = 2 ? "hsl(142 71% 45% / 0.2)" : "hsl(0 0% 8%)"}
+ stroke={flowStep >= 2 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth="0.4"
+ />
+ = 2 ? "hsl(142 71% 45%)" : "hsl(0 0% 60%)"} fontSize="2" fontFamily="monospace">
+ get
+
+
+
+
+
+
+ getByCategory
+
+
+
+ {/* App nodes */}
+
+ = 2 ? "hsl(142 71% 45% / 0.2)" : "hsl(0 0% 8%)"}
+ stroke={flowStep >= 2 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth="0.4"
+ />
+ = 2 ? "hsl(142 71% 45%)" : "hsl(0 0% 60%)"} fontSize="2.2" fontFamily="monospace">
+ Dynamic Router
+
+
+
+
+ = 3 ? "hsl(142 71% 45% / 0.2)" : "hsl(0 0% 8%)"}
+ stroke={flowStep >= 3 ? "hsl(142 71% 45%)" : "hsl(0 0% 25%)"}
+ strokeWidth="0.4"
+ />
+ = 3 ? "hsl(142 71% 45%)" : "hsl(0 0% 60%)"} fontSize="2" fontFamily="monospace">
+ Visualizer Renderer
+
+
+
+
+ {/* Current step indicator */}
+
+ {[0, 1, 2, 3, 4].map((step) => (
+
+ ))}
+
+
+ );
+}
diff --git a/apps/web/src/components/animations/array-search.tsx b/apps/web/src/components/animations/array-search.tsx
new file mode 100644
index 0000000..689a89b
--- /dev/null
+++ b/apps/web/src/components/animations/array-search.tsx
@@ -0,0 +1,125 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+
+const DESKTOP_ARRAY = [2, 5, 8, 11, 12, 16, 23, 28, 38, 56, 60, 67, 72, 81, 91, 99, 123, 212];
+const MOBILE_ARRAY = [67, 69, 70, 77, 81, 98];
+
+export function ArraySearch() {
+ const [array, setArray] = useState(DESKTOP_ARRAY);
+ const target = 67;
+ const [currentIndex, setCurrentIndex] = useState(-1);
+ const [left, setLeft] = useState(0);
+ const [right, setRight] = useState(DESKTOP_ARRAY.length - 1);
+ const [found, setFound] = useState(false);
+
+ // Handle responsive array
+ useEffect(() => {
+ const handleResize = () => {
+ if (window.innerWidth < 768) {
+ setArray(MOBILE_ARRAY);
+ } else {
+ setArray(DESKTOP_ARRAY);
+ }
+ };
+
+ // Initial check
+ handleResize();
+
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ useEffect(() => {
+ let isCancelled = false;
+
+ const animateBinarySearch = async () => {
+ if (isCancelled) return;
+
+ setCurrentIndex(-1);
+ setLeft(0);
+ setRight(array.length - 1);
+ setFound(false);
+
+ let l = 0;
+ let r = array.length - 1;
+
+ while (l <= r) {
+ if (isCancelled) return;
+
+ const mid = Math.floor((l + r) / 2);
+ setCurrentIndex(mid);
+ setLeft(l);
+ setRight(r);
+ await new Promise((resolve) => setTimeout(resolve, 700));
+
+ if (array[mid] === target) {
+ setFound(true);
+ break;
+ } else if (array[mid] < target) {
+ l = mid + 1;
+ } else {
+ r = mid - 1;
+ }
+ }
+
+ if (!isCancelled) {
+ await new Promise((resolve) => setTimeout(resolve, 2500));
+ }
+ };
+
+ const interval = setInterval(animateBinarySearch, 8000);
+ animateBinarySearch();
+
+ return () => {
+ isCancelled = true;
+ clearInterval(interval);
+ };
+ }, [array]); // Restart animation when array changes
+
+ return (
+
+
+ {array.map((num, index) => {
+ const isInRange = index >= left && index <= right;
+ const isCurrent = index === currentIndex;
+ const isFound = found && isCurrent;
+
+ return (
+
+ {num}
+
+ );
+ })}
+
+
+ Target: {target}
+ {found && (
+
+ Found!
+
+ )}
+
+
+ );
+}
diff --git a/apps/web/src/components/animations/binary-tree.tsx b/apps/web/src/components/animations/binary-tree.tsx
new file mode 100644
index 0000000..bd14586
--- /dev/null
+++ b/apps/web/src/components/animations/binary-tree.tsx
@@ -0,0 +1,118 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+
+interface TreeNode {
+ value: number;
+ x: number;
+ y: number;
+ left?: TreeNode;
+ right?: TreeNode;
+}
+
+export function BinaryTree() {
+ const [visitedNodes, setVisitedNodes] = useState([]);
+
+ const tree: TreeNode = {
+ value: 50,
+ x: 100,
+ y: 20,
+ left: {
+ value: 30,
+ x: 50,
+ y: 60,
+ left: { value: 20, x: 25, y: 100 },
+ right: { value: 40, x: 75, y: 100 },
+ },
+ right: {
+ value: 70,
+ x: 150,
+ y: 60,
+ left: { value: 60, x: 125, y: 100 },
+ right: { value: 80, x: 175, y: 100 },
+ },
+ };
+
+ const getAllNodes = (node: TreeNode | undefined): TreeNode[] => {
+ if (!node) return [];
+ return [node, ...getAllNodes(node.left), ...getAllNodes(node.right)];
+ };
+
+ const nodes = getAllNodes(tree);
+
+ useEffect(() => {
+ const animateTraversal = async () => {
+ setVisitedNodes([]);
+ const order = [50, 30, 20, 40, 70, 60, 80];
+
+ for (const value of order) {
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ setVisitedNodes((prev) => [...prev, value]);
+ }
+
+ await new Promise((resolve) => setTimeout(resolve, 2000));
+ };
+
+ const interval = setInterval(animateTraversal, 8000);
+ animateTraversal();
+
+ return () => clearInterval(interval);
+ }, []);
+
+ const edges = [
+ { x1: 100, y1: 30, x2: 50, y2: 55 },
+ { x1: 100, y1: 30, x2: 150, y2: 55 },
+ { x1: 50, y1: 70, x2: 25, y2: 95 },
+ { x1: 50, y1: 70, x2: 75, y2: 95 },
+ { x1: 150, y1: 70, x2: 125, y2: 95 },
+ { x1: 150, y1: 70, x2: 175, y2: 95 },
+ ];
+
+ return (
+
+ {/* Edges */}
+ {edges.map((edge, index) => (
+
+ ))}
+
+ {/* Nodes */}
+ {nodes.map((node) => (
+
+
+
+ {node.value}
+
+
+ ))}
+
+ );
+}
diff --git a/apps/web/src/components/animations/code-preview.tsx b/apps/web/src/components/animations/code-preview.tsx
new file mode 100644
index 0000000..e755e12
--- /dev/null
+++ b/apps/web/src/components/animations/code-preview.tsx
@@ -0,0 +1,58 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+
+export function CodePreview() {
+ const [highlightedLine, setHighlightedLine] = useState(0);
+
+ const codeLines = [
+ { content: "function bubbleSort(arr) {", indent: 0 },
+ { content: "for (let i = 0; i < arr.length; i++) {", indent: 1 },
+ { content: "for (let j = 0; j < arr.length - i - 1; j++) {", indent: 2 },
+ { content: "if (arr[j] > arr[j + 1]) {", indent: 3 },
+ { content: "[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];", indent: 4 },
+ { content: "}", indent: 3 },
+ { content: "}", indent: 2 },
+ { content: "}", indent: 1 },
+ { content: "return arr;", indent: 1 },
+ { content: "}", indent: 0 },
+ ];
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setHighlightedLine((prev) => (prev + 1) % codeLines.length);
+ }, 800);
+
+ return () => clearInterval(interval);
+ }, [codeLines.length]);
+
+ return (
+
+ {codeLines.map((line, index) => (
+
+
+ {index + 1}
+
+
+ {line.content}
+
+
+ ))}
+
+ );
+}
diff --git a/apps/web/src/components/animations/graph-visualization.tsx b/apps/web/src/components/animations/graph-visualization.tsx
new file mode 100644
index 0000000..500b3c7
--- /dev/null
+++ b/apps/web/src/components/animations/graph-visualization.tsx
@@ -0,0 +1,126 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+
+interface Node {
+ id: string;
+ x: number;
+ y: number;
+}
+
+interface Edge {
+ from: string;
+ to: string;
+}
+
+export function GraphVisualization() {
+ const [visitedNodes, setVisitedNodes] = useState([]);
+ const [visitedEdges, setVisitedEdges] = useState([]);
+
+ const nodes: Node[] = [
+ { id: "A", x: 50, y: 30 },
+ { id: "B", x: 100, y: 20 },
+ { id: "C", x: 150, y: 40 },
+ { id: "D", x: 30, y: 80 },
+ { id: "E", x: 90, y: 90 },
+ { id: "F", x: 160, y: 100 },
+ ];
+
+ const edges: Edge[] = [
+ { from: "A", to: "B" },
+ { from: "A", to: "D" },
+ { from: "B", to: "C" },
+ { from: "B", to: "E" },
+ { from: "D", to: "E" },
+ { from: "C", to: "F" },
+ { from: "E", to: "F" },
+ ];
+
+ useEffect(() => {
+ const animateBFS = async () => {
+ setVisitedNodes([]);
+ setVisitedEdges([]);
+
+ const order = ["A", "B", "D", "C", "E", "F"];
+ const edgeOrder = ["A-B", "A-D", "B-C", "B-E", "D-E", "C-F"];
+
+ for (let i = 0; i < order.length; i++) {
+ await new Promise((resolve) => setTimeout(resolve, 400));
+ setVisitedNodes((prev) => [...prev, order[i]]);
+ if (edgeOrder[i]) {
+ setVisitedEdges((prev) => [...prev, edgeOrder[i]]);
+ }
+ }
+
+ await new Promise((resolve) => setTimeout(resolve, 2500));
+ };
+
+ const interval = setInterval(animateBFS, 7000);
+ animateBFS();
+
+ return () => clearInterval(interval);
+ }, []);
+
+ const getNodePos = (id: string) => nodes.find((n) => n.id === id)!;
+
+ return (
+
+ {/* Edges */}
+ {edges.map((edge) => {
+ const from = getNodePos(edge.from);
+ const to = getNodePos(edge.to);
+ const edgeId = `${edge.from}-${edge.to}`;
+ const isVisited = visitedEdges.includes(edgeId);
+
+ return (
+
+ );
+ })}
+
+ {/* Nodes */}
+ {nodes.map((node) => {
+ const isVisited = visitedNodes.includes(node.id);
+
+ return (
+
+
+
+ {node.id}
+
+
+ );
+ })}
+
+ );
+}
diff --git a/apps/web/src/components/animations/keyboard-demo.tsx b/apps/web/src/components/animations/keyboard-demo.tsx
new file mode 100644
index 0000000..783779b
--- /dev/null
+++ b/apps/web/src/components/animations/keyboard-demo.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState } from "react";
+
+const keys = [
+ { key: "Space", label: "Play/Pause", width: "flex-1" },
+ { key: "←", label: "Prev Step", width: "w-10" },
+ { key: "→", label: "Next Step", width: "w-10" },
+ { key: "R", label: "Reset", width: "w-10" },
+];
+
+export function KeyboardDemo() {
+ const [activeKey, setActiveKey] = useState(null);
+ const [currentIndex, setCurrentIndex] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ const key = keys[currentIndex].key;
+ setActiveKey(key);
+
+ setTimeout(() => {
+ setActiveKey(null);
+ }, 300);
+
+ setCurrentIndex((prev) => (prev + 1) % keys.length);
+ }, 1500);
+
+ return () => clearInterval(interval);
+ }, [currentIndex]);
+
+ return (
+
+ {/* Keyboard row */}
+
+ {keys.map(({ key, width }) => (
+
+ {key}
+
+ ))}
+
+
+ {/* Current action indicator */}
+
+
+ {keys[currentIndex].key}
+ →
+ {keys[currentIndex].label}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/animations/sorting-bars.tsx b/apps/web/src/components/animations/sorting-bars.tsx
new file mode 100644
index 0000000..fd955a6
--- /dev/null
+++ b/apps/web/src/components/animations/sorting-bars.tsx
@@ -0,0 +1,77 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { useEffect, useState, useRef } from "react";
+
+export function SortingBars() {
+ const [bars, setBars] = useState([45, 80, 30, 95, 55, 70, 25, 85, 40, 60]);
+ const [activeIndices, setActiveIndices] = useState([]);
+ const [sortedIndices, setSortedIndices] = useState([]);
+ const isSorting = useRef(false);
+
+ useEffect(() => {
+ const animateBubbleSort = async () => {
+ if (isSorting.current) return;
+ isSorting.current = true;
+
+ const arr = [45, 80, 30, 95, 55, 70, 25, 85, 40, 60];
+ setBars([...arr]);
+ setSortedIndices([]);
+ setActiveIndices([]);
+
+ await new Promise((resolve) => setTimeout(resolve, 500));
+
+ const n = arr.length;
+
+ for (let i = 0; i < n - 1; i++) {
+ for (let j = 0; j < n - i - 1; j++) {
+ // Highlight comparing elements
+ setActiveIndices([j, j + 1]);
+ await new Promise((resolve) => setTimeout(resolve, 200));
+
+ // Swap if needed
+ if (arr[j] > arr[j + 1]) {
+ [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
+ setBars([...arr]);
+ await new Promise((resolve) => setTimeout(resolve, 150));
+ }
+ }
+ // Mark the last element of this pass as sorted
+ setSortedIndices((prev) => [...prev, n - 1 - i]);
+ }
+
+ // Mark first element as sorted too
+ setSortedIndices((prev) => [...prev, 0]);
+ setActiveIndices([]);
+
+ // Wait before resetting
+ await new Promise((resolve) => setTimeout(resolve, 2500));
+ isSorting.current = false;
+ };
+
+ animateBubbleSort();
+ const interval = setInterval(animateBubbleSort, 8000);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ {bars.map((height, index) => (
+
+ ))}
+
+ );
+}
diff --git a/apps/web/src/components/sections/algorithm-checklist.tsx b/apps/web/src/components/sections/algorithm-checklist.tsx
new file mode 100644
index 0000000..8d1bc93
--- /dev/null
+++ b/apps/web/src/components/sections/algorithm-checklist.tsx
@@ -0,0 +1,272 @@
+"use client";
+
+import { motion, AnimatePresence } from "framer-motion";
+import { useState } from "react";
+import { ChevronDown, ChevronRight, Check, Circle, Terminal, Sparkles, Rocket } from "lucide-react";
+import { categories, getTotalCount, getCategoryCount, type Category, type AlgorithmTopic } from "@/lib/algorithms-data";
+
+interface SubcategoryProps {
+ name: string;
+ topics: AlgorithmTopic[];
+}
+
+function Subcategory({ name, topics }: SubcategoryProps) {
+ const [isOpen, setIsOpen] = useState(false);
+ const implementedCount = topics.filter(t => t.implemented).length;
+
+ return (
+
+
setIsOpen(!isOpen)}
+ className="w-full text-left text-[hsl(var(--foreground))]/80 text-xs sm:text-sm font-medium flex items-center gap-2 hover:text-[hsl(var(--foreground))] transition-colors py-1"
+ >
+ {isOpen ? (
+
+ ) : (
+
+ )}
+ {name}
+
+ {implementedCount}/{topics.length}
+
+
+
+
+ {isOpen && (
+
+ {topics.map((item, index) => (
+
+
+
+ {index === topics.length - 1 ? "└─" : "├─"}
+
+ {item.name}
+
+
+ {item.implemented ? (
+
+ ) : (
+
+ )}
+
+
+ ))}
+
+ )}
+
+
+ );
+}
+
+interface CategorySectionProps {
+ category: Category;
+ visible: boolean;
+ setVisible: (visible: boolean) => void;
+}
+
+function CategorySection({ category, visible, setVisible }: CategorySectionProps) {
+ const { total, implemented } = getCategoryCount(category);
+
+ return (
+
+
setVisible(!visible)}
+ >
+ {visible ? (
+
+ ) : (
+
+ )}
+ {category.title}
+
+ {implemented}/{total}
+
+
+
+
+ {visible && (
+
+ {Object.entries(category.items).map(([topic, { topics }]) => (
+
+ ))}
+
+ )}
+
+
+ );
+}
+
+export function AlgorithmChecklist() {
+ const [dsVisible, setDsVisible] = useState(true);
+ const [algoVisible, setAlgoVisible] = useState(true);
+ const { total, implemented } = getTotalCount();
+ const progress = Math.round((implemented / total) * 100);
+
+ return (
+
+ {/* Background */}
+
+
+
+
+ {/* Noise overlay */}
+
+
+
+ {/* Section header */}
+
+
+
+ / Implementation Roadmap
+
+
+
+ THE AMBITIOUS LIST
+
+
+
+ {total}+ algorithms and data structures. This is what we're building together.
+ Pick one and contribute, or suggest new ones. ML/DL, algorithms from other fields, and visualizers are all welcome.
+
+
+ {/* Progress bar */}
+
+
+ Progress
+ {implemented}/{total} ({progress}%)
+
+
+
+
+
+
+
+ {/* Terminal-style container */}
+
+ {/* Terminal header */}
+
+
+
+ opendsa@roadmap ~ $
+
+
+
+ {/* Terminal content */}
+
+ {/* Header banner */}
+
+
+
+ OpenDSA Implementation Roadmap
+
+
+
+ Click on any category to expand/collapse
+
+
+
+ {/* Two columns */}
+
+
+ {/* Legend */}
+
+ Status:
+
+ Implemented
+
+
+ Pending
+
+
+
+ {/* Cursor */}
+
+ $
+
+
+
+
+
+ {/* Future plans */}
+
+
+ Open to Contributions: {" "}
+ Machine Learning & Deep Learning Algorithm Visualizers etc...
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/architecture.tsx b/apps/web/src/components/sections/architecture.tsx
new file mode 100644
index 0000000..4bc4dbf
--- /dev/null
+++ b/apps/web/src/components/sections/architecture.tsx
@@ -0,0 +1,330 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Settings2, ArrowRight } from "lucide-react";
+import { useState, useEffect } from "react";
+import { ArchitectureFlow } from "@/components/animations/architecture-flow";
+
+const codeTabs = [
+ {
+ name: "plugin.ts",
+ code: `interface VisualizerPlugin {
+ meta: {
+ id: "bubble-sort",
+ name: "Bubble Sort",
+ category: "sorting",
+ },
+ generateSteps(arr: number[]): Step[],
+ component: React.FC,
+}`,
+ },
+ {
+ name: "types.ts",
+ code: `interface AnimationStep {
+ type: "compare" | "swap" | "done";
+ indices: number[];
+ description: string;
+}
+
+type VisualizerCategory =
+ | "sorting"
+ | "searching"
+ | "graph";`,
+ },
+ {
+ name: "registry.ts",
+ code: `const registry = new Map();
+
+export function register(plugin) {
+ registry.set(plugin.meta.id, plugin);
+}
+
+export function get(id: string) {
+ return registry.get(id);
+}`,
+ },
+];
+
+const flowSteps = [
+ { id: "plugin", label: "BubbleSortPlugin", color: "primary" },
+ { id: "register", label: "registry.register()", color: "yellow" },
+ { id: "registry", label: "Visualizer Registry", color: "blue" },
+ { id: "router", label: "/visualize/bubble-sort", color: "purple" },
+ { id: "render", label: "Renderer", color: "primary" },
+];
+
+export function Architecture() {
+ const [activeTab, setActiveTab] = useState(0);
+ const [activeFlowStep, setActiveFlowStep] = useState(0);
+ const [showDiagram, setShowDiagram] = useState(false);
+
+ // Animate through flow steps
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setActiveFlowStep((prev) => (prev + 1) % flowSteps.length);
+ }, 1500);
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ {/* Background */}
+
+
+
+ {/* Noise overlay */}
+
+
+
+ {/* Top section: Text + Code Editor */}
+
+ {/* Left side - Content */}
+
+ {/* Label */}
+
+
+ / System Architecture
+
+
+ {/* Heading */}
+
+ PLUGIN-BASED
+
+ VISUALIZER ENGINE
+
+
+ {/* Description */}
+
+ Every algorithm is a self-contained plugin with its own visualization logic.
+ This makes OpenDSA extensible, maintainable, and community-friendly.
+
+
+ {/* Features list */}
+
+ {[
+ "Step-based animation system",
+ "Modular visualizer registry",
+ "Shared UI components",
+ "URL state sync",
+ ].map((item, index) => (
+
+
+ {item}
+
+ ))}
+
+
+
+ {/* Right side - Code Editor with Tabs */}
+
+
+ {/* Browser header */}
+
+
+ {/* Clickable tabs */}
+
+ {codeTabs.map((tab, index) => (
+ setActiveTab(index)}
+ className={`px-3 py-1 rounded-md text-xs font-mono transition-all ${
+ activeTab === index
+ ? "bg-[hsl(var(--secondary))] text-[hsl(var(--primary))]"
+ : "text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]"
+ }`}
+ >
+ {tab.name}
+
+ ))}
+
+
+
+ {/* Code content */}
+
+
+
+ {codeTabs[activeTab].code.split("\n").map((line, i) => (
+
+ {line.includes("interface") || line.includes("type") || line.includes("const") || line.includes("export") ? (
+ {line.split(" ")[0]}
+ ) : null}
+ {line.includes("interface") || line.includes("type") ? (
+ {line.split(" ").slice(1).join(" ")}
+ ) : line.includes("const") || line.includes("export") || line.includes("function") ? (
+ {line.split(" ").slice(1).join(" ")}
+ ) : line.includes(":") && !line.includes("//") ? (
+ <>
+ {line.split(":")[0]}
+ :{line.split(":").slice(1).join(":")}
+ >
+ ) : line.includes('"') ? (
+ {line}
+ ) : (
+ {line}
+ )}
+
+ ))}
+
+
+
+
+
+ {/* Decorative gradient */}
+
+
+
+
+ {/* Middle section: Toggle between Flow types */}
+
+ {/* Flow title with toggle */}
+
+
+
/ Plugin Registration Flow
+
+
+
+ setShowDiagram(false)}
+ className={`px-3 py-1.5 rounded-md text-xs font-mono transition-all ${
+ !showDiagram
+ ? "bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]"
+ : "bg-[hsl(var(--secondary))] text-[hsl(var(--muted-foreground))]"
+ }`}
+ >
+ Linear
+
+ setShowDiagram(true)}
+ className={`px-3 py-1.5 rounded-md text-xs font-mono transition-all ${
+ showDiagram
+ ? "bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]"
+ : "bg-[hsl(var(--secondary))] text-[hsl(var(--muted-foreground))]"
+ }`}
+ >
+ Diagram
+
+
+
+
+ {/* Flow visualization */}
+
+ {/* Noise overlay */}
+
+
+ {showDiagram ? (
+ /* Architecture Diagram Flow */
+
+ ) : (
+ /* Linear Flow */
+ <>
+
+ {flowSteps.map((step, index) => (
+
+
+ {activeFlowStep === index && (
+
+ )}
+
+ {step.label}
+
+
+
+ {/* Arrow */}
+ {index < flowSteps.length - 1 && (
+
+
+
+ )}
+
+ ))}
+
+
+ {/* Step description */}
+
+
+ {activeFlowStep === 0 && "Plugin defines meta, component, and step generator"}
+ {activeFlowStep === 1 && "Plugin is registered with the central registry"}
+ {activeFlowStep === 2 && "Registry stores all available visualizers"}
+ {activeFlowStep === 3 && "URL routes to specific visualizer by ID"}
+ {activeFlowStep === 4 && "Renderer loads and displays the visualization"}
+
+
+ >
+ )}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/faq.tsx b/apps/web/src/components/sections/faq.tsx
new file mode 100644
index 0000000..3584e45
--- /dev/null
+++ b/apps/web/src/components/sections/faq.tsx
@@ -0,0 +1,174 @@
+"use client";
+
+import { motion, AnimatePresence } from "framer-motion";
+import { ChevronRight, Terminal, MessageSquare } from "lucide-react";
+import Link from "next/link";
+import { useState } from "react";
+
+interface FAQItem {
+ id: string;
+ question: string;
+ answer: string;
+}
+
+const faqItems: FAQItem[] = [
+ {
+ id: "0x01",
+ question: "IS OPENDSA REALLY FREE?",
+ answer: "Yes! OpenDSA is 100% free and open source under the MIT license. No subscriptions, no premium tiers, no hidden costs. Ever.",
+ },
+ {
+ id: "0x02",
+ question: "WHAT ALGORITHMS ARE SUPPORTED?",
+ answer: "We support sorting algorithms (bubble, quick, merge, heap, insertion, selection), searching (binary, linear), graph algorithms (BFS, DFS, Dijkstra's), and tree operations (BST, AVL). More are being added regularly.",
+ },
+ {
+ id: "0x03",
+ question: "CAN I CONTRIBUTE NEW ALGORITHMS?",
+ answer: "Absolutely! We welcome contributions. Check our CONTRIBUTING.md guide on GitHub to get started. Each visualizer is a modular plugin, making it easy to add new ones.",
+ },
+ {
+ id: "0x04",
+ question: "DOES IT WORK OFFLINE?",
+ answer: "Yes, once loaded, the visualizations work entirely in your browser. No server calls needed for running animations or stepping through algorithms.",
+ },
+ {
+ id: "0x05",
+ question: "CAN I USE IT FOR TEACHING?",
+ answer: "Yes! OpenDSA is perfect for educators. Share specific visualization states via URL, embed visualizers in your course materials, and let students explore at their own pace.",
+ },
+];
+
+export function FAQ() {
+ const [openId, setOpenId] = useState(null);
+
+ return (
+
+ {/* Background */}
+
+
+
+ {/* Noise overlay */}
+
+
+
+
+ {/* Left side - Header */}
+
+ {/* Label */}
+
+
+ / HELP_TERMINAL
+
+
+ {/* Heading - stacked words */}
+
+ FREQ.
+
+ ASKED
+
+ QUEST.
+
+
+ {/* Description */}
+
+ Common questions about licensing, architecture, and technical capabilities.
+
+
+ {/* Contact card */}
+
+
+
+
+
+ Still have questions?
+
+
+ JOIN DISCUSSIONS
+
+
+
+ github.com/soloshun/opendsa
+
+
+
+
+
+ {/* Right side - FAQ items */}
+
+ {faqItems.map((item, index) => (
+
+ setOpenId(openId === item.id ? null : item.id)}
+ className="w-full group"
+ >
+
+
+
+ {item.id}
+
+
+ {item.question}
+
+
+
+
+
+
+ {openId === item.id && (
+
+
+ {item.answer}
+
+
+ )}
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/features.tsx b/apps/web/src/components/sections/features.tsx
new file mode 100644
index 0000000..5345452
--- /dev/null
+++ b/apps/web/src/components/sections/features.tsx
@@ -0,0 +1,328 @@
+"use client";
+
+import React from "react";
+
+import { motion } from "framer-motion";
+import {
+ BarChart3,
+ Binary,
+ Braces,
+ GitBranch,
+ Layers,
+ Play,
+ Zap,
+ Keyboard,
+ Share2,
+ Sparkles,
+ ClipboardCopy,
+ Check
+} from "lucide-react";
+import { AnimatePresence } from "framer-motion";
+import { SortingBars } from "@/components/animations/sorting-bars";
+import { BinaryTree } from "@/components/animations/binary-tree";
+import { GraphVisualization } from "@/components/animations/graph-visualization";
+import { CodePreview } from "@/components/animations/code-preview";
+import { ArraySearch } from "@/components/animations/array-search";
+import { AIAssistant } from "@/components/animations/ai-assistant";
+import { KeyboardDemo } from "@/components/animations/keyboard-demo";
+
+interface FeatureCardProps {
+ title: string;
+ description: string;
+ icon: React.ReactNode;
+ children?: React.ReactNode;
+ className?: string;
+ index?: number;
+}
+
+function CopyButton({ text }: { text: string }) {
+ const [copied, setCopied] = React.useState(false);
+
+ const handleCopy = async () => {
+ try {
+ await navigator.clipboard.writeText(text);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch (err) {
+ console.error("Failed to copy:", err);
+ }
+ };
+
+ return (
+
+
+
+ {copied ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+ {/* Tooltip */}
+
+
+ {copied ? "Copied!" : "Copy URL"}
+ {/* Arrow */}
+
+
+
+
+
+ );
+}
+
+function FeatureCard({ title, description, icon, children, className = "", index = 0 }: FeatureCardProps) {
+ return (
+
+ {/* Noise overlay */}
+
+
+ {/* Hover gradient - diagonal slant */}
+
+
+ {/* Corner glow on hover - slanted */}
+
+
+ {/* Content */}
+
+ {/* Icon */}
+
+ {icon}
+
+
+ {/* Title */}
+
+ {title}
+
+
+ {/* Description */}
+
+ {description}
+
+
+ {/* Custom content */}
+ {children &&
{children}
}
+
+
+ );
+}
+
+export function Features() {
+ return (
+
+ {/* Background with gradient */}
+
+
+
+ {/* Noise overlay */}
+
+
+
+ {/* Section header - left aligned */}
+
+
+
+ EVERYTHING YOU NEED
+
+ 100% FREE
+
+
+ Professional visualizations. Zero cost. No catch.
+
+
+
+ {/* Bento Grid - Row 1: Large + 2 small stacked */}
+
+ {/* Sorting Algorithms - Large card */}
+
}
+ className="lg:col-span-2"
+ index={0}
+ >
+
+
+
+
+
+ {/* Right column with 2 stacked cards */}
+
+ {/* Step Control */}
+
}
+ index={1}
+ >
+
+ {["Play", "Pause", "Step", "Reset"].map((action) => (
+
+ {action}
+
+ ))}
+
+
+
+ {/* Speed Control */}
+
}
+ index={2}
+ >
+
+
+
+
+
+ {/* Row 2: Search full width */}
+
+
}
+ index={3}
+ >
+
+
+
+
+ {/* Row 3: Tree + Keyboard + Graph (3 columns) */}
+
+ {/* Tree Structures */}
+
}
+ index={4}
+ >
+
+
+
+
+
+ {/* Keyboard Shortcuts - with demo animation */}
+
}
+ index={5}
+ >
+
+
+
+
+
+ {/* Graph Algorithms */}
+
}
+ className="md:col-span-2 lg:col-span-1"
+ index={6}
+ >
+
+
+
+
+
+
+ {/* Row 4: AI Assistant + Code Sync (2 columns) */}
+
+ {/* AI Assistant */}
+
}
+ index={7}
+ >
+
+
+
+ {/* Code Sync */}
+
}
+ index={8}
+ >
+
+
+
+
+
+
+ {/* Row 5: Shareable URLs full width */}
+
}
+ index={9}
+ >
+
+ opendsa.dev/visualize/sorting/bubble?data=5,3,8,1&step=4
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/footer.tsx b/apps/web/src/components/sections/footer.tsx
new file mode 100644
index 0000000..9919bad
--- /dev/null
+++ b/apps/web/src/components/sections/footer.tsx
@@ -0,0 +1,182 @@
+"use client";
+
+import { Github, Twitter, Heart } from "lucide-react";
+import Image from "next/image";
+import Link from "next/link";
+import { useEffect, useState } from "react";
+
+const footerLinks = {
+ product: [
+ { label: "Features", href: "#features" },
+ { label: "Roadmap", href: "#roadmap" },
+ { label: "Launch App", href: "https://app.opendsa.dev" },
+ ],
+ resources: [
+ { label: "Documentation", href: "https://docs.opendsa.dev" },
+ { label: "Contributing", href: "https://github.com/soloshun/opendsa/blob/main/CONTRIBUTING.md" },
+ { label: "Changelog", href: "https://github.com/soloshun/opendsa/releases" },
+ ],
+ community: [
+ { label: "GitHub", href: "https://github.com/soloshun/opendsa" },
+ { label: "Discord", href: "#" },
+ { label: "Twitter", href: "#" },
+ { label: "Support Us ☕", href: "https://docs.opendsa.dev/sponsors" },
+ ],
+};
+
+export function Footer() {
+ const [avatarUrl, setAvatarUrl] = useState(null);
+
+ useEffect(() => {
+ async function fetchAvatar() {
+ try {
+ const res = await fetch("https://api.github.com/users/soloshun");
+ if (res.ok) {
+ const data = await res.json();
+ setAvatarUrl(data.avatar_url);
+ }
+ } catch (error) {
+ console.error("Failed to fetch avatar:", error);
+ }
+ }
+ fetchAvatar();
+ }, []);
+
+ return (
+
+ {/* Gradient from bottom */}
+
+
+
+ {/* Background */}
+
+
+ {/* Noise overlay */}
+
+
+
+
+ {/* Brand */}
+
+
+
+
+ {"<>"}
+
+
+
+ OPENDSA
+
+
+
+ An open-source, interactive platform for visualizing data
+ structures and algorithms.
+
+
+
+
+
+
+
+
+
+
+
+ {/* Product */}
+
+
Product
+
+ {footerLinks.product.map((link) => (
+
+
+ {link.label}
+
+
+ ))}
+
+
+
+ {/* Resources */}
+
+
Resources
+
+ {footerLinks.resources.map((link) => (
+
+
+ {link.label}
+
+
+ ))}
+
+
+
+ {/* Community */}
+
+
Community
+
+ {footerLinks.community.map((link) => (
+
+
+ {link.label}
+
+
+ ))}
+
+
+
+
+ {/* Bottom */}
+
+
+ © {new Date().getFullYear()} OpenDSA. MIT License.
+
+
+ Made with
+
+ by
+
+ {avatarUrl && (
+
+ )}
+ Solomon Eshun
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/header.tsx b/apps/web/src/components/sections/header.tsx
new file mode 100644
index 0000000..e453214
--- /dev/null
+++ b/apps/web/src/components/sections/header.tsx
@@ -0,0 +1,143 @@
+"use client";
+
+import { motion } from "framer-motion";
+import {
+ Github,
+ Menu,
+ X,
+ // Sun
+} from "lucide-react";
+import Link from "next/link";
+import { useState } from "react";
+
+const navLinks = [
+ { href: "#features", label: "Features" },
+ { href: "#roadmap", label: "Roadmap" },
+ // { href: "#open-source", label: "Open Source" },
+ { href: "https://docs.opendsa.dev", label: "Docs", external: true },
+];
+
+export function Header() {
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
+
+ return (
+
+ {/* Main nav container - rounded pill style */}
+
+ {/* Logo */}
+
+
+
+ {"<>"}
+
+
+
+ OPENDSA
+
+
+
+ {/* Desktop Navigation - centered */}
+
+ {navLinks.map((link) => (
+
+ {link.label}
+
+ ))}
+
+
+ {/* Right side buttons */}
+
+ {/* Theme toggle placeholder */}
+ {/*
+
+ */}
+
+ {/* GitHub star button */}
+
+
+ Star
+ 0
+
+
+ {/* Launch App CTA */}
+
+ LAUNCH APP
+
+
+
+ {/* Mobile menu button */}
+ setMobileMenuOpen(!mobileMenuOpen)}
+ >
+ {mobileMenuOpen ? (
+
+ ) : (
+
+ )}
+
+
+
+ {/* Mobile Navigation */}
+ {mobileMenuOpen && (
+
+
+ {navLinks.map((link) => (
+ setMobileMenuOpen(false)}
+ >
+ {link.label}
+
+ ))}
+
+
+
+
+ GitHub
+
+
+ Launch App
+
+
+
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/sections/hero.tsx b/apps/web/src/components/sections/hero.tsx
new file mode 100644
index 0000000..09652e7
--- /dev/null
+++ b/apps/web/src/components/sections/hero.tsx
@@ -0,0 +1,147 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { ArrowRight, Github, Sparkles } from "lucide-react";
+import Link from "next/link";
+
+export function Hero() {
+ return (
+
+ {/* Background - base layer */}
+
+
+ {/* Grid pattern - subtle overlay */}
+
+
+ {/* Noise texture overlay */}
+
+
+ {/* Gradient orbs - decorative */}
+
+
+
+ {/* Main content */}
+
+ {/* Centered content wrapper */}
+
+ {/* Top badges */}
+
+
+
+ 100% Open Source
+
+
+
+ Star on GitHub
+
+
+
+ {/* Main heading - Mobile responsive and always centered */}
+
+
+ VISUALIZE
+
+
+
+ ALGORITHMS
+
+
+
+ BEAUTIFULLY
+
+
+
+ {/* Description */}
+
+ The open-source algorithm visualization platform. Interactive visualizations
+ for sorting, searching, graphs, trees, and more. Learn through{" "}
+ step-by-step animations .
+
+
+ {/* Feature tags */}
+
+ Free forever
+ ·
+ No sign-up
+ ·
+ MIT Licensed
+
+
+ {/* CTA Buttons */}
+
+
+ Start Visualizing
+
+
+
+ See Features
+
+
+
+
+
+ {/* Bottom gradient fade */}
+
+
+ {/* Scroll indicator - hide on mobile */}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/open-source.tsx b/apps/web/src/components/sections/open-source.tsx
new file mode 100644
index 0000000..b1ad90e
--- /dev/null
+++ b/apps/web/src/components/sections/open-source.tsx
@@ -0,0 +1,432 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Github, Star, GitFork, Users, ExternalLink, Crown, Code2 } from "lucide-react";
+import Link from "next/link";
+import Image from "next/image";
+import { useEffect, useState, useRef } from "react";
+
+interface GitHubStats {
+ stars: number;
+ forks: number;
+ contributors: number;
+}
+
+interface Contributor {
+ login: string;
+ id: number;
+ avatar_url: string;
+ html_url: string;
+ contributions: number;
+}
+
+// Contribution tier colors and badges
+function getContributorTier(contributions: number) {
+ if (contributions >= 100) {
+ return {
+ tier: "legendary",
+ color: "from-amber-400 via-yellow-500 to-amber-600",
+ border: "border-amber-400/60",
+ glow: "shadow-amber-500/30",
+ badge: "bg-gradient-to-r from-amber-500 to-yellow-500",
+ textColor: "text-amber-400",
+ emoji: "👑",
+ };
+ }
+ if (contributions >= 50) {
+ return {
+ tier: "gold",
+ color: "from-yellow-400 to-amber-500",
+ border: "border-yellow-400/50",
+ glow: "shadow-yellow-500/20",
+ badge: "bg-gradient-to-r from-yellow-500 to-amber-500",
+ textColor: "text-yellow-400",
+ emoji: "⭐",
+ };
+ }
+ if (contributions >= 20) {
+ return {
+ tier: "silver",
+ color: "from-slate-300 to-slate-400",
+ border: "border-slate-400/40",
+ glow: "shadow-slate-400/15",
+ badge: "bg-gradient-to-r from-slate-400 to-slate-500",
+ textColor: "text-slate-300",
+ emoji: "",
+ };
+ }
+ if (contributions >= 10) {
+ return {
+ tier: "bronze",
+ color: "from-orange-400 to-orange-600",
+ border: "border-orange-400/30",
+ glow: "shadow-orange-500/10",
+ badge: "bg-gradient-to-r from-orange-500 to-orange-600",
+ textColor: "text-orange-400",
+ emoji: "",
+ };
+ }
+ return {
+ tier: "contributor",
+ color: "from-[hsl(var(--primary))] to-emerald-600",
+ border: "border-[hsl(var(--border))]",
+ glow: "",
+ badge: "bg-[hsl(var(--primary))]",
+ textColor: "text-[hsl(var(--primary))]",
+ emoji: "",
+ };
+}
+
+function formatContributions(count: number): string {
+ if (count >= 100) return "99+";
+ return count.toString();
+}
+
+interface ContributorAvatarProps {
+ contributor: Contributor;
+ index: number;
+}
+
+function ContributorAvatar({ contributor, index }: ContributorAvatarProps) {
+ const [isLoaded, setIsLoaded] = useState(false);
+ const [isInView, setIsInView] = useState(false);
+ const ref = useRef(null);
+ const tier = getContributorTier(contributor.contributions);
+
+ // Intersection Observer for lazy loading
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setIsInView(true);
+ observer.disconnect();
+ }
+ },
+ { rootMargin: "100px" }
+ );
+
+ if (ref.current) {
+ observer.observe(ref.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
+ return (
+
+
+ {/* Glow effect for top contributors */}
+ {tier.tier === "legendary" && (
+
+ )}
+ {tier.tier === "gold" && (
+
+ )}
+
+ {/* Avatar container */}
+
+ {isInView ? (
+
setIsLoaded(true)}
+ sizes="56px"
+ />
+ ) : null}
+
+ {/* Loading skeleton */}
+ {(!isInView || !isLoaded) && (
+
+ )}
+
+
+ {/* Crown for legendary contributors */}
+ {tier.emoji && (
+
+ {tier.emoji}
+
+ )}
+
+ {/* Contribution badge */}
+
+ {formatContributions(contributor.contributions)}
+
+
+ {/* Hover tooltip */}
+
+
+ {/* Username */}
+
+ @{contributor.login}
+
+ {/* Contribution count */}
+
+
+ {contributor.contributions} commits
+ {tier.emoji && {tier.emoji} }
+
+ {/* Tier badge */}
+
+ {tier.tier}
+
+ {/* Arrow */}
+
+
+
+
+
+ );
+}
+
+export function OpenSource() {
+ const [stats, setStats] = useState({ stars: 0, forks: 0, contributors: 1 });
+ const [contributors, setContributors] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ async function fetchGitHubData() {
+ try {
+ // Fetch repo data
+ const repoRes = await fetch("https://api.github.com/repos/soloshun/opendsa");
+ if (repoRes.ok) {
+ const repoData = await repoRes.json();
+ setStats(prev => ({
+ ...prev,
+ stars: repoData.stargazers_count || 0,
+ forks: repoData.forks_count || 0,
+ }));
+ }
+
+ // Fetch contributors
+ const contribRes = await fetch("https://api.github.com/repos/soloshun/opendsa/contributors?per_page=50");
+ if (contribRes.ok) {
+ const contribData: Contributor[] = await contribRes.json();
+ setContributors(contribData);
+ setStats(prev => ({ ...prev, contributors: contribData.length }));
+ }
+ } catch (error) {
+ console.error("Failed to fetch GitHub data:", error);
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ fetchGitHubData();
+ }, []);
+
+ return (
+
+ {/* Full-width gradient background */}
+
+
+
+ {/* Noise overlay */}
+
+
+ {/* Grid pattern */}
+
+
+ {/* Gradient orbs */}
+
+
+
+
+ {/* Heading */}
+
+
+ / Open Source
+
+
+
+ BUILT BY THE COMMUNITY
+
+ FOR THE COMMUNITY
+
+
+
+ OpenDSA is 100% open source and always will be. Join us in building
+ the best algorithm visualization platform.
+
+
+ {/* Contributors showcase */}
+
+ {/* Contributors header */}
+
+
+
+
+ Contributors
+ ({stats.contributors})
+
+
+
+
+ {/* Contributors grid */}
+
+ {/* Terminal-like header */}
+
+
+
+ git log --format="%an" | sort -u
+
+
+
+ {/* Contributors avatars */}
+
+ {loading ? (
+
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+ ) : contributors.length > 0 ? (
+
+ {contributors.map((contributor, index) => (
+
+ ))}
+
+ ) : (
+
+ Be the first contributor!
+
+ )}
+
+
+ {/* Legend */}
+
+
+
+ 👑 100+ commits
+
+
+
+ ⭐ 50+ commits
+
+
+
+ 20+ commits
+
+
+
+ Contributor
+
+
+
+
+
+ {/* Stats */}
+
+ {[
+ { icon:
, label: "Stars", value: loading ? "..." : stats.stars.toString() },
+ { icon:
, label: "Forks", value: loading ? "..." : stats.forks.toString() },
+ { icon:
, label: "Contributors", value: loading ? "..." : stats.contributors.toString() },
+ { icon:
, label: "MIT License", value: "Free" },
+ ].map((stat, index) => (
+
+
+
+
{stat.icon}
+
{stat.value}
+
{stat.label}
+
+
+ ))}
+
+
+ {/* CTAs */}
+
+
+
+ Star on GitHub
+
+
+
+ Become a Contributor
+
+
+
+ {/* Contribution types */}
+
+ {[
+ "New Algorithms",
+ "Bug Fixes",
+ "Documentation",
+ "UI/UX Design",
+ "Testing",
+ "Translations",
+ ].map((type) => (
+
+ {type}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/roadmap.tsx b/apps/web/src/components/sections/roadmap.tsx
new file mode 100644
index 0000000..e737651
--- /dev/null
+++ b/apps/web/src/components/sections/roadmap.tsx
@@ -0,0 +1,240 @@
+"use client";
+
+import { motion } from "framer-motion";
+import {
+ Code2,
+ Compass,
+ Rocket,
+ Users,
+ CheckCircle2,
+ Circle,
+} from "lucide-react";
+
+interface RoadmapItem {
+ phase: string;
+ title: string;
+ quarter: string;
+ status: "completed" | "current" | "upcoming";
+ items: string[];
+ icon: React.ReactNode;
+}
+
+const roadmapItems: RoadmapItem[] = [
+ {
+ phase: "01",
+ title: "Foundation",
+ quarter: "Q1 2026",
+ status: "current",
+ icon: ,
+ items: [
+ "Turborepo monorepo setup",
+ "5 sorting algorithms",
+ "2 searching algorithms",
+ "Animation engine",
+ ],
+ },
+ {
+ phase: "02",
+ title: "Core Features",
+ quarter: "Q2 2026",
+ status: "upcoming",
+ icon: ,
+ items: [
+ "Graph algorithms",
+ "Tree visualizations",
+ "Data structures",
+ "Code editor integration",
+ ],
+ },
+ {
+ phase: "03",
+ title: "Learning",
+ quarter: "Q3 2026",
+ status: "upcoming",
+ icon: ,
+ items: [
+ "Learning paths",
+ "Interactive tutorials",
+ "Challenge mode",
+ "Community features",
+ ],
+ },
+ {
+ phase: "04",
+ title: "Advanced",
+ quarter: "Q4 2026",
+ status: "upcoming",
+ icon: ,
+ items: [
+ "User accounts",
+ "Save visualizations",
+ "Embed widget",
+ "Public API",
+ ],
+ },
+];
+
+export function Roadmap() {
+ return (
+
+ {/* Background with subtle gradient */}
+
+
+
+ {/* Noise overlay */}
+
+
+
+ {/* Section header - right aligned */}
+
+
+
+ THE PATH TO{" "}
+ V1.0
+
+
+ Building in public. Ship fast, iterate faster.
+
+
+
+ {/* Zigzag Timeline */}
+
+ {/* Animated connecting line - hidden on mobile */}
+
+
+
+
+ {/* Timeline items */}
+
+ {roadmapItems.map((item, index) => {
+ const isEven = index % 2 === 0;
+
+ return (
+
+ {/* Connector dot */}
+
+
+ {item.status === "current" && (
+
+ )}
+
+
+ {/* Card */}
+
+ {/* Noise overlay */}
+
+
+ {/* Hover gradient */}
+
+
+
+ {/* Phase number and status */}
+
+
+ {item.phase}
+
+ {item.status === "current" ? (
+
+
+
+
+
+ In Progress
+
+ ) : item.status === "completed" ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Icon */}
+
+ {item.icon}
+
+
+ {/* Title and quarter */}
+
+ {item.title}
+
+
+ {item.quarter}
+
+
+ {/* Items list */}
+
+ {item.items.map((listItem, i) => (
+
+
+ {listItem}
+
+ ))}
+
+
+
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/tech-stack.tsx b/apps/web/src/components/sections/tech-stack.tsx
new file mode 100644
index 0000000..fa0b001
--- /dev/null
+++ b/apps/web/src/components/sections/tech-stack.tsx
@@ -0,0 +1,148 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Cpu, Zap, Box, Palette, Database, Layers } from "lucide-react";
+
+const technologies = [
+ {
+ category: "Framework",
+ name: "Next.js 14",
+ description: "App Router & Server Components",
+ icon: ,
+ highlight: true,
+ },
+ {
+ category: "Animation",
+ name: "Framer Motion",
+ description: "Smooth declarative animations",
+ icon: ,
+ highlight: true,
+ },
+ {
+ category: "Visualization",
+ name: "D3.js + Canvas",
+ description: "Powerful data visualization",
+ icon: ,
+ highlight: false,
+ },
+ {
+ category: "Styling",
+ name: "TailwindCSS",
+ description: "Utility-first CSS",
+ icon: ,
+ highlight: false,
+ },
+ {
+ category: "State",
+ name: "Zustand",
+ description: "Lightweight state",
+ icon: ,
+ highlight: false,
+ },
+ {
+ category: "Build",
+ name: "Turborepo",
+ description: "High-performance monorepo",
+ icon: ,
+ highlight: false,
+ },
+];
+
+export function TechStack() {
+ return (
+
+ {/* Background with accent gradient */}
+
+
+
+
+ {/* Noise overlay */}
+
+
+ {/* Decorative orb */}
+
+
+
+
+ {/* Left side - Header */}
+
+ {/* Label */}
+
+
+ / System Diagnostics
+
+
+ {/* Heading */}
+
+ UNDER THE
+
+ HOOD
+
+
+ {/* Description */}
+
+ Built on modern browser capabilities. No servers needed for visualizations.
+ Everything runs client-side for instant feedback.
+
+
+
+ {/* Right side - Tech grid */}
+
+
+ {technologies.map((tech, index) => (
+
+ {/* Noise overlay */}
+
+
+ {/* Hover effect */}
+
+
+
+ {/* Icon */}
+
+ {tech.icon}
+
+
+
+ {tech.category}
+
+
+ {tech.name}
+
+
+ {tech.description}
+
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/ui/bento-grid.tsx b/apps/web/src/components/ui/bento-grid.tsx
new file mode 100644
index 0000000..36f4c2b
--- /dev/null
+++ b/apps/web/src/components/ui/bento-grid.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import { cn } from "@/lib/utils";
+import { motion } from "framer-motion";
+import { ReactNode } from "react";
+
+interface BentoGridProps {
+ children: ReactNode;
+ className?: string;
+}
+
+export function BentoGrid({ children, className }: BentoGridProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+interface BentoCardProps {
+ title: string;
+ description: string;
+ icon?: ReactNode;
+ className?: string;
+ children?: ReactNode;
+ index?: number;
+}
+
+export function BentoCard({
+ title,
+ description,
+ icon,
+ className,
+ children,
+ index = 0,
+}: BentoCardProps) {
+ return (
+
+ {/* Gradient overlay on hover */}
+
+
+ {/* Content */}
+
+ {icon && (
+
+ {icon}
+
+ )}
+
+ {title}
+
+
+ {description}
+
+ {children &&
{children}
}
+
+
+ {/* Shimmer effect */}
+
+
+ );
+}
diff --git a/apps/web/src/components/ui/button.tsx b/apps/web/src/components/ui/button.tsx
new file mode 100644
index 0000000..ec0694f
--- /dev/null
+++ b/apps/web/src/components/ui/button.tsx
@@ -0,0 +1,97 @@
+"use client";
+
+import { cn } from "@/lib/utils";
+import { motion } from "framer-motion";
+import { forwardRef, ReactNode } from "react";
+import Link from "next/link";
+
+interface ButtonProps {
+ variant?: "primary" | "secondary" | "outline" | "ghost";
+ size?: "sm" | "md" | "lg";
+ className?: string;
+ children?: ReactNode;
+ asChild?: boolean;
+ href?: string;
+ target?: string;
+ rel?: string;
+ onClick?: () => void;
+ disabled?: boolean;
+ type?: "button" | "submit" | "reset";
+}
+
+export const Button = forwardRef(
+ (
+ {
+ className,
+ variant = "primary",
+ size = "md",
+ children,
+ asChild,
+ href,
+ target,
+ rel,
+ onClick,
+ disabled,
+ type = "button",
+ },
+ ref
+ ) => {
+ const variants = {
+ primary:
+ "bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] hover:opacity-90 shadow-lg shadow-[hsl(var(--primary))]/25",
+ secondary:
+ "bg-[hsl(var(--secondary))] text-[hsl(var(--secondary-foreground))] hover:bg-[hsl(var(--secondary))]/80",
+ outline:
+ "border border-[hsl(var(--border))] bg-transparent hover:bg-[hsl(var(--secondary))] hover:border-[hsl(var(--primary))]/50",
+ ghost: "bg-transparent hover:bg-[hsl(var(--secondary))]",
+ };
+
+ const sizes = {
+ sm: "h-9 px-4 text-sm",
+ md: "h-11 px-6 text-sm",
+ lg: "h-12 px-8 text-base",
+ };
+
+ const baseClassName = cn(
+ "inline-flex items-center justify-center gap-2 rounded-full font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))] disabled:pointer-events-none disabled:opacity-50",
+ variants[variant],
+ sizes[size],
+ className
+ );
+
+ if (asChild && href) {
+ return (
+
+
+ {children}
+
+
+ );
+ }
+
+ return (
+ }
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ className={baseClassName}
+ onClick={onClick}
+ disabled={disabled}
+ type={type}
+ >
+ {children}
+
+ );
+ }
+);
+
+Button.displayName = "Button";
diff --git a/apps/web/src/components/ui/particles-background.tsx b/apps/web/src/components/ui/particles-background.tsx
new file mode 100644
index 0000000..a78d770
--- /dev/null
+++ b/apps/web/src/components/ui/particles-background.tsx
@@ -0,0 +1,110 @@
+"use client";
+
+import { useCallback, useEffect, useMemo, useState } from "react";
+import Particles, { initParticlesEngine } from "@tsparticles/react";
+import { type Container, type ISourceOptions } from "@tsparticles/engine";
+import { loadSlim } from "@tsparticles/slim";
+
+export function ParticlesBackground() {
+ const [init, setInit] = useState(false);
+
+ useEffect(() => {
+ initParticlesEngine(async (engine) => {
+ await loadSlim(engine);
+ }).then(() => {
+ setInit(true);
+ });
+ }, []);
+
+ const particlesLoaded = useCallback(async () => { }, []);
+
+ const options: ISourceOptions = useMemo(
+ () => ({
+ fullScreen: {
+ enable: false,
+ },
+ background: {
+ color: {
+ value: "transparent",
+ },
+ },
+ fpsLimit: 60,
+ interactivity: {
+ events: {
+ onClick: {
+ enable: true,
+ mode: "push",
+ },
+ onHover: {
+ enable: true,
+ mode: "grab",
+ },
+ },
+ modes: {
+ grab: {
+ distance: 180,
+ links: {
+ opacity: 0.4,
+ color: "#22c55e",
+ },
+ },
+ push: {
+ quantity: 2,
+ },
+ },
+ },
+ particles: {
+ color: {
+ value: "#22c55e", // Green primary color
+ },
+ links: {
+ color: "#22c55e",
+ distance: 180,
+ enable: true,
+ opacity: 0.4, // Very subtle links
+ width: 1,
+ },
+ move: {
+ direction: "none",
+ enable: true,
+ outModes: {
+ default: "bounce",
+ },
+ random: false,
+ speed: 0.6,
+ straight: false,
+ },
+ number: {
+ density: {
+ enable: true,
+ width: 1400,
+ height: 900,
+ },
+ value: 60,
+ },
+ opacity: {
+ value: 0.4, // More visible dots
+ },
+ shape: {
+ type: "circle",
+ },
+ size: {
+ value: { min: 2, max: 4 }, // Visible dots
+ },
+ },
+ detectRetina: true,
+ }),
+ []
+ );
+
+ if (!init) return null;
+
+ return (
+
+ );
+}
diff --git a/apps/web/src/lib/algorithms-data.ts b/apps/web/src/lib/algorithms-data.ts
new file mode 100644
index 0000000..af0b8d8
--- /dev/null
+++ b/apps/web/src/lib/algorithms-data.ts
@@ -0,0 +1,205 @@
+// Comprehensive list of algorithms and data structures for OpenDSA
+// This is an ambitious roadmap - contributions welcome!
+
+export interface AlgorithmTopic {
+ name: string;
+ implemented: boolean;
+ description?: string;
+}
+
+export interface CategoryItem {
+ topics: AlgorithmTopic[];
+}
+
+export interface Category {
+ title: string;
+ items: Record;
+}
+
+export interface AlgorithmCategories {
+ dataStructures: Category;
+ algorithms: Category;
+}
+
+export const categories: AlgorithmCategories = {
+ dataStructures: {
+ title: "Data Structures",
+ items: {
+ Arrays: {
+ topics: [
+ { name: "Basic Array Operations", implemented: true },
+ { name: "Dynamic Arrays", implemented: false },
+ { name: "Multi-dimensional Arrays", implemented: false },
+ ],
+ },
+ "Linked Lists": {
+ topics: [
+ { name: "Singly Linked List", implemented: false },
+ { name: "Doubly Linked List", implemented: false },
+ { name: "Circular Linked List", implemented: false },
+ ],
+ },
+ Stacks: {
+ topics: [
+ { name: "Basic Stack Operations", implemented: false },
+ { name: "Applications (Balancing Parentheses)", implemented: false },
+ ],
+ },
+ Queues: {
+ topics: [
+ { name: "Basic Queue", implemented: false },
+ { name: "Circular Queue", implemented: false },
+ { name: "Priority Queue", implemented: false },
+ { name: "Deque (Double-Ended Queue)", implemented: false },
+ ],
+ },
+ Trees: {
+ topics: [
+ { name: "Binary Tree", implemented: false },
+ { name: "Binary Search Tree (BST)", implemented: false },
+ { name: "AVL Tree (Self-Balancing BST)", implemented: false },
+ { name: "Red-Black Tree", implemented: false },
+ { name: "Segment Tree", implemented: false },
+ { name: "Trie", implemented: false },
+ { name: "B-Tree and B+ Tree", implemented: false },
+ ],
+ },
+ Heaps: {
+ topics: [
+ { name: "Min Heap", implemented: false },
+ { name: "Max Heap", implemented: false },
+ { name: "Fibonacci Heap", implemented: false },
+ ],
+ },
+ Graphs: {
+ topics: [
+ { name: "Directed/Undirected Graphs", implemented: false },
+ { name: "Weighted/Unweighted Graphs", implemented: false },
+ { name: "Adjacency Matrix", implemented: false },
+ { name: "Adjacency List", implemented: false },
+ { name: "Edge List", implemented: false },
+ ],
+ },
+ Hashing: {
+ topics: [
+ { name: "Hash Tables", implemented: false },
+ { name: "Hash Maps", implemented: false },
+ { name: "Open Addressing", implemented: false },
+ { name: "Separate Chaining", implemented: false },
+ ],
+ },
+ },
+ },
+ algorithms: {
+ title: "Algorithms",
+ items: {
+ "Sorting (Easy)": {
+ topics: [
+ { name: "Bubble Sort", implemented: true },
+ { name: "Selection Sort", implemented: false },
+ { name: "Insertion Sort", implemented: false },
+ ],
+ },
+ "Sorting (Intermediate)": {
+ topics: [
+ { name: "Merge Sort", implemented: false },
+ { name: "Quick Sort", implemented: false },
+ ],
+ },
+ "Sorting (Advanced)": {
+ topics: [
+ { name: "Heap Sort", implemented: false },
+ { name: "Counting Sort", implemented: false },
+ { name: "Radix Sort", implemented: false },
+ { name: "Bucket Sort", implemented: false },
+ ],
+ },
+ Searching: {
+ topics: [
+ { name: "Linear Search", implemented: true },
+ { name: "Binary Search", implemented: false },
+ { name: "Jump Search", implemented: false },
+ { name: "Exponential Search", implemented: false },
+ ],
+ },
+ "Graph Algorithms": {
+ topics: [
+ { name: "Breadth-First Search (BFS)", implemented: false },
+ { name: "Depth-First Search (DFS)", implemented: false },
+ { name: "Dijkstra's Algorithm", implemented: false },
+ { name: "Floyd-Warshall", implemented: false },
+ { name: "Bellman-Ford", implemented: false },
+ { name: "Prim's MST", implemented: false },
+ { name: "Kruskal's MST", implemented: false },
+ { name: "A* Search", implemented: false },
+ ],
+ },
+ "Dynamic Programming": {
+ topics: [
+ { name: "Fibonacci", implemented: false },
+ { name: "Coin Change (Minimum Coins)", implemented: false },
+ { name: "Longest Common Subsequence (LCS)", implemented: false },
+ { name: "Knapsack Problem", implemented: false },
+ { name: "Matrix Chain Multiplication", implemented: false },
+ ],
+ },
+ Backtracking: {
+ topics: [
+ { name: "Rat in a Maze", implemented: false },
+ { name: "N-Queens Problem", implemented: false },
+ { name: "Knight's Tour", implemented: false },
+ { name: "Sudoku Solver", implemented: false },
+ ],
+ },
+ "Greedy Algorithms": {
+ topics: [
+ { name: "Activity Selection", implemented: false },
+ { name: "Fractional Knapsack", implemented: false },
+ { name: "Huffman Coding", implemented: false },
+ { name: "Job Sequencing", implemented: false },
+ ],
+ },
+ "Miscellaneous Algorithms": {
+ topics: [
+ { name: "Sieve of Eratosthenes (Prime Numbers)", implemented: false },
+ { name: "Euclidean Algorithm (GCD)", implemented: false },
+ { name: "KMP Pattern Matching", implemented: false },
+ { name: "Rabin-Karp Algorithm", implemented: false },
+ { name: "Bit Manipulation", implemented: false },
+ { name: "Randomized Algorithms (QuickSelect)", implemented: false },
+ ],
+ },
+ },
+ },
+};
+
+// Helper functions
+export function getTotalCount(): { total: number; implemented: number } {
+ let total = 0;
+ let implemented = 0;
+
+ (Object.values(categories) as Category[]).forEach((category) => {
+ Object.values(category.items).forEach((item: CategoryItem) => {
+ item.topics.forEach((topic) => {
+ total++;
+ if (topic.implemented) implemented++;
+ });
+ });
+ });
+
+ return { total, implemented };
+}
+
+export function getCategoryCount(category: Category): { total: number; implemented: number } {
+ let total = 0;
+ let implemented = 0;
+
+ Object.values(category.items).forEach((item) => {
+ item.topics.forEach((topic) => {
+ total++;
+ if (topic.implemented) implemented++;
+ });
+ });
+
+ return { total, implemented };
+}
diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts
new file mode 100644
index 0000000..365058c
--- /dev/null
+++ b/apps/web/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3f513d4..ace5cd6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -63,6 +63,12 @@ importers:
apps/docs:
dependencies:
+ '@theguild/remark-mermaid':
+ specifier: ^0.3.0
+ version: 0.3.0(react@19.2.3)
+ katex:
+ specifier: ^0.16.27
+ version: 0.16.27
next:
specifier: 16.1.4
version: 16.1.4(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -81,6 +87,24 @@ importers:
apps/web:
dependencies:
+ '@tsparticles/engine':
+ specifier: ^3.9.1
+ version: 3.9.1
+ '@tsparticles/react':
+ specifier: ^3.0.0
+ version: 3.0.0(@tsparticles/engine@3.9.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@tsparticles/slim':
+ specifier: ^3.9.1
+ version: 3.9.1
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
+ framer-motion:
+ specifier: ^12.29.0
+ version: 12.29.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ lucide-react:
+ specifier: ^0.563.0
+ version: 0.563.0(react@19.2.3)
next:
specifier: 16.1.4
version: 16.1.4(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -90,6 +114,9 @@ importers:
react-dom:
specifier: 19.2.3
version: 19.2.3(react@19.2.3)
+ tailwind-merge:
+ specifier: ^3.4.0
+ version: 3.4.0
devDependencies:
'@tailwindcss/postcss':
specifier: ^4
@@ -826,6 +853,121 @@ packages:
'@ts-morph/common@0.28.1':
resolution: {integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==}
+ '@tsparticles/basic@3.9.1':
+ resolution: {integrity: sha512-ijr2dHMx0IQHqhKW3qA8tfwrR2XYbbWYdaJMQuBo2CkwBVIhZ76U+H20Y492j/NXpd1FUnt2aC0l4CEVGVGdeQ==}
+
+ '@tsparticles/engine@3.9.1':
+ resolution: {integrity: sha512-DpdgAhWMZ3Eh2gyxik8FXS6BKZ8vyea+Eu5BC4epsahqTGY9V3JGGJcXC6lRJx6cPMAx1A0FaQAojPF3v6rkmQ==}
+
+ '@tsparticles/interaction-external-attract@3.9.1':
+ resolution: {integrity: sha512-5AJGmhzM9o4AVFV24WH5vSqMBzOXEOzIdGLIr+QJf4fRh9ZK62snsusv/ozKgs2KteRYQx+L7c5V3TqcDy2upg==}
+
+ '@tsparticles/interaction-external-bounce@3.9.1':
+ resolution: {integrity: sha512-bv05+h70UIHOTWeTsTI1AeAmX6R3s8nnY74Ea6p6AbQjERzPYIa0XY19nq/hA7+Nrg+EissP5zgoYYeSphr85A==}
+
+ '@tsparticles/interaction-external-bubble@3.9.1':
+ resolution: {integrity: sha512-tbd8ox/1GPl+zr+KyHQVV1bW88GE7OM6i4zql801YIlCDrl9wgTDdDFGIy9X7/cwTvTrCePhrfvdkUamXIribQ==}
+
+ '@tsparticles/interaction-external-connect@3.9.1':
+ resolution: {integrity: sha512-sq8YfUNsIORjXHzzW7/AJQtfi/qDqLnYG2qOSE1WOsog39MD30RzmiOloejOkfNeUdcGUcfsDgpUuL3UhzFUOA==}
+
+ '@tsparticles/interaction-external-grab@3.9.1':
+ resolution: {integrity: sha512-QwXza+sMMWDaMiFxd8y2tJwUK6c+nNw554+/9+tEZeTTk2fCbB0IJ7p/TH6ZGWDL0vo2muK54Njv2fEey191ow==}
+
+ '@tsparticles/interaction-external-pause@3.9.1':
+ resolution: {integrity: sha512-Gzv4/FeNir0U/tVM9zQCqV1k+IAgaFjDU3T30M1AeAsNGh/rCITV2wnT7TOGFkbcla27m4Yxa+Fuab8+8pzm+g==}
+
+ '@tsparticles/interaction-external-push@3.9.1':
+ resolution: {integrity: sha512-GvnWF9Qy4YkZdx+WJL2iy9IcgLvzOIu3K7aLYJFsQPaxT8d9TF8WlpoMlWKnJID6H5q4JqQuMRKRyWH8aAKyQw==}
+
+ '@tsparticles/interaction-external-remove@3.9.1':
+ resolution: {integrity: sha512-yPThm4UDWejDOWW5Qc8KnnS2EfSo5VFcJUQDWc1+Wcj17xe7vdSoiwwOORM0PmNBzdDpSKQrte/gUnoqaUMwOA==}
+
+ '@tsparticles/interaction-external-repulse@3.9.1':
+ resolution: {integrity: sha512-/LBppXkrMdvLHlEKWC7IykFhzrz+9nebT2fwSSFXK4plEBxDlIwnkDxd3FbVOAbnBvx4+L8+fbrEx+RvC8diAw==}
+
+ '@tsparticles/interaction-external-slow@3.9.1':
+ resolution: {integrity: sha512-1ZYIR/udBwA9MdSCfgADsbDXKSFS0FMWuPWz7bm79g3sUxcYkihn+/hDhc6GXvNNR46V1ocJjrj0u6pAynS1KQ==}
+
+ '@tsparticles/interaction-particles-attract@3.9.1':
+ resolution: {integrity: sha512-CYYYowJuGwRLUixQcSU/48PTKM8fCUYThe0hXwQ+yRMLAn053VHzL7NNZzKqEIeEyt5oJoy9KcvubjKWbzMBLQ==}
+
+ '@tsparticles/interaction-particles-collisions@3.9.1':
+ resolution: {integrity: sha512-ggGyjW/3v1yxvYW1IF1EMT15M6w31y5zfNNUPkqd/IXRNPYvm0Z0ayhp+FKmz70M5p0UxxPIQHTvAv9Jqnuj8w==}
+
+ '@tsparticles/interaction-particles-links@3.9.1':
+ resolution: {integrity: sha512-MsLbMjy1vY5M5/hu/oa5OSRZAUz49H3+9EBMTIOThiX+a+vpl3sxc9AqNd9gMsPbM4WJlub8T6VBZdyvzez1Vg==}
+
+ '@tsparticles/move-base@3.9.1':
+ resolution: {integrity: sha512-X4huBS27d8srpxwOxliWPUt+NtCwY+8q/cx1DvQxyqmTA8VFCGpcHNwtqiN+9JicgzOvSuaORVqUgwlsc7h4pQ==}
+
+ '@tsparticles/move-parallax@3.9.1':
+ resolution: {integrity: sha512-whlOR0bVeyh6J/hvxf/QM3DqvNnITMiAQ0kro6saqSDItAVqg4pYxBfEsSOKq7EhjxNvfhhqR+pFMhp06zoCVA==}
+
+ '@tsparticles/plugin-easing-quad@3.9.1':
+ resolution: {integrity: sha512-C2UJOca5MTDXKUTBXj30Kiqr5UyID+xrY/LxicVWWZPczQW2bBxbIbfq9ULvzGDwBTxE2rdvIB8YFKmDYO45qw==}
+
+ '@tsparticles/plugin-hex-color@3.9.1':
+ resolution: {integrity: sha512-vZgZ12AjUicJvk7AX4K2eAmKEQX/D1VEjEPFhyjbgI7A65eX72M465vVKIgNA6QArLZ1DLs7Z787LOE6GOBWsg==}
+
+ '@tsparticles/plugin-hsl-color@3.9.1':
+ resolution: {integrity: sha512-jJd1iGgRwX6eeNjc1zUXiJivaqC5UE+SC2A3/NtHwwoQrkfxGWmRHOsVyLnOBRcCPgBp/FpdDe6DIDjCMO715w==}
+
+ '@tsparticles/plugin-rgb-color@3.9.1':
+ resolution: {integrity: sha512-SBxk7f1KBfXeTnnklbE2Hx4jBgh6I6HOtxb+Os1gTp0oaghZOkWcCD2dP4QbUu7fVNCMOcApPoMNC8RTFcy9wQ==}
+
+ '@tsparticles/react@3.0.0':
+ resolution: {integrity: sha512-hjGEtTT1cwv6BcjL+GcVgH++KYs52bIuQGW3PWv7z3tMa8g0bd6RI/vWSLj7p//NZ3uTjEIeilYIUPBh7Jfq/Q==}
+ peerDependencies:
+ '@tsparticles/engine': ^3.0.2
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@tsparticles/shape-circle@3.9.1':
+ resolution: {integrity: sha512-DqZFLjbuhVn99WJ+A9ajz9YON72RtCcvubzq6qfjFmtwAK7frvQeb6iDTp6Ze9FUipluxVZWVRG4vWTxi2B+/g==}
+
+ '@tsparticles/shape-emoji@3.9.1':
+ resolution: {integrity: sha512-ifvY63usuT+hipgVHb8gelBHSeF6ryPnMxAAEC1RGHhhXfpSRWMtE6ybr+pSsYU52M3G9+TF84v91pSwNrb9ZQ==}
+
+ '@tsparticles/shape-image@3.9.1':
+ resolution: {integrity: sha512-fCA5eme8VF3oX8yNVUA0l2SLDKuiZObkijb0z3Ky0qj1HUEVlAuEMhhNDNB9E2iELTrWEix9z7BFMePp2CC7AA==}
+
+ '@tsparticles/shape-line@3.9.1':
+ resolution: {integrity: sha512-wT8NSp0N9HURyV05f371cHKcNTNqr0/cwUu6WhBzbshkYGy1KZUP9CpRIh5FCrBpTev34mEQfOXDycgfG0KiLQ==}
+
+ '@tsparticles/shape-polygon@3.9.1':
+ resolution: {integrity: sha512-dA77PgZdoLwxnliH6XQM/zF0r4jhT01pw5y7XTeTqws++hg4rTLV9255k6R6eUqKq0FPSW1/WBsBIl7q/MmrqQ==}
+
+ '@tsparticles/shape-square@3.9.1':
+ resolution: {integrity: sha512-DKGkDnRyZrAm7T2ipqNezJahSWs6xd9O5LQLe5vjrYm1qGwrFxJiQaAdlb00UNrexz1/SA7bEoIg4XKaFa7qhQ==}
+
+ '@tsparticles/shape-star@3.9.1':
+ resolution: {integrity: sha512-kdMJpi8cdeb6vGrZVSxTG0JIjCwIenggqk0EYeKAwtOGZFBgL7eHhF2F6uu1oq8cJAbXPujEoabnLsz6mW8XaA==}
+
+ '@tsparticles/slim@3.9.1':
+ resolution: {integrity: sha512-CL5cDmADU7sDjRli0So+hY61VMbdroqbArmR9Av+c1Fisa5ytr6QD7Jv62iwU2S6rvgicEe9OyRmSy5GIefwZw==}
+
+ '@tsparticles/updater-color@3.9.1':
+ resolution: {integrity: sha512-XGWdscrgEMA8L5E7exsE0f8/2zHKIqnTrZymcyuFBw2DCB6BIV+5z6qaNStpxrhq3DbIxxhqqcybqeOo7+Alpg==}
+
+ '@tsparticles/updater-life@3.9.1':
+ resolution: {integrity: sha512-Oi8aF2RIwMMsjssUkCB6t3PRpENHjdZf6cX92WNfAuqXtQphr3OMAkYFJFWkvyPFK22AVy3p/cFt6KE5zXxwAA==}
+
+ '@tsparticles/updater-opacity@3.9.1':
+ resolution: {integrity: sha512-w778LQuRZJ+IoWzeRdrGykPYSSaTeWfBvLZ2XwYEkh/Ss961InOxZKIpcS6i5Kp/Zfw0fS1ZAuqeHwuj///Osw==}
+
+ '@tsparticles/updater-out-modes@3.9.1':
+ resolution: {integrity: sha512-cKQEkAwbru+hhKF+GTsfbOvuBbx2DSB25CxOdhtW2wRvDBoCnngNdLw91rs+0Cex4tgEeibkebrIKFDDE6kELg==}
+
+ '@tsparticles/updater-rotate@3.9.1':
+ resolution: {integrity: sha512-9BfKaGfp28JN82MF2qs6Ae/lJr9EColMfMTHqSKljblwbpVDHte4umuwKl3VjbRt87WD9MGtla66NTUYl+WxuQ==}
+
+ '@tsparticles/updater-size@3.9.1':
+ resolution: {integrity: sha512-3NSVs0O2ApNKZXfd+y/zNhTXSFeG1Pw4peI8e6z/q5+XLbmue9oiEwoPy/tQLaark3oNj3JU7Q903ZijPyXSzw==}
+
+ '@tsparticles/updater-stroke-color@3.9.1':
+ resolution: {integrity: sha512-3x14+C2is9pZYTg9T2TiA/aM1YMq4wLdYaZDcHm3qO30DZu5oeQq0rm/6w+QOGKYY1Z3Htg9rlSUZkhTHn7eDA==}
+
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
@@ -1917,6 +2059,20 @@ packages:
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
engines: {node: '>=0.4.x'}
+ framer-motion@12.29.0:
+ resolution: {integrity: sha512-1gEFGXHYV2BD42ZPTFmSU9buehppU+bCuOnHU0AD18DKh9j4DuTx47MvqY5ax+NNWRtK32qIcJf1UxKo1WwjWg==}
+ peerDependencies:
+ '@emotion/is-prop-valid': '*'
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/is-prop-valid':
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -2445,6 +2601,11 @@ packages:
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lucide-react@0.563.0:
+ resolution: {integrity: sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -2678,6 +2839,12 @@ packages:
mlly@1.8.0:
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
+ motion-dom@12.29.0:
+ resolution: {integrity: sha512-3eiz9bb32yvY8Q6XNM4AwkSOBPgU//EIKTZwsSWgA9uzbPBhZJeScCVcBuwwYVqhfamewpv7ZNmVKTGp5qnzkA==}
+
+ motion-utils@12.27.2:
+ resolution: {integrity: sha512-B55gcoL85Mcdt2IEStY5EEAsrMSVE2sI14xQ/uAdPL+mfQxhKKFaEag9JmfxedJOR4vZpBGoPeC/Gm13I/4g5Q==}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -3278,6 +3445,9 @@ packages:
tabbable@6.4.0:
resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==}
+ tailwind-merge@3.4.0:
+ resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
+
tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
@@ -4295,6 +4465,188 @@ snapshots:
path-browserify: 1.0.1
tinyglobby: 0.2.15
+ '@tsparticles/basic@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+ '@tsparticles/move-base': 3.9.1
+ '@tsparticles/plugin-hex-color': 3.9.1
+ '@tsparticles/plugin-hsl-color': 3.9.1
+ '@tsparticles/plugin-rgb-color': 3.9.1
+ '@tsparticles/shape-circle': 3.9.1
+ '@tsparticles/updater-color': 3.9.1
+ '@tsparticles/updater-opacity': 3.9.1
+ '@tsparticles/updater-out-modes': 3.9.1
+ '@tsparticles/updater-size': 3.9.1
+
+ '@tsparticles/engine@3.9.1': {}
+
+ '@tsparticles/interaction-external-attract@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-bounce@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-bubble@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-connect@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-grab@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-pause@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-push@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-remove@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-repulse@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-external-slow@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-particles-attract@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-particles-collisions@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/interaction-particles-links@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/move-base@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/move-parallax@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/plugin-easing-quad@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/plugin-hex-color@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/plugin-hsl-color@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/plugin-rgb-color@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/react@3.0.0(@tsparticles/engine@3.9.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+
+ '@tsparticles/shape-circle@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/shape-emoji@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/shape-image@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/shape-line@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/shape-polygon@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/shape-square@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/shape-star@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/slim@3.9.1':
+ dependencies:
+ '@tsparticles/basic': 3.9.1
+ '@tsparticles/engine': 3.9.1
+ '@tsparticles/interaction-external-attract': 3.9.1
+ '@tsparticles/interaction-external-bounce': 3.9.1
+ '@tsparticles/interaction-external-bubble': 3.9.1
+ '@tsparticles/interaction-external-connect': 3.9.1
+ '@tsparticles/interaction-external-grab': 3.9.1
+ '@tsparticles/interaction-external-pause': 3.9.1
+ '@tsparticles/interaction-external-push': 3.9.1
+ '@tsparticles/interaction-external-remove': 3.9.1
+ '@tsparticles/interaction-external-repulse': 3.9.1
+ '@tsparticles/interaction-external-slow': 3.9.1
+ '@tsparticles/interaction-particles-attract': 3.9.1
+ '@tsparticles/interaction-particles-collisions': 3.9.1
+ '@tsparticles/interaction-particles-links': 3.9.1
+ '@tsparticles/move-parallax': 3.9.1
+ '@tsparticles/plugin-easing-quad': 3.9.1
+ '@tsparticles/shape-emoji': 3.9.1
+ '@tsparticles/shape-image': 3.9.1
+ '@tsparticles/shape-line': 3.9.1
+ '@tsparticles/shape-polygon': 3.9.1
+ '@tsparticles/shape-square': 3.9.1
+ '@tsparticles/shape-star': 3.9.1
+ '@tsparticles/updater-life': 3.9.1
+ '@tsparticles/updater-rotate': 3.9.1
+ '@tsparticles/updater-stroke-color': 3.9.1
+
+ '@tsparticles/updater-color@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/updater-life@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/updater-opacity@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/updater-out-modes@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/updater-rotate@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/updater-size@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
+ '@tsparticles/updater-stroke-color@3.9.1':
+ dependencies:
+ '@tsparticles/engine': 3.9.1
+
'@tybys/wasm-util@0.10.1':
dependencies:
tslib: 2.8.1
@@ -5655,6 +6007,15 @@ snapshots:
format@0.2.2: {}
+ framer-motion@12.29.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
+ dependencies:
+ motion-dom: 12.29.0
+ motion-utils: 12.27.2
+ tslib: 2.8.1
+ optionalDependencies:
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+
function-bind@1.1.2: {}
function.prototype.name@1.1.8:
@@ -6251,6 +6612,10 @@ snapshots:
dependencies:
yallist: 3.1.1
+ lucide-react@0.563.0(react@19.2.3):
+ dependencies:
+ react: 19.2.3
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -6798,6 +7163,12 @@ snapshots:
pkg-types: 1.3.1
ufo: 1.6.3
+ motion-dom@12.29.0:
+ dependencies:
+ motion-utils: 12.27.2
+
+ motion-utils@12.27.2: {}
+
ms@2.1.3: {}
nano-spawn@2.0.0: {}
@@ -7616,6 +7987,8 @@ snapshots:
tabbable@6.4.0: {}
+ tailwind-merge@3.4.0: {}
+
tailwindcss@4.1.18: {}
tapable@2.3.0: {}