diff --git a/frontend/src/stores/explore.js b/frontend/src/stores/explore.js index 29f7cc0..1bb269f 100644 --- a/frontend/src/stores/explore.js +++ b/frontend/src/stores/explore.js @@ -11,7 +11,7 @@ import { toast } from '../utils/toast.js' // trail. The store ALSO acts as a TagPanel "host" (current/currentImageId + // tag CRUD over the anchor) so the Explore workspace reuses the modal's tag // rail verbatim for modal-parity tagging while rabbit-holing. -const NEIGHBOR_LIMIT = 24 +const NEIGHBOR_LIMIT = 40 // a wider pool → more variety to browse + jump into export const useExploreStore = defineStore('explore', () => { const api = useApi() @@ -81,16 +81,26 @@ export const useExploreStore = defineStore('explore', () => { return cursor.value > 0 ? breadcrumb.value[cursor.value - 1].id : null } - // → target: the next already-visited crumb if we'd stepped back, else a - // RANDOM neighbour to keep the rabbit-hole going. Null if neither exists. + // → target: after a ←, walk forward through the already-visited trail + // (browser-style). Otherwise jump to a varied neighbour to keep the + // rabbit-hole going — null if neither exists. function forwardTarget () { if (cursor.value >= 0 && cursor.value < breadcrumb.value.length - 1) { return breadcrumb.value[cursor.value + 1].id } - if (neighbors.value.length) { - return neighbors.value[Math.floor(Math.random() * neighbors.value.length)].id - } - return null + if (!neighbors.value.length) return null + // Prefer UNVISITED neighbours so → opens something new instead of landing on + // a crumb (which snaps the cursor back into the trail — the "loops back" + // report). Fall back to the full set only if every neighbour's been seen. + const seen = new Set(breadcrumb.value.map((c) => c.id)) + let pool = neighbors.value.filter((n) => !seen.has(n.id)) + if (!pool.length) pool = neighbors.value + // neighbors come similarity-sorted (nearest first). Skip the closest slice — + // those near-duplicates are exactly what you get stuck cycling through — and + // pick from the more-varied remainder, for real variance in the walk. + const skip = pool.length >= 6 ? Math.floor(pool.length / 3) : 0 + const cands = pool.slice(skip) + return cands[Math.floor(Math.random() * cands.length)].id } function reset () {