@@ -117,31 +117,42 @@ document.addEventListener("DOMContentLoaded", () => {
117117 let isMoving = false ;
118118 let isVisible = false ;
119119 let activeElement = null ;
120+ // Timestamp until which mouseover events should be ignored after spawn (grace period)
121+ let spawnGraceUntil = 0 ;
120122
121123 const breadWidth = 40 ;
122124 const breadHeight = 34 ;
123125
124- // Initial spawn from active language option
125- const activeLang = document . querySelector (
126- ".lang-option.active" ,
127- ) ;
128- if ( activeLang ) {
129- activeElement = activeLang ;
130- const rect = activeLang . getBoundingClientRect ( ) ;
131- targetX =
132- rect . left + window . scrollX - breadWidth / 2 ;
133- targetY =
134- rect . bottom + window . scrollY - breadHeight ;
135- currentX = targetX ;
136- currentY = targetY ;
137- isVisible = true ;
138- bread . classList . add ( "is-visible" , "is-spawning" ) ;
139- bread . style . transform = `translate3d(${ currentX } px, ${ currentY } px, 0)` ;
140-
141- setTimeout ( ( ) => {
142- bread . classList . remove ( "is-spawning" ) ;
143- } , 600 ) ;
144- }
126+ // Initial spawn: appear at screen center and stay there.
127+ // 初期生成時はアクティブな言語要素をターゲットにせず、
128+ // spawn位置に留まるよう target を current と同値にする。
129+ const centerX =
130+ window . scrollX +
131+ window . innerWidth / 2 -
132+ breadWidth / 2 ;
133+ const centerY =
134+ window . scrollY +
135+ window . innerHeight / 2 -
136+ breadHeight / 2 ;
137+
138+ currentX = centerX ;
139+ currentY = centerY ;
140+
141+ // 初期ターゲットを現在位置に合わせる(これによりスポーン後は移動しない)
142+ targetX = currentX ;
143+ targetY = currentY ;
144+
145+ // activeElement は設定しない(null のまま) -> animate では移動しない
146+ activeElement = null ;
147+
148+ isVisible = true ;
149+ bread . classList . add ( "is-visible" , "is-spawning" ) ;
150+ bread . style . transform = `translate3d(${ currentX } px, ${ currentY } px, 0)` ;
151+
152+ // remove spawning class after animation duration
153+ setTimeout ( ( ) => {
154+ bread . classList . remove ( "is-spawning" ) ;
155+ } , 600 ) ;
145156
146157 // Track hovers on any interactive element in the document
147158 document . addEventListener (
@@ -151,7 +162,28 @@ document.addEventListener("DOMContentLoaded", () => {
151162 "a, button, .lang-option, input, select, textarea, [role='button']" ,
152163 ) ;
153164
165+ // Ignore mouseover events during the spawn grace period so bread stays at spawn
166+ if (
167+ typeof spawnGraceUntil === "number" &&
168+ Date . now ( ) < spawnGraceUntil
169+ ) {
170+ return ;
171+ }
172+
173+ // Ignore interactions on the language switch control itself so the bread
174+ // doesn't move to the language switch button (e.g. elements with .lang-switch)
175+ if (
176+ target &&
177+ target . closest &&
178+ target . closest ( ".lang-switch" )
179+ ) {
180+ return ;
181+ }
182+
154183 if ( target ) {
184+ // ユーザーが意図的に要素にホバーした場合のみ追従させる挙動を残す。
185+ // ただし初期スポーン直後に自動で移動してしまうのを防ぐため、
186+ // ここでは通常のホバー時に activeElement を設定して追従を開始する。
155187 activeElement = target ;
156188 const rect = target . getBoundingClientRect ( ) ;
157189
0 commit comments