On a big tablet held in two hands, one pile in the middle leaves both thumbs doing the same job in turn. Two piles, one per side, do not: each thumb owns a pile, they never wait for each other, and the queue drains twice as fast. There are two ways to build it, and they feel different enough to be worth trying both.
piles: 2 on a single deck. One set of zones, one carving, two cards dealt side by side โ the
card you touch is the one the keyboard and the suggestion follow. Half the screen furniture, and the aim is
shared: both hands throw at the same targets.
Two decks, each with its own zones, sharing a queue and a model. More room per hand and independent layouts, at the price of two sets of tiles on screen โ and of aiming at a different dev with each hand.
Both decks pull from the same pile and top themselves back up when a card leaves. Whichever hand is free takes the next card, so a slow decision on the left never idles the right.
A single recommender advises both piles. What the left hand teaches, the right hand's suggestion knows about on the very next card โ which is the real argument for sorting with two hands rather than in two sessions.
Two stages mean two layouts, two suggestion loops and two sets of zones on screen at once: on a 13-inch tablet that is comfortable, on a phone it is absurd. The library will happily run four โ whether a human can is the open question, and the answer is probably two.
new Deck(el, {
touchPreview: false,
items, zones, meta, renderCard,
piles: 2, // two cards dealt side by side, one set of zones
advisor: brain,
touchFullscreen: false,
});
// the pile you touch is the one the keyboard talks to
deck.active // 0 or 1
deck.active = 0; // or set it yourself A pile keeps its card until that card actually leaves. Filing on the left never shuffles what the right hand was about to drop โ which sounds obvious until you build it the other way and watch a card change under a thumb already moving towards a zone.
const brain = createRecommender({ key: 'two-hands' });
const queue = shuffled(60);
const make = (el, keys) => new Deck(el, {
touchPreview: false,
items: queue.splice(0, 3),
zones, meta, renderCard, keys,
advisor: brain, // one model, both hands
touchFullscreen: false, // side by side, neither deck is the screen
onSort: (item, zone) => api.file(item.id, zone.id),
onEmpty: () => {},
});
const left = make(document.querySelector('#left'), 'qweasd');
const right = make(document.querySelector('#right'), 'uiojkl');
// whichever hand frees up takes the next card
for (const deck of [left, right]) {
deck.root.addEventListener('trieur:sort', () => {
if (queue.length) deck.setItems([...deck.items, queue.shift()]);
});
} touchFullscreen: false matters here: side by side, neither deck is the screen, and a tap that
expanded one of them would break the symmetry the whole idea rests on. The two decks stay inline and take the
gesture themselves.