Skip to content

Commit 764fbeb

Browse files
committed
fix: EncapsulatedPacket animation timing and visibility logic
1 parent 322019b commit 764fbeb

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

src/components/EncapsulatedPacket.tsx

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface Props {
1212
}
1313

1414
const TOTAL_STAGES = 9
15+
const BASE_DURATION = 0.5 // Base duration for each stage
1516

1617
function EncapsulatedPacket(props: Props) {
1718
const { onComplete, onStageChange } = props
@@ -47,12 +48,15 @@ function EncapsulatedPacket(props: Props) {
4748
for (let s = stageRef.current; s < TOTAL_STAGES; s++) {
4849
if (cancelled) break
4950
setStage(s)
50-
onStageChange?.(s)
5151
await controls.start({
5252
left: `${positions[s].x}%`,
5353
top: positions[s].y,
54-
transition: { duration: 0.5 / props.speed, ease: 'linear' },
54+
transition: {
55+
duration: BASE_DURATION / props.speed,
56+
ease: 'anticipate',
57+
},
5558
})
59+
onStageChange?.(s)
5660
stageRef.current = s + 1
5761
if (!props.isPlaying) break
5862
}
@@ -78,14 +82,6 @@ function EncapsulatedPacket(props: Props) {
7882
onStageChange,
7983
])
8084

81-
const visibleHeaders = useMemo(() => {
82-
const visibleHeaders: number[] = []
83-
if (stage >= 1 && stage <= 7) visibleHeaders.push(1)
84-
if (stage >= 2 && stage <= 6) visibleHeaders.push(2)
85-
if (stage >= 3 && stage <= 5) visibleHeaders.push(3)
86-
return visibleHeaders
87-
}, [stage])
88-
8985
const Icon = props.packet.type.icon
9086
const isClientToServer = props.packet.from === 'client'
9187
const isOnSenderSide = stage < 4
@@ -108,22 +104,29 @@ function EncapsulatedPacket(props: Props) {
108104
<div className="w-16 h-12 mt-2 bg-white border-2 border-black rounded flex items-start justify-center">
109105
<Icon className="mt-0.5 w-6 h-6 text-black" />
110106
</div>
111-
{visibleHeaders.map((layerIndex, i) => {
107+
{[1, 2, 3].map((layerIndex, i) => {
112108
const layer = TCP_IP_LAYERS[layerIndex]
113109
const verticalSpacing = 20
114110
const verticalOffset = i * verticalSpacing
111+
let headerVisible = false
112+
if (layerIndex === 1) headerVisible = stage >= 1 && stage <= 7 // Transport: stages 1-7
113+
if (layerIndex === 2) headerVisible = stage >= 2 && stage <= 6 // Internet: stages 2-6
114+
if (layerIndex === 3) headerVisible = stage >= 3 && stage <= 5 // Network Interface: stages 3-5
115115
return (
116116
<div key={`header-${layerIndex}`}>
117-
<div
117+
<motion.div
118118
className="absolute inset-0 border-4 rounded"
119119
style={{
120120
borderColor: layer.color,
121-
transform: `scale(${1 + (visibleHeaders.length - i) * 0.12})`,
121+
transform: `scale(${1 + (3 - i) * 0.12})`,
122122
zIndex: -layerIndex,
123123
}}
124+
initial={{ opacity: 0 }}
125+
animate={{ opacity: headerVisible ? 1 : 0 }}
126+
transition={{ duration: 0.25, delay: headerVisible ? 0.5 : 0 }}
124127
/>
125128
{!isOnTransmission && (
126-
<div
129+
<motion.div
127130
className="absolute text-[8px] font-bold px-1 py-0.5 rounded whitespace-nowrap text-white text-center min-w-18"
128131
style={{
129132
top: `${verticalOffset}px`,
@@ -132,9 +135,15 @@ function EncapsulatedPacket(props: Props) {
132135
transform: `translateX(${alignRight ? '16px' : '-16px'})`,
133136
backgroundColor: layer.color,
134137
}}
138+
initial={{ opacity: 0 }}
139+
animate={{ opacity: headerVisible ? 1 : 0 }}
140+
transition={{
141+
duration: 0.25,
142+
delay: headerVisible ? 0.5 : 0,
143+
}}
135144
>
136145
{layer.header}
137-
</div>
146+
</motion.div>
138147
)}
139148
</div>
140149
)

0 commit comments

Comments
 (0)