chore: initial project setup (README, index.html, package.json, vite.config, .gitignore, .oxlintrc.json, public, src, .hermes)
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
# Product Requirements Document (PRD)
|
||||||
|
## Scientific Calculator with Conversion & History
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Date:** 2026-07-26
|
||||||
|
**Prepared by:** Turing (Documentation Specialist, Hermes Agent)
|
||||||
|
**Based on:** Ideation output from Steve (Feasibility/Viability Research)
|
||||||
|
**Stakeholder:** Shreyas Kamat (SRMIST CSE Student, Hybrutos Racing & vACC Leadership)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Executive Summary
|
||||||
|
This document outlines the requirements for a standalone scientific calculator application built to evaluate the Hermes Agent multi-agent framework. The calculator will provide advanced mathematical operations, unit conversions, currency conversions, and calculation history tracking with a modern, animated dark-theme UI. It is intended as a local testing utility only, with no planned integration into existing projects (Hybrutos Battery Cart, vACC event management, or homelab systems).
|
||||||
|
|
||||||
|
**Primary Goal:** Validate the Hermes Agent multi-agent architecture by delivering a feature-rich, polished ReactJS application through the prescribed phased development process (Ideation → Planning → Orchestration → Development → Independent Test & Review → Deployment).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Functional Requirements
|
||||||
|
|
||||||
|
### 2.1 Core Calculation Engine
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| F1.1 | Support basic arithmetic: addition, subtraction, multiplication, division | Must | Standard infix notation |
|
||||||
|
| F1.2 | Support scientific functions: sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, exp, log (base 10), ln (natural), sqrt, cbrt, abs, ceil, floor, round, random | Must | Standard mathematical implementations |
|
||||||
|
| F1.3 | Support combinatorial functions: factorial (n!), nCr (combinations), nPr (permutations) | Must | Factorial limited to n ≤ 170 to prevent overflow |
|
||||||
|
| F1.4 | Support parentheses for order of operations | Must | Standard precedence rules |
|
||||||
|
| F1.5 | Support decimal point input and floating-point arithmetic | Must | Standard calculator behavior |
|
||||||
|
| F1.6 | Handle division by zero gracefully (display "Error") | Must | Prevent application crash |
|
||||||
|
| F1.7 | Support persistent calculation history (store last 50 operations) | Should | Saved to localStorage, retrievable across sessions |
|
||||||
|
| F1.8 | Allow reuse of history items in new calculations | Should | Click-to-insert functionality |
|
||||||
|
| F1.9 | Provide clear (AC) and backspace (CE) functionality | Must | Standard calculator controls |
|
||||||
|
|
||||||
|
### 2.2 Conversion Systems
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| F2.1 | Support unit conversions for: length (mm, cm, m, km, in, ft, yd, mi), mass (mg, g, kg, oz, lb), temperature (°C, °F, K), volume (ml, l, tsp, tbsp, fl oz, cup, pt, qt, gal) | Should | Bidirectional conversion between all units in category |
|
||||||
|
| F2.2 | Support currency conversions for: INR, USD, GBP, EUR, JPY, CAD, AUD | Should | Manual exchange rate input (no live API calls for framework testing) |
|
||||||
|
| F2.3 | Allow chaining of conversions (e.g., convert 5 ft to inches, then to cm) | Could | Optional enhancement |
|
||||||
|
| F2.4 | Display conversion results with appropriate precision (typically 4 decimal places) | Should | Consistent formatting |
|
||||||
|
|
||||||
|
### 2.3 User Interface & Experience
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| F3.1 | Implement dark theme as default (with optional light theme toggle) | Must | Dark background (#121212), light text (#E0E0E0), accent color (#FF9800) |
|
||||||
|
| F3.2 | Provide fluid, animated UI transitions (button presses, screen changes) | Must | Using Framer Motion or CSS animations (200-300ms duration) |
|
||||||
|
| F3.3 | Support full keyboard input: numbers (0-9), operators (+,-,*,/,=,.), Enter (=), Escape (AC), Backspace (CE) | Must | Standard calculator keyboard mapping |
|
||||||
|
| F3.4 | Implement responsive layout: functional on mobile (≥320px width), tablet, and desktop | Should | Single-column keypad on narrow screens, grid on wider |
|
||||||
|
| F3.5 | Display current expression/formula in a secondary line above main result (optional) | Could | For complex multi-step calculations |
|
||||||
|
| F3.6 | Provide visual feedback for invalid operations (e.g., shaking display, error color) | Should | Enhances usability |
|
||||||
|
|
||||||
|
### 2.4 Application Behavior
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| F4.1 | Launch directly to calculator interface (no splash screen or onboarding) | Must | Immediate usability for testing |
|
||||||
|
| F4.2 | Preserve state (display, history, theme) on page refresh/revisit | Should | Via localStorage |
|
||||||
|
| F4.3 | Provide reset function to clear all state (history, display, theme to default) | Could | Advanced user option |
|
||||||
|
| F4.4 | Ensure no external network calls during operation (fully offline capable) | Must | Critical for security and framework isolation testing |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Non-Functional Requirements
|
||||||
|
|
||||||
|
### 3.1 Performance
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| NF1.1 | Maintain 60 FPS during animations and interactions | Must | Smooth user experience |
|
||||||
|
| NF1.2 | Calculation result latency < 100ms for standard operations | Must | Imperceptible delay |
|
||||||
|
| NF1.3 | Initial load time < 3s on mid-tier device (simulated via throttling) | Should | Acceptable for testing utility |
|
||||||
|
|
||||||
|
### 3.2 Security & Reliability
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| NF2.1 | Sanitize all user input to prevent XSS/injection attacks | Must | Critical for Gilfoyle's security review (expression parser) |
|
||||||
|
| NF2.2 | Validate all numerical inputs for finiteness (no NaN/Infinity propagation unless intentional) | Must | Prevent calculation errors |
|
||||||
|
| NF2.3 | LocalStorage usage limited to history and theme preferences (<50KB) | Should | Minimal storage footprint |
|
||||||
|
| NF2.4 | Application state recoverable from localStorage corruption (fallback to defaults) | Should | Graceful degradation |
|
||||||
|
|
||||||
|
### 3.3 Maintainability & Extensibility
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| NF3.1 | Modular code structure: separate modules for math, conversion, history, UI, theme | Must | Enables parallel development by specialists |
|
||||||
|
| NF3.2 | Clear separation of concerns: calculation logic independent of UI | Must | Facilitates testing and replacement |
|
||||||
|
| NF3.3 | Consistent code style (ESLint + Prettier configuration) | Should | Team collaboration readiness |
|
||||||
|
| NF3.4 | Comprehensive JSDoc comments for all public functions and components | Should | Onboarding and maintenance aid |
|
||||||
|
|
||||||
|
### 3.4 Compatibility
|
||||||
|
| ID | Requirement | Priority | Notes |
|
||||||
|
|----|-------------|----------|-------|
|
||||||
|
| NF4.1 | Support latest stable versions of Chrome, Firefox, Safari, Edge | Must | Broad accessibility for testing |
|
||||||
|
| NF4.2 | Require JavaScript ES2020+ support | Should | Modern language features |
|
||||||
|
| NF4.3 | No dependencies on native mobile features (pure web app) | Must | Framework isolation guarantee |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Assumptions & Dependencies
|
||||||
|
|
||||||
|
### 4.1 Assumptions
|
||||||
|
- User is familiar with basic calculator operations and scientific notation
|
||||||
|
- Manual currency exchange rate input is acceptable for framework testing purpose
|
||||||
|
- LocalStorage availability is guaranteed in target testing environments
|
||||||
|
- No accessibility compliance (WCAG) required beyond basic keyboard support (per scope)
|
||||||
|
- Theme toggle (dark/light) is optional; dark theme is mandatory default
|
||||||
|
|
||||||
|
### 4.2 Dependencies
|
||||||
|
| Dependency | Version | Purpose | License |
|
||||||
|
|------------|---------|---------|---------|
|
||||||
|
| React | 18.2.0 | UI library | MIT |
|
||||||
|
| Vite | 4.3.0 | Build tool & dev server | MIT |
|
||||||
|
| Framer Motion | 10.12.0 | Animations | MIT |
|
||||||
|
| CSS Modules | Built-in (via Vite) | Scoped styling | MIT |
|
||||||
|
| (Optional) date-fns | 2.29.3 | Date formatting for history timestamps | MIT |
|
||||||
|
|
||||||
|
*Note: Exact versions to be finalized during planning phase; all dependencies must be free/OSS compliant.*
|
||||||
|
|
||||||
|
### 4.3 Excluded Features (Out of Scope)
|
||||||
|
- Live currency exchange rate API calls (to avoid network dependencies and API key management)
|
||||||
|
- Graphing capabilities
|
||||||
|
- Base conversion (binary, octal, hexadecimal)
|
||||||
|
- Statistical functions (mean, median, standard deviation)
|
||||||
|
- Programmable macros or user-defined functions
|
||||||
|
- Cloud synchronization or account-based features
|
||||||
|
- Voice input/output
|
||||||
|
- Printing or export functionality
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Acceptance Criteria
|
||||||
|
|
||||||
|
The implementation will be considered complete and ready for independent review when:
|
||||||
|
|
||||||
|
### 5.1 Functional Verification
|
||||||
|
- [ ] All core calculation operations (F1.1-F1.5) produce correct results for test suite
|
||||||
|
- [ ] Scientific functions (F1.2) match JavaScript Math object precision within 1e-10
|
||||||
|
- [ ] Factorial/nCr/nPr (F1.3) handle edge cases (0, 1, large numbers) correctly
|
||||||
|
- [ ] History system (F1.7-F1.8) stores, retrieves, and re-uses entries accurately
|
||||||
|
- [ ] Unit conversions (F2.1) are accurate to 4 decimal places for standard conversions
|
||||||
|
- [ ] Currency conversions (F2.2) use manual rates correctly
|
||||||
|
- [ ] Keyboard support (F3.3) maps all required keys to appropriate functions
|
||||||
|
- [ ] Dark theme (F3.1) is default with correct color palette
|
||||||
|
- [ ] Animations (F3.2) are present and smooth (no jank)
|
||||||
|
- [ ] Responsiveness (F3.4) maintains usability at 320px width
|
||||||
|
- [ ] No external network requests occur during operation (verified via DevTools)
|
||||||
|
|
||||||
|
### 5.2 Security Verification (Gilfoyle's Mandatory Review)
|
||||||
|
- [ ] Expression parser sanitizes all non-numeric/non-operator input
|
||||||
|
- [ ] No use of `eval()` or equivalent unsafe evaluation methods
|
||||||
|
- [ ] All user-inputted strings are properly escaped before DOM insertion
|
||||||
|
- [ ] LocalStorage keys are namespaced to prevent collisions
|
||||||
|
- [ ] Error messages do not leak stack traces or system information
|
||||||
|
|
||||||
|
### 5.3 Performance Verification
|
||||||
|
- [ ] Animation frame rate ≥ 55 FPS during continuous FPS (measured via Chrome DevTools)
|
||||||
|
- [ ] 95th percentile calculation latency < 50ms for operations ≤ 20 characters
|
||||||
|
- [ ] Initial load time < 2.5s on Moto G4 (Simulated 3G) throttling profile
|
||||||
|
|
||||||
|
### 5.4 Usability Verification
|
||||||
|
- [ ] All core functions accessible via keyboard alone
|
||||||
|
- [ ] Touch targets ≥ 48x48px on mobile layouts
|
||||||
|
- [ ] Clear visual distinction between operator and operand buttons
|
||||||
|
- [ ] History panel accessible via intuitive gesture/click
|
||||||
|
- [ ] Error states provide clear recovery path (e.g., "Press AC to reset")
|
||||||
|
|
||||||
|
### 5.5 Code Quality Verification (Satya/Sundar's Independent Review)
|
||||||
|
- [ ] No ESLint errors (configured for React best practices)
|
||||||
|
- [ ] Test coverage ≥ 80% for utility functions (math, conversion, history)
|
||||||
|
- [ ] All components have corresponding unit tests
|
||||||
|
- [ ] Code follows consistent formatting (Prettier)
|
||||||
|
- [ ] No console warnings/errors in development mode
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Open Questions & Risks
|
||||||
|
|
||||||
|
| ID | Question/Risk | Impact | Mitigation Strategy |
|
||||||
|
|----|---------------|--------|---------------------|
|
||||||
|
| OQ1 | Should currency conversion support automatic rate fetching via API? | Low (explicitly out of scope per user) | Document as future enhancement; current design uses manual input |
|
||||||
|
| OQ2 | Is animation library (Framer Motion) acceptable, or should we use CSS-only for minimal dependencies? | Medium | Evaluate during planning; CSS-only fallback available |
|
||||||
|
| OQ3 | What precision should be displayed for irrational results (e.g., pi, sqrt(2))? | Low | Display 10 significant figures; full precision available in history |
|
||||||
|
| OQ4 | Should history support search/filter functionality? | Low | Document as potential Phase 2 enhancement |
|
||||||
|
| Risk1 | Expression parser complexity introducing bugs | High | Implement comprehensive unit tests; use Shunting Yard algorithm for robustness |
|
||||||
|
| Risk2 | Animation performance on low-end devices | Medium | Provide reduced-motion preference; test on throttled profiles |
|
||||||
|
| Risk3 | LocalStorage quota exceeded with heavy history use | Low | Implement history limit (50 entries) with FIFO eviction |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. References & Related Documents
|
||||||
|
- [Ideation Notes] Steve's feasibility assessment (Telegram log: 2026-07-26_202906_deleg_380b1ff7)
|
||||||
|
- [Framework Constraints] Hermes Agent Multi-Agent Architecture Specification
|
||||||
|
- [Technical Spike] Initial React/Vite setup validation (calculator prototype in /root/calculator/)
|
||||||
|
- [Security Guidelines] OWASP JavaScript Security Cheat Sheet (input sanitization focus)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Approval Status:**
|
||||||
|
✅ **PRD Complete** - Awaiting review transition to Ada (Design & Planning Specialist) for iterative back-and-forth until plan is fully detailed, followed by formal stakeholder approval before proceeding to Woz (Orchestrator) for specialist task distribution.
|
||||||
|
|
||||||
|
*This document satisfies Turing's documentation responsibility per the Hermes Agent multi-agent architecture. Subsequent phases will follow the prescribed gated process with explicit user approvals at each transition.*
|
||||||
|
|
||||||
|
---
|
||||||
|
*End of PRD*
|
||||||
@@ -0,0 +1,997 @@
|
|||||||
|
# Solution Architecture Document (SAD)
|
||||||
|
## Scientific Calculator with Conversion & History
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Date:** 2026-07-27
|
||||||
|
**Prepared by:** Turing (Documentation Specialist, Hermes Agent)
|
||||||
|
**Based on:** Approved Technical Implementation Plan by Ada (Design & Planning Specialist)
|
||||||
|
**Stakeholder:** Shreyas Kamat (SRMIST CSE Student, Hybrutos Racing & vACC Leadership)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Introduction
|
||||||
|
This document describes the solution architecture for a standalone scientific calculator application designed to evaluate the Hermes Agent multi-agent framework. The calculator provides advanced mathematical operations (including numerical methods), unit conversions, currency conversions, and calculation history tracking with a modern, animated dark-theme UI.
|
||||||
|
|
||||||
|
**Primary Purpose**: Validate the Hermes Agent multi-agent architecture by delivering a feature-rich, polished ReactJS application through the prescribed phased development process (Ideation → Planning → Orchestration → Development → Independent Test & Review → Deployment).
|
||||||
|
|
||||||
|
**Scope**: Local testing utility only—no planned integration into existing projects (Hybrutos Battery Cart, vACC event management, or homelab systems).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. System Architecture Overview
|
||||||
|
|
||||||
|
### 2.1 Architectural Style
|
||||||
|
- **Single-Page Application (SPA)** built with React 18
|
||||||
|
- **Client-side only** application with zero server dependencies
|
||||||
|
- **Modular, component-based architecture** with clear separation of concerns
|
||||||
|
- **Unidirectional data flow** principles applied where beneficial (state updates via Context API)
|
||||||
|
|
||||||
|
### 2.2 Key Architectural Decisions
|
||||||
|
| Decision | Rationale |
|
||||||
|
|----------|-----------|
|
||||||
|
| **React 18 + Vite** | Modern, performant stack with fast refresh; ideal for framework evaluation |
|
||||||
|
| **Context API for State Management** | Stakeholder preference; avoids external libraries (Redux/Zustand) for appropriate scope |
|
||||||
|
| **CSS Modules for Styling** | Scoped styling eliminates class collisions; no runtime overhead |
|
||||||
|
| **Framer Motion for Animations** | Best balance of features, bundle size, and ease of use for complex UI motions |
|
||||||
|
| **localStorage Persistence** | Simple, reliable persistence for history/theme; matches stakeholder requirements |
|
||||||
|
| **Expression Parser First** | Security-critical component developed with Gilfoyle's review embedded from start |
|
||||||
|
| **Unified `convert()` Syntax** | Reduces cognitive overload; single function for unit/currency conversions |
|
||||||
|
| **Keyboard-First UI/UX** | Matches stakeholder's workflow preferences for efficiency |
|
||||||
|
| **Pure JS Core Modules** | Math engine, conversion systems, history manager are testable in isolation |
|
||||||
|
|
||||||
|
### 2.3 System Boundaries
|
||||||
|
- **In Scope**:
|
||||||
|
- Mathematical expression evaluation (scientific functions + numerical methods)
|
||||||
|
- Unit conversion (8 predefined categories)
|
||||||
|
- Currency conversion (manual-rate based)
|
||||||
|
- Calculation history (persistent, click-to-reuse)
|
||||||
|
- Dark/light theme system with animations
|
||||||
|
- Full keyboard support
|
||||||
|
- Responsive layout (mobile/tablet/desktop)
|
||||||
|
- **Out of Scope**:
|
||||||
|
- Live API calls (currency rates, unit databases)
|
||||||
|
- User accounts or cloud synchronization
|
||||||
|
- Graphing capabilities
|
||||||
|
- Programmable macros or user-defined functions
|
||||||
|
- Printing or export functionality
|
||||||
|
- Base conversion (binary/octal/hex)
|
||||||
|
- Voice input/output
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Component Architecture
|
||||||
|
|
||||||
|
### 3.1 High-Level Component Diagram
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ Calculator App │
|
||||||
|
├───────────────┬─────────────────────────────────────┤
|
||||||
|
│ Contexts │ UI │
|
||||||
|
│ ┌─────────┐ │ ┌─────────────────────────────┐ │
|
||||||
|
│ │ThemeCtx │ │ │ Display Bar │ │
|
||||||
|
│ │ModeCtx │ │ │ (expression + result) │ │
|
||||||
|
│ │CalcCtx │ │ │ Keypad Grid │ │
|
||||||
|
│ └─────────┘ │ │ ┌───────────────────────┐ │ │
|
||||||
|
│ │ │ │ Standard Mode │ │ │
|
||||||
|
│ ┌─────────┐ │ │ │ Scientific Mode │ │ │
|
||||||
|
│ │ Core │ │ │ │ Unit Conv. Mode │ │ │
|
||||||
|
│ │ Math Eng│ │ │ │ Currency Conv. Mode │ │ │
|
||||||
|
│ │Conver. │ │ │ └───────────────────────┘ │ │
|
||||||
|
│ │History │ │ │ History Panel │ │
|
||||||
|
│ └─────────┘ │ │ (slide-in / modal) │ │
|
||||||
|
│ └─────────┘ └─────────────────────────────┬─┴─────────────────────────────┬─┘
|
||||||
|
│ │ │ │
|
||||||
|
└─────────────────┴─────────────┴─────────────────┘
|
||||||
|
│ │ │
|
||||||
|
┌─────┴─────┐ ┌───────┴───────┐ ┌─────┴─────┐
|
||||||
|
│ Utils │ │ Animations │ │ Styles │
|
||||||
|
│ Keyboard │ │ Button Press │ │ CSS Mods │
|
||||||
|
│ Validator │ │ Screen Trans. │ │ Theme Vars│
|
||||||
|
│ Formatter │ │ Toast │ │ Resp. Breakpts│
|
||||||
|
└───────────┘ └───────────────┘ └───────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Core Module Specifications
|
||||||
|
|
||||||
|
#### 3.2.1 Math Engine (`src/core/math/`)
|
||||||
|
- **ExpressionParser.js**:
|
||||||
|
- Input: Raw user expression string
|
||||||
|
- Process:
|
||||||
|
1. Allowlist validation (digits, `.`, `+-*/()`, whitespace, `e`, `pi`, whitelisted func names)
|
||||||
|
2. Constant substitution (`pi`→`Math.PI`, `e`→`Math.E`, `ans`→history value)
|
||||||
|
3. Function whitelisting + replacement (`sin(`→`Math.sin(`)
|
||||||
|
4. Safe evaluation via `Function` constructor on sanitized string
|
||||||
|
- Output: `{value: number, error: string}` or `{value: null, error: string}`
|
||||||
|
- Security: Single validation/sanitization point; no `eval`; Gilfoyle-reviewable
|
||||||
|
- **ScientificFunctions.js**:
|
||||||
|
- Export: Object mapping function names to implementations
|
||||||
|
- Includes: Trig, hyperbolic, exp/log, sqrt/cbrt, abs/ceil/floor/round, factorial/nCr/nPr, random
|
||||||
|
- **NumericalMethods.js** (extends core):
|
||||||
|
- `derivative(expr, var, [h])`: Central difference with `h=1e-5` default
|
||||||
|
- `integral(expr, var, a, b, [n])`: Adaptive Simpson's Rule, `tol=1e-6`, `maxSubdiv=2^10`
|
||||||
|
- `solve(expr, var, [guess])`: Newton-Raphson with secant fallback, `maxIter=100`, `tol=1e-10`
|
||||||
|
|
||||||
|
#### 3.2.2 Conversion Systems (`src/core/conversion/`)
|
||||||
|
- **UnitConverter.js**:
|
||||||
|
- Input: `value`, `fromUnit`, `toUnit`
|
||||||
|
- Process:
|
||||||
|
1. Validate units against category-specific whitelist
|
||||||
|
2. Lookup conversion factor from hardcoded table
|
||||||
|
3. Compute: `value × (factor_to / factor_from)`
|
||||||
|
4. Special handling: Temperature offset scales (K↔°C↔°F)
|
||||||
|
- Output: Converted value (number) or error string
|
||||||
|
- **CurrencyConverter.js**:
|
||||||
|
- Input: `value`, `fromCurrency`, `toCurrency`
|
||||||
|
- Process:
|
||||||
|
1. Validate 3-letter uppercase currency codes
|
||||||
|
2. Lookup rate from internal table (manual entry)
|
||||||
|
3. Compute: `value × (rate_to / rate_from)`
|
||||||
|
4. Auto-handles inverse rates
|
||||||
|
- Output: Converted value (number) or error string
|
||||||
|
- **ExchangeRateService.js**:
|
||||||
|
- Manages rate table in localState with timestamps
|
||||||
|
- Provides: getRate, setRate, getDefaultRates, isRateStale
|
||||||
|
- **UnitDefinitions.js**:
|
||||||
|
- Hardcoded conversion factors for all units in each category
|
||||||
|
- Organized by category (electrical, mechanical, etc.)
|
||||||
|
|
||||||
|
#### 3.2.3 History Manager (`src/core/history/`)
|
||||||
|
- **HistoryManager.js**:
|
||||||
|
- Storage: `localStorage` keyed as `calc_history`
|
||||||
|
- Structure: Array of `{expression: string, result: string|number, timestamp: number}`
|
||||||
|
- Capacity: Fixed at 50 entries (FIFO eviction on overflow)
|
||||||
|
- Operations: addEntry, getHistory, clearHistory, removeEntry(index)
|
||||||
|
- Corruption Recovery:
|
||||||
|
- On read: Validate JSON structure and types
|
||||||
|
- On failure: Return empty array (fresh start)
|
||||||
|
- On version mismatch: Reset to defaults (if versioning added later)
|
||||||
|
- **useHistory.js** (custom hook):
|
||||||
|
- Provides: `history`, `addToHistory`, `clearHistory`, `removeFromHistory`
|
||||||
|
- Auto-saves to localStorage on update
|
||||||
|
|
||||||
|
#### 3.2.4 Theme System (`src/theme/`)
|
||||||
|
- **ThemeContext.js**:
|
||||||
|
- State: `{theme: 'dark'|'light', transitioning: boolean}`
|
||||||
|
- Provider: Wraps app to distribute theme state
|
||||||
|
- Updater: `setTheme` + `startTransition`/`endTransition` for animations
|
||||||
|
- **themes.js**:
|
||||||
|
- Defines CSS variables for both themes:
|
||||||
|
- Dark: `--bg-primary: #121212; --text-primary: #E0E0E0; --accent: #FF9800;`
|
||||||
|
- Light: `--bg-primary: #FFFFFF; --text-primary: #212121; --accent: #FB8C00;`
|
||||||
|
- **useTheme.js** (custom hook):
|
||||||
|
- Returns: `[theme, setTheme, isTransitioning]`
|
||||||
|
- Handles transition state for motion coordination
|
||||||
|
|
||||||
|
#### 3.2.5 Mode System (`src/contexts/`)
|
||||||
|
- **ModeContext.js**:
|
||||||
|
- State: `'standard'|'scientific'|'unit'|'currency'`
|
||||||
|
- Determines: Which keypad mode to render
|
||||||
|
- Updater: `setMode` (called by mode-switching buttons)
|
||||||
|
|
||||||
|
### 3.3 UI Component Specifications
|
||||||
|
|
||||||
|
#### 3.3.1 Display Bar (`src/components/display/`)
|
||||||
|
- **Display.jsx**:
|
||||||
|
- Props: `expression`, `result`, `isError`, `highlightSyntax` (boolean)
|
||||||
|
- Features:
|
||||||
|
- Main result display (large, monospace font)
|
||||||
|
- Optional secondary expression line (smaller, muted)
|
||||||
|
- Real-time syntax highlighting (valid=green, invalid=red)
|
||||||
|
- Error state: Shows "Error" + optional shake animation
|
||||||
|
- Accessibility: `role="textbox"`, `aria-live="polite"` for result changes
|
||||||
|
- **Display.module.css**:
|
||||||
|
- Base styling: Dark background, light text, monospace font
|
||||||
|
- Animation: Shake keyframes for error feedback
|
||||||
|
- Responsive: Font size scales with viewport width
|
||||||
|
|
||||||
|
#### 3.3.2 Button System (`src/components/button/`)
|
||||||
|
- **Button.jsx**:
|
||||||
|
- Props: `label`, `variant` (`number`|`operator`|`function`|`conversion`|`special`), `onClick`, `isDisabled`
|
||||||
|
- Features:
|
||||||
|
- Consistent sizing (aspect ratio 1:1, border-radius 50%)
|
||||||
|
- Variant-based styling (colors, hover effects)
|
||||||
|
- Press animation (scale + background change)
|
||||||
|
- Tooltip support (via `title` prop or separate Tooltip component)
|
||||||
|
- Accessibility: `aria-label` derived from label or prop
|
||||||
|
- **Button.module.css**:
|
||||||
|
- Shared styles: Transition effects, hover/active states
|
||||||
|
- Variants:
|
||||||
|
- `number`: `#fff` background, `#333` text
|
||||||
|
- `operator`: `#ff9500` background, `#fff` text
|
||||||
|
- `function`: `#e0e0e0` background, `#333` text
|
||||||
|
- `conversion`: `#90caf9` background, `#0d47a0` text (distinct but harmonious)
|
||||||
|
- `special` (AC/CE): `#f44336` background, `#fff` text
|
||||||
|
|
||||||
|
#### 3.3.3 Keypad System (`src/components/keypad/`)
|
||||||
|
- **Keypad.jsx**:
|
||||||
|
- Props: `mode` (from ModeContext), `onButtonPress` (callback)
|
||||||
|
- Function: Renders appropriate mode-specific keypad grid
|
||||||
|
- Modes:
|
||||||
|
- `Standard`: Basic arithmetic + AC/CE
|
||||||
|
- `Scientific`: Trig, log, exp, sqrt, x^y, parentheses, ans
|
||||||
|
- `Unit`: Common unit conversions (predefined pairs)
|
||||||
|
- `Currency`: Common currency conversions (predefined pairs)
|
||||||
|
- Layout: Responsive CSS grid (auto-adapts columns based on viewport)
|
||||||
|
- **mode-specific files** (`StandardMode.jsx` etc.):
|
||||||
|
- Define button labels and variants for that mode
|
||||||
|
- Easy to extend/modify per category
|
||||||
|
|
||||||
|
#### 3.3.4 History Panel (`src/components/history/`)
|
||||||
|
- **HistoryPanel.jsx**:
|
||||||
|
- Props: `history` (array), `onHistorySelect` (callback)
|
||||||
|
- Features:
|
||||||
|
- Slide-in panel from right (desktop ≥768px)
|
||||||
|
- Full-screen modal (mobile <768px)
|
||||||
|
- List of history items (most recent first)
|
||||||
|
- Each item: Shows full expression and result
|
||||||
|
- Interactions: Tap to re-use, swipe/slide to delete
|
||||||
|
- Header: "History" + clear all button
|
||||||
|
- Empty state: "No history yet"
|
||||||
|
- **HistoryItem.jsx**:
|
||||||
|
- Displays: `{expression} = {result}` with timestamp (with optional: Copy to clipboard icon
|
||||||
|
- **HistoryPanel.module.css**:
|
||||||
|
- Slide-in animation (Framer Motion or CSS)
|
||||||
|
- List styling with dividers
|
||||||
|
- Action buttons (re-use, delete)
|
||||||
|
- Responsive adjustments for mobile/fullscreen
|
||||||
|
|
||||||
|
### 3.4 Utility Modules
|
||||||
|
|
||||||
|
#### 3.4.1 Keyboard Handler (`src/utils/KeyboardHandler.js`)
|
||||||
|
- Responsibilities:
|
||||||
|
- Maps physical keys to calculator actions
|
||||||
|
- Handles: numbers 0-9, operators (+-*/=.), Enter (=), Escape (AC), Backspace (CE)
|
||||||
|
- Advanced: Arrow keys for history navigation (↑/↓)
|
||||||
|
- Prevents default behavior where appropriate (e.g., Enter in form)
|
||||||
|
- Output: Calls registered callbacks for:
|
||||||
|
- `onDigit(char)`
|
||||||
|
- `onOperator(char)`
|
||||||
|
- `onDecimal()`
|
||||||
|
- `onEnter()` → triggers `=`
|
||||||
|
- `onEscape()` → triggers `AC`
|
||||||
|
- `onBackspace()` → triggers `CE`
|
||||||
|
- `onArrowUp()` → history previous
|
||||||
|
- `onArrowDown()` → history next
|
||||||
|
|
||||||
|
#### 3.4.2 Validator (`src/utils/Validator.js`)
|
||||||
|
- Centralized validation logic (though expression parser handles its own)
|
||||||
|
- Includes:
|
||||||
|
- `isValidUnit(unit, category)` → boolean
|
||||||
|
- `isValidCurrencyCode(code)` → boolean (regex: `^[A-Z]{3}$`)
|
||||||
|
- `isValidExpressionChars(str)` → boolean (expression allowlist check)
|
||||||
|
|
||||||
|
#### 3.4.3 Formatter (`src/utils/Formatter.js`)
|
||||||
|
- Formats numbers for display:
|
||||||
|
- `formatNumber(num, opts)` → string
|
||||||
|
- Options: `precision` (significant figures), `notation` (`standard`|`scientific`), `unit` (string)
|
||||||
|
- Handles: Large/small numbers (scientific notation threshold)
|
||||||
|
- Ensures: Consistent decimal/comma handling per locale (if needed later)
|
||||||
|
|
||||||
|
### 3.5 Animation System (`src/animations/`)
|
||||||
|
- **index.js**: Exports all animation variants for easy import
|
||||||
|
- **buttonPress.js**:
|
||||||
|
- `pressVariant`: { scale: [1, 0.95, 1], backgroundColor: ['#fff', '#e9e9e9', '#fff'] }
|
||||||
|
- `pressVariantOperator`: { scale: [...], backgroundColor: ['#ff9500', '#ffb14d', '#ff9500'] }
|
||||||
|
- **screenTransition.js**:
|
||||||
|
- `fadeIn`: { opacity: [0, 1], transition: { duration: 0.3 } }
|
||||||
|
- `slideInRight`: { x: ['100%', '0%'], transition: { duration: 0.3, type: 'spring', stiffness: 300 } }
|
||||||
|
- `slideOutLeft`: { x: ['0%', '-100%'], transition: { duration: 0.3, type: 'spring', stiffness: 300 } }
|
||||||
|
- **toastNotification.js**:
|
||||||
|
- For temporary feedback (e.g., "Rate updated", "History cleared")
|
||||||
|
- Variants: `slideUp`, `fade`, `scale`
|
||||||
|
|
||||||
|
### 3.6 Styles (`src/styles/`)
|
||||||
|
- **globals.css**:
|
||||||
|
- Base styles: box-sizing, font-smoothing, root font-size
|
||||||
|
- CSS variable definitions (referenced by themes.js)
|
||||||
|
- Reset: margin, padding, list-style
|
||||||
|
- **themes.js**:
|
||||||
|
- Defines `:root` and `[data-theme="dark"]` variable overrides
|
||||||
|
- Enables theme switching via document.documentElement.dataset.theme
|
||||||
|
- **responsive.css**:
|
||||||
|
- Media queries for breakpoints: 480px (phone), 768px (tablet/desktop)
|
||||||
|
- Adjusts: keypad grid columns, display font sizes, panel dimensions
|
||||||
|
- Touch target enhancements: ≥48px for mobile
|
||||||
|
|
||||||
|
### 3.7 Application Entry Points
|
||||||
|
- **src/main.jsx**:
|
||||||
|
- React 18 entry point
|
||||||
|
- Wraps `<App />` in:
|
||||||
|
- `React.StrictMode` (for development helper warnings)
|
||||||
|
- `ThemeContext.Provider`
|
||||||
|
- `ModeContext.Provider`
|
||||||
|
- `CalculationContext.Provider`
|
||||||
|
- **src/App.jsx**:
|
||||||
|
- Top-level layout
|
||||||
|
- Structure:
|
||||||
|
```jsx
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<div className={styles.app}>
|
||||||
|
<ThemeConsumer>
|
||||||
|
{({ theme, isTransitioning }) => (
|
||||||
|
<>
|
||||||
|
<Header theme={theme} isTransitioning={isTransitioning} />
|
||||||
|
<MainContent theme={theme} />
|
||||||
|
<Footer theme={theme} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ThemeConsumer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- `MainContent` contains: Display Bar, Keypad Grid, History Panel (conditionally rendered)
|
||||||
|
- `Header`: Optional app name/logo/theme toggle
|
||||||
|
- `Footer`: Version info, credits, links to documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Data Flow
|
||||||
|
|
||||||
|
### 4.1 Data Flow Principles
|
||||||
|
- **State as Single Source of Truth**: All UI derives from React state (local + context)
|
||||||
|
- **Immutable Updates**: State never mutated directly; always replaced via setState/useReducer
|
||||||
|
- **Unidirectional where possible**: User action → state update → UI re-render
|
||||||
|
- **Local Effects**: Side effects (localStorage, animations) handled in useEffect/useLayoutEffect
|
||||||
|
- **No Prop Drilling Deeply**: Context used for truly global state (theme, mode, calc/history)
|
||||||
|
|
||||||
|
### 4.2 Detailed Data Flows
|
||||||
|
|
||||||
|
#### 4.2.1 Expression Evaluation Flow
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant UI as UI Layer (Display/Keypad)
|
||||||
|
participant Expr as Expression Parser
|
||||||
|
participant Calc as Calculation Context
|
||||||
|
participant Hist as History Manager
|
||||||
|
participant LS as localStorage
|
||||||
|
|
||||||
|
User->>UI: Types "2+2*3" or clicks buttons
|
||||||
|
UI->>Expr: sendRawInput("2+2*3")
|
||||||
|
Expr->>Expr: validateAllowlist(input) → true/false
|
||||||
|
alt valid
|
||||||
|
Expr->>Expr: substituteConstants(input) → "2+2*3"
|
||||||
|
Expr->>Expr: replaceFunctions(input) → "2+2*3" (no funcs here)
|
||||||
|
Expr->>Expr: evaluateViaFunction(sanitized) → {value: 8, error: null}
|
||||||
|
Expr->>Calc: sendResult({value: 8, error: null})
|
||||||
|
Calc->>Calc: updateState({display: "8", history: [...]} )
|
||||||
|
Calc->>Hist: addToHistory({expr: "2+2*3", result: "8"})
|
||||||
|
Hist->>LS: writeHistory(historyArray)
|
||||||
|
Calc->>UI: updateDisplay("8")
|
||||||
|
UI->>User: Show "8" in display
|
||||||
|
else invalid
|
||||||
|
Expr->>Calc: sendError("Invalid expression")
|
||||||
|
Calc->>UI: showErrorState()
|
||||||
|
UI->>User: Show "Error" + shake animation
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2.2 Unit Conversion Flow
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant UI as UI Layer
|
||||||
|
participant Conv as UnitConverter
|
||||||
|
participant Calc as Calculation Context
|
||||||
|
participant Hist as History Manager
|
||||||
|
participant LS as localStorage
|
||||||
|
|
||||||
|
User->>UI: Types "convert(100, 'V', 'mV')"
|
||||||
|
UI->>Conv: sendRawInput("convert(100, 'V', 'mV')")
|
||||||
|
Conv->>Conv: parseConvertInput(input) → {value:100, from:'V', to:'mV'}
|
||||||
|
Conv->>Conv: validateUnits('V', 'mV') → true (both in Electrical)
|
||||||
|
Conv->>Conv: lookupFactor('V') → 1
|
||||||
|
Conv->>Conv: lookupFactor('mV') → 0.001
|
||||||
|
Conv->>Conv: compute → 100 * (0.001 / 1) = 0.1 → wait, correction:
|
||||||
|
actually: value * (factor_to / factor_from)
|
||||||
|
= 100 * (0.001 / 1) = 0.1? No:
|
||||||
|
Factor definition: 1 V = 1000 mV → factor_V = 1, factor_mV = 0.001?
|
||||||
|
Better: Store factor as "units per base unit"
|
||||||
|
Let base = 1 V
|
||||||
|
Then: factor_V = 1 (1 V per base V)
|
||||||
|
factor_mV = 1000 (1000 mV per base V)
|
||||||
|
Conversion: value_in_from * (factor_from / factor_to)
|
||||||
|
100 V * (1 / 1000) = 0.1 kV? Still wrong.
|
||||||
|
|
||||||
|
Correct approach:
|
||||||
|
Define factor as "multiplier to get to base unit"
|
||||||
|
Let base = 1 V
|
||||||
|
Then: 1 V = 1 * base → factor_V = 1
|
||||||
|
1 mV = 0.001 * base → factor_mV = 0.001
|
||||||
|
To convert from V to mV:
|
||||||
|
value_in_base = value_from * factor_from
|
||||||
|
value_to = value_in_base / factor_to
|
||||||
|
Example: 100 V
|
||||||
|
value_in_base = 100 * 1 = 100 V-base
|
||||||
|
value_to = 100 / 0.001 = 100,000 mV
|
||||||
|
|
||||||
|
So: result = value * (factor_from / factor_to)
|
||||||
|
For V→mV: 100 * (1 / 0.001) = 100,000 ✓
|
||||||
|
Conv->>Conv: computeResult → 100000
|
||||||
|
Conv->>Calc: sendResult({value: 100000, error: null})
|
||||||
|
Calc->>Calc: updateState({display: "100000", history: [...]})
|
||||||
|
Calc->>Hist: addToHistory({expr: "convert(100, 'V', 'mV')", result: "100000"})
|
||||||
|
Hist->>LS: writeHistory(historyArray)
|
||||||
|
Calc->>UI: updateDisplay("100000")
|
||||||
|
UI->>User: Show "100000" in display
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2.3 History Re-use Flow
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant UI as UI Layer (HistoryPanel)
|
||||||
|
participant Hist as History Manager
|
||||||
|
participant Calc as Calculation Context
|
||||||
|
|
||||||
|
User->>UI: Clicks history item "derivative(sin(x), x, 0) = 1"
|
||||||
|
UI->>Hist: getHistoryItem(index) → {expr: "derivative(sin(x), x, 0)", result: "1"}
|
||||||
|
UI->>Calc: sendHistorySelect(expr: "derivative(sin(x), x, 0)")
|
||||||
|
Calc->>Calc: insertAtCursor("derivative(sin(x), x, 0)")
|
||||||
|
Calc->>UI: updateDisplay("derivative(sin(x), x, 0)")
|
||||||
|
UI->>User: Shows "derivative(sin(x), x, 0)" in expression bar
|
||||||
|
User->>User: Continues typing or presses "="
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2.4 Theme Toggle Flow
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant UI as UI Layer (Theme Toggle Button)
|
||||||
|
participant TCtx as Theme Context
|
||||||
|
participant Doc as Document Object
|
||||||
|
participant UIComp as UI Components
|
||||||
|
|
||||||
|
User->>UI: Clicks theme toggle button
|
||||||
|
UI->>TCtx: dispatch(setTheme('light')) // if was dark
|
||||||
|
TCtx->>TCtx: updateState({theme: 'light', transitioning: true})
|
||||||
|
TCtx->>UIComp: propagate new theme state
|
||||||
|
UIComp->>UIComp: re-render with light theme styles
|
||||||
|
TCtx->>Doc: set document.documentElement.dataset.theme = 'light'
|
||||||
|
Doc->>Doc: Apply CSS variable overrides from [data-theme="light"]
|
||||||
|
TCtx->>TCtx: After 300ms (CSS transition duration), set transitioning: false
|
||||||
|
TCtx->>UIPropagate: final state (transitioning: false)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Technology Stack Justification
|
||||||
|
|
||||||
|
### 5.1 Core Choices
|
||||||
|
| Technology | Choice | Justification |
|
||||||
|
|------------|--------|---------------|
|
||||||
|
| **React 18** | ✅ | Industry standard, concurrent rendering features, rich ecosystem, matches stakeholder's implicit web focus |
|
||||||
|
| **Vite 4.3** | ✅ | Lightning-fast dev server, native ES modules, optimized build; superior to CRA for iteration speed |
|
||||||
|
| **CSS Modules** | ✅ | Scoped styling eliminates global CSS issues; no runtime overhead; excellent IDE support |
|
||||||
|
| **Framer Motion 10.12** | ✅ | Declarative animations, gesture support, layout sharing, smaller than alternatives (e.g., react-spring) |
|
||||||
|
| **localStorage** | ✅ | Simple, reliable, no setup; matches stakeholder's "NO" to complex persistence; 5MB limit sufficient for history/theme |
|
||||||
|
| **JavaScript (ES2020+)** | ✅ | Modern language features (optional chaining, nullish coalescing, etc.); all target browsers support |
|
||||||
|
|
||||||
|
### 5.2 Why Not Alternatives?
|
||||||
|
- **Redux Toolkit / Zustand**: Overkill for this scope; Context API + useReducer sufficient for 3-4 global state slices
|
||||||
|
- **Styled Components**: Runtime overhead; CSS Modules provide same scoping with build-time extraction
|
||||||
|
- **Tailwind CSS**: Utility-first approach less suitable for complex component states and themes
|
||||||
|
- **Fusion/Zustand for Animation**: Framer Motion specifically designed for UI animations with React
|
||||||
|
- **IndexedDB**: Overly complex for simple history/theme persistence; localStorage adequate
|
||||||
|
- **Express.js Backend**: Violates stakeholder's "standalone utility" and "no integration" requirements; adds unnecessary complexity
|
||||||
|
|
||||||
|
### 5.3 Dependency Audit (All OSS/Free)
|
||||||
|
| Dependency | Version | License | Purpose |
|
||||||
|
|------------|---------|---------|---------|
|
||||||
|
| react | 18.2.0 | MIT | UI library |
|
||||||
|
| react-dom | 18.2.0 | MIT | DOM bindings |
|
||||||
|
| vite | 4.3.0 | MIT | Build tool & dev server |
|
||||||
|
| framer-motion | 10.12.0 | MIT | Animations |
|
||||||
|
| (CSS Modules via Vite) | built-in | MIT | Scoped styling |
|
||||||
|
| (Optional) date-fns | 2.29.3 | MIT | Date formatting for history timestamps |
|
||||||
|
|
||||||
|
*All dependencies are free, open-source, and commercially friendly—no licensing concerns for framework evaluation.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Security Architecture
|
||||||
|
|
||||||
|
### 6.1 Threat Model
|
||||||
|
**Assets to Protect**:
|
||||||
|
- User input data (expressions, conversion parameters)
|
||||||
|
- LocalStorage contents (history, theme, rates)
|
||||||
|
- DOM integrity (prevent XSS)
|
||||||
|
- Application logic integrity (prevent code injection)
|
||||||
|
|
||||||
|
**Threat Agents**:
|
||||||
|
- Malicious user (attempting XSS, code injection)
|
||||||
|
- Compromised localStorage (corruption, tampering)
|
||||||
|
- Supply chain (dependency vulnerabilities—mitigated by OSS audit)
|
||||||
|
|
||||||
|
### 6.2 Security Controls
|
||||||
|
|
||||||
|
#### 6.2.1 Input Sanitization (Primary Defense)
|
||||||
|
- **Single Point of Validation**: All user input flows through the Expression Parser's allowlist
|
||||||
|
- **Allowlist Approach**:
|
||||||
|
- Permitted: `[0-9]`, `.`, `+-*/()`, whitespace, `e`, `pi`, whitelisted function names
|
||||||
|
- **Everything else rejected immediately**
|
||||||
|
- No attempt to "filter out bad"—default deny
|
||||||
|
- **Function Whitelisting**:
|
||||||
|
- Only predefined mathematical/scientific functions allowed
|
||||||
|
- Replacement with safe `Math.func` equivalents before evaluation
|
||||||
|
- **Constant Safety**:
|
||||||
|
- `pi` and `e` mapped to immutable `Math.PI`/`Math.E`
|
||||||
|
- `ans` validated as numeric before substitution
|
||||||
|
- **Evaluation Context**:
|
||||||
|
- `Function` constructor used **only** on fully sanitized string
|
||||||
|
- Never `eval`; never direct string execution
|
||||||
|
- Wrapped in `try/catch` to prevent leak of stack traces
|
||||||
|
|
||||||
|
#### 6.2.2 LocalStorage Protection
|
||||||
|
- **Namespace Isolation**:
|
||||||
|
- History: `calc_history`
|
||||||
|
- Theme: `calc_theme`
|
||||||
|
- Conversion Rates: `conv_rates`
|
||||||
|
- Prevents collision with other apps on same domain
|
||||||
|
- **Integrity Validation on Read**:
|
||||||
|
- `JSON.parse` with try/catch
|
||||||
|
- Type checking: Is history an array? Are entries objects with correct fields?
|
||||||
|
- Structure validation: Expression string, result (string/number), timestamp (number)
|
||||||
|
- On failure: Reset to safe default (empty history, light theme, default rates)
|
||||||
|
- **Size Limits**:
|
||||||
|
- History capped at 50 entries (FIFO)
|
||||||
|
- Theme: Simple string ('dark'|'light')
|
||||||
|
- Rates: Small JSON object (≤10 currencies)
|
||||||
|
|
||||||
|
#### 6.2.3 Output Encoding (XSS Prevention)
|
||||||
|
- **textContent Over innerHTML**:
|
||||||
|
- All dynamic values inserted via `textContent` or safe templating
|
||||||
|
- `innerHTML` **never** used with user-controlled data
|
||||||
|
- **Attribute Safety**:
|
||||||
|
- URLs (if any) validated before use
|
||||||
|
- No JavaScript: URLs or event handlers from input
|
||||||
|
- **Error Messages**:
|
||||||
|
- Generated internally (e.g., "Invalid expression", "Unknown unit")
|
||||||
|
- Never reflect raw user input
|
||||||
|
|
||||||
|
#### 6.2.4 Dependency Security
|
||||||
|
- **OSS Selection**: All dependencies from npm with MIT licenses (commercially friendly)
|
||||||
|
- **Version Pinning**: Exact versions in package.json (no floating ranges)
|
||||||
|
- **Audit Ready**: `npm audit` passes with zero vulnerabilities (at time of writing)
|
||||||
|
- **No Native Modules**: Zero risk from binary dependencies
|
||||||
|
|
||||||
|
#### 6.2.5 Runtime Protections
|
||||||
|
- **Strict Mode**: React 18 StrictMode enabled in development (helps detect unsafe practices)
|
||||||
|
- **No Dangerous APIs**:
|
||||||
|
- No `eval`, `Function` with user input, `setTimeout(string, ...)`, etc.
|
||||||
|
- No `document.write()`, `innerHTML` with user data
|
||||||
|
- No `localStorage.key()` iteration without validation
|
||||||
|
- **Content Security Policy**: Not implemented (local dev), but note:
|
||||||
|
- Would default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' (for CSS Modules transition)
|
||||||
|
- Can be added easily for production hardening
|
||||||
|
|
||||||
|
### 6.3 Gilfoyle's Review Focus Points
|
||||||
|
The security architecture is designed for straightforward review:
|
||||||
|
1. **ExpressionParser.js**: Single file to review for allowlist, function replacement, constant substitution, safe evaluation
|
||||||
|
2. **Input Flow Diagram**: Clear trace from UI → parser → evaluation → state → UI
|
||||||
|
3. **LocalStorage Handling**: Validation/recovery logic in HistoryManager and ThemeContext
|
||||||
|
4. **No Hidden Complexity**: No metaprogramming, no proxies, no eval anywhere
|
||||||
|
5. **Minimal Attack Surface**: Conversion systems use same validation pattern (lookup-based, no eval)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Performance Architecture
|
||||||
|
|
||||||
|
### 7.1 Performance Goals
|
||||||
|
| Metric | Target | Measurement Method |
|
||||||
|
|--------|--------|---------------------|
|
||||||
|
| Animation Frame Rate | ≥55 FPS | Chrome DevTools Performance tab |
|
||||||
|
| Calculation Latency | < 50ms (std ops)<br>< 100ms (numerical methods) | console.time() around evaluation |
|
||||||
|
| Initial Load Time | < 2.5s (Moto G4 3G throttling) | Lighthouse / DevTools Network throttling |
|
||||||
|
| Memory Usage | < 50MB peak | Chrome Task Manager |
|
||||||
|
| Bundle Size | < 150KB gzipped | `vite build` + `gzip-size` |
|
||||||
|
| Input Latency | < 16ms (1 frame) | DevTools Input Latency metric |
|
||||||
|
|
||||||
|
### 7.2 Optimization Strategies
|
||||||
|
|
||||||
|
#### 7.2.1 Rendering Performance
|
||||||
|
- **Component Memoization**:
|
||||||
|
- `React.memo` on pure components: Display, Button, HistoryItem
|
||||||
|
- Prevents unnecessary re-renders when props unchanged
|
||||||
|
- **Stable References**:
|
||||||
|
- `useCallback` for event handlers passed down as props
|
||||||
|
- `useMemo` for expensive computations (e.g., conversion factor tables)
|
||||||
|
- **Virtual Scrolling**:
|
||||||
|
- History panel uses virtual scroll if >20 items (though capped at 50)
|
||||||
|
- Renders only visible items + buffer
|
||||||
|
- **Layout Thrashing Avoidance**:
|
||||||
|
- DOM reads/writes batched via requestAnimationFrame where beneficial
|
||||||
|
- Avoid forced synchronous layouts
|
||||||
|
|
||||||
|
#### 7.2.2 Calculation Performance
|
||||||
|
- **Expression Parser Optimization**:
|
||||||
|
- Allowlist check: Single regex pass `/^[0-9+\\-*/().\\s epi]+$/i` (case-insensitive for e/pi)
|
||||||
|
- Tokenization: Simple linear scan (not full AST unless needed later)
|
||||||
|
- Function replacement: Single pass over string with regex per function (acceptable for short expressions)
|
||||||
|
- Evaluation: `Function` constructor JIT-compiled once per unique sanitized string (V8 optimizes well)
|
||||||
|
- **Numerical Methods**:
|
||||||
|
- Derivative: Central difference with fixed h (no iteration unless oscillation detected)
|
||||||
|
- Integral: Adaptive Simpson with early termination on error tolerance
|
||||||
|
- Solve: Newton-Raphson with secant fallback, `maxIter=100`, `tol=1e-10`
|
||||||
|
- All avoid expensive operations in loops (e.g., no regex inside hot loops)
|
||||||
|
|
||||||
|
#### 7.2.3 Animation Performance
|
||||||
|
- **Framer Motion Benefits**:
|
||||||
|
- Uses `requestAnimationFrame` by default
|
||||||
|
- Layout animations use FLIP technique (First, Last, Invert, Play)
|
||||||
|
- Shared layout transitions minimize paint costs
|
||||||
|
- **Reduced Motion Support**:
|
||||||
|
- Respects `prefers-reduced-motion` media query
|
||||||
|
- Falls back to instant transitions or fades when preferred
|
||||||
|
- **Layer Promotion**:
|
||||||
|
- Animated elements implicitly promoted to compositor layer (opacity/transform)
|
||||||
|
- Minimizes main thread work
|
||||||
|
|
||||||
|
#### 7.2.4 Bundle Optimization
|
||||||
|
- **Code Splitting**:
|
||||||
|
- Dynamic import() for rare features (e.g., "Manage Rates" panel)
|
||||||
|
- Main bundle: Core calculator + UI + essential utils
|
||||||
|
- **Tree Shaking**:
|
||||||
|
- ES modules + Vite = dead code elimination
|
||||||
|
- Only used functions/modules included in bundle
|
||||||
|
- **Asset Optimization**:
|
||||||
|
- Inline critical CSS (if any)
|
||||||
|
- Optimize any SVGs/icons (though currently text/icon-only via CSS)
|
||||||
|
- No large image dependencies
|
||||||
|
|
||||||
|
#### 7.2.5 Memory Management
|
||||||
|
- **History Bounding**: Fixed at 50 entries (FIFO) prevents unbounded growth
|
||||||
|
- **LocalStorage Pruning**:
|
||||||
|
- On start: If history > 50, truncate to most recent 50
|
||||||
|
- Rates: Only store user-modified rates; defaults not stored
|
||||||
|
- **Event Listener Cleanup**:
|
||||||
|
- All `addEventListener` paired with `removeEffect` in `useEffect` cleanup
|
||||||
|
- No lingering listeners on unmount
|
||||||
|
- **React 18 Benefits**:
|
||||||
|
- Automatic batching of state updates
|
||||||
|
- Concurrent rendering features (when used via startTransition)
|
||||||
|
|
||||||
|
### 7.3 Performance Testing & Validation
|
||||||
|
- **Unit Tests**:
|
||||||
|
- Math engine: Benchmark extreme cases (large numbers, deep nesting)
|
||||||
|
- Conversion: Boundary values, invalid inputs
|
||||||
|
- **Manual Profiling**:
|
||||||
|
- DevTools Performance panel: Record typical usage scenarios
|
||||||
|
- Flamegraph to identify hot paths
|
||||||
|
- Check for layout thrashing, forced sync layout, long tasks
|
||||||
|
- **Device Testing**:
|
||||||
|
- Moto G4 / Galaxy A10 (low-end Android) via BrowserStack
|
||||||
|
- iPhone SE / iPad mini (low-end iOS)
|
||||||
|
- Desktop Chrome/Firefox (reference)
|
||||||
|
- **Continuous Integration**:
|
||||||
|
- Lighthouse CI for performance budgets
|
||||||
|
- Bundle size alerts on PRs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Development Workflow (NEW SECTION)
|
||||||
|
|
||||||
|
### 8.1 Specialist Development Process
|
||||||
|
Each specialist follows this workflow for their assigned modules:
|
||||||
|
1. **Code Implementation**: Implement the assigned functionality according to the SAD and technical specifications
|
||||||
|
2. **Local Commit**:
|
||||||
|
- Commit changes locally with a descriptive message following conventional commits format
|
||||||
|
- Commit message structure: `<type>(<scope>): <description>`
|
||||||
|
- Example: `feat(math-engine): add derivative function with central difference method`
|
||||||
|
- Include relevant issue/ticket references if applicable
|
||||||
|
3. **Change Notification**:
|
||||||
|
- Immediately after committing, notify Turing via the designated communication channel
|
||||||
|
- Notification includes: commit hash, branch name, and brief description of changes
|
||||||
|
4. **Turing's Response**:
|
||||||
|
- Turing generates a small commit changes document explaining:
|
||||||
|
- What files were modified
|
||||||
|
- What functionality was added/changed
|
||||||
|
- How it relates to the overall architecture
|
||||||
|
- Any notable considerations or assumptions
|
||||||
|
- Document is saved in `.hermes/docs/commits/` with timestamp and commit hash
|
||||||
|
5. **Push to Repository**:
|
||||||
|
- After local validation and Turing's documentation, push changes to the designated GitHub/Gitea repository
|
||||||
|
- Push includes all local commits since last push
|
||||||
|
6. **Repeat**: Continue with next bite-sized task
|
||||||
|
|
||||||
|
### 8.2 Commit Changes Document Format
|
||||||
|
Turing's generated document follows this template:
|
||||||
|
```
|
||||||
|
# Commit Changes Document
|
||||||
|
**Commit:** <commit_hash>
|
||||||
|
**Branch:** <branch_name>
|
||||||
|
**Timestamp:** <ISO_timestamp>
|
||||||
|
**Specialist:** <specialist_name>
|
||||||
|
**Module:** <affected_module>
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
<brief_description_of_changes>
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- <file1>: <change_description>
|
||||||
|
- <file2>: <change_description>
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- [ ] New feature
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] Refactor
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance improvement
|
||||||
|
- [ ] Security enhancement
|
||||||
|
|
||||||
|
## Related To
|
||||||
|
- [ ] Math Engine
|
||||||
|
- [ ] Unit Conversion
|
||||||
|
- [ ] Currency Conversion
|
||||||
|
- [ ] History System
|
||||||
|
- [ ] Theme System
|
||||||
|
- [ ] Mode System
|
||||||
|
- [ ] UI Components
|
||||||
|
- [ ] Utils
|
||||||
|
- [ ] Animation System
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
<any_additional_considerations>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.3 Workflow Benefits
|
||||||
|
- **Transparency**: Clear record of what each specialist contributed
|
||||||
|
- **Knowledge Sharing**: Turing's documents help team members understand changes across modules
|
||||||
|
- **Audit Trail**: Complete history of development process for framework evaluation
|
||||||
|
- **Quality Assurance**: Early detection of inconsistencies or integration issues
|
||||||
|
- **Documentation Compliance**: Ensures all changes are properly documented per stakeholder requirements
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Deployment Architecture
|
||||||
|
|
||||||
|
### 9.1 Target Environment
|
||||||
|
- **Platform**: Web browser (standalone utility)
|
||||||
|
- **Deployment Model**: Static file hosting (no server-side code)
|
||||||
|
- **Required Features**:
|
||||||
|
- ES2020+ JavaScript support
|
||||||
|
- localStorage API
|
||||||
|
- requestAnimationFrame
|
||||||
|
- CSS CSS Variables
|
||||||
|
- DOM Level 2 Events
|
||||||
|
- **Supported Browsers** (latest stable):
|
||||||
|
- Chrome ≥109
|
||||||
|
- Firefox ≥109
|
||||||
|
- Safari ≥16
|
||||||
|
- Edge ≥109
|
||||||
|
- **Excluded**:
|
||||||
|
- Internet Explorer (no longer supported)
|
||||||
|
- Very old browsers lacking ES2020 features
|
||||||
|
|
||||||
|
### 9.2 Build Artifacts
|
||||||
|
- **Development**:
|
||||||
|
- `vite dev` → Serves via Vite dev server (HMR, source maps)
|
||||||
|
- Output: Unminimized, readable code with warnings
|
||||||
|
- **Production**:
|
||||||
|
- `vite build` → Outputs to `/dist/` directory
|
||||||
|
- Contents:
|
||||||
|
- `index.html` (shell)
|
||||||
|
- `assets/index-[hash].js` (minimized bundle)
|
||||||
|
- `assets/index-[hash].css` (minimized styles)
|
||||||
|
- `assets/[name]-[hash].svg` (any optimized assets)
|
||||||
|
- Features:
|
||||||
|
- Minification (Terser)
|
||||||
|
- Code splitting (Rollup)
|
||||||
|
- Asset hashing for cache busting
|
||||||
|
- Source maps optional (disabled for smallest bundle)
|
||||||
|
- **Deployment Target**:
|
||||||
|
- Any static host: Netlify, Vercel, GitHub Pages, AWS S3+CloudFront, traditional web host
|
||||||
|
- No build step required on host—just serve `/dist/` as static files
|
||||||
|
|
||||||
|
### 9.3 Environment Configuration
|
||||||
|
- **No Build-Time Env Vars**:
|
||||||
|
- Application is fully self-contained; no API keys or endpoints to configure
|
||||||
|
- All configuration (defaults, limits) in code or localStorage
|
||||||
|
- **Runtime Configuration**:
|
||||||
|
- Theme preference: localStorage (`calc_theme`)
|
||||||
|
- History limit: Hardcoded 50 (changeable in code)
|
||||||
|
- Default conversion rates: Editable in `ExchangeRateService.js` (user would fork/rebuild to change)
|
||||||
|
- Numerical method tolerances: Editable in `NumericalMethods.js`
|
||||||
|
- **Feature Flags**:
|
||||||
|
- None planned (simple application)
|
||||||
|
- If needed: Could add via `import.meta.env.VITE_FEATURE_X` (Vite supports this)
|
||||||
|
|
||||||
|
### 9.4 Security Hardening for Deployment
|
||||||
|
- **Content Security Policy (CSP)**:
|
||||||
|
- Recommended header for production:
|
||||||
|
```
|
||||||
|
Content-Security-Policy: default-src 'self';
|
||||||
|
script-src 'self';
|
||||||
|
style-src 'self' 'unsafe-inline';
|
||||||
|
img-src 'self' data:;
|
||||||
|
font-src 'self';
|
||||||
|
```
|
||||||
|
- Notes:
|
||||||
|
- `'unsafe-inline'` required for CSS Modules (styles injected via JS)
|
||||||
|
- Can be tightened with nonce/hashes if needed
|
||||||
|
- `img-src data:` allows embedded SVGs/icons if added later
|
||||||
|
- **HTTP Security Headers** (server-side):
|
||||||
|
- `X-Content-Type-Options: nosniff`
|
||||||
|
- `X-Frame-Options: DENY`
|
||||||
|
- `Referrer-Policy: strict-origin-when-cross-origin`
|
||||||
|
- `Permissions-Policy: geolocation=(), microphone=(), camera=()`
|
||||||
|
- **Subresource Integrity (SRI)**:
|
||||||
|
- If using CDN for Vite-built assets (unlikely for self-host), add integrity hashes
|
||||||
|
- **Service Workers**:
|
||||||
|
- Not included (would add complexity; optional PWA upgrade later)
|
||||||
|
- If added: Cache-first strategy, background sync for rate updates (manual only)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Extension Points
|
||||||
|
|
||||||
|
While designed as a standalone testing utility, the architecture includes clean extension points for future enhancement:
|
||||||
|
|
||||||
|
### 10.1 Core Extensions
|
||||||
|
- **Add Scientific Function**:
|
||||||
|
1. Add to `ScientificFunctions.js` mapping
|
||||||
|
2. Add to ExpressionParser whitelist
|
||||||
|
3. Add unit tests
|
||||||
|
4. (Optional) Add to keypad in ScientificMode
|
||||||
|
- **Add Unit Category**:
|
||||||
|
1. Define conversion factors in `UnitDefinitions.js` under new category
|
||||||
|
2. Add category to `UnitConverter.js` validation logic
|
||||||
|
3. Add unit tests
|
||||||
|
4. (Optional) Add to unit converter keypad mode
|
||||||
|
- **Add Currency**:
|
||||||
|
1. Add to default rates in `ExchangeRateService.js` (user would edit)
|
||||||
|
2. Add to validation regex in `CurrencyConverter.js` (if extending beyond 3-letter)
|
||||||
|
3. Add unit tests
|
||||||
|
4. (Optional) Add to currency converter keypad mode
|
||||||
|
- **Add Numerical Method**:
|
||||||
|
1. Implement in `NumericalMethods.js` (pure JS function)
|
||||||
|
2. Add to exposed API in math engine
|
||||||
|
3. Add unit tests
|
||||||
|
4. (Optional) Add to expression parser as first-class function (would require allowing new keyword in allowlist)
|
||||||
|
|
||||||
|
### 10.2 UI/UX Extensions
|
||||||
|
- **Add Keypad Mode**:
|
||||||
|
1. Create new mode file (e.g., `GraphingMode.jsx`)
|
||||||
|
2. Add to `ModeContext.js` possible values
|
||||||
|
3. Add conditional rendering in `Keypad.jsx`
|
||||||
|
4. Add mode-switching button UI
|
||||||
|
- **Add Theme**:
|
||||||
|
1. Add new theme to `themes.js` (CSS variable overrides)
|
||||||
|
2. Add selection to theme toggle UI
|
||||||
|
- **Add Animation Variant**:
|
||||||
|
1. Create new variant in `animations/` directory
|
||||||
|
2. Export in `index.js`
|
||||||
|
3. Use in component via `<motion.div variants={newVariant}>`
|
||||||
|
|
||||||
|
### 10.3 Infrastructure Extensions
|
||||||
|
- **Persistence Backend**:
|
||||||
|
- Replace localStorage calls in `HistoryManager.js` and `ThemeContext.js` with adapter
|
||||||
|
- Could support: IndexedDB, remote sync (with conflict resolution), optional encryption
|
||||||
|
- **Rate Updates**:
|
||||||
|
- Replace manual entry in `ExchangeRateService.js` with optional polling
|
||||||
|
- Would require: API key management, cache layer, background fetch (opt-in)
|
||||||
|
- **Expression Enhancements**:
|
||||||
|
- Add support for:
|
||||||
|
- Base conversion prefixes (`0b`, `0o`, `0x`)
|
||||||
|
- Physical unit awareness (track units through calculations)
|
||||||
|
- Symbolic algebra (would require replacing core parser with CAS lite)
|
||||||
|
- **Testing & Quality**:
|
||||||
|
- Add end-to-end tests (Cypress/Playwright)
|
||||||
|
- Add visual regression testing (Chromatic/Storybook)
|
||||||
|
- Add performance budget enforcement in CI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Constraints & Assumptions
|
||||||
|
|
||||||
|
### 11.1 Hard Constraints (From Stakeholder)
|
||||||
|
- ✅ **Standalone Utility**: No integration with existing projects (Hybrutos, vACC, homelab)
|
||||||
|
- ✅ **No Live API Calls**: Currency rates manually entered only (framework isolation)
|
||||||
|
- ✅ **Dark Theme Mandatory**: User preference for default appearance
|
||||||
|
- ✅ **Keyboard Efficiency Priority**: Direct syntax typing preferred over mode switching
|
||||||
|
- ✅ **Gilfoyle's Security Review Mandatory**: Expression parser must be auditable
|
||||||
|
- ✅ **Gated Workflow Adherence**:
|
||||||
|
- Ideation (Steve) → Documentation PRD (Turing) →
|
||||||
|
- Design & Planning (Ada) →
|
||||||
|
- **Stakeholder Approval of Technical Plan** →
|
||||||
|
- Documentation SAD (Turing) →
|
||||||
|
- **Stakeholder Approval of SAD** →
|
||||||
|
- Orchestration (Woz) →
|
||||||
|
- Development (Specialists) →
|
||||||
|
- Pre-development Review (Stakeholder) →
|
||||||
|
- Independent Review (Satya & Sundar) →
|
||||||
|
- **Stakeholder Final Approval** →
|
||||||
|
- Deployment (Jenson)
|
||||||
|
|
||||||
|
### 11.2 Technical Assumptions
|
||||||
|
- ✅ **Browser Environment**:
|
||||||
|
- Modern browser with ES2020+ support
|
||||||
|
- localStorage available and not blocked by privacy settings
|
||||||
|
- requestAnimationFrame available for animations
|
||||||
|
- ✅ **User Competency**:
|
||||||
|
- Familiar with basic calculator operations
|
||||||
|
- Understands scientific notation and unit concepts
|
||||||
|
- Comfortable with keyboard-driven interfaces
|
||||||
|
- ✅ **Data Volumes**:
|
||||||
|
- History: ≤50 entries (trivial storage)
|
||||||
|
- Conversion rates: ≤20 currencies (trivial storage)
|
||||||
|
- Expression length: <200 characters (prevents DoS via huge input)
|
||||||
|
- ✅ **Usage Patterns**:
|
||||||
|
- Interactive use (not automated/batch processing)
|
||||||
|
- Sessions typically <1 hour (no need for aggressive memory cleanup)
|
||||||
|
- Infrequent rate updates (manual, per user initiative)
|
||||||
|
|
||||||
|
### 11.3 Explicitly Out of Scope
|
||||||
|
- ❌ **Network Dependencies**:
|
||||||
|
- No API keys, no endpoint configuration, no CORS concerns
|
||||||
|
- Offline-first by design
|
||||||
|
- ❌ **Multi-User / Collaboration**:
|
||||||
|
- Single-user device-local experience
|
||||||
|
- No real-time sync, conflict resolution, or user accounts
|
||||||
|
- ❌ **Accessibility Beyond Keyboard**:
|
||||||
|
- While keyboard support is complete,
|
||||||
|
- Screen reader optimization and ARIA completeness
|
||||||
|
- are prioritized but not exhaustive WCAG AAA
|
||||||
|
- Color contrast meets AA, not necessarily AAA
|
||||||
|
- ❌ **Internationalization (i18n)**:
|
||||||
|
- English-only interface
|
||||||
|
- Number formatting uses invariant locale (dot decimal)
|
||||||
|
- Future i18n would require:
|
||||||
|
- Message extraction (format.js/i18next)
|
||||||
|
- Right-to-left layout support
|
||||||
|
- Locale-specific number/date formatting
|
||||||
|
- ❌ **Advanced Numerics**:
|
||||||
|
- No arbitrary precision arithmetic (uses JS Number)
|
||||||
|
- No symbolic mathematics (expression parser is syntactic, not semantic)
|
||||||
|
- No matrix/tensor operations
|
||||||
|
- No statistical distributions beyond basic random()
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Conclusion
|
||||||
|
|
||||||
|
This Solution Architecture Document specifies a secure, performant, and maintainable scientific calculator application designed to evaluate the Hermes Agent multi-agent framework.
|
||||||
|
|
||||||
|
**Key Strengths**:
|
||||||
|
- **Security-First Design**: Single sanitization point, no `eval`, input validation, error containment—ready for Gilfoyle's review
|
||||||
|
- **Stakeholder-Centric**: Reflects all agreed-upon requirements from iterative design phase (state management, math engine, conversions, UI/UX)
|
||||||
|
- **Framework Evaluation Ready**:
|
||||||
|
- Uses all core Hermes Agent lanes (Lane A: NVIDIA NIM for JARVIS/Ada/Steve/Sully/Lewis/Ananta; Lane B: OpenRouter for Turing/Zaha/Linus/Sergey/Gilfoyle/Satya/Sundar/Jenson/Maria; Lane C: NVIDIA NIM for Woz/Ananta overflow)
|
||||||
|
- Modular structure enables parallel specialist work
|
||||||
|
- Clear gates and review processes match the prescribed workflow
|
||||||
|
- **Engineering Utility**:
|
||||||
|
- Numerical methods (derivative/integral/solve) directly applicable to Battery Cart FEA and vACC flight planning
|
||||||
|
- Unit/currency systems tailored to stakeholder's project domains
|
||||||
|
- Keyboard-efficient workflow matches professional workflows
|
||||||
|
- **Production Quality**:
|
||||||
|
- Performance targets met via memoization, virtual scrolling, efficient algorithms
|
||||||
|
- Maintainability via modularity, tested core, clear extension points
|
||||||
|
- Accessibility and responsiveness addressed from the start
|
||||||
|
|
||||||
|
**New Development Workflow Enhancement**:
|
||||||
|
- Specialists follow structured commit, notify, document, push cycle
|
||||||
|
- Turing generates commit changes documents for transparency and knowledge sharing
|
||||||
|
- Ensures full traceability of changes for framework evaluation purposes
|
||||||
|
|
||||||
|
**Next Steps Upon Stakeholder Approval of this SAD**:
|
||||||
|
1. Proceed to **Phase 5: Orchestration (Woz)**
|
||||||
|
- Woz distributes tasks to specialists with Gilfoyle's security review embedded from the start
|
||||||
|
- Development begins under stakeholder oversight
|
||||||
|
2. Proceed to **Phase 6: Development (Specialists)**
|
||||||
|
- Regular commits after each bite-sized task (2-5 min focus)
|
||||||
|
- After each local commit: notify Turing → Turing generates commit changes document → push to GitHub/Gitea
|
||||||
|
- Stakeholder approval required before moving to review phase
|
||||||
|
3. Proceed to **Phase 7: Independent Review (Satya & Sundar)**
|
||||||
|
- Satya (Review): Code quality, spec compliance, best practices
|
||||||
|
- Sundar (Test): Functional testing, edge cases, performance, accessibility
|
||||||
|
- Work independently as specified
|
||||||
|
4. Proceed to **Phase 8: Deployment (Jenson)**
|
||||||
|
- Release to target (local testing environment)
|
||||||
|
- Stakeholder final go/no-go
|
||||||
|
|
||||||
|
This architecture provides a solid foundation for evaluating the Hermes Agent framework while delivering a genuinely useful tool for the stakeholder's engineering and project management workflows.
|
||||||
|
|
||||||
|
---
|
||||||
|
*End of SAD*
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Commit Changes Document
|
||||||
|
**Commit:** c449352
|
||||||
|
**Branch:** master
|
||||||
|
**Timestamp:** 2026-07-27T10:45:00Z
|
||||||
|
**Specialist:** Linus (Backend Specialist)
|
||||||
|
**Module:** Math Engine - Numerical Methods
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Implemented the numerical methods module for the scientific calculator, providing derivative, integral, and equation solving capabilities as first-class syntax functions.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- `src/core/math/NumericalMethods.js`: Created new file containing:
|
||||||
|
- `derivative(expr, var, [h])`: Computes numerical derivative using central difference method with default h=1e-5
|
||||||
|
- `integral(expr, var, a, b, [n])`: Computes definite integral using adaptive Simpson's rule with error tolerance 1e-6
|
||||||
|
- `solve(expr, var, [guess])`: Finds roots using Newton-Raphson with secant-method fallback, max 100 iterations, tolerance 1e-10
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- [x] New feature
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] Refactor
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance improvement
|
||||||
|
- [ ] Security enhancement
|
||||||
|
|
||||||
|
## Related To
|
||||||
|
- [x] Math Engine
|
||||||
|
- [ ] Unit Conversion
|
||||||
|
- [ ] Currency Conversion
|
||||||
|
- [ ] History System
|
||||||
|
- [ ] Theme System
|
||||||
|
- [ ] Mode System
|
||||||
|
- [ ] UI Components
|
||||||
|
- [ ] Utils
|
||||||
|
- [ ] Animation System
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- All methods reuse the existing expression parser's sanitization and evaluation pipeline, maintaining the security guarantees of the allowlist-based approach.
|
||||||
|
- The implementation follows the specifications in the SAD section 3.1.4 Numerical Methods.
|
||||||
|
- Error handling includes: invalid expressions, non-convergence, and domain violations.
|
||||||
|
- The module is designed to be imported and used by the math engine's public API.
|
||||||
|
- No external dependencies; pure JavaScript implementation.
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Commit Changes Document
|
||||||
|
**Commit:** '${commit}'
|
||||||
|
**Branch:** master
|
||||||
|
**Timestamp:** $(git show -s --format=%ci ${commit})
|
||||||
|
**Specialist:** Linus (Backend Specialist)
|
||||||
|
**Module:** Math Engine - $(case ${commit} in 56bfb25) echo "Expression Parser" ;; 88db038) echo "Scientific Functions" ;; c449352) echo "Numerical Methods" ;; esac)
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Implemented the $(case ${commit} in 56bfb25) echo "ExpressionParser.js module" ;; 88db038) echo "ScientificFunctions.js module" ;; c449352) echo "NumericalMethods.js module" ;; esac) for the scientific calculator.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- src/core/math/$(case ${commit} in 56bfb25) echo "ExpressionParser.js" ;; 88db038) echo "ScientificFunctions.js" ;; c449352) echo "NumericalMethods.js" ;; esac): $(case ${commit} in 56bfb25) echo "Created new file containing:" ;; 88db038) echo "Created new file containing:" ;; c449352) echo "Created new file containing:" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Allowlist validation for input sanitization" ;; 88db038) echo " - Export: Object mapping function names to implementations" ;; c449352) echo " - Implemented derivative, integral, and solve functions" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Constant substitution (pi→Math.PI, e→Math.E, ans→history value)" ;; 88db038) echo " - Includes: Trig, hyperbolic, exp/log, sqrt/cbrt, abs/ceil/floor/round, factorial/nCr/nPr, random" ;; c449352) echo " - Derivative: Central difference with h=1e-5 default" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Function whitelisting + replacement (sin(→Math.sin()" ;; 88db038) echo " - All implementations are pure JavaScript with no external dependencies" ;; c449352) echo " - Integral: Adaptive Simpson's Rule with error tolerance 1e-6" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Safe evaluation via Function constructor on sanitized string (never eval)" ;; 88db038) echo " - Ready for Gilfoyle's security review" ;; c449352) echo " - Solve: Newton-Raphson with secant fallback, max 100 iterations, tolerance 1e-10" ;; esac)
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- [x] New feature
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] Refactor
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance improvement
|
||||||
|
- [ ] Security enhancement
|
||||||
|
|
||||||
|
## Related To
|
||||||
|
- [x] Math Engine
|
||||||
|
- [ ] Unit Conversion
|
||||||
|
- [ ] Currency Conversion
|
||||||
|
- [ ] History System
|
||||||
|
- [ ] Theme System
|
||||||
|
- [ ] Mode System
|
||||||
|
- [ ] UI Components
|
||||||
|
- [ ] Utils
|
||||||
|
- [ ] Animation System
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- All methods reuse the existing expression parser's sanitization and evaluation pipeline, maintaining the security guarantees of the allowlist-based approach.
|
||||||
|
- The implementation follows the specifications in the SAD section 3.2.1 Math Engine.
|
||||||
|
- Error handling includes: invalid expressions, non-convergence, and domain violations.
|
||||||
|
- The module is designed to be imported and used by the math engine's public API.
|
||||||
|
- No external dependencies; pure JavaScript implementation.
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Commit Changes Document
|
||||||
|
**Commit:** '${commit}'
|
||||||
|
**Branch:** master
|
||||||
|
**Timestamp:** $(git show -s --format=%ci ${commit})
|
||||||
|
**Specialist:** Linus (Backend Specialist)
|
||||||
|
**Module:** Math Engine - $(case ${commit} in 56bfb25) echo "Expression Parser" ;; 88db038) echo "Scientific Functions" ;; c449352) echo "Numerical Methods" ;; esac)
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Implemented the $(case ${commit} in 56bfb25) echo "ExpressionParser.js module" ;; 88db038) echo "ScientificFunctions.js module" ;; c449352) echo "NumericalMethods.js module" ;; esac) for the scientific calculator.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- src/core/math/$(case ${commit} in 56bfb25) echo "ExpressionParser.js" ;; 88db038) echo "ScientificFunctions.js" ;; c449352) echo "NumericalMethods.js" ;; esac): $(case ${commit} in 56bfb25) echo "Created new file containing:" ;; 88db038) echo "Created new file containing:" ;; c449352) echo "Created new file containing:" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Allowlist validation for input sanitization" ;; 88db038) echo " - Export: Object mapping function names to implementations" ;; c449352) echo " - Implemented derivative, integral, and solve functions" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Constant substitution (pi→Math.PI, e→Math.E, ans→history value)" ;; 88db038) echo " - Includes: Trig, hyperbolic, exp/log, sqrt/cbrt, abs/ceil/floor/round, factorial/nCr/nPr, random" ;; c449352) echo " - Derivative: Central difference with h=1e-5 default" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Function whitelisting + replacement (sin(→Math.sin()" ;; 88db038) echo " - All implementations are pure JavaScript with no external dependencies" ;; c449352) echo " - Integral: Adaptive Simpson's Rule with error tolerance 1e-6" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Safe evaluation via Function constructor on sanitized string (never eval)" ;; 88db038) echo " - Ready for Gilfoyle's security review" ;; c449352) echo " - Solve: Newton-Raphson with secant fallback, max 100 iterations, tolerance 1e-10" ;; esac)
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- [x] New feature
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] Refactor
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance improvement
|
||||||
|
- [ ] Security enhancement
|
||||||
|
|
||||||
|
## Related To
|
||||||
|
- [x] Math Engine
|
||||||
|
- [ ] Unit Conversion
|
||||||
|
- [ ] Currency Conversion
|
||||||
|
- [ ] History System
|
||||||
|
- [ ] Theme System
|
||||||
|
- [ ] Mode System
|
||||||
|
- [ ] UI Components
|
||||||
|
- [ ] Utils
|
||||||
|
- [ ] Animation System
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- All methods reuse the existing expression parser's sanitization and evaluation pipeline, maintaining the security guarantees of the allowlist-based approach.
|
||||||
|
- The implementation follows the specifications in the SAD section 3.2.1 Math Engine.
|
||||||
|
- Error handling includes: invalid expressions, non-convergence, and domain violations.
|
||||||
|
- The module is designed to be imported and used by the math engine's public API.
|
||||||
|
- No external dependencies; pure JavaScript implementation.
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Commit Changes Document
|
||||||
|
**Commit:** '${commit}'
|
||||||
|
**Branch:** master
|
||||||
|
**Timestamp:** $(git show -s --format=%ci ${commit})
|
||||||
|
**Specialist:** Linus (Backend Specialist)
|
||||||
|
**Module:** Math Engine - $(case ${commit} in 56bfb25) echo "Expression Parser" ;; 88db038) echo "Scientific Functions" ;; c449352) echo "Numerical Methods" ;; esac)
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Implemented the $(case ${commit} in 56bfb25) echo "ExpressionParser.js module" ;; 88db038) echo "ScientificFunctions.js module" ;; c449352) echo "NumericalMethods.js module" ;; esac) for the scientific calculator.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- src/core/math/$(case ${commit} in 56bfb25) echo "ExpressionParser.js" ;; 88db038) echo "ScientificFunctions.js" ;; c449352) echo "NumericalMethods.js" ;; esac): $(case ${commit} in 56bfb25) echo "Created new file containing:" ;; 88db038) echo "Created new file containing:" ;; c449352) echo "Created new file containing:" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Allowlist validation for input sanitization" ;; 88db038) echo " - Export: Object mapping function names to implementations" ;; c449352) echo " - Implemented derivative, integral, and solve functions" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Constant substitution (pi→Math.PI, e→Math.E, ans→history value)" ;; 88db038) echo " - Includes: Trig, hyperbolic, exp/log, sqrt/cbrt, abs/ceil/floor/round, factorial/nCr/nPr, random" ;; c449352) echo " - Derivative: Central difference with h=1e-5 default" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Function whitelisting + replacement (sin(→Math.sin()" ;; 88db038) echo " - All implementations are pure JavaScript with no external dependencies" ;; c449352) echo " - Integral: Adaptive Simpson's Rule with error tolerance 1e-6" ;; esac)
|
||||||
|
- $(case ${commit} in 56bfb25) echo " - Safe evaluation via Function constructor on sanitized string (never eval)" ;; 88db038) echo " - Ready for Gilfoyle's security review" ;; c449352) echo " - Solve: Newton-Raphson with secant fallback, max 100 iterations, tolerance 1e-10" ;; esac)
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- [x] New feature
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] Refactor
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance improvement
|
||||||
|
- [ ] Security enhancement
|
||||||
|
|
||||||
|
## Related To
|
||||||
|
- [x] Math Engine
|
||||||
|
- [ ] Unit Conversion
|
||||||
|
- [ ] Currency Conversion
|
||||||
|
- [ ] History System
|
||||||
|
- [ ] Theme System
|
||||||
|
- [ ] Mode System
|
||||||
|
- [ ] UI Components
|
||||||
|
- [ ] Utils
|
||||||
|
- [ ] Animation System
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- All methods reuse the existing expression parser's sanitization and evaluation pipeline, maintaining the security guarantees of the allowlist-based approach.
|
||||||
|
- The implementation follows the specifications in the SAD section 3.2.1 Math Engine.
|
||||||
|
- Error handling includes: invalid expressions, non-convergence, and domain violations.
|
||||||
|
- The module is designed to be imported and used by the math engine's public API.
|
||||||
|
- No external dependencies; pure JavaScript implementation.
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
# Unit & Currency Conversion Systems - Design Proposal
|
||||||
|
|
||||||
|
## ✅ Context: Continuing Our Iterative Design Phase (Ada's Role)
|
||||||
|
|
||||||
|
Having finalized the math engine design through our collaborative back-and-forth, we now proceed to the next topic: **Unit & Currency Conversion Systems**. This proposal incorporates:
|
||||||
|
- Your project context (Hybrutos Racing Battery Cart, vACC event management, homelab)
|
||||||
|
- Security-first principles (Gilfoyle's review focus)
|
||||||
|
- Your UI/UX preferences (keyboard efficiency, dark theme, animations)
|
||||||
|
- Framework testing constraints (no live API calls, local-only)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **Proposed Conversion System Architecture**
|
||||||
|
|
||||||
|
### 🎯 **Core Design Goals**
|
||||||
|
1. **Relevance**: Prioritize units used in your Battery Cart (electrochemistry, mechanics, thermal), vACC (aviation, event logistics), and homelab (self-hosted services, monitoring)
|
||||||
|
2. **Security**: Reuse the same sanitized expression parser framework—no new attack surface for Gilfoyle
|
||||||
|
3. **Keyboard Efficiency**: Primary access via expression syntax (e.g., `convert(100, "V", "mV")`), no mandatory mode switching
|
||||||
|
4. **Extensibility**: Easy to add new units/currencies later without breaking changes
|
||||||
|
5. **Isolation**: All conversions use manual input/data—zero external dependencies for framework purity
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📏 **Unit Conversion System**
|
||||||
|
|
||||||
|
### ⚙️ **Approach: Categorized, Bidirectional Conversion**
|
||||||
|
We define conversion **categories**—each with its own set of interconvertible units. Within a category, any unit can convert to any other.
|
||||||
|
|
||||||
|
#### 🔋 **Recommended Categories (Based on Your Projects)**
|
||||||
|
| Category | Key Units | Relevance to Your Work |
|
||||||
|
|----------|-----------|------------------------|
|
||||||
|
| **Electrical** | V, mV, kV, μV; A, mA, μA, nA; Ω, kΩ, MΩ; F, μF, pF, nF; W, kW, MW; J, kWh, Wh; C, Ah, mAh | Battery voltage/current/resistance/capacitance/power/energy/charge; telemetry sensing; solar panel specs |
|
||||||
|
| **Mechanical** | N, kN; kgf, lbf; Pa, kPa, MPa, bar, psi; m/s, km/h, mph; m/s², g; Nm, ft·lb; Hz, RPM | Battery structural loads (Al 6061-T6); brake force; tire pressure; vehicle speed/acceleration; torque; vibration analysis |
|
||||||
|
| **Thermal** | K, °C, °F; J/(kg·K), J/(g·°C); W/(m·K); W, kW | Battery thermal management; heat dissipation in enclosures; ambient temperature effects; cooling system design |
|
||||||
|
| **Volume** | L, mL, μL, cm³, in³, ft³; tsp, tbsp, fl oz, cup, pt, qt, gal | Battery electrolyte volumes; coolant reservoirs; cleaning solution mixing |
|
||||||
|
| **Mass** | kg, g, mg, μg, lb, oz | Cell casing materials; sensor weights; payload calculations for drones (if applicable) |
|
||||||
|
| **Time** | s, ms, μs, ns; min, h, d; yr | Sampling rates; event timing (vACC); log timestamps; battery cycle life |
|
||||||
|
| **Frequency** | Hz, kHz, MHz, GHz; RPM | Clock speeds; signal processing; motor rotational speed; radio frequencies (homelab) |
|
||||||
|
| **Data** | bit, byte, KB, MB, GB, TB; KiB, MiB, GiB, TiB | Storage capacity (Gitea/Immich/Jellyfin); RAM usage; network bandwidth |
|
||||||
|
|
||||||
|
#### 🔐 **Security Integration (Gilfoyle's Focus)**
|
||||||
|
- **Same sanitization pipeline** as math engine:
|
||||||
|
- Input: `convert(100, "V", "mV")` →
|
||||||
|
- Validate: digits, decimal, commas, spaces, letters (only in unit strings), parentheses
|
||||||
|
- Whitelist allowed unit symbols (from predefined list per category)
|
||||||
|
- Convert to canonical form: `convert(100, "volt", "millivolt")` (case-insensitive, singular/plural handling)
|
||||||
|
- Evaluation: Pure mathematical operation (value × conversion factor)
|
||||||
|
- **No dynamic code execution**—conversion factors are hardcoded constants
|
||||||
|
- **Critical**: Unit strings are **never** evaluated as code—they're looked up in a map
|
||||||
|
- **Outcome**: Single, auditable validation point (same as math engine); zero added risk
|
||||||
|
|
||||||
|
#### ⚡ **Numerical Precision & Handling**
|
||||||
|
- Conversion factors stored as high-precision numbers (e.g., 1 inch = 0.0254 m exactly)
|
||||||
|
- Results rounded to **significant figures** based on input precision (or fixed 10 sig figs for display)
|
||||||
|
- Temperature: Special handling for offset scales (see below)
|
||||||
|
- Invalid unit pairs (e.g., "V → ): return error
|
||||||
|
|
||||||
|
#### 🌡️ **Temperature Special Handling**
|
||||||
|
Temperature requires offset scaling (not purely multiplicative):
|
||||||
|
- **Kelvin (K)**: Absolute scale
|
||||||
|
- **Celsius (°C)**: `T_K = T_°C + 273.15`
|
||||||
|
- **Fahrenheit (°F)**: `T_K = (T_°F + 459.67) × 5/9`
|
||||||
|
- Implementation:
|
||||||
|
- Convert input → Kelvin (using offset formula)
|
||||||
|
- Convert Kelvin → target unit (using inverse offset formula)
|
||||||
|
- Units: `K`, `C` or `°C`, `F` or `°F` (we'll normalize input)
|
||||||
|
|
||||||
|
#### ⌨️ **UI/UX for Exposure (Keyboard-First)**
|
||||||
|
- **Primary Access**: Direct syntax in expression bar:
|
||||||
|
- `convert(150, "psi", "kPa")` → `1034.21`
|
||||||
|
- `convert(25, "C", "F")` → `77`
|
||||||
|
- `convert(500, "mL", "L")` → `0.5`
|
||||||
|
- **Discoverability**:
|
||||||
|
- Tooltips on unit/category buttons showing examples
|
||||||
|
- History: `convert(100, "V", "mV") = 100000`
|
||||||
|
- Click-to-insert: tap history to reuse
|
||||||
|
- **Optional**:
|
||||||
|
- "Unit Converter" mode (like scientific/shift) for touch users—but **never required** for keyboard workflow
|
||||||
|
- Favorite conversions panel (user-pinnable frequent pairs)
|
||||||
|
|
||||||
|
#### 📐 **Example Conversions Relevant to You**
|
||||||
|
| Use Case | Conversion | Result |
|
||||||
|
|----------|------------|--------|
|
||||||
|
| Battery Cart: Voltage sensing | `convert(3.7, "V", "mV")` | `3700` |
|
||||||
|
| Battery Cart: Current shunt | `convert(50, "mA", "A")` | `0.05` |
|
||||||
|
| Battery Cart: Capacitance | `convert(470, "μF", "F")` | `0.00047` |
|
||||||
|
| vACC: Runway length | `convert(8000, "ft", "m")` | `2438.4` |
|
||||||
|
| vACC: Fuel flow | `convert(12, "gal/h", "L/s")` | `0.126` |
|
||||||
|
| Homelab: Disk space | `convert(4, "TB", "GB")` | `4096` |
|
||||||
|
| Homelab: Network speed | `convert(100, "Mbps", "MB/s")` | `12.5` |
|
||||||
|
| Thermodynamics: Battery temp | `convert(25, "C", "K")` | `298.15` |
|
||||||
|
| Electrochemistry: Charge | `convert(2, "Ah", "C")` | `7200` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💱 **Currency Conversion System**
|
||||||
|
|
||||||
|
### 🌍 **Approach: Manual-Rate Based (For Framework Isolation)**
|
||||||
|
Per your requirement for a standalone utility testing the Hermes agent framework, we **exclude live API calls**. Instead:
|
||||||
|
- User manually enters exchange rates (updated as needed)
|
||||||
|
- System stores rates with timestamps
|
||||||
|
- All conversions use these fixed rates
|
||||||
|
- Zero external dependencies → perfect for isolated framework testing
|
||||||
|
|
||||||
|
### 💰 **Supported Currencies (Per Your Request: INR, USD, GBP, etc.)**
|
||||||
|
We'll start with your requested set plus common pairs for travel/trading:
|
||||||
|
| Currency | Code | Symbol | Notes |
|
||||||
|
|----------|------|--------|-------|
|
||||||
|
| Indian Rupee | INR | ₹ | Your home currency |
|
||||||
|
| US Dollar | USD | $ | Global reserve currency |
|
||||||
|
| British Pound | GBP | £ | Common for international events |
|
||||||
|
| Euro | EUR | € | Widely used |
|
||||||
|
| Japanese Yen | JPY | ¥ | Tech hardware pricing |
|
||||||
|
| Canadian Dollar | CAD | $ | North American trade |
|
||||||
|
| Australian Dollar | AUD | $ | Asia-Pacific relevant |
|
||||||
|
| Swiss Franc | CHF | CHF | Optional (financial hub) |
|
||||||
|
| Chinese Yuan | CNY | ¥ | Manufacturing costs |
|
||||||
|
|
||||||
|
### 🔐 **Security Integration**
|
||||||
|
- **Same pattern**:
|
||||||
|
- Input: `convert(1000, "INR", "USD")` →
|
||||||
|
- Validate: numbers, currency codes (3-letter uppercase whitelist)
|
||||||
|
- Lookup rate from internal table (no eval)
|
||||||
|
- Compute: `amount × (rate_to / rate_from)`
|
||||||
|
- **No risk**: Currency codes are lookup keys, never evaluated as code
|
||||||
|
- **Rate storage**: Simple JSON object in localState (e.g., `{ "USD_INR": 83.5, "EUR_USD": 1.08 }`)
|
||||||
|
|
||||||
|
### 📈 **Rate Management**
|
||||||
|
- **Manual Entry**:
|
||||||
|
- "Manage Rates" panel (optional, not required for basic use)
|
||||||
|
- Table: From ▼ [USD] → To ▼ [INR] | Rate: ______ | [Update]
|
||||||
|
- Auto-calculates inverse (if USD→INR = 83.5, then INR→USD = 1/83.5)
|
||||||
|
- **Timestamp**: Each rate stores last-updated time (user sees "Rate updated: 2h ago")
|
||||||
|
- **Default Rates**: Pre-populated with approximate values (clearly marked as "defaults—update for accuracy")
|
||||||
|
- **Validation**: Reject non-numeric/negative rates; warn if suspiciously far from market (optional)
|
||||||
|
|
||||||
|
### ⌨️ **UI/UX for Exposure**
|
||||||
|
- **Primary Access**: Direct syntax:
|
||||||
|
- `convert(1000, "INR", "USD")` → `12.01` (if 1 USD = 83.5 INR)
|
||||||
|
- `convert(50, "EUR", "GBP")` → `43.10`
|
||||||
|
- **Discoverability**:
|
||||||
|
- Tooltips showing example pairs
|
||||||
|
- History: `convert(1000, "INR", "USD") = 12.01 USD`
|
||||||
|
- Click-to-insert
|
||||||
|
- **Optional**: Currency converter mode (toggle via UI—but keyboard syntax always works)
|
||||||
|
|
||||||
|
### 💱 **Example Conversions Relevant to You**
|
||||||
|
| Use Case | Conversion | Result (at 1 USD = 83.5 INR, 1 EUR = 1.08 USD) |
|
||||||
|
|----------|------------|------------------------------------------------|
|
||||||
|
| vACC Event: Budget | `convert(50000, "INR", "USD")` | `598.80` |
|
||||||
|
| vACC Event: Fuel cost | `convert(150, "EUR", "INR")` | `13522.50` |
|
||||||
|
| Hardware: Component cost | `convert(299, "USD", "INR")` | `24966.50` |
|
||||||
|
| Subscription: Service fee | `convert(9.99, "USD", "INR")` | `834.17` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **Integration with Calculator Core**
|
||||||
|
|
||||||
|
### 🧮 **Unified Expression Syntax**
|
||||||
|
Both unit and currency conversions use the **same function** to maintain simplicity:
|
||||||
|
```
|
||||||
|
convert(<value>, <from_unit>, <to_unit>)
|
||||||
|
```
|
||||||
|
- **Units**:
|
||||||
|
- Unit conversion: `"V"`, `"mA"`, `"°C"`, `"L"`, `"kg"` etc.
|
||||||
|
- Currency conversion: `"INR"`, `"USD"`, `"GBP"` etc.
|
||||||
|
- **Disambiguation**:
|
||||||
|
- System checks if arguments match known unit categories first
|
||||||
|
- If not found, checks currency codes
|
||||||
|
- Error if neither (or ambiguous—e.g., if we had a unit named "USD", but we won't)
|
||||||
|
- **Examples**:
|
||||||
|
- `convert(5, "ft", "m")` → `1.524` (unit)
|
||||||
|
- `convert(5, "USD", "EUR")` → `4.63` (currency)
|
||||||
|
- `convert(100, "V", "mV")` → `100000` (unit)
|
||||||
|
|
||||||
|
### 📜 **History & Re-use**
|
||||||
|
- All conversions appear in history with full expression:
|
||||||
|
- `convert(100, "V", "mV") = 100000`
|
||||||
|
- `convert(1000, "INR", "USD") = 11.98`
|
||||||
|
- Click-to-insert: reuse past conversions in new expressions
|
||||||
|
- Chain conversions: `convert(convert(100, "USD", "INR"), "INR", "JPY")`
|
||||||
|
|
||||||
|
### 🎨 **UI/UX Consistency**
|
||||||
|
- Shares the **same theme** (dark/light) and **animation system** (Framer Motion) as calculator
|
||||||
|
- Conversion results appear in the **same display** as calculations
|
||||||
|
- Input uses the **same expression bar**—no context switching
|
||||||
|
- Tooltips, hover effects, and feedback patterns match calculator buttons
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **Summary: Conversion System Proposal**
|
||||||
|
|
||||||
|
| Component | Specification | Status |
|
||||||
|
|-----------|---------------|--------|
|
||||||
|
| **Unit Categories** | Electrical, Mechanical, Thermal, Volume, Mass, Time, Frequency, Data (others addable) | ⏳ Proposed |
|
||||||
|
| **Key Units** | Tailored to your Battery Cart, vACC, homelab projects (see tables above) | ⏳ Proposed |
|
||||||
|
| **Conversion Method** | `convert(<value>, <from>, <to>)` syntax | ⏳ Proposed |
|
||||||
|
| **Security** | Reuses math engine sanitizer; unit/currency as lookup keys (no eval) | ⏳ Proposed (Gilfoyle-safe) |
|
||||||
|
| **Temperature** | Special offset handling (K↔°C↔°F) | ⏳ Proposed |
|
||||||
|
| **Currency** | Manual rate input only (INR, USD, GBP, EUR, JPY, CAD, AUD +); timestamps | ⏳ Proposed |
|
||||||
|
| **UI/UX** | Direct syntax typing; tooltips; history display; click-to-insert; optional mode | ⏳ Proposed |
|
||||||
|
| **Persistence** | Rates & favorites in localState (separate from calc history) | ⏳ Proposed |
|
||||||
|
| **Defaults** | Pre-populated approximate rates (user-overridable) | ⏳ Proposed |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **Next Step: Your Feedback Requested**
|
||||||
|
|
||||||
|
Please confirm or adjust:
|
||||||
|
|
||||||
|
### 📏 **Unit Conversion**
|
||||||
|
1. **Categories**:
|
||||||
|
- Are the proposed 8 categories aligned with your project needs?
|
||||||
|
- Any missing categories critical for your work (e.g., luminous intensity for lighting projects, radiation dose for experiments)?
|
||||||
|
- Should we prioritize certain categories for initial implementation?
|
||||||
|
|
||||||
|
2. **Specific Units**:
|
||||||
|
- Any units you frequently convert that aren't listed (e.g., for battery capacity: Ah, mAh; for airflow: CFM, m³/s; for pressure: Torr, mmHg)?
|
||||||
|
- Temperature: Any preference for unit symbols (we propose `K`, `C`, `F`—should we accept `°C`, `°F` as aliases)?
|
||||||
|
- Data: Use SI (kB = 1000 B) or binary (KiB = 1024 B)? (We propose SI for consistency with storage marketing, but note binary is common in OS)
|
||||||
|
|
||||||
|
3. **Syntax & UX**:
|
||||||
|
- Is the `convert(value, "from", "to")` syntax intuitive for your workflow?
|
||||||
|
- Should we add aliases (e.g., `conv()` shorthand)?
|
||||||
|
- Any preferences for how complex conversions appear in history?
|
||||||
|
|
||||||
|
### 💱 **Currency Conversion**
|
||||||
|
1. **Currencies**:
|
||||||
|
- Is the proposed set (INR, USD, GBP, EUR, JPY, CAD, AUD) sufficient?
|
||||||
|
- Any others you'd like to include initially (e.g., CHF, CNY, SGD)?
|
||||||
|
2. **Rate Management**:
|
||||||
|
- Preferred default source for initial rates (e.g., xe.com, Google Finance, or manual entry only)?
|
||||||
|
- How often would you expect to update rates for your use cases (daily, weekly, per trip)?
|
||||||
|
3. **Syntax**:
|
||||||
|
- Same `convert()` function for units and currency—does this cause confusion, or is the context clear from the arguments?
|
||||||
|
|
||||||
|
### 🧪 **Validation & Testing**
|
||||||
|
- Should we add any sanity checks (e.g., warn if converting electron volts to joules yields unexpected scale)?
|
||||||
|
- Any edge cases you've encountered in your projects that we should handle gracefully?
|
||||||
|
|
||||||
|
Once you confirm the conversion system design, we'll have completed the **full technical plan** for your formal approval. After that:
|
||||||
|
1. Turing writes the **SAD** (Solution Architecture Document) based on this agreed plan
|
||||||
|
2. You review and approve the **SAD**
|
||||||
|
3. Woz distributes tasks to specialists (with Gilfoyle's security review embedded from the start)
|
||||||
|
4. Development proceeds under your oversight
|
||||||
|
|
||||||
|
Your guidance on the conversion system is now awaited—this is our collaborative design phase in action. I await your input to refine this to your exact satisfaction.
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
# Math Engine Design - Agreed Specifications
|
||||||
|
|
||||||
|
## ✅ Fully Agreed Upon (Per Iterative Design Phase)
|
||||||
|
|
||||||
|
### 1. State Management
|
||||||
|
- **Approach**: React Context API with `useReducer` for global state (theme, mode, calculation/history)
|
||||||
|
- **Persistence**: localStorage for history and theme preference
|
||||||
|
- **Corruption Handling**: On localStorage corruption/Session corruption/data mismatch, restore last known good state
|
||||||
|
- **Rationale**: Avoids external libraries (Redux/Zustand), keeps bundle size appropriate for scope, matches user's "NO" to additional persistence requirements
|
||||||
|
|
||||||
|
### 2. Core Expression Processor
|
||||||
|
- **Input Sanitization** (Gilfoyle's Security Focus):
|
||||||
|
- Strict allowlist: digits (`0-9`), decimal (`.`), operators (`+-*/().`), whitespace
|
||||||
|
- Constants: `e` (Euler's number), `pi` (π)
|
||||||
|
- Whitelisted function names: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`, `exp`, `log` (base 10), `ln` (natural), `sqrt`, `cbrt`, `abs`, `ceil`, `floor`, `round`, `random`, `factorial`, `nCr`, `nPr`
|
||||||
|
- Constant substitution: `pi` → `Math.PI`, `e` → `Math.E`
|
||||||
|
- Special handling: `ans` → last valid history value (if numeric)
|
||||||
|
- Function replacement: `sin(` → `Math.sin(` (etc.) before evaluation
|
||||||
|
- **Evaluation**: `Function` constructor **only** on fully sanitized string (never `eval`)
|
||||||
|
- **Error Handling**: Returns `{value: null, error: string}` for invalid expressions
|
||||||
|
- **Outcome**: Single, auditable sanitization point for Gilfoyle's review
|
||||||
|
|
||||||
|
### 3. Scientific Functions (Standard Set)
|
||||||
|
- Trigonometric: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`
|
||||||
|
- Hyperbolic: `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`
|
||||||
|
- Exponential/Logarithmic: `exp`, `log` (base 10), `ln` (natural)
|
||||||
|
- Root/Power: `sqrt`, `cbrt`, `**` (exponentiation)
|
||||||
|
- Absolute/Rounding: `abs`, `ceil`, `floor`, `round`
|
||||||
|
- Combinatorics: `factorial` (n!), `nCr` (combinations), `nPr` (permutations)
|
||||||
|
- Random: `random` ([0,1) uniform distribution)
|
||||||
|
- Constants: `e` (Euler's number), `pi` (π)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔢 **Agreed Extensions (Per User Confirmation)**
|
||||||
|
|
||||||
|
### ➕ **Additional Mathematical Constants**
|
||||||
|
*(User confirmed: "Yes, add constants")*
|
||||||
|
All defined as pure numbers (unit awareness deferred to later phase per user request):
|
||||||
|
|
||||||
|
| Symbol | Value | Description |
|
||||||
|
|--------|-------|-------------|
|
||||||
|
| `c` | 299792458 | Speed of light (m/s) |
|
||||||
|
| `g` | 9.80665 | Standard gravity (m/s²) |
|
||||||
|
| `NA` | 6.02214076e23 | Avogadro's number (mol⁻¹) |
|
||||||
|
| `R` | 8.314462618 | Molar gas constant (J/(mol·K)) |
|
||||||
|
| `q_e` | 1.602176634e-19 | Elementary charge (C) *[Note: `e` reserved for Euler's number]* |
|
||||||
|
| `kB` | 1.380649e-23 | Boltzmann constant (J/K) |
|
||||||
|
| `atm` | 101325 | Standard atmosphere (Pa) |
|
||||||
|
|
||||||
|
**Rationale**: Covers mechanics (`g`), electrochemistry (`NA`, `q_e`), thermodynamics (`R`, `kB`), and gas laws (`atm`, `c`) relevant to:
|
||||||
|
- Hybrutos Racing: Battery thermal management, electrochemical reactions, structural mechanics
|
||||||
|
- vACC: Pressure conversions, timing calculations
|
||||||
|
- Homelab: Sensor calibration, thermodynamic monitoring
|
||||||
|
|
||||||
|
### ➕ **Numerical Methods as First-Class Syntax**
|
||||||
|
*(User confirmed interest in "basic numerical calculation" via earlier context; specific parameters approved below)*
|
||||||
|
|
||||||
|
All methods reuse the **sanitized expression parser**—no additional attack surface for Gilfoyle.
|
||||||
|
|
||||||
|
#### 1. `derivative(expr, var, [h])`
|
||||||
|
- **Purpose**: Approximate derivative of `expr` w.r.t. `var`
|
||||||
|
- **Method**: Central difference: `[f(var+h) - f(var-h)] / (2h)` (O(h²) accuracy)
|
||||||
|
- **Defaults**: `h = 1e-5` (optimal for double-precision precision)
|
||||||
|
- **Error Handling**:
|
||||||
|
- Invalid expression → returns error
|
||||||
|
- Non-numeric result after substitution → error
|
||||||
|
- Oscillation detected (discontinuity) → error with suggestion
|
||||||
|
- Max 20 iterations for adaptive step refinement (if needed)
|
||||||
|
- **Examples**:
|
||||||
|
- `derivative(x^2, x, 3)` → `6.0`
|
||||||
|
- `derivative(sin(x), x, 0)` → `1.0` (cos(0))
|
||||||
|
- `derivative(log(x), x, 1)` → `1.0`
|
||||||
|
|
||||||
|
#### 2. `integral(expr, var, a, b, [n])`
|
||||||
|
- **Purpose**: Approximate definite integral of `expr` from `a` to `b` w.r.t. `var`
|
||||||
|
- **var, Simpson's Rule with error-controlled subdivision
|
||||||
|
- **Defaults**: Target relative error `1e-6`, max subdivisions `2^10` (102. **Method**: Adaptive Simpson's Rule with error-controlled subdivision
|
||||||
|
- **Defaults**: Target relative error `1e-6`, max subdivisions `2^10` (1024)
|
||||||
|
- **Error Handling**:
|
||||||
|
- Requires `a < b` (automatically swaps & negates if reversed)
|
||||||
|
- Divergent integrals (e.g., `1/x` on `[0,1]`) → error
|
||||||
|
- Function evaluation cap prevents hanging
|
||||||
|
- **Examples**:
|
||||||
|
- `integral(x, x, 0, 2)` → `2.0`
|
||||||
|
- `integral(1, x, 0, 5)` → `5.0`
|
||||||
|
- `integral(exp(-x^2), x, -20, 20)` → `√π ≈ 1.7724538509` (Gaussian integral)
|
||||||
|
|
||||||
|
#### 3. `solve(expr, var, [guess])`
|
||||||
|
- **Purpose**: Find root of `expr ≈ 0` (solve for `var`)
|
||||||
|
- **Method**: Newton-Raphson with secant-method fallback (avoids needing analytical derivative)
|
||||||
|
- **Defaults**: `guess = 0`, max iterations `100`, tolerance `1e-10`
|
||||||
|
- **Error Handling**:
|
||||||
|
- Failure to converge → error with suggestion to adjust guess
|
||||||
|
- Derivative too small → error (avoids division by near-zero)
|
||||||
|
- May return one root if multiple exist (dependent on initial guess)
|
||||||
|
- **Examples**:
|
||||||
|
- `solve(x^2-4, x)` → `2.0` or `-2.0` (depends on guess)
|
||||||
|
- `solve(sin(x), x, 3)` → `3.1415926535` (π)
|
||||||
|
- `solve(exp(x)-2, x)` → `0.69314718056` (ln(2))
|
||||||
|
|
||||||
|
**Parameter Justification**:
|
||||||
|
- `h=1e-5`: Balances truncation and round-off error for double precision
|
||||||
|
- `tol=1e-6` (integral): Sufficient for engineering accuracy (0.0001% error)
|
||||||
|
- `maxIter=100` (solve): More than enough for well-behaved functions; prevents infinite loops
|
||||||
|
- These are standard defaults in numerical libraries (NumPy, SciPy, MATLAB)
|
||||||
|
|
||||||
|
### ⌨️ **UI/UX for Numerical Methods Exposure**
|
||||||
|
*(User confirmed keyboard-efficient workflow preference)*
|
||||||
|
|
||||||
|
- **Primary Access**: Direct syntax typing (e.g., `derivative(sin(x), x, 0)`)
|
||||||
|
- Always available in expression input (no mode switching required)
|
||||||
|
- Matches user's workflow for engineering calculations
|
||||||
|
- **Discoverability & Assistance**:
|
||||||
|
- Tooltips on function buttons showing syntax (e.g., hover over "deriv" → `derivative(expr, var, [h])`)
|
||||||
|
- History entries display full expression: `derivative(sin(x), x, 0) = 1.000000`
|
||||||
|
- Click-to-insert: Tap any history item to insert it at cursor position
|
||||||
|
- Optional: "f(x)=?" helper pane showing syntax examples (collapsible)
|
||||||
|
- **Validation**: Real-time syntax highlighting as user types (valid operators/functions in green, invalid in red)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **Summary: Math Engine Design Complete**
|
||||||
|
|
||||||
|
| Component | Specification | Status |
|
||||||
|
|-----------|---------------|--------|
|
||||||
|
| State Management | Context API + `useReducer`; localStorage; corruption → last good state | ✅ Agreed |
|
||||||
|
| Core Processor | Allowlist sanitization; function whitelist; safe `Function` eval | ✅ Agreed |
|
||||||
|
| Standard Functions | Trig, log, exp, sqrt, abs, rounding, factorial, nCr, nPr, random | ✅ Agreed |
|
||||||
|
| **Constants** | `c`, `g`, `NA`, `R`, `q_e`, `kB`, `atm` (pure numbers) | ✅ **Agreed** (per user confirmation) |
|
||||||
|
| **Numerical Methods** | `derivative`, `integral`, `solve` as first-class syntax | ✅ **Agreed** (per user confirmation + parameter approval) |
|
||||||
|
| Constant Naming | `e` = Euler's number; electron charge = `q_e` | ✅ Agreed (avoids conflict) |
|
||||||
|
| Unit Awareness | Deferred (treat as pure numbers now; add later) | ✅ Agreed (per user request) |
|
||||||
|
| UI/UX | Direct syntax typing; tooltips; history display; click-to-insert | ✅ Agreed (per workflow preference) |
|
||||||
|
|
||||||
|
**Next Step**: With the math engine design now fully agreed upon, we proceed to our next iterative topic:
|
||||||
|
**Unit & Currency Conversion Systems** (including your requested INR, USD, GBP, etc.).
|
||||||
|
|
||||||
|
I propose the following structure for our discussion:
|
||||||
|
1. **Unit Conversion**:
|
||||||
|
- Categories: Length, mass, temperature, volume, time, speed, pressure, energy, power
|
||||||
|
- Bidirectional conversion within each category
|
||||||
|
- Temperature special handling (offset scales)
|
||||||
|
- Common units: mm, cm, m, km, in, ft, yd, mi; mg, g, kg, oz, lb; °C, °F, K; ml, l, tsp, tbsp, fl oz, cup, pt, qt, gal; etc.
|
||||||
|
2. **Currency Conversion**:
|
||||||
|
- Manual rate input (no live API calls for framework isolation/testing)
|
||||||
|
- Supported currencies: INR, USD, GBP, EUR, JPY, CAD, AUD, CNY (user-extendable)
|
||||||
|
- Base currency selection + rate table
|
||||||
|
- Timestamp for rate validity (user-managed)
|
||||||
|
3. **Integration**:
|
||||||
|
- Conversion modes accessible via keypad (like scientific/shift layers)
|
||||||
|
- Expression syntax: `convert(100, "in", "cm")` or similar
|
||||||
|
- History tracking for conversions
|
||||||
|
- Shared number formatting with calculator
|
||||||
|
|
||||||
|
Please confirm if this approach aligns with your expectations, or share any specific preferences/conversions you'd prioritize for your projects (e.g., battery capacity units, airflow rates for vACC, etc.).
|
||||||
|
|
||||||
|
Once we agree on the conversion system design, we'll finalize the full technical plan for your formal approval before proceeding to the SAD (Turing) and specialist task distribution (Woz).
|
||||||
|
|
||||||
|
Your guidance on the conversion system is now awaited.
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
# Updated Math Engine Proposal (Post-Iteration Feedback)
|
||||||
|
|
||||||
|
## ✅ Agreed Decisions So Far
|
||||||
|
1. **State Management**: React Context API with `useReducer` for global state (theme, mode, calculation/history). localStorage for history/theme preference; on corruption, restore last known good state.
|
||||||
|
2. **Core Expression Parser**:
|
||||||
|
- Strict allowlist: digits, decimal, operators (`+-*/().`), whitespace, `e`, `pi`, and whitelisted function names
|
||||||
|
- Function whitelisting + safe replacement (e.g., `sin(` → `Math.sin(`)
|
||||||
|
- Constant substitution: `pi`→`Math.PI`, `e`→`Math.E`, `ans`→history value (if valid number)
|
||||||
|
- Safe evaluation via `Function` constructor **only** on fully sanitized string (never `eval`)
|
||||||
|
- Error handling: return `{value: null, error: string}` for invalid expressions
|
||||||
|
3. **Scientific Functions**: Standard trig, log, exp, root, abs, rounding, combinatorics (factorial, nCr, nPr), random
|
||||||
|
|
||||||
|
## 🔢 **Updated: Extended Math Engine with Numerical Methods & Constants**
|
||||||
|
|
||||||
|
### ➕ **Additional Constants (Per User Request: "Yes, add constants")**
|
||||||
|
We propose the following engineering/physics-relevant constants. All are pure numbers (unit awareness deferred to later phase):
|
||||||
|
|
||||||
|
| Constant | Symbol | Value | Description | Relevance to Your Projects |
|
||||||
|
|----------|--------|-------|-------------|----------------------------|
|
||||||
|
| Speed of light | `c` | 299792458 | m/s | Useful for EM simulations, timing analysis |
|
||||||
|
| Gravitational acceleration | `g` | 9.80665 | m/s² | Battery Cart mechanical analysis, brake force calculations |
|
||||||
|
| Avogadro's number | `NA` | 6.02214076e23 | mol⁻¹ | Electrochemistry (battery reactions) |
|
||||||
|
| Gas constant | `R` | 8.314462618 | J/(mol·K) | Thermodynamics (battery thermal management) |
|
||||||
|
| Electron charge | `e` | 1.602176634e-19 | C | Already reserved for Euler's number → we'll use `electronCharge` or `q_e` to avoid conflict |
|
||||||
|
| Planck's constant | `h` | 6.62607015e-34 | J·s | Quantum effects (less likely in current projects) |
|
||||||
|
| Boltzmann constant | `kB` | 1.380649e-23 | J/K | Statistical mechanics, thermal noise |
|
||||||
|
| Standard atmosphere | `atm` | 101325 | Pa | Pressure conversions, vacuum systems |
|
||||||
|
| Electron mass | `m_e` | 9.1093837015e-31 | kg | Particle physics (unlikely needed) |
|
||||||
|
| Proton mass | `m_p` | 1.67262192369e-27 | kg | Nucleon mass (unlikely needed) |
|
||||||
|
|
||||||
|
**Naming Note**: To avoid conflict with Euler's number (`e`), we will **not** expose `e` as electron charge. Instead:
|
||||||
|
- Keep `e` = Euler's number (2.71828...) as standard
|
||||||
|
- Provide electron charge as `q_e` or `electronCharge` (user preference)
|
||||||
|
- Similarly, we'll avoid other single-letter conflicts where possible (e.g., `m` for meters is problematic; we'll use explicit names)
|
||||||
|
|
||||||
|
**Proposed Constant Set for Initial Implementation**:
|
||||||
|
- `c` = 299792458 (speed of light)
|
||||||
|
- `g` = 9.80665 (gravitational acceleration)
|
||||||
|
- `NA` = 6.02214076e23 (Avogadro's number)
|
||||||
|
- `R` = 8.314462618 (gas constant)
|
||||||
|
- `q_e` = 1.602176634e-19 (electron charge)
|
||||||
|
- `kB` = 1.380649e-23 (Boltzmann constant)
|
||||||
|
- `atm` = 101325 (standard atmosphere)
|
||||||
|
|
||||||
|
We can add more later; this covers mechanics, electrochemistry, thermodynamics, and gas laws relevant to your Battery Cart and homelab projects.
|
||||||
|
|
||||||
|
### ➕ **Numerical Methods (Per User Selection: "Full scientific + basic numerical calc")**
|
||||||
|
We will implement three higher-order functions that accept expressions as arguments, enabling engineering calculations like those in your FEA work.
|
||||||
|
|
||||||
|
#### 1. `derivative(expr, var, [h])`
|
||||||
|
- **Purpose**: Approximate derivative of `expr` with respect to `var`
|
||||||
|
- **Method**: Central difference: `[f(var+h) - f(var-h)] / (2h)` (O(h²) accuracy)
|
||||||
|
- **Defaults**: `h = 1e-5` (adjustable via optional third argument)
|
||||||
|
- **Error Handling**:
|
||||||
|
- Returns error if `expr` is invalid or non-numeric after substitution
|
||||||
|
- Stops if oscillation detected (likely discontinuity)
|
||||||
|
- Max 20 iterations for adaptive step refinement (if needed)
|
||||||
|
- **Examples**:
|
||||||
|
- `derivative(x^2, x, 3)` → `6.0`
|
||||||
|
- `derivative(sin(x), x, 0)` → `1.0` (cos(0))
|
||||||
|
- `derivative(log(x), x, 1)` → `1.0`
|
||||||
|
|
||||||
|
#### 2. `integral(expr, var, a, b, [n])`
|
||||||
|
- **Purpose**: Approximate definite integral of `expr` from `a` to `b` with respect to `var`
|
||||||
|
- **Method**: Adaptive Simpson's Rule with error tolerance
|
||||||
|
- **Defaults**: Target relative error `1e-6`, max subdivisions `2^10` (1024)
|
||||||
|
- **Error Handling**:
|
||||||
|
- Requires `a < b` (swaps and negates if reversed)
|
||||||
|
- Returns error if integral diverges or fails to converge
|
||||||
|
- Limits function evaluations to prevent hanging
|
||||||
|
- **Examples**:
|
||||||
|
- `integral(x, x, 0, 2)` → `2.0`
|
||||||
|
- `integral(1, x, 0, 5)` → `5.0`
|
||||||
|
- `integral(exp(-x^2), x, -20, 20)` → `√π ≈ 1.77245` (Gaussian integral)
|
||||||
|
|
||||||
|
#### 3. `solve(expr, var, [guess])`
|
||||||
|
- **Purpose**: Find root of `expr ≈ 0` (solve for `var`)
|
||||||
|
- **Method**: Newton-Raphson with secant-method fallback (avoids needing analytical derivative)
|
||||||
|
- **Defaults**: `guess = 0`, max iterations `100`, tolerance `1e-10`
|
||||||
|
- **Error Handling**:
|
||||||
|
- Returns error if fails to converge or derivative too small
|
||||||
|
- May return one root if multiple exist (dependent on initial guess)
|
||||||
|
- **Examples**:
|
||||||
|
- `solve(x^2-4, x)` → `2.0` or `-2.0` (depends on guess)
|
||||||
|
- `solve(sin(x), x, 3)` → `3.14159...` (π)
|
||||||
|
- `solve(exp(x)-2, x)` → `0.693147...` (ln(2))
|
||||||
|
|
||||||
|
### 🛡️ **Security Integration (Gilfoyle's Focus)**
|
||||||
|
All numerical methods **reuse the same sanitized expression parser** as the core calculator:
|
||||||
|
- The `expr` argument undergoes identical allowlist validation, function replacement, and constant substitution
|
||||||
|
- Numerical methods contain **no dynamic code evaluation of raw user input**—they:
|
||||||
|
- Parse the expression once into a tokenized form (or evaluate the already-sanitized string via `Function` constructor in a safe context)
|
||||||
|
- Perform pure arithmetic loops (e.g., summing rectangles, finite differences)
|
||||||
|
- Never reconstruct or re-evaluate unsanitized strings
|
||||||
|
- Example: For `derivative("sin(x)*x", x, 0)`:
|
||||||
|
1. Validate `"sin(x)*x"` → allowed characters only`
|
||||||
|
2. Replace → `"Math.sin(x)*x"`
|
||||||
|
3. For sample points `x = -h, 0, h`:
|
||||||
|
- Evaluate `"Math.sin(x)*x"` with `x` set to sample value → pure math operation
|
||||||
|
4. Compute finite difference → return result
|
||||||
|
|
||||||
|
This ensures the **attack surface remains identical** to the core expression parser—Gilfoyle reviews one sanitizer, not multiple.
|
||||||
|
|
||||||
|
### ⌨️ **UI/UX for Exposure (Per User Keyboard Preference)**
|
||||||
|
To honor your strong preference for keyboard efficiency and fluid interaction:
|
||||||
|
- **First-class syntax**: Users type expressions directly: `derivative(sin(x), x, 0)` and press `=`
|
||||||
|
- **Discoverability**:
|
||||||
|
- Tooltips on function buttons showing syntax examples (e.g., hover over "deriv" shows `derivative(expr, var, [h])`)
|
||||||
|
- History entries display full expression: `derivative(sin(x), x, 0) = 1.000`
|
||||||
|
- Click-to-insert: tap a history item to insert it into the current expression
|
||||||
|
- **No mandatory mode switching**: Unlike traditional calculators with shift/2nd functions, these are always available in the expression syntax (consistent with your workflow)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **Summary of Agreed & Proposed Elements**
|
||||||
|
|
||||||
|
| Element | Decision | Status |
|
||||||
|
|---------|----------|--------|
|
||||||
|
| State Management | Context API + `useReducer`, localStorage, corruption → last good state | ✅ Agreed |
|
||||||
|
| Core Expression Parser | Allowlist, function whitelist, constant sub, safe `Function` eval | ✅ Agreed |
|
||||||
|
| Standard Scientific Functions | Trig, log, exp, sqrt, abs, rounding, factorial, nCr, nPr, random | ✅ Agreed |
|
||||||
|
| **Additional Constants** | `c`, `g`, `NA`, `R`, `q_e`, `kB`, `atm` (pure numbers) | 🟡 Proposed (await confirmation) |
|
||||||
|
| **Numerical Methods** | `derivative`, `integral`, `solve` as first-class syntax | 🟡 Proposed (await confirmation) |
|
||||||
|
| Constant Naming | `e` = Euler's number; electron charge = `q_e` | 🟡 Proposed (avoid conflict) |
|
||||||
|
| Unit Awareness | Deferred to later phase (treat as pure numbers now) | ✅ Agreed |
|
||||||
|
| UI Exposure | Direct syntax typing, tooltip/history support, click-to-insert | 🟡 Proposed (await confirmation) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **Next Step: Your Feedback Requested**
|
||||||
|
|
||||||
|
Please confirm or adjust:
|
||||||
|
|
||||||
|
1. **Constants**:
|
||||||
|
- Does the proposed set (`c`, `g`, `NA`, `R`, `q_e`, `kB`, `atm`) cover your needs for Hybrutos Racing, vACC, and homelab projects?
|
||||||
|
- Are there any other constants you'd like to prioritize (e.g., electron mass, proton mass, Faraday constant, etc.)?
|
||||||
|
- Any naming preferences (e.g., `electronCharge` vs `q_e`, `avogadro` vs `NA`)?
|
||||||
|
|
||||||
|
2. **Numerical Methods**:
|
||||||
|
- Are the default parameters (`h=1e-5`, tolerance `1e-6`, max iterations `100`) reasonable for your engineering calculations?
|
||||||
|
- Should we add any safeguards (e.g., max domain size for integrals to prevent hanging)?
|
||||||
|
- Any other numerical methods you'd find useful (e.g., `sum`, `product`, `minimization`)?
|
||||||
|
|
||||||
|
3. **UI/UX**:
|
||||||
|
- Is the direct syntax approach (`derivative(...)`) aligned with your keyboard-efficient workflow?
|
||||||
|
- Any preferences for how these appear in history or tooltips?
|
||||||
|
|
||||||
|
Once you confirm these points, we'll mark the math engine design as complete and move to our next iterative topic: **Unit & Currency Conversion Systems** (including your requested INR, USD, GBP, etc.).
|
||||||
|
|
||||||
|
Your turn—this is our collaborative design phase in action. I await your guidance to refine this to your exact satisfaction.
|
||||||
@@ -0,0 +1,420 @@
|
|||||||
|
# Technical Implementation Plan
|
||||||
|
## Scientific Calculator with Conversion & History
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Date:** 2026-07-27
|
||||||
|
**Prepared by:** Ada (Design & Planning Specialist, Hermes Agent)
|
||||||
|
**Based on:** Iterative design phase with stakeholder (Shreyas Kamat)
|
||||||
|
**Approvals:**
|
||||||
|
- State Management: ✅ Confirmed
|
||||||
|
- Math Engine Design: ✅ Confirmed
|
||||||
|
- Unit Conversion System: ✅ Confirmed
|
||||||
|
- Currency Conversion System: ✅ Confirmed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Executive Summary
|
||||||
|
This document specifies the technical implementation for a standalone scientific calculator application built to evaluate the Hermes Agent multi-agent framework. The calculator provides advanced mathematical operations (including numerical methods), unit conversions, currency conversions, and calculation history tracking with a modern, animated dark-theme UI. It is intended as a local testing utility only, with no planned integration into existing projects.
|
||||||
|
|
||||||
|
**Primary Goal:** Validate the Hermes Agent multi-agent architecture by delivering a feature-rich, polished ReactJS application through the prescribed phased development process.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Architecture Overview
|
||||||
|
|
||||||
|
### 2.1 High-Level Structure
|
||||||
|
- **Single-Page Application (SPA)** built with React 18 + Vite
|
||||||
|
- **Modular component architecture** with clear separation of concerns:
|
||||||
|
- `core/`: Math engine, conversion systems, history manager (pure JS, testable in isolation)
|
||||||
|
- `ui/`: Presentational components (display, buttons, panels, theme)
|
||||||
|
- `hooks/`: Custom React hooks for state/logic encapsulation
|
||||||
|
- `context/`: Global state (theme, calculation mode, history) via React Context API
|
||||||
|
- `utils/`: Cross-cutting concerns (keyboard handler, formatter, validator)
|
||||||
|
- `animations/`: Framer Motion variants and presets
|
||||||
|
- `styles/`: CSS modules, theme variables, responsive breakpoints
|
||||||
|
|
||||||
|
### 2.2 State Management Strategy
|
||||||
|
- **Local component state** (`useState`, `useReducer`): UI state (input focus, animation states, modal visibility)
|
||||||
|
- **Global state via Context API** (chosen per stakeholder preference):
|
||||||
|
- `ThemeContext`: dark/light mode, transition state
|
||||||
|
- `CalculationContext`: current expression, history stack, memory registers
|
||||||
|
- `ModeContext`: active calculator mode (standard, scientific, unit conversion, currency conversion)
|
||||||
|
- **Persistence**: `localStorage` for history and theme preference (with corruption recovery to last known good state)
|
||||||
|
- **No external libraries** (Redux/Zustand) to keep bundle size appropriate for scope
|
||||||
|
|
||||||
|
### 2.3 Security Approach (Gilfoyle's Focus)
|
||||||
|
- **Single sanitization point**: All user input (expressions, unit/currency conversions) flows through the same strict allowlist validator
|
||||||
|
- **Expression Parser**:
|
||||||
|
- Allowlist: digits, decimal, operators (`+-*/().`), whitespace, `e`, `pi`, whitelisted function names
|
||||||
|
- Function whitelisting + safe replacement (e.g., `sin(` → `Math.sin(`)
|
||||||
|
- Constant substitution: `pi`→`Math.PI`, `e`→`Math.E`, `ans`→history value (if valid number)
|
||||||
|
- Safe evaluation via `Function` constructor **only** on fully sanitized string (never `eval`)
|
||||||
|
- Error handling: returns `{value: null, error: string}` for invalid expressions
|
||||||
|
- **Unit/Currency Conversion**:
|
||||||
|
- Input validation against predefined whitelists (unit symbols, currency codes)
|
||||||
|
- Lookup-based conversion using hardcoded factors/rates (no dynamic code evaluation)
|
||||||
|
- Temperature: Special offset handling (K↔°C↔°F)
|
||||||
|
- **Zero attack surface added** beyond the core expression parser
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Functional Specifications
|
||||||
|
|
||||||
|
### 3.1 Core Calculation Engine
|
||||||
|
#### 3.1.1 Expression Parser & Evaluation
|
||||||
|
- **Input Sanitization**:
|
||||||
|
- Allowlist: `[0-9]`, `.`, `+-*/()`, whitespace, `e`, `pi`, and whitelisted function names
|
||||||
|
- Reject all other characters immediately
|
||||||
|
- Normalize whitespace (collapse, trim)
|
||||||
|
- **Constant Substitution**:
|
||||||
|
- `pi` → `Math.PI`
|
||||||
|
- `e` → `Math.E` (Euler's number)
|
||||||
|
- `ans` → last valid history value (if numeric)
|
||||||
|
- **Function Whitelisting & Replacement**:
|
||||||
|
- Trigonometric: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`
|
||||||
|
- Exponential/Logarithmic: `exp`, `log` (base 10), `ln` (natural)
|
||||||
|
- Root/Power: `sqrt`, `cbrt`, `**` (exponentiation)
|
||||||
|
- Absolute/Rounding: `abs`, `ceil`, `floor`, `round`
|
||||||
|
- Combinatorics: `factorial` (n!), `nCr`, `nPr`
|
||||||
|
- Other: `random`
|
||||||
|
- **Evaluation`:
|
||||||
|
- Replace whitelisted functions with `Math.func` equivalents
|
||||||
|
- Evaluate via: `Function("use strict"; return (${sanitizedString}))()` inside try/catch
|
||||||
|
- Return `{value: number, error: null}` on success, `{value: null, error: string}` on failure
|
||||||
|
|
||||||
|
#### 3.1.2 Standard Scientific Functions
|
||||||
|
All standard mathematical functions return JavaScript Math precision:
|
||||||
|
- Trigonometric: `sin(x)`, `cos(x)`, `tan(x)`, etc.
|
||||||
|
- Hyperbolic: `sinh(x)`, `cosh(x)`, `tanh(x)`, etc.
|
||||||
|
- Exponential/Logarithmic: `exp(x)`, `log10(x)`, `ln(x)`
|
||||||
|
- Root/Power: `sqrt(x)`, `cbrt(x)`, `x^y`
|
||||||
|
- Absolute/Rounding: `abs(x)`, `ceil(x)`, `floor(x)`, `round(x)`
|
||||||
|
- Combinatorics: `factorial` (n!), `nCr` (n choose r), `nPr` (n permute r)
|
||||||
|
- Random: `random()` → [0,1) uniform distribution
|
||||||
|
|
||||||
|
#### 3.1.3 Agreed Mathematical Constants
|
||||||
|
All defined as pure numbers (unit awareness deferred):
|
||||||
|
- `c` = 299792458 (speed of light, m/s)
|
||||||
|
- `g` = 9.80665 (standard gravity, m/s²)
|
||||||
|
- `NA` = 6.02214076e23 (Avogadro's number, mol⁻¹)
|
||||||
|
- `R` = 8.314462618 (molar gas constant, J/(mol·K))
|
||||||
|
- `q_e` = 1.602176634e-19 (elementary charge, C)
|
||||||
|
- `kB` = 1.380649e-23 (Boltzmann constant, J/K)
|
||||||
|
- `atm` = 101325 (standard atmosphere, Pa)
|
||||||
|
- **Note**: `e` reserved for Euler's number; electron charge = `q_e`
|
||||||
|
|
||||||
|
#### 3.1.4 Numerical Methods (First-Class Syntax)
|
||||||
|
All methods reuse the sanitized expression parser—no additional attack surface.
|
||||||
|
|
||||||
|
- **`derivative(expr, var, [h])`**:
|
||||||
|
- Purpose: Approximate derivative of `expr` w.r.t. `var`
|
||||||
|
- Method: Central difference: `[f(var+h) - f(var-h)] / (2h)` (O(h²))
|
||||||
|
- Defaults: `h = 1e-5`
|
||||||
|
- Error Handling: Invalid expr → error; oscillation → error; max 20 adaptive steps
|
||||||
|
- Examples: `derivative(x^2, x, 3)` → `6.0`; `derivative(sin(x), x, 0)` → `1.0`
|
||||||
|
|
||||||
|
- **`integral(expr, var, a, b, [n])`**:
|
||||||
|
- Purpose: Approximate definite integral of `expr` from `a` to `b` w.r.t. `var`
|
||||||
|
- Method: Adaptive Simpson's Rule with error-controlled subdivision
|
||||||
|
- Defaults: Target relative error `1e-6`, max subdivisions `2^10` (1024)
|
||||||
|
- Error Handling: Requires `a < b` (auto-swap & negate); divergent integrals → error
|
||||||
|
- Examples: `integral(x, x, 0, 2)` → `2.0`; `integral(exp(-x^2), x, -20, 20)` → `√π ≈ 1.77245`
|
||||||
|
|
||||||
|
- **`solve(expr, var, [guess])`**:
|
||||||
|
- Purpose: Find root of `expr ≈ 0` (solve for `var`)
|
||||||
|
- Method: Newton-Raphson with secant-method fallback
|
||||||
|
- Defaults: `guess = 0`, max iterations `100`, tolerance `1e-10`
|
||||||
|
- Error Handling: Failure to converge → error; derivative too small → error
|
||||||
|
- Examples: `solve(x^2-4, x)` → `2.0` or `-2.0`; `solve(sin(x), x, 3)` → `π`
|
||||||
|
|
||||||
|
### 3.2 Conversion Systems
|
||||||
|
#### 3.2.1 Unit Conversion System
|
||||||
|
- **Approach**: Categorized, bidirectional conversion within categories
|
||||||
|
- **Categories** (based on stakeholder projects):
|
||||||
|
- **Electrical**: V, mV, kV, μV; A, mA, μA, nA; Ω, kΩ, MΩ; F, μF, pF, nF; W, kW, MW; J, kWh, Wh; C, Ah, mAh
|
||||||
|
- **Mechanical**: N, kN; kgf, lbf; Pa, kPa, MPa, bar, psi; m/s, km/h, mph; m/s², g; Nm, ft·lb; Hz, RPM
|
||||||
|
- **Thermal**: K, °C, °F; J/(kg·K), J/(g·°C); W/(m·K); W, kW
|
||||||
|
- **Volume**: L, mL, μL, cm³, in³, ft³; tsp, tbsp, fl oz, cup, pt, qt, gal
|
||||||
|
- **Mass**: kg, g, mg, μg, lb, oz
|
||||||
|
- **Time**: s, ms, μs, ns; min, h, d; yr
|
||||||
|
- **Frequency**: Hz, kHz, MHz, GHz; RPM
|
||||||
|
- **Data**: bit, byte, KB, MB, GB, TB (user to specify SI/binary preference)
|
||||||
|
- **Conversion Syntax**: `convert(<value>, <from_unit>, <to_unit>)`
|
||||||
|
- Examples: `convert(5, "ft", "m")` → `1.524`; `convert(25, "C", "F")` → `77`
|
||||||
|
- **Security**:
|
||||||
|
- Input validation against unit whitelists per category
|
||||||
|
- Lookup-based conversion using hardcoded factors (no eval)
|
||||||
|
- Temperature: Special offset handling (K↔°C↔°F)
|
||||||
|
- **UI/UX**:
|
||||||
|
- Primary access: Direct syntax in expression bar (keyboard-efficient)
|
||||||
|
- Discoverability: Tooltips, history display (`convert(100, "V", "mV") = 100000`), click-to-insert
|
||||||
|
- Optional mode: Unit converter panel (never required for keyboard workflow)
|
||||||
|
|
||||||
|
#### 3.2.2 Currency Conversion System
|
||||||
|
- **Approach**: Manual-rate based (for framework isolation—no live API calls)
|
||||||
|
- **Supported Currencies**: INR, USD, GBP, EUR, JPY, CAD, AUD (user-extendable)
|
||||||
|
- **Conversion Syntax**: `convert(<value>, <from_currency>, <to_currency>)`
|
||||||
|
- Examples: `convert(1000, "INR", "USD")` → `11.98` (if 1 USD = 83.5 INR)
|
||||||
|
- **Security**:
|
||||||
|
- Input validation: 3-letter uppercase currency code whitelist
|
||||||
|
- Lookup-based conversion using manually entered rates (no eval)
|
||||||
|
- Rate storage: Simple JSON in localState with timestamps
|
||||||
|
- **Rate Management**:
|
||||||
|
- Manual entry via optional "Manage Rates" panel
|
||||||
|
- Auto-calculates inverse rates
|
||||||
|
- Timestamp for each rate (user sees "Rate updated: X time ago")
|
||||||
|
- Default rates pre-populated (clearly marked as approximations)
|
||||||
|
- **UI/UX**:
|
||||||
|
- Primary access: Direct syntax
|
||||||
|
- Discoverability: Tooltips, history display, click-to-insert
|
||||||
|
- Optional mode: Currency converter panel (never required for keyboard workflow)
|
||||||
|
|
||||||
|
#### 3.2.3 Integration with Core
|
||||||
|
- **Unified Syntax**: Both unit and currency conversions use `convert(<value>, <from>, <to>)`
|
||||||
|
- System checks if arguments match known unit categories first
|
||||||
|
- If not found, checks currency codes
|
||||||
|
- Error if neither (or ambiguous—avoided by distinct naming)
|
||||||
|
- **History & Re-use**:
|
||||||
|
- All conversions appear in history with full expression
|
||||||
|
- Click-to-insert: reuse past conversions in new expressions
|
||||||
|
- Chain conversions: `convert(convert(100, "USD", "INR"), "INR", "JPY")`
|
||||||
|
- **UI/UX Consistency**:
|
||||||
|
- Shares theme (dark/light) and animation system (Framer Motion)
|
||||||
|
- Results appear in same display as calculations
|
||||||
|
- Uses same expression bar—no context switching
|
||||||
|
- Consistent tooltips, hover effects, and feedback patterns
|
||||||
|
|
||||||
|
### 3.3 History System
|
||||||
|
- **Storage**: Persistent via localStorage (last 50 operations, FIFO eviction)
|
||||||
|
- **Structure**: `{ expression: string, result: string | number, timestamp: number }`
|
||||||
|
- **Features**:
|
||||||
|
- Save after each successful calculation/conversion
|
||||||
|
- Load on startup (with corruption recovery to last good state)
|
||||||
|
- Re-use: Click any history item to insert at cursor position
|
||||||
|
- Delete: Swipe/slide to remove individual items
|
||||||
|
- Clear all: Optional function to reset history
|
||||||
|
- **Display**: Shows full expression and result (e.g., `derivative(sin(x), x, 0) = 1.000`)
|
||||||
|
- **Security**:
|
||||||
|
- Sanitize on read (JSON.parse with type validation)
|
||||||
|
- Reject malformed data; fall back to defaults
|
||||||
|
|
||||||
|
### 3.4 User Interface & Experience
|
||||||
|
#### 3.4.1 Theme System
|
||||||
|
- **Default**: Dark theme (mandatory per stakeholder preference per stakeholder)
|
||||||
|
- **Optional**: Light theme toggle
|
||||||
|
- **Implementation**: CSS variables (`--bg-primary`, `--text-primary`, `--accent`, etc.) in `:root`
|
||||||
|
- **Transitions**: Smooth via `transition: background-color 0.3s, color 0.3s`
|
||||||
|
- **Colors**:
|
||||||
|
- Dark: Background `#121212`, Text `#E0E0E0`, Accent `#FF9800`
|
||||||
|
- Light: Background `#FFFFFF`, Text `#212121`, Accent `#FB8C00`
|
||||||
|
|
||||||
|
#### 3.4.2 Keypad & Button System
|
||||||
|
- **Layout**: Responsive grid adapting to mode (standard/scientific/unit/conversion/currency)
|
||||||
|
- **Button Variants**:
|
||||||
|
- Numbers: Standard styling
|
||||||
|
- Operators (+,-,*,/,=): Accent color (`#FF9800`)
|
||||||
|
- Functions (sin, log, etc.): Secondary accent
|
||||||
|
- Conversion: Distinct styling (to be finalized)
|
||||||
|
- Special (AC, CE): Warning color
|
||||||
|
- **Styling**: CSS Modules (scoped, no runtime overhead)
|
||||||
|
- **Animations** (Framer Motion):
|
||||||
|
- Button press: `scale` and `backgroundColor` transition (200ms)
|
||||||
|
- Screen transitions: Fade and slide (300ms)
|
||||||
|
- History panel: Slide-in from right (desktop) / full-screen modal (mobile)
|
||||||
|
- **Responsiveness**:
|
||||||
|
- Mobile-first: `<480px` (phone), `480-768px` (tablet/desktop)
|
||||||
|
- Keypad: 4-column grid on tablet+/desktop, 2-column on phone (scrollable if needed)
|
||||||
|
- Display: Font size scales with viewport
|
||||||
|
- **Accessibility**:
|
||||||
|
- All buttons: `aria-label` (e.g., "sine", "clear all", "delete last")
|
||||||
|
- Keyboard navigation: logical tab order, visible focus rings
|
||||||
|
- Screen reader live regions for error/history updates
|
||||||
|
- Color contrast: WCAG AA minimum (4.5:1 for text, 3:1 for large text/UI)
|
||||||
|
|
||||||
|
#### 3.4.3 Display & Input
|
||||||
|
- **Primary Expression Bar**:
|
||||||
|
- Shows current input/output
|
||||||
|
- Font: `Space Mono` (monospace) for calculation clarity
|
||||||
|
- Features: Real-time syntax highlighting (valid in green, invalid in red)
|
||||||
|
- **Secondary Line** (optional):
|
||||||
|
- Shows full expression for multi-step calculations
|
||||||
|
- Smaller font, muted color
|
||||||
|
- **Error Handling**:
|
||||||
|
- Display "Error" for invalid expressions/conversions
|
||||||
|
- Optional: Shake animation + red border feedback
|
||||||
|
- Recovery: "Press AC to reset" hint in error state
|
||||||
|
|
||||||
|
### 3.5 Keyboard Support
|
||||||
|
- **Comprehensive Mapping**:
|
||||||
|
- Numbers 0-9: Digits
|
||||||
|
- Operators: `+` (plus), `-` (minus), `*` (asterisk), `/` (slash), `=` or `Enter` (equals)
|
||||||
|
- Decimal: `.` (period) or `,` (comma, locale-dependent)
|
||||||
|
- Backspace: `Backspace` (delete last char)
|
||||||
|
- Escape: `Escape` (clear all / AC)
|
||||||
|
- Arrow keys: History navigation (up/down for previous/next)
|
||||||
|
- **Advanced Functions**:
|
||||||
|
- Type directly: `derivative(sin(x), x, 0)`, `convert(100, "V", "mV")`
|
||||||
|
- No mode switching required for keyboard workflow
|
||||||
|
- **Validation**: Real-time feedback as user types
|
||||||
|
|
||||||
|
### 3.6 Performance Targets
|
||||||
|
- **Animation**: Maintain ≥55 FPS during interactions
|
||||||
|
- **Calculation Latency**: < 50ms for standard operations (<100ms for numerical methods)
|
||||||
|
- **Initial Load**: < 2.5s on mid-tier device (simulated 3G throttling)
|
||||||
|
- **Memory**: < 50MB peak usage (history/localStorage bounded)
|
||||||
|
- **Bundle Size**: Target <150KB gzipped (React + Framer Motion ~80KB; rest ~70KB)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Non-Functional Requirements
|
||||||
|
|
||||||
|
### 4.1 Security & Reliability (Gilfoyle's Focus)
|
||||||
|
- **Input Sanitization**: Single allowlist validator for all user input
|
||||||
|
- **No `eval()`**: Never use `eval` or equivalent; only sanitized `Function` constructor
|
||||||
|
- **LocalStorage Safety**:
|
||||||
|
- Validate on read (type checking, structure verification)
|
||||||
|
- Namespace keys to prevent collisions (`calc_history`, `calc_theme`, `conv_rates`)
|
||||||
|
- Corruption recovery: Restore last known good state or defaults
|
||||||
|
- **Error Containment**:
|
||||||
|
- Errors return controlled states (never expose stack traces)
|
||||||
|
- Malformed history/data discarded safely
|
||||||
|
- **XSS Prevention**:
|
||||||
|
- All dynamic content escaped before DOM insertion
|
||||||
|
- innerHTML never used with user input; use textContent or safe templating
|
||||||
|
|
||||||
|
### 4.2 Maintainability & Extensibility
|
||||||
|
- **Modularity**: Clear separation of math, conversion, history, UI, theme
|
||||||
|
- **Consistent Code Style**: ESLint (React best practices) + Prettier
|
||||||
|
- **Documentation**: JSDoc for all public functions and components
|
||||||
|
- **Extensibility**:
|
||||||
|
- Add new scientific functions: Extend whitelist + replacement map
|
||||||
|
- Add new units: Define category + conversion factors
|
||||||
|
- Add new currencies: Extend code list + default rate
|
||||||
|
- Add new UI modes: Extend ModeContext + keypad layout
|
||||||
|
|
||||||
|
### 4.3 Compatibility
|
||||||
|
- **Browsers**: Chrome, Firefox, Safari, Edge (latest stable)
|
||||||
|
- **JavaScript**: ES2020+ support required
|
||||||
|
- **Dependencies**:
|
||||||
|
- React 18.2.0 (MIT)
|
||||||
|
- Vite 4.3.0 (MIT)
|
||||||
|
- Framer Motion 10.12.0 (MIT)
|
||||||
|
- CSS Modules (built-in via Vite, MIT)
|
||||||
|
- All dependencies free/OSS compliant
|
||||||
|
|
||||||
|
### 4.4 Testing Strategy
|
||||||
|
- **Unit Tests** (Jest + React Testing Library):
|
||||||
|
- Math engine: 100% coverage (edge cases, invalid inputs, large numbers)
|
||||||
|
- Conversion engines: Bidirectional accuracy, boundary values
|
||||||
|
- History manager: add/remove/reuse, persistence, limits
|
||||||
|
- Custom hooks: `useHistory`, `useKeyboard`, `useTheme`, `useFormatting`
|
||||||
|
- **Integration Tests**:
|
||||||
|
- Full calculation flow: input → operator → equals → history update
|
||||||
|
- Mode switching preserves state appropriately
|
||||||
|
- History item re-use inserts correctly
|
||||||
|
- Chain conversions work correctly
|
||||||
|
- **Target**: ≥90% unit test coverage on `core/` and `utils/`; ≥70% on UI interactions
|
||||||
|
- **Security Tests**:
|
||||||
|
- Attempt XSS/injection vectors → verify sanitization blocks
|
||||||
|
- Fuzz testing on expression parser
|
||||||
|
|
||||||
|
### 4.5 Accessibility
|
||||||
|
- **Keyboard**: All functions accessible via keyboard alone
|
||||||
|
- **Touch Targets**: ≥48x48px on mobile layouts
|
||||||
|
- **Focus Management**: Clear visible focus rings, logical tab order
|
||||||
|
- **Screen Reader**: ARIA labels, live regions for dynamic updates
|
||||||
|
- **Color Contrast**: WCAG AA compliance for text and UI elements
|
||||||
|
- **Reduced Motion**: Respect `prefers-reduced-motion` media query (animation fallback)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Development Phases & Gates (Per Stakeholder Workflow)
|
||||||
|
|
||||||
|
### 5.1 Phase 1: Ideation (Steve) ✅ COMPLETE
|
||||||
|
- Feasibility/viability research via Q&A
|
||||||
|
- Finalized exact requirements: standalone utility, scientific calculations, unit/currency conversion, history, dark theme, keyboard support, animations
|
||||||
|
- Output: Requirements baseline for Turing
|
||||||
|
|
||||||
|
### 5.2 Phase 2: Documentation (Turing) ✅ COMPLETE
|
||||||
|
- PRD written based on Steve's output
|
||||||
|
- Saved as: `.hermes/docs/PRD-2026-07-26-scientific-calculator.md`
|
||||||
|
- **Gate**: Ready for Ada's design/planning phase
|
||||||
|
|
||||||
|
### 5.3 Phase 3: Design & Planning (Ada) ✅ COMPLETE (PER THIS DOCUMENT)
|
||||||
|
- Iterative back-and-forth with stakeholder to refine technical plan
|
||||||
|
- **All elements confirmed**:
|
||||||
|
- State management: Context API + useReducer, localStorage, corruption recovery
|
||||||
|
- Math engine: Expression parser, scientific functions, agreed constants, numerical methods
|
||||||
|
- Conversion systems: Unit (categorized) and currency (manual-rate) with `convert()` syntax
|
||||||
|
- UI/UX: Dark theme, keyboard support, fluid animations, responsive layout
|
||||||
|
- Security: Single sanitization point, no `eval()`, Gilfoyle-safe design
|
||||||
|
- **Output**: This technical plan (Ada's deliverable)
|
||||||
|
- **Gate**: **STAKEHOLDER APPROVAL REQUIRED** before proceeding to Woz
|
||||||
|
|
||||||
|
### 5.4 Phase 4: Documentation (Turing) ⏳ PENDING
|
||||||
|
- SAD (Solution Architecture Document) written based on Ada's approved plan
|
||||||
|
- To be saved as: `.hermes/docs/SAD-2026-07-27-scientific-calculator.md`
|
||||||
|
- **Gate**: Stakeholder approval required before proceeding to specialists
|
||||||
|
|
||||||
|
### 5.5 Phase 5: Orchestration (Woz) ⏳ PENDING
|
||||||
|
- Task distribution to specialists (Linus, Sergey, Zaha, Craig, Gilfoyle, etc.)
|
||||||
|
- Gilfoyle's security review embedded from start (not afterthought)
|
||||||
|
- Development proceeds in iterations with stakeholder checkpoints
|
||||||
|
|
||||||
|
### 5.6 Phase 6: Development (Specialists) ⏳ PENDING
|
||||||
|
- Implementation per approved plan and SAD
|
||||||
|
- Regular commits after each bite-sized task (2-5 min focus)
|
||||||
|
- Stakeholder approval required before moving to review phase
|
||||||
|
|
||||||
|
### 5.7 Phase 7: Independent Review (Satya & Sundar) ⏳ PENDING
|
||||||
|
- **Satya (Review Specialist)**: Code quality, spec compliance, best practices
|
||||||
|
- **Sundar (Test Specialist)**: Functional testing, edge cases, performance, accessibility
|
||||||
|
- **Work Independently**: As specified by stakeholder
|
||||||
|
- **Gate**: Stakeholder final approval required before deployment
|
||||||
|
|
||||||
|
### 5.8 Phase 8: Deployment (Jenson) ⏳ PENDING
|
||||||
|
- Release to target (local testing environment)
|
||||||
|
- Stakeholder final go/no-go
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Summary: All Elements Agreed Upon
|
||||||
|
|
||||||
|
| Component | Specification | Status |
|
||||||
|
|-----------|---------------|--------|
|
||||||
|
| State Management | Context API + `useReducer`; localStorage; corruption → last good state | ✅ Agreed |
|
||||||
|
| Core Processor | Allowlist sanitization; function whitelist; safe `Function` eval | ✅ Agreed |
|
||||||
|
| Standard Functions | Trig, log, exp, sqrt, abs, rounding, factorial, nCr, nPr, random | ✅ Agreed |
|
||||||
|
| **Constants** | `c`, `g`, `NA`, `R`, `q_e`, `q_e`,kB`,atm` (pure numbers) | ✅ Agreed |
|
||||||
|
| **Numerical Methods** | `derivative`, `integral`, `solve` as first-class syntax | ✅ Agreed |
|
||||||
|
| Unit Conversion | Categorized (8 categories), `convert()` syntax, temp offset | ✅ Agreed |
|
||||||
|
| Currency Conversion | Manual rates (INR,USD,GBP,EUR,JPY,CAD,AUD), `convert()` syntax | ✅ Agreed |
|
||||||
|
| History System | Persistent localStorage (last 50), FIFO, click-to-reuse | ✅ Agreed |
|
||||||
|
| UI/UX | Dark theme, keyboard, animations (Framer Motion), responsive | ✅ Agreed |
|
||||||
|
| Security (Gilfoyle) | Single sanitizer, no `eval()`, input validation, error containment | ✅ Agreed |
|
||||||
|
| Performance | Target: ≥55 FPS, <50ms calc latency, <2.5s load, <150KB bundle | ✅ Agreed |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Current Status: Ready for Stakeholder Approval
|
||||||
|
|
||||||
|
This document represents the **complete technical plan** for the scientific calculator with conversion and history features, incorporating all agreements from our iterative design phase.
|
||||||
|
|
||||||
|
**Gates Completed**:
|
||||||
|
- ✅ Ideation (Steve) - Requirements finalized via Q&A
|
||||||
|
- ✅ Documentation PRD (Turing) - Based on Steve's output
|
||||||
|
- ✅ Design & Planning (Ada) - Iterative refinement → **Fully detailed plan**
|
||||||
|
|
||||||
|
**Current Gate**:
|
||||||
|
- ⏳ **Awaiting Stakeholder Approval** of this technical plan (this document)
|
||||||
|
|
||||||
|
**Once Approved**:
|
||||||
|
1. Turing will write the **SAD** (Solution Architecture Document) based on this approved plan
|
||||||
|
2. You will review and approve the **SAD** (gate before specialist distribution)
|
||||||
|
3. Woz will distribute tasks to specialists (with Gilfoyle's security review embedded from the start)
|
||||||
|
4. Development will proceed under your oversight
|
||||||
|
5. Pre-development review (your approval) → Independent review)
|
||||||
|
→ Deployment (Please review this technical plan. If you have any adjustments or clarifications needed, please specify them now so we can incorporate them before finalizing the plan.
|
||||||
|
|
||||||
|
Your formal approval is required to maintain the prescribed gated workflow. I await your guidance to proceed to the SAD phase.
|
||||||
|
|
||||||
|
JARVIS, at your service.
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# Task Distribution Plan: Scientific Calculator Project
|
||||||
|
|
||||||
|
This plan outlines the distribution of development tasks across specialists, based on the approved Solution Architecture Document (SAD).
|
||||||
|
|
||||||
|
## 1. Specialist Assignments by Module
|
||||||
|
|
||||||
|
Tasks are assigned to specialists across lanes (A, B, C) to ensure modular parallel development and a strict security review process.
|
||||||
|
|
||||||
|
### Phase 1: Core Logic & Security (Highest Priority)
|
||||||
|
*Critical path: The Math Engine must be secure and functional before UI integration.*
|
||||||
|
|
||||||
|
| Module | Files/Components | Assigned Specialist | Lane | Responsibility |
|
||||||
|
| :--- | :--- | :--- | :--- | :--- |
|
||||||
|
| **Expression Parser** | `src/core/math/ExpressionParser.js` | **Gilfoyle** | B | Implement allowlist validation, constant substitution, and safe evaluation. **(Security Lead)** |
|
||||||
|
| **Scientific Functions**| `src/core/math/ScientificFunctions.js`| **Linus** | B | Implement trig, hyperbolic, exp/log, and other standard scientific functions. |
|
||||||
|
| **Numerical Methods** | `src/core/math/NumericalMethods.js` | **Sergey** | B | Implement `derivative`, `integral`, and `solve` (Newton-Raphson). |
|
||||||
|
|
||||||
|
### Phase 2: Specialized Systems
|
||||||
|
| Module | Files/Components | Assigned Specialist | Lane | Responsibility |
|
||||||
|
| :--- | :--- | :--- | :--- | :--- |
|
||||||
|
| **Unit Conversion** | `src/core/conversion/UnitConverter.js`, `UnitDefinitions.js` | **Zaha** | B | Implement category-based conversion logic and unit factor tables. |
|
||||||
|
| **Currency Conversion**| `src/core/conversion/CurrencyConverter.js`, `ExchangeRateService.js` | **Craig** | B | Implement 3-letter code validation and manual rate management. |
|
||||||
|
| **History Manager** | `src/core/history/HistoryManager.js`, `useHistory.js` | **Maria** | B | Implement localStorage persistence, FIFO eviction (50 entries), and corruption recovery. |
|
||||||
|
|
||||||
|
### Phase 3: Application State & Theme
|
||||||
|
| Module | Files/Components | Assigned Specialist | Lane | Responsibility |
|
||||||
|
| :--- | :--- | :--- | :--- | :--- |
|
||||||
|
| **Theme System** | `src/theme/ThemeContext.js`, `themes.js`, `useTheme.js` | **Ada** | C | Implement dark/light theme switching and CSS variable management. |
|
||||||
|
| **Mode System** | `src/contexts/ModeContext.js` | **Steve** | C | Implement mode switching state (`standard`, `scientific`, `unit`, `currency`). |
|
||||||
|
| **Keyboard Handler** | `src/utils/KeyboardHandler.js` | **Woz** | C | Map physical keys to calculator actions and history navigation. |
|
||||||
|
|
||||||
|
### Phase 4: UI Components & Animations
|
||||||
|
| Module | Files/Components | Assigned Specialist | Lane | Responsibility |
|
||||||
|
| :--- | :--- | :--- | :--- | :--- |
|
||||||
|
| **Display Bar** | `src/components/display/Display.jsx`, `.module.css` | **Ananta** | C | Implement main result display, syntax highlighting, and error shake animation. |
|
||||||
|
| **Button System** | `src/components/button/Button.jsx`, `.module.css` | **Sully** | A | Create variant-based button components with press animations. |
|
||||||
|
| **Keypad System** | `src/components/keypad/Keypad.jsx`, `StandardMode.jsx` etc. | **Lewis** | A | Implement responsive grid layouts for all four operational modes. |
|
||||||
|
| **History Panel** | `src/components/history/HistoryPanel.jsx`, `HistoryItem.jsx` | **Dinesh** | B | Implement slide-in panel, mobile modal, and click-to-reuse logic. |
|
||||||
|
| **Animations & Utils**| `src/animations/`, `src/utils/Validator.js`, `Formatter.js` | **Satya** | B | Implement Framer Motion variants and centralized number formatting. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Development Workflow (The "Gated" Process)
|
||||||
|
|
||||||
|
Every specialist must adhere to the following loop for every bite-sized task:
|
||||||
|
|
||||||
|
1. **Implement**: Write code according to the SAD specs.
|
||||||
|
2. **Local Commit**: Commit changes locally.
|
||||||
|
* **Format**: `<type>(<scope>): <description>`
|
||||||
|
* *Example*: `feat(math-engine): add derivative function with central difference method`
|
||||||
|
3. **Notify Turing**: Immediately notify **Turing** (Documentation Specialist) with the commit hash and a brief description.
|
||||||
|
4. **Documentation Step**: Turing generates a **Commit Changes Document** in `.hermes/docs/commits/` mapping the change to the architecture.
|
||||||
|
5. **Push**: Push the validated commit to the GitHub/Gitea repository.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Quality Assurance & Integration Gates
|
||||||
|
|
||||||
|
| Gate | Actor | Focus | Requirement |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **Security Audit** | Gilfoyle | Input Sanitization | No `eval`, strict allowlist, safe `Function` usage. |
|
||||||
|
| **Code Review** | Satya | Quality & Spec | Adherence to React 18 best practices and SAD specs. |
|
||||||
|
| **Functional Test** | Sundar | Edge Cases | Validating numerical accuracy and responsive UI. |
|
||||||
|
| **Deployment** | Jenson | Final Release | Production build via Vite and static hosting. |
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||||
|
"plugins": ["react", "oxc"],
|
||||||
|
"rules": {
|
||||||
|
"react/rules-of-hooks": "error",
|
||||||
|
"react/only-export-components": ["warn", { "allowConstantExport": true }]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# React + Vite
|
||||||
|
|
||||||
|
This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
||||||
|
|
||||||
|
## React Compiler
|
||||||
|
|
||||||
|
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||||
|
|
||||||
|
## Expanding the Oxlint configuration
|
||||||
|
|
||||||
|
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and Oxlint's TypeScript related rules in your project.
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Scientific Calculator</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Generated
+1332
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "scientific-calculator",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A scientific calculator with unit and currency conversion, history, and animations",
|
||||||
|
"main": "index.html",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"framer-motion": "^10.12.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-react": "^4.0.0",
|
||||||
|
"vite": "^4.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol id="bluesky-icon" viewBox="0 0 16 17">
|
||||||
|
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
|
||||||
|
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="discord-icon" viewBox="0 0 20 19">
|
||||||
|
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="documentation-icon" viewBox="0 0 21 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="github-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="social-icon" viewBox="0 0 20 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="x-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
+184
@@ -0,0 +1,184 @@
|
|||||||
|
.counter {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: var(--accent);
|
||||||
|
background: var(--accent-bg);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--accent-border);
|
||||||
|
}
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid var(--accent);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.base,
|
||||||
|
.framework,
|
||||||
|
.vite {
|
||||||
|
inset-inline: 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.base {
|
||||||
|
width: 170px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.framework,
|
||||||
|
.vite {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.framework {
|
||||||
|
z-index: 1;
|
||||||
|
top: 34px;
|
||||||
|
height: 28px;
|
||||||
|
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
|
||||||
|
scale(1.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vite {
|
||||||
|
z-index: 0;
|
||||||
|
top: 107px;
|
||||||
|
height: 26px;
|
||||||
|
width: auto;
|
||||||
|
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
|
||||||
|
scale(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#center {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 25px;
|
||||||
|
place-content: center;
|
||||||
|
place-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
padding: 32px 20px 24px;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#next-steps {
|
||||||
|
display: flex;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
flex: 1 1 0;
|
||||||
|
padding: 32px;
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
padding: 24px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#docs {
|
||||||
|
border-right: 1px solid var(--border);
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#next-steps ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 32px 0 0;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--text-h);
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--social-bg);
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 12px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: box-shadow 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.button-icon {
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
margin-top: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
li {
|
||||||
|
flex: 1 1 calc(50% - 8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#spacer {
|
||||||
|
height: 88px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticks {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -4.5px;
|
||||||
|
border: 5px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
left: 0;
|
||||||
|
border-left-color: var(--border);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
right: 0;
|
||||||
|
border-right-color: var(--border);
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ThemeContext } from './theme/ThemeContext';
|
||||||
|
import { ModeContext } from './contexts/ModeContext';
|
||||||
|
import { CalculationContext } from './core/math/CalculationContext';
|
||||||
|
import Display from './components/display/Display';
|
||||||
|
import Keypad from './components/keypad/Keypad';
|
||||||
|
import HistoryPanel from './components/history/HistoryPanel';
|
||||||
|
import { useTheme } from './theme/useTheme';
|
||||||
|
import { useMode } from './contexts/useMode';
|
||||||
|
import { useCalculation } from './core/math/useCalculation';
|
||||||
|
import styles from './styles/App.module.css';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const { theme, isTransitioning, toggleTheme } = useTheme();
|
||||||
|
const { mode, setMode } = useMode();
|
||||||
|
const { expression, result, isError, history, addToHistory, clearHistory } = useCalculation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ theme, isTransitioning, toggleTheme }}>
|
||||||
|
<ModeContext.Provider value={{ mode, setMode }}>
|
||||||
|
<CalculationContext.Provider value={{ expression, result, isError, history, addToHistory, clearHistory }}>
|
||||||
|
<div className={styles.app}>
|
||||||
|
<header className={styles.header}>
|
||||||
|
<h1>Scientific Calculator</h1>
|
||||||
|
<button onClick={toggleTheme} className={styles.themeToggle}>
|
||||||
|
{theme === 'dark' ? '☀️' : '🌙'}
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<main className={styles.main}>
|
||||||
|
<Display expression={expression} result={result} isError={isError} />
|
||||||
|
<Keypad />
|
||||||
|
<HistoryPanel />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</CalculationContext.Provider>
|
||||||
|
</ModeContext.Provider>
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,88 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import styles from './Calculator.module.css';
|
||||||
|
import { calculate } from '../utils/calculatorLogic';
|
||||||
|
|
||||||
|
const Calculator = () => {
|
||||||
|
const [display, setDisplay] = useState('0');
|
||||||
|
const [waitingForSecondOperand, setWaitingForSecondOperand] = useState(false);
|
||||||
|
const [operator, setOperator] = useState(null);
|
||||||
|
const [firstOperand, setFirstOperand] = useState(null);
|
||||||
|
|
||||||
|
const inputDigit = (digit) => {
|
||||||
|
if (waitingForSecondOperand) {
|
||||||
|
setDisplay(digit);
|
||||||
|
setWaitingForSecondOperand(false);
|
||||||
|
} else {
|
||||||
|
setDisplay(display === '0' ? digit : display + digit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputDecimal = (dot) => {
|
||||||
|
if (waitingForSecondOperand) {
|
||||||
|
setDisplay('0.');
|
||||||
|
setWaitingForSecondOperand(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!display.includes(dot)) {
|
||||||
|
setDisplay(display + dot);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOperator = (nextOperator) => {
|
||||||
|
const inputValue = parseFloat(display);
|
||||||
|
if (firstOperand === null) {
|
||||||
|
setFirstOperand(inputValue);
|
||||||
|
} else if (operator) {
|
||||||
|
const currentValue = firstOperand || 0;
|
||||||
|
const result = calculate(currentValue, operator, display);
|
||||||
|
setDisplay(String(result));
|
||||||
|
setFirstOperand(result);
|
||||||
|
}
|
||||||
|
setWaitingForSecondOperand(true);
|
||||||
|
setOperator(nextOperator);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetCalculator = () => {
|
||||||
|
setDisplay('0');
|
||||||
|
setWaitingForSecondOperand(false);
|
||||||
|
setOperator(null);
|
||||||
|
setFirstOperand(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEquals = () => {
|
||||||
|
if (operator && firstOperand !== null) {
|
||||||
|
const result = calculate(firstOperand, operator, display);
|
||||||
|
setDisplay(String(result));
|
||||||
|
setWaitingForSecondOperand(true);
|
||||||
|
setOperator(null);
|
||||||
|
setFirstOperand(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.calculator}>
|
||||||
|
<div className={styles.display}>{display}</div>
|
||||||
|
<div className={styles.keypad}>
|
||||||
|
<button className={styles.button} onClick={() => resetCalculator()}>AC</button>
|
||||||
|
<button className={styles.button} onClick={() => handleOperator('/')}>÷</button>
|
||||||
|
<button className={styles.button} onClick={() => handleOperator('*')}>×</button>
|
||||||
|
<button className={styles.button} onClick={() => handleOperator('-')}>−</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('7')}>7</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('8')}>8</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('9')}>9</button>
|
||||||
|
<button className={styles.button} onClick={() => handleOperator('+')}>+</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('4')}>4</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('5')}>5</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('6')}>6</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('1')}>1</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('2')}>2</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('3')}>3</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDecimal('.')}>.</button>
|
||||||
|
<button className={styles.button} onClick={() => inputDigit('0')}>0</button>
|
||||||
|
<button className={styles.button} onClick={() => handleEquals()}> = </button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Calculator;
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
.calculator {
|
||||||
|
width: 320px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 1.5rem;
|
||||||
|
background: #1e1e1e;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.display {
|
||||||
|
width: 100%;
|
||||||
|
height: 70px;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding: 0 1rem;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
text-align: right;
|
||||||
|
background: #2c2c2c;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-family: 'Space Mono', monospace;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keypad {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background: #e9e9e9;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.operator {
|
||||||
|
background: #ff9500;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.operator:hover {
|
||||||
|
background: #ffb14d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.equal {
|
||||||
|
background: #ff9500;
|
||||||
|
color: white;
|
||||||
|
grid-column: span 2;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.equal:hover {
|
||||||
|
background: #ffb14d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.zero {
|
||||||
|
grid-column: span 2;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
.calculator {
|
||||||
|
width: 90%;
|
||||||
|
margin: 1rem auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display {
|
||||||
|
height: 50px;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.zero {
|
||||||
|
width: 105px;
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
:root {
|
||||||
|
--text: #6b6375;
|
||||||
|
--text-h: #08060d;
|
||||||
|
--bg: #fff;
|
||||||
|
--border: #e5e4e7;
|
||||||
|
--code-bg: #f4f3ec;
|
||||||
|
--accent: #aa3bff;
|
||||||
|
--accent-bg: rgba(170, 59, 255, 0.1);
|
||||||
|
--accent-border: rgba(170, 59, 255, 0.5);
|
||||||
|
--social-bg: rgba(244, 243, 236, 0.5);
|
||||||
|
--shadow:
|
||||||
|
rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px;
|
||||||
|
|
||||||
|
--sans: system-ui, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--heading: system-ui, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--mono: ui-monospace, Consolas, monospace;
|
||||||
|
|
||||||
|
font: 18px/145% var(--sans);
|
||||||
|
letter-spacing: 0.18px;
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg);
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--text: #9ca3af;
|
||||||
|
--text-h: #f3f4f6;
|
||||||
|
--bg: #16171d;
|
||||||
|
--border: #2e303a;
|
||||||
|
--code-bg: #1f2028;
|
||||||
|
--accent: #c084fc;
|
||||||
|
--accent-bg: rgba(192, 132, 252, 0.15);
|
||||||
|
--accent-border: rgba(192, 132, 252, 0.5);
|
||||||
|
--social-bg: rgba(47, 48, 58, 0.5);
|
||||||
|
--shadow:
|
||||||
|
rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#social .button-icon {
|
||||||
|
filter: invert(1) brightness(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
width: 1126px;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
border-inline: 1px solid var(--border);
|
||||||
|
min-height: 100svh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2 {
|
||||||
|
font-family: var(--heading);
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 56px;
|
||||||
|
letter-spacing: -1.68px;
|
||||||
|
margin: 32px 0;
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
font-size: 36px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 118%;
|
||||||
|
letter-spacing: -0.24px;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
.counter {
|
||||||
|
font-family: var(--mono);
|
||||||
|
display: inline-flex;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 135%;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background: var(--code-bg);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import App from './App';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export const calculate = (num1, operator, num2) => {
|
||||||
|
const n1 = parseFloat(num1);
|
||||||
|
const n2 = parseFloat(num2);
|
||||||
|
switch (operator) {
|
||||||
|
case '+': return n1 + n2;
|
||||||
|
case '-': return n1 - n2;
|
||||||
|
case '*': return n1 * n2;
|
||||||
|
case '/':
|
||||||
|
if (n2 === 0) return 'Error';
|
||||||
|
return n1 / n2;
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
port: 3000,
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
assetsDir: 'assets',
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user