fix: remove wobble physics and enhance wood grain visibility
**Changes:** - Removed wobble physics feature (was janky and distracting) - Increased wood grain opacity from 0.15 → 0.4 (realistic) and 0.45 (delightful) - Enhanced wood grain pattern with bolder strokes and more visible knots - Removed getWobbleRotation utility function - Simplified Abacus3DPhysics interface to only hoverParallax - Updated all stories to remove wobble references - Removed velocity tracking code from Bead component Wood grain is now much more visible on frame elements without affecting bead spacing or layout. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
26bdb11237
commit
5d97673406
|
|
@ -161,11 +161,14 @@
|
|||
"Bash(printenv:*)",
|
||||
"Bash(typst:*)",
|
||||
"Bash(npx tsx:*)",
|
||||
"Bash(sort:*)"
|
||||
"Bash(sort:*)",
|
||||
"Bash(scp:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"enabledMcpjsonServers": ["sqlite"]
|
||||
"enabledMcpjsonServers": [
|
||||
"sqlite"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { writeFileSync, readFileSync, mkdirSync, rmSync } from 'fs'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { AbacusReact, useAbacusConfig } from '@soroban/abacus-react'
|
|||
import { css } from '../../styled-system/css'
|
||||
import { useMyAbacus } from '@/contexts/MyAbacusContext'
|
||||
import { HomeHeroContext } from '@/contexts/HomeHeroContext'
|
||||
import { Z_INDEX } from '@/constants/zIndex'
|
||||
|
||||
export function MyAbacus() {
|
||||
const { isOpen, close, toggle } = useMyAbacus()
|
||||
|
|
@ -99,7 +98,7 @@ export function MyAbacus() {
|
|||
inset: 0,
|
||||
bg: 'rgba(0, 0, 0, 0.8)',
|
||||
backdropFilter: 'blur(12px)',
|
||||
zIndex: Z_INDEX.MY_ABACUS_BACKDROP,
|
||||
zIndex: 101,
|
||||
animation: 'backdropFadeIn 0.4s ease-out',
|
||||
})}
|
||||
onClick={close}
|
||||
|
|
@ -129,7 +128,7 @@ export function MyAbacus() {
|
|||
fontWeight: 'bold',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s',
|
||||
zIndex: Z_INDEX.MY_ABACUS + 1,
|
||||
zIndex: 103,
|
||||
animation: 'fadeIn 0.3s ease-out 0.2s both',
|
||||
_hover: {
|
||||
bg: 'rgba(255, 255, 255, 0.2)',
|
||||
|
|
@ -149,7 +148,7 @@ export function MyAbacus() {
|
|||
onClick={isOpen || isHeroMode ? undefined : toggle}
|
||||
className={css({
|
||||
position: isHeroMode ? 'absolute' : 'fixed',
|
||||
zIndex: Z_INDEX.MY_ABACUS,
|
||||
zIndex: 102,
|
||||
cursor: isOpen || isHeroMode ? 'default' : 'pointer',
|
||||
transition: 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
// Three modes: hero (absolute - scrolls with document), button (fixed), open (fixed)
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
|
||||
/* Wood grain texture overlay */
|
||||
.abacus-3d-container.enhanced-realistic .frame-wood {
|
||||
opacity: 0.15;
|
||||
opacity: 0.4;
|
||||
mix-blend-mode: multiply;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
@ -293,11 +293,6 @@
|
|||
z-index: -1;
|
||||
}
|
||||
|
||||
/* Wobble physics - applied via inline styles from React Spring */
|
||||
.bead-wobble {
|
||||
/* transform-origin set dynamically */
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
/* Frame depth enhancement */
|
||||
.abacus-3d-container.enhanced-delightful rect[class*="column-post"],
|
||||
|
|
@ -307,25 +302,11 @@
|
|||
drop-shadow(0 0 2px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
/* Wood grain texture - enhanced */
|
||||
.frame-wood-enhanced {
|
||||
background-image:
|
||||
repeating-linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
transparent 2px,
|
||||
rgba(139, 90, 43, 0.03) 2px,
|
||||
rgba(139, 90, 43, 0.03) 4px
|
||||
),
|
||||
repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 1px,
|
||||
rgba(101, 67, 33, 0.02) 1px,
|
||||
rgba(101, 67, 33, 0.02) 2px
|
||||
);
|
||||
opacity: 0.2;
|
||||
/* Wood grain texture - enhanced for delightful mode */
|
||||
.abacus-3d-container.enhanced-delightful .frame-wood {
|
||||
opacity: 0.45;
|
||||
mix-blend-mode: multiply;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Accessibility - Reduced motion */
|
||||
|
|
|
|||
|
|
@ -143,19 +143,6 @@ export function getBeadZDepth(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate wobble rotation based on velocity (for delightful mode)
|
||||
*/
|
||||
export function getWobbleRotation(velocity: number, axis: "x" | "y" = "x"): string {
|
||||
const maxRotation = 3; // degrees
|
||||
const rotation = Math.max(-maxRotation, Math.min(maxRotation, velocity * -2));
|
||||
|
||||
if (axis === "x") {
|
||||
return `rotateX(${rotation}deg)`;
|
||||
}
|
||||
return `rotateY(${rotation}deg)`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate parallax offset based on mouse position
|
||||
*/
|
||||
|
|
@ -197,16 +184,17 @@ export function calculateParallaxOffset(
|
|||
export function getWoodGrainPattern(id: string): string {
|
||||
return `
|
||||
<pattern id="${id}" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
|
||||
<rect width="100" height="100" fill="#8B5A2B" opacity="0.3"/>
|
||||
<!-- Grain lines -->
|
||||
<path d="M 0 10 Q 25 8 50 10 T 100 10" stroke="#654321" stroke-width="0.5" fill="none" opacity="0.4"/>
|
||||
<path d="M 0 30 Q 25 28 50 30 T 100 30" stroke="#654321" stroke-width="0.5" fill="none" opacity="0.3"/>
|
||||
<path d="M 0 50 Q 25 48 50 50 T 100 50" stroke="#654321" stroke-width="0.5" fill="none" opacity="0.4"/>
|
||||
<path d="M 0 70 Q 25 68 50 70 T 100 70" stroke="#654321" stroke-width="0.5" fill="none" opacity="0.3"/>
|
||||
<path d="M 0 90 Q 25 88 50 90 T 100 90" stroke="#654321" stroke-width="0.5" fill="none" opacity="0.4"/>
|
||||
<!-- Knots -->
|
||||
<ellipse cx="20" cy="25" rx="8" ry="6" fill="#654321" opacity="0.2"/>
|
||||
<ellipse cx="75" cy="65" rx="6" ry="8" fill="#654321" opacity="0.2"/>
|
||||
<rect width="100" height="100" fill="#8B5A2B" opacity="0.5"/>
|
||||
<!-- Grain lines - more visible -->
|
||||
<path d="M 0 10 Q 25 8 50 10 T 100 10" stroke="#654321" stroke-width="1" fill="none" opacity="0.6"/>
|
||||
<path d="M 0 30 Q 25 28 50 30 T 100 30" stroke="#654321" stroke-width="1" fill="none" opacity="0.5"/>
|
||||
<path d="M 0 50 Q 25 48 50 50 T 100 50" stroke="#654321" stroke-width="1" fill="none" opacity="0.6"/>
|
||||
<path d="M 0 70 Q 25 68 50 70 T 100 70" stroke="#654321" stroke-width="1" fill="none" opacity="0.5"/>
|
||||
<path d="M 0 90 Q 25 88 50 90 T 100 90" stroke="#654321" stroke-width="1" fill="none" opacity="0.6"/>
|
||||
<!-- Knots - more prominent -->
|
||||
<ellipse cx="20" cy="25" rx="8" ry="6" fill="#654321" opacity="0.35"/>
|
||||
<ellipse cx="75" cy="65" rx="6" ry="8" fill="#654321" opacity="0.35"/>
|
||||
<ellipse cx="45" cy="82" rx="5" ry="7" fill="#654321" opacity="0.3"/>
|
||||
</pattern>
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ Three levels of progressive 3D enhancement for the abacus to make interactions f
|
|||
## Proposal 3: Delightful (Physics + Micro-interactions)
|
||||
- Everything from Proposal 2 +
|
||||
- Enhanced physics with satisfying bounce
|
||||
- Wobble rotation during movement
|
||||
- Hover parallax with Z-depth lift
|
||||
- Maximum satisfaction
|
||||
`
|
||||
|
|
@ -99,7 +98,7 @@ export const CompareAllLevels: Story = {
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<h3 style={{ marginBottom: '10px', textAlign: 'center' }}>Proposal 3: Delightful (Glossy + Wobble + Parallax)</h3>
|
||||
<h3 style={{ marginBottom: '10px', textAlign: 'center' }}>Proposal 3: Delightful (Glossy + Parallax)</h3>
|
||||
<AbacusReact
|
||||
value={4242}
|
||||
columns={4}
|
||||
|
|
@ -116,7 +115,6 @@ export const CompareAllLevels: Story = {
|
|||
woodGrain: true
|
||||
}}
|
||||
physics3d={{
|
||||
wobble: true,
|
||||
hoverParallax: true
|
||||
}}
|
||||
/>
|
||||
|
|
@ -386,44 +384,13 @@ export const Delightful_FullExperience: Story = {
|
|||
woodGrain: true
|
||||
},
|
||||
physics3d: {
|
||||
wobble: true,
|
||||
hoverParallax: true
|
||||
}
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: '🎉 **Full delightful experience!** Click beads to see wobble physics. Hover your mouse over the abacus to see parallax lift. Sound enabled for maximum satisfaction!'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const Delightful_WobblePhysics: Story = {
|
||||
name: '3️⃣ Delightful - Wobble Physics',
|
||||
args: {
|
||||
value: 5555,
|
||||
columns: 4,
|
||||
showNumbers: true,
|
||||
interactive: true,
|
||||
animated: true,
|
||||
colorScheme: 'heaven-earth',
|
||||
scaleFactor: 1.3,
|
||||
enhanced3d: 'delightful',
|
||||
material3d: {
|
||||
heavenBeads: 'glossy',
|
||||
earthBeads: 'glossy',
|
||||
lighting: 'top-down'
|
||||
},
|
||||
physics3d: {
|
||||
wobble: true, // Enable wobble rotation
|
||||
hoverParallax: false
|
||||
}
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: '**Wobble physics enabled!** Click beads rapidly to see them wobble and rotate during movement. Enhanced spring physics with bounce!'
|
||||
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!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -446,7 +413,6 @@ export const Delightful_HoverParallax: Story = {
|
|||
lighting: 'ambient'
|
||||
},
|
||||
physics3d: {
|
||||
wobble: false,
|
||||
hoverParallax: true // Enable hover parallax
|
||||
}
|
||||
},
|
||||
|
|
@ -477,7 +443,6 @@ export const Delightful_Traditional: Story = {
|
|||
woodGrain: true
|
||||
},
|
||||
physics3d: {
|
||||
wobble: true,
|
||||
hoverParallax: true
|
||||
}
|
||||
},
|
||||
|
|
@ -501,7 +466,6 @@ export const Playground: Story = {
|
|||
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 [wobble, setWobble] = React.useState(true);
|
||||
const [parallax, setParallax] = React.useState(true);
|
||||
|
||||
return (
|
||||
|
|
@ -549,17 +513,10 @@ export const Playground: Story = {
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
||||
<input type="checkbox" checked={wobble} onChange={e => setWobble(e.target.checked)} />
|
||||
<span>Wobble Physics</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
||||
<input type="checkbox" checked={parallax} onChange={e => setParallax(e.target.checked)} />
|
||||
<span>Hover Parallax</span>
|
||||
<span>Hover Parallax (Delightful)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -581,7 +538,6 @@ export const Playground: Story = {
|
|||
woodGrain: woodGrain
|
||||
}}
|
||||
physics3d={{
|
||||
wobble: wobble,
|
||||
hoverParallax: parallax
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -254,11 +254,7 @@ export interface Abacus3DMaterial {
|
|||
}
|
||||
|
||||
export interface Abacus3DPhysics {
|
||||
wobble?: boolean; // Beads rotate slightly during movement
|
||||
clackEffect?: boolean; // Visual ripple when beads snap
|
||||
hoverParallax?: boolean; // Beads lift on hover
|
||||
particleSnap?: "off" | "subtle" | "sparkle"; // Particle effects on snap
|
||||
hapticFeedback?: boolean; // Trigger haptic feedback on mobile
|
||||
hoverParallax?: boolean; // Beads lift on hover (delightful mode only)
|
||||
}
|
||||
|
||||
export interface AbacusConfig {
|
||||
|
|
@ -1306,10 +1302,6 @@ const Bead: React.FC<BeadProps> = ({
|
|||
config: physicsConfig
|
||||
}));
|
||||
|
||||
// Track velocity for wobble effect (delightful mode only)
|
||||
const velocityRef = useRef(0);
|
||||
const lastYRef = useRef(y);
|
||||
|
||||
// Calculate parallax offset for hover effect
|
||||
const parallaxOffset = React.useMemo(() => {
|
||||
if (enhanced3d === 'delightful' && physics3d?.hoverParallax && mousePosition && containerBounds) {
|
||||
|
|
@ -1402,11 +1394,6 @@ const Bead: React.FC<BeadProps> = ({
|
|||
|
||||
React.useEffect(() => {
|
||||
if (enableAnimation) {
|
||||
// Calculate velocity for wobble effect
|
||||
const deltaY = y - lastYRef.current;
|
||||
velocityRef.current = deltaY;
|
||||
lastYRef.current = y;
|
||||
|
||||
api.start({ x, y, config: physicsConfig });
|
||||
} else {
|
||||
api.set({ x, y });
|
||||
|
|
@ -1508,7 +1495,6 @@ const Bead: React.FC<BeadProps> = ({
|
|||
};
|
||||
|
||||
// Build style object based on animation mode
|
||||
const wobbleEnabled = enhanced3d === 'delightful' && physics3d?.wobble;
|
||||
const parallaxEnabled = enhanced3d === 'delightful' && physics3d?.hoverParallax;
|
||||
const beadStyle: any = enableAnimation
|
||||
? {
|
||||
|
|
@ -1523,11 +1509,6 @@ const Bead: React.FC<BeadProps> = ({
|
|||
transforms.push(`translateZ(${parallaxOffset.z}px)`);
|
||||
}
|
||||
|
||||
// Add wobble rotation
|
||||
if (wobbleEnabled && velocityRef.current !== 0) {
|
||||
transforms.push(Abacus3DUtils.getWobbleRotation(velocityRef.current, 'x'));
|
||||
}
|
||||
|
||||
return transforms.join(' ');
|
||||
},
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue