Hey!
I made a modified image occlusion note type that displays vertical images larger (with scroll bar) and auto-scrolls to the current occlusion:

Code for the frontside:
{{#Header}}<div>{{Header}}</div>{{/Header}}
<div style="display: none">{{cloze:Occlusion}}</div>
<div id="err"></div>
<div id="image-occlusion-container">
{{Image}}
<canvas id="image-occlusion-canvas"></canvas>
</div>
<script>
function scrollToActiveOcclusion() {
const canvas = document.getElementById('image-occlusion-canvas');
// Frontside: .cloze, Backside: .cloze-highlight
const shapes = [...document.querySelectorAll('.cloze[data-shape], .cloze-highlight[data-shape]')];
if (!canvas || !shapes.length) return;
const top = Math.min(...shapes.map(s => +s.dataset.top));
const bottom = Math.max(...shapes.map(s => +s.dataset.top + +s.dataset.height));
const center = (top + bottom) / 2;
const box = canvas.getBoundingClientRect();
const y = box.top + window.scrollY + center * box.height;
const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
const target = y - window.innerHeight / 2;
const toBottom = maxScroll - target < window.innerHeight / 4;
window.scrollTo({ top: toBottom ? maxScroll : Math.max(0, target) });
}
try {
const container = document.getElementById('image-occlusion-container');
const img = container.querySelector('img');
const imgReady = img.complete
? Promise.resolve()
: new Promise(resolve => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', resolve, { once: true });
});
imgReady.then(() => {
container.classList.toggle('tall', img.naturalHeight > img.naturalWidth);
anki.imageOcclusion.setup();
setTimeout(function(){
requestAnimationFrame(scrollToActiveOcclusion);
}, 10);
});
} catch (exc) {
document.getElementById("err").innerHTML = `Failed to load image occlusion. Are you using the latest Anki version?<br><br>${exc}`;
}
</script>
Code for the backside:
{{#Header}}<div>{{Header}}</div>{{/Header}}
<div style="display: none">{{cloze:Occlusion}}</div>
<div id="err"></div>
<div id="image-occlusion-container">
{{Image}}
<canvas id="image-occlusion-canvas"></canvas>
</div>
<script>
function scrollToActiveOcclusion() {
const canvas = document.getElementById('image-occlusion-canvas');
const shapes = [...document.querySelectorAll('.cloze[data-shape], .cloze-highlight[data-shape]')];
if (!canvas || !shapes.length) return;
const top = Math.min(...shapes.map(s => +s.dataset.top));
const bottom = Math.max(...shapes.map(s => +s.dataset.top + +s.dataset.height));
const center = (top + bottom) / 2;
const box = canvas.getBoundingClientRect();
const y = box.top + window.scrollY + center * box.height;
const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
const target = y - window.innerHeight / 2;
const toBottom = maxScroll - target < window.innerHeight / 4;
window.scrollTo({ top: toBottom ? maxScroll : Math.max(0, target) });
}
try {
const container = document.getElementById('image-occlusion-container');
const img = container.querySelector('img');
const imgReady = img.complete
? Promise.resolve()
: new Promise(resolve => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', resolve, { once: true });
});
imgReady.then(() => {
container.classList.toggle('tall', img.naturalHeight > img.naturalWidth);
anki.imageOcclusion.setup();
setTimeout(function(){
requestAnimationFrame(scrollToActiveOcclusion);
}, 10);
});
} catch (exc) {
document.getElementById("err").innerHTML = `Failed to load image occlusion. Are you using the latest Anki version?<br><br>${exc}`;
}
</script>
<div><button id="toggle">Occlusions on/off</button></div>
Code for style:
#image-occlusion-canvas {
--inactive-shape-color: #ffeba2;
--active-shape-color: #ff8e8e;
--inactive-shape-border: 1px #212121;
--active-shape-border: 1px #212121;
}
.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
margin-bottom: 75px;
}
img{
max-height: none !important;
max-width: none !important;
width: 100%;
height: auto;
}
#image-occlusion-container.tall{
max-height: 150vh !important;
}
Note: You may need to adjust the field names on the front and back side (e.g. {{Bild}} instead of {{Image}} for the german Anki version).
Best
anghenfil