diff --git a/apps/web/src/components/MyAbacus.tsx b/apps/web/src/components/MyAbacus.tsx index 4cd8b54a..f361bcda 100644 --- a/apps/web/src/components/MyAbacus.tsx +++ b/apps/web/src/components/MyAbacus.tsx @@ -235,8 +235,8 @@ export function MyAbacus() { animated={isOpen || isHeroMode} customStyles={isHeroMode ? structuralStyles : trophyStyles} onValueChange={setAbacusValue} - // 3D Enhancement - delightful mode for hero and open states - enhanced3d={isOpen || isHeroMode ? 'delightful' : undefined} + // 3D Enhancement - realistic mode for hero and open states + enhanced3d={isOpen || isHeroMode ? 'realistic' : undefined} material3d={ isOpen || isHeroMode ? { @@ -247,65 +247,10 @@ export function MyAbacus() { } : undefined } - physics3d={ - isOpen || isHeroMode - ? { - hoverParallax: true, - } - : undefined - } /> - {/* Title and achievement info - only visible when open */} - {isOpen && ( -
-

- My Abacus -

-

- Your personal abacus grows with you -

-

- Complete tutorials, play games, and earn achievements to unlock higher place values -

-
- )} {/* Keyframes for animations */} diff --git a/packages/abacus-react/src/Abacus3DUtils.ts b/packages/abacus-react/src/Abacus3DUtils.ts index 467dc20d..5670c945 100644 --- a/packages/abacus-react/src/Abacus3DUtils.ts +++ b/packages/abacus-react/src/Abacus3DUtils.ts @@ -124,7 +124,7 @@ export function getLightingFilter(lighting: LightingStyle = "top-down"): string * Calculate Z-depth for a bead based on enhancement level and state */ export function getBeadZDepth( - enhanced3d: boolean | "subtle" | "realistic" | "delightful", + enhanced3d: boolean | "subtle" | "realistic", active: boolean ): number { if (!enhanced3d || enhanced3d === true) return 0; @@ -136,48 +136,11 @@ export function getBeadZDepth( return 6; case "realistic": return 10; - case "delightful": - return 12; default: return 0; } } -/** - * Calculate parallax offset based on mouse position - */ -export function calculateParallaxOffset( - beadX: number, - beadY: number, - mouseX: number, - mouseY: number, - containerX: number, - containerY: number, - intensity: number = 0.5 -): { x: number; y: number; z: number } { - // Calculate distance from bead center to mouse - const dx = (mouseX - containerX) - beadX; - const dy = (mouseY - containerY) - beadY; - const distance = Math.sqrt(dx * dx + dy * dy); - - // Max influence radius (pixels) - const maxRadius = 150; - - if (distance > maxRadius) { - return { x: 0, y: 0, z: 0 }; - } - - // Calculate lift amount (inverse square falloff) - const influence = Math.max(0, 1 - (distance / maxRadius)); - const lift = influence * influence * intensity; - - return { - x: dx * lift * 0.1, - y: dy * lift * 0.1, - z: lift * 8 - }; -} - /** * Generate wood grain texture SVG pattern */ @@ -203,9 +166,8 @@ export function getWoodGrainPattern(id: string): string { * Get container class names for 3D enhancement level */ export function get3DContainerClasses( - enhanced3d: boolean | "subtle" | "realistic" | "delightful" | undefined, - lighting?: LightingStyle, - parallaxEnabled?: boolean + enhanced3d: boolean | "subtle" | "realistic" | undefined, + lighting?: LightingStyle ): string { const classes: string[] = ["abacus-3d-container"]; @@ -216,8 +178,6 @@ export function get3DContainerClasses( classes.push("enhanced-subtle"); } else if (enhanced3d === "realistic") { classes.push("enhanced-realistic"); - } else if (enhanced3d === "delightful") { - classes.push("enhanced-delightful"); } // Add lighting class @@ -225,11 +185,6 @@ export function get3DContainerClasses( classes.push(`lighting-${lighting}`); } - // Add parallax class - if (parallaxEnabled && enhanced3d === "delightful") { - classes.push("parallax-enabled"); - } - return classes.join(" "); } @@ -248,7 +203,7 @@ export function getBeadGradientId( /** * Physics config for different enhancement levels */ -export function getPhysicsConfig(enhanced3d: boolean | "subtle" | "realistic" | "delightful") { +export function getPhysicsConfig(enhanced3d: boolean | "subtle" | "realistic") { const base = { tension: 300, friction: 22, @@ -260,20 +215,11 @@ export function getPhysicsConfig(enhanced3d: boolean | "subtle" | "realistic" | return { ...base, clamp: true }; } - if (enhanced3d === "realistic") { - return { - tension: 320, - friction: 24, - mass: 0.6, - clamp: false - }; - } - - // delightful + // realistic return { - tension: 280, - friction: 20, - mass: 0.7, - clamp: false, // Allow overshoot for satisfying settle + tension: 320, + friction: 24, + mass: 0.6, + clamp: false }; } diff --git a/packages/abacus-react/src/AbacusReact.3d-effects.stories.tsx b/packages/abacus-react/src/AbacusReact.3d-effects.stories.tsx index 15b29d37..e97c7c3b 100644 --- a/packages/abacus-react/src/AbacusReact.3d-effects.stories.tsx +++ b/packages/abacus-react/src/AbacusReact.3d-effects.stories.tsx @@ -12,26 +12,20 @@ const meta: Meta = { component: ` # 3D Enhancement Showcase -Three levels of progressive 3D enhancement for the abacus to make interactions feel satisfying and real. +Two levels of progressive 3D enhancement for the abacus to make interactions feel satisfying and real. -## Proposal 1: Subtle (CSS Perspective + Shadows) +## Subtle (CSS Perspective + Shadows) - Light perspective tilt - Depth shadows on active beads - Smooth transitions - **Zero performance cost** -## Proposal 2: Realistic (Lighting + Materials) -- Everything from Proposal 1 + +## Realistic (Lighting + Materials) +- Everything from Subtle + - Realistic lighting effects with material gradients - Glossy/Satin/Matte bead materials - Wood grain textures on frame - Enhanced physics for realistic motion - -## Proposal 3: Delightful (Physics + Micro-interactions) -- Everything from Proposal 2 + -- Enhanced physics with satisfying bounce -- Hover parallax with Z-depth lift -- Maximum satisfaction ` } } @@ -64,7 +58,7 @@ export const CompareAllLevels: Story = {
-

Proposal 1: Subtle

+

Subtle

-

Proposal 2: Realistic (Satin Beads + Wood Frame)

+

Realistic (Satin Beads + Wood Frame)

- -
-

Proposal 3: Delightful (Glossy + Parallax)

- -
), parameters: { docs: { description: { - story: 'Side-by-side comparison of all three enhancement levels. **Click beads** to see how they move! **Hover over the Delightful version** to see parallax effect.' + story: 'Side-by-side comparison of both enhancement levels. **Click beads** to see how they move!' } } } @@ -361,100 +332,6 @@ export const Realistic_LightingComparison: Story = { } }; -// ============================================ -// PROPOSAL 3: DELIGHTFUL (Physics) -// ============================================ - -export const Delightful_FullExperience: Story = { - name: '3️⃣ Delightful - Full Experience', - args: { - value: 8642, - columns: 4, - showNumbers: true, - interactive: true, - animated: true, - soundEnabled: true, - colorScheme: 'rainbow', - scaleFactor: 1.4, - enhanced3d: 'delightful', - material3d: { - heavenBeads: 'glossy', - earthBeads: 'satin', - lighting: 'dramatic', - woodGrain: true - }, - physics3d: { - hoverParallax: true - } - }, - parameters: { - docs: { - description: { - story: '🎉 **Full delightful experience!** Click beads to see enhanced physics. Hover your mouse over the abacus to see parallax lift. Sound enabled for maximum satisfaction!' - } - } - } -}; - -export const Delightful_HoverParallax: Story = { - name: '3️⃣ Delightful - Hover Parallax', - args: { - value: 1234, - columns: 4, - showNumbers: true, - interactive: true, - animated: true, - colorScheme: 'place-value', - scaleFactor: 1.3, - enhanced3d: 'delightful', - material3d: { - heavenBeads: 'satin', - earthBeads: 'satin', - lighting: 'ambient' - }, - physics3d: { - hoverParallax: true // Enable hover parallax - } - }, - parameters: { - docs: { - description: { - story: '**Hover parallax enabled!** Move your mouse over the abacus. Beads near your cursor will lift up with Z-depth. Creates magical depth perception!' - } - } - } -}; - -export const Delightful_Traditional: Story = { - name: '3️⃣ Delightful - Traditional Wood', - args: { - value: 99999, - columns: 5, - showNumbers: true, - interactive: true, - animated: true, - colorScheme: 'monochrome', - scaleFactor: 1.2, - enhanced3d: 'delightful', - material3d: { - heavenBeads: 'matte', - earthBeads: 'matte', - lighting: 'ambient', - woodGrain: true - }, - physics3d: { - hoverParallax: true - } - }, - parameters: { - docs: { - description: { - story: 'Traditional aesthetic with **wood grain frame** + modern delightful physics. Best of both worlds!' - } - } - } -}; - // ============================================ // INTERACTIVE PLAYGROUND // ============================================ @@ -462,29 +339,27 @@ export const Delightful_Traditional: Story = { export const Playground: Story = { name: '🎮 Interactive Playground', render: () => { - const [level, setLevel] = React.useState<'subtle' | 'realistic' | 'delightful'>('delightful'); + const [level, setLevel] = React.useState<'subtle' | 'realistic'>('realistic'); const [material, setMaterial] = React.useState<'glossy' | 'satin' | 'matte'>('glossy'); const [lighting, setLighting] = React.useState<'top-down' | 'ambient' | 'dramatic'>('dramatic'); const [woodGrain, setWoodGrain] = React.useState(true); - const [parallax, setParallax] = React.useState(true); return (
@@ -512,13 +387,6 @@ export const Playground: Story = { Wood Grain
- -
- -

diff --git a/packages/abacus-react/src/AbacusReact.tsx b/packages/abacus-react/src/AbacusReact.tsx index d4464f91..52451a1a 100644 --- a/packages/abacus-react/src/AbacusReact.tsx +++ b/packages/abacus-react/src/AbacusReact.tsx @@ -253,10 +253,6 @@ export interface Abacus3DMaterial { woodGrain?: boolean; // Add wood texture to frame } -export interface Abacus3DPhysics { - hoverParallax?: boolean; // Beads lift on hover (delightful mode only) -} - export interface AbacusConfig { // Basic configuration value?: number | bigint; @@ -275,9 +271,8 @@ export interface AbacusConfig { soundVolume?: number; // 3D Enhancement - enhanced3d?: boolean | "subtle" | "realistic" | "delightful"; + enhanced3d?: boolean | "subtle" | "realistic"; material3d?: Abacus3DMaterial; - physics3d?: Abacus3DPhysics; // Advanced customization customStyles?: AbacusCustomStyles; @@ -1244,12 +1239,9 @@ interface BeadProps { colorPalette?: string; totalColumns?: number; // 3D Enhancement - enhanced3d?: boolean | "subtle" | "realistic" | "delightful"; + enhanced3d?: boolean | "subtle" | "realistic"; material3d?: Abacus3DMaterial; - physics3d?: Abacus3DPhysics; columnIndex?: number; - mousePosition?: { x: number; y: number }; - containerBounds?: { x: number; y: number }; } const Bead: React.FC = ({ @@ -1280,10 +1272,7 @@ const Bead: React.FC = ({ totalColumns = 1, enhanced3d, material3d, - physics3d, columnIndex, - mousePosition, - containerBounds, }) => { // Detect server-side rendering const isServer = typeof window === 'undefined'; @@ -1302,22 +1291,6 @@ const Bead: React.FC = ({ config: physicsConfig })); - // Calculate parallax offset for hover effect - const parallaxOffset = React.useMemo(() => { - if (enhanced3d === 'delightful' && physics3d?.hoverParallax && mousePosition && containerBounds) { - return Abacus3DUtils.calculateParallaxOffset( - x, - y, - mousePosition.x, - mousePosition.y, - containerBounds.x, - containerBounds.y, - 0.5 - ); - } - return { x: 0, y: 0, z: 0 }; - }, [enhanced3d, physics3d?.hoverParallax, mousePosition, containerBounds, x, y]); - // Arrow pulse animation for urgency indication const [{ arrowPulse }, arrowApi] = useSpring(() => ({ arrowPulse: 1, @@ -1427,9 +1400,9 @@ const Bead: React.FC = ({ const renderShape = () => { const halfSize = size / 2; - // Determine fill - use gradient for realistic/delightful modes, otherwise use color + // Determine fill - use gradient for realistic mode, otherwise use color let fillValue = color; - if ((enhanced3d === 'realistic' || enhanced3d === 'delightful') && columnIndex !== undefined) { + if (enhanced3d === 'realistic' && columnIndex !== undefined) { if (bead.type === 'heaven') { fillValue = `url(#bead-gradient-${columnIndex}-heaven)`; } else { @@ -1495,25 +1468,12 @@ const Bead: React.FC = ({ }; // Build style object based on animation mode - const parallaxEnabled = enhanced3d === 'delightful' && physics3d?.hoverParallax; const beadStyle: any = enableAnimation ? { transform: to( [springX, springY], - (sx, sy) => { - const translate = `translate(${sx - getXOffset() + parallaxOffset.x}px, ${sy - getYOffset() + parallaxOffset.y}px)`; - const transforms = [translate]; - - // Add parallax Z translation - if (parallaxEnabled && parallaxOffset.z > 0) { - transforms.push(`translateZ(${parallaxOffset.z}px)`); - } - - return transforms.join(' '); - }, + (sx, sy) => `translate(${sx - getXOffset()}px, ${sy - getYOffset()}px)`, ), - transformOrigin: 'center center', - transformStyle: 'preserve-3d', cursor: enableGestures ? "grab" : onClick ? "pointer" : "default", touchAction: "none" as const, transition: "opacity 0.2s ease-in-out", @@ -1624,7 +1584,6 @@ export const AbacusReact: React.FC = ({ // 3D enhancement props enhanced3d, material3d, - physics3d, // Advanced customization props customStyles, callbacks, @@ -2048,33 +2007,17 @@ export const AbacusReact: React.FC = ({ // 3D Enhancement: Calculate container classes const containerClasses = Abacus3DUtils.get3DContainerClasses( enhanced3d, - material3d?.lighting, - physics3d?.hoverParallax + material3d?.lighting ); - // 3D Enhancement: Track mouse position for parallax - const containerRef = useRef(null); - const [mousePos, setMousePos] = React.useState({ x: 0, y: 0 }); - const [containerBounds, setContainerBounds] = React.useState({ x: 0, y: 0 }); - - const handleMouseMove = useCallback((e: React.MouseEvent) => { - if (enhanced3d === 'delightful' && physics3d?.hoverParallax && containerRef.current) { - const rect = containerRef.current.getBoundingClientRect(); - setMousePos({ x: e.clientX, y: e.clientY }); - setContainerBounds({ x: rect.left, y: rect.top }); - } - }, [enhanced3d, physics3d?.hoverParallax]); - return (

= ({ `} {/* 3D Enhancement: Material gradients for beads */} - {(enhanced3d === 'realistic' || enhanced3d === 'delightful') && material3d && ( + {enhanced3d === 'realistic' && material3d && ( <> {/* Generate gradients for all beads based on material type */} {Array.from({ length: effectiveColumns }, (_, colIndex) => { @@ -2270,7 +2213,7 @@ export const AbacusReact: React.FC = ({ className="column-post" /> {/* Wood grain texture overlay for column posts */} - {(enhanced3d === 'realistic' || enhanced3d === 'delightful') && material3d?.woodGrain && ( + {enhanced3d === 'realistic' && material3d?.woodGrain && ( = ({ className="reckoning-bar" /> {/* Wood grain texture overlay for reckoning bar */} - {(enhanced3d === 'realistic' || enhanced3d === 'delightful') && material3d?.woodGrain && ( + {enhanced3d === 'realistic' && material3d?.woodGrain && ( = ({ totalColumns={effectiveColumns} enhanced3d={enhanced3d} material3d={material3d} - physics3d={physics3d} columnIndex={colIndex} - mousePosition={mousePos} - containerBounds={containerBounds} /> ); }),