fix(explore): variance + no loop-back on → navigation (#94)
Two reports: → sometimes "loops back", and the walk gets stuck on near-identical images. Cause: forwardTarget picked a uniformly-random neighbour from the 24 NEAREST, so it (a) often landed on an image already in the trail — which snaps the cursor back into history and makes → bounce between visited nodes — and (b) only ever offered near-duplicates. forwardTarget now: excludes already-visited neighbours (→ opens something new, no snap-back), and skips the closest third of the (similarity-sorted) pool so the jump favours the more-varied remainder instead of lookalikes. Neighbour pool widened 24→40 for more variety to browse + jump into. The post-← browser-forward walk through visited crumbs is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa
This commit is contained in:
@@ -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 () {
|
||||
|
||||
Reference in New Issue
Block a user