Skip to content

Commit 6335deb

Browse files
tmck-codeclaude
andcommitted
pikachu companion: desktop F key flips about the column under the cursor; device-specific hints
Detect fine-pointer/hover devices; on desktop F toggles front/back pivoting on the hovered column, tooltips/hints say click/scroll/F; on touch the hints keep tap/pinch/long-press wording. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a353941 commit 6335deb

1 file changed

Lines changed: 50 additions & 9 deletions

File tree

  • pages/pikachu-stitch-companion/js

pages/pikachu-stitch-companion/js/input.js

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,22 @@ setStartBtn.addEventListener('click', ()=>{
3838
/* ---------- flip (front/back view) + symbol overlay toggles ---------- */
3939
const flipBtn = document.getElementById('flipBtn');
4040
const viewLabel = document.getElementById('viewLabel');
41-
flipBtn.addEventListener('click', ()=>{
42-
// keep the same cells in view: mirror the pan offset about the pivot
43-
// column's screen x (pinned by long-press), or the stage centre when none
44-
// is pinned. For a column centre at screen X, front: X = tx+(c+.5)s and
45-
// back: X = tx+N*s-(c+.5)s, so preserving X gives tx' = 2X - tx - N*s.
41+
// desktop = fine pointer + hover (mouse/trackpad); phones/tablets are coarse
42+
export const isDesktop = window.matchMedia('(hover: hover) and (pointer: fine)').matches;
43+
44+
/**
45+
* flipView(pivotCol?) - toggle front/back, mirroring the pan offset about a
46+
* column's screen x so the same cells stay in view: pivotCol if given, else
47+
* the long-press-pinned view.pivotCol, else the stage centre. For a column
48+
* centre at screen X, front: X = tx+(c+.5)s and back: X = tx+N*s-(c+.5)s,
49+
* so preserving X gives tx' = 2X - tx - N*s.
50+
*/
51+
function flipView(pivotCol){
4652
const gs = N*view.base*view.scale, cs = view.base*view.scale;
53+
const col = pivotCol!=null ? pivotCol : view.pivotCol;
4754
let X = stage.clientWidth/2;
48-
if (view.pivotCol!=null){
49-
const off = (view.pivotCol+0.5)*cs;
55+
if (col!=null){
56+
const off = (col+0.5)*cs;
5057
X = view.backView ? view.tx + gs - off : view.tx + off;
5158
}
5259
view.backView = !view.backView;
@@ -55,11 +62,32 @@ flipBtn.addEventListener('click', ()=>{
5562
flipBtn.classList.toggle('on', view.backView);
5663
flipBtn.setAttribute('aria-pressed', String(view.backView));
5764
viewLabel.textContent = view.backView ? 'Back' : 'Front';
58-
const lbl = view.backView ? 'Flip to front view' : 'Flip to back view';
65+
const lbl = (view.backView ? 'Flip to front view' : 'Flip to back view') + (isDesktop ? ' (F)' : '');
5966
flipBtn.setAttribute('aria-label', lbl);
6067
flipBtn.title = lbl;
6168
draw();
62-
});
69+
}
70+
flipBtn.addEventListener('click', ()=>flipView());
71+
72+
// desktop: F flips about the column under the mouse cursor (no pinning
73+
// needed); falls back to the pinned column / centre when the cursor isn't
74+
// over the grid
75+
let lastMouse = null;
76+
if (isDesktop){
77+
flipBtn.title = 'Flip to back view (F)';
78+
flipBtn.setAttribute('aria-label', 'Flip to back view (F)');
79+
stage.addEventListener('pointermove', e=>{ if (e.pointerType==='mouse') lastMouse = {x:e.clientX, y:e.clientY}; });
80+
stage.addEventListener('pointerleave', ()=>{ lastMouse = null; });
81+
window.addEventListener('keydown', e=>{
82+
if (e.key!=='f' && e.key!=='F') return;
83+
if (e.ctrlKey || e.metaKey || e.altKey) return;
84+
const t = e.target;
85+
if (t && (t.tagName==='INPUT' || t.tagName==='SELECT' || t.tagName==='TEXTAREA' || t.isContentEditable)) return;
86+
e.preventDefault();
87+
const i = lastMouse ? cellAtClient(lastMouse.x, lastMouse.y) : -1;
88+
flipView(i>=0 ? i % N : undefined);
89+
});
90+
}
6391

6492
const symbolsBtn = document.getElementById('symbolsBtn');
6593
symbolsBtn.addEventListener('click', ()=>{
@@ -69,6 +97,19 @@ symbolsBtn.addEventListener('click', ()=>{
6997
draw();
7098
});
7199

100+
/* ---------- device-specific hint copy ---------- */
101+
{
102+
const hint = document.querySelector('header .hint');
103+
const zoomHint = document.getElementById('zoomHint');
104+
if (isDesktop){
105+
if (hint) hint.innerHTML = 'click a colour to isolate it<br>scroll to zoom';
106+
if (zoomHint) zoomHint.textContent = 'drag to pan · double-click to zoom · F flips around the column under the cursor';
107+
} else {
108+
if (hint) hint.innerHTML = 'tap a colour to isolate it<br>pinch to zoom';
109+
if (zoomHint) zoomHint.textContent = 'drag to pan · double-tap to zoom · hold a column to pin it for flipping';
110+
}
111+
}
112+
72113
/* ---------- marking gesture state ---------- */
73114
let gesture = null; // {startCell, dir, touched:Set, longPressTimer, moved}
74115
const LONG_PRESS_MS = 500;

0 commit comments

Comments
 (0)