The current state of infinite-scroll.js from the default Casper theme is buggy. I’m going to improve the script and make it work.

Found out it’s my own fault for editing index.hbs file. I didn’t expect you need to add extra argument page to load correct offset from a list. Get Posts exclude tags
;(() => {
	const nextElement = document.querySelector('link[rel=next]'), // next link element
		feedElement = document.querySelector('.post-feed') // post feed element
	if (!nextElement || !feedElement) return

	const state = {
		activeZoneHeight: 300,
		ticking: false,
		lastScrollY: window.scrollY,
		lastWindowHeight: window.innerHeight,
		lastDocumentHeight: document.documentElement.scrollHeight,
		href: nextElement.href
	}

	const app = {
		loading: false,
		onPageLoad(doc) {
			const nextElement = doc.querySelector('link[rel=next]')
			state.href = nextElement && nextElement.href
			!state.href && EventListeners.onDestroy()

			const postElements = doc.querySelectorAll('.post-card')
			Array.from(postElements).forEach(item => {
				console.log(`# ${item.querySelector('.post-card-title').innerHTML}`)
				// document.importNode is important, without it the item's owner
				// document will be different which can break resizing of
				// `object-fit: cover` images in Safari
				// feedElement.appendChild(body.importNode(item, true))
				feedElement.appendChild(item)
			})
		},
		onUpdate() {
			const {
					lastScrollY,
					lastWindowHeight,
					lastDocumentHeight,
					activeZoneHeight,
					href
				} = state,
				{ loading } = this

			if (loading || !href) return

			// return if not scroll to the bottom
			if (
				lastScrollY + lastWindowHeight <=
				lastDocumentHeight - activeZoneHeight
			) {
				state.ticking = false
				return
			}

			this.loading = true
			console.log('---- onUpdate: START', { href })
			fetch(href)
				.then(r => r.text())
				.then(text => new DOMParser().parseFromString(text, 'text/html'))
				.then(this.onPageLoad)
				.then(() => {
					console.log('---- onUpdate: END')
					// sync status
					this.loading = false
					state.lastDocumentHeight = document.documentElement.scrollHeight
					state.ticking = false
				})
		}
	}

	const requestTick = () => {
			state.ticking || requestAnimationFrame(app.onUpdate.bind(app))
			state.ticking = true
		},
		onScroll = event => {
			state.lastScrollY = window.scrollY
			requestTick()
		},
		onResize = event => {
			state.lastWindowHeight = window.innerHeight
			state.lastDocumentHeight = document.documentElement.scrollHeight
			requestTick()
		}

	const factoryListener = list => {
		let isCreated = false
		return {
			onCreate() {
				if (!isCreated) {
					list.forEach(element => addEventListener(...element))
					isCreated = true
				}
			},
			onDestroy() {
				if (isCreated) {
					list.forEach(element => removeEventListener(...element))
					isCreated = false
				}
			}
		}
	}

	const eventListeners = [
			['scroll', onScroll, { passive: true }],
			['resize', onResize]
		],
		EventListeners = factoryListener(eventListeners)
	EventListeners.onCreate()
})()
File: infinite-scroll.js
I made little bloat for factoryListener function. It’s an idea to have multiple listeners in a list to destroy later if you worry about memory management or element manipulation. Some best practises are when you create an addEventListner you must have removeEventListener too clean it up.