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 +
|
// 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
|
// tag CRUD over the anchor) so the Explore workspace reuses the modal's tag
|
||||||
// rail verbatim for modal-parity tagging while rabbit-holing.
|
// 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', () => {
|
export const useExploreStore = defineStore('explore', () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
@@ -81,16 +81,26 @@ export const useExploreStore = defineStore('explore', () => {
|
|||||||
return cursor.value > 0 ? breadcrumb.value[cursor.value - 1].id : null
|
return cursor.value > 0 ? breadcrumb.value[cursor.value - 1].id : null
|
||||||
}
|
}
|
||||||
|
|
||||||
// → target: the next already-visited crumb if we'd stepped back, else a
|
// → target: after a ←, walk forward through the already-visited trail
|
||||||
// RANDOM neighbour to keep the rabbit-hole going. Null if neither exists.
|
// (browser-style). Otherwise jump to a varied neighbour to keep the
|
||||||
|
// rabbit-hole going — null if neither exists.
|
||||||
function forwardTarget () {
|
function forwardTarget () {
|
||||||
if (cursor.value >= 0 && cursor.value < breadcrumb.value.length - 1) {
|
if (cursor.value >= 0 && cursor.value < breadcrumb.value.length - 1) {
|
||||||
return breadcrumb.value[cursor.value + 1].id
|
return breadcrumb.value[cursor.value + 1].id
|
||||||
}
|
}
|
||||||
if (neighbors.value.length) {
|
if (!neighbors.value.length) return null
|
||||||
return neighbors.value[Math.floor(Math.random() * neighbors.value.length)].id
|
// Prefer UNVISITED neighbours so → opens something new instead of landing on
|
||||||
}
|
// a crumb (which snaps the cursor back into the trail — the "loops back"
|
||||||
return null
|
// 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 () {
|
function reset () {
|
||||||
|
|||||||
Reference in New Issue
Block a user