<img src="https://picsum.photos/200/200"
data-creepyface
data-src-hover="https://picsum.photos/150/150"
data-src-look-0="https://picsum.photos/210/210"
data-src-look-45="https://picsum.photos/180/180"
data-src-look-135="https://picsum.photos/300/300"
data-src-look-225="https://picsum.photos/60/60"

data-src-look-315="https://picsum.photos/170/170"
/>
body{  display: flex;
  flex-direction: column;
  align-items: center;
	margin-top:100px;
}

img{width:200px;}
/*
https://github.com/4lejandrito/creepyface

*/
! function(e, n) {
    "object" == typeof exports && "undefined" != typeof module ? module.exports = n() : "function" == typeof define && define.amd ? define(n) : (e = e || self).creepyface = n()
}(this, function() {
    "use strict";
    var s = function(o, c) {
        var u = [];
        o.forEach(function(e) {
            var n, t, r;
            n = e, t = function(e) {
                u.push(e), u.length === o.length && c(u)
            }, (r = new Image).src = n, r.onload = r.onerror = function() {
                r.naturalWidth || console.error("Creepyface was unable to load ".concat(n)), delete r.onload, delete r.onerror, t(r)
            }
        })
    };
    var c = function(n) {
        return {
            subscribe: function(e) {
                return {
                    unsubscribe: n({
                        next: e
                    })
                }
            }
        }
    }, t = [];
    document.addEventListener("mousemove", function(n) {
        return t.forEach(function(e) {
            return e.next([n.clientX, n.clientY])
        })
    }, !0);
    var u = c(function(e) {
        return t.push(e),
        function() {
            t.splice(t.indexOf(e), 1)
        }
    }),
        i = function(e, t) {
            return e.map(function(e, n) {
                return e + t[n]
            })
        }, a = function(e) {
            return e * Math.PI / 180
        }, f = function(e) {
            return n = Math.atan2(e[1], e[0]), t = 2 * Math.PI, 180 * ((t + n % t) % t) / Math.PI;
            var n, t
        }, n = [];
    document.addEventListener("touchmove", function(o) {
        return n.forEach(function(e) {
            for (var n = [0, 0], t = 0; t < o.touches.length; t++) {
                var r = o.touches[t];
                n = i(n, [r.clientX, r.clientY])
            }
            e.next(n)
        })
    }, !0);
    var l = c(function(e) {
        return n.push(e),
        function() {
            n.splice(n.indexOf(e), 1)
        }
    }),
        d = function() {}, r = function(e) {
            var n = e ? parseFloat(e) : NaN;
            return isNaN(n) ? void 0 : n
        }, v = function(e) {
            return {
                hover: e.getAttribute("data-src-hover") || void 0,
                looks: function(e) {
                    for (var n = /data-src-look-(\d+)/i, t = [], r = 0; r < e.attributes.length; r++) {
                        var o = e.attributes[r],
                            c = n.exec(o.name);
                        c && t.push({
                            angle: parseFloat(c[1]),
                            src: o.value
                        })
                    }
                    return t.length ? t : void 0
                }(e),
                timeToDefault: r(e.getAttribute("data-timetodefault")),
                throttle: r(e.getAttribute("data-throttle")),
                fieldOfVision: r(e.getAttribute("data-fieldofvision")),
                resetOnCancel: !("false" === e.getAttribute("data-resetoncancel"))
            }
        };

    function h(e) {
        var t, n = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : {}, r = function(o) {
            for (var e = 1; e < arguments.length; e++) {
                var c = null != arguments[e] ? arguments[e] : {}, n = Object.keys(c);
                "function" == typeof Object.getOwnPropertySymbols && (n = n.concat(Object.getOwnPropertySymbols(c).filter(function(e) {
                    return Object.getOwnPropertyDescriptor(c, e).enumerable
                }))), n.forEach(function(e) {
                    var n, t, r;
                    n = o, r = c[t = e], t in n ? Object.defineProperty(n, t, {
                        value: r,
                        enumerable: !0,
                        configurable: !0,
                        writable: !0
                    }) : n[t] = r
                })
            }
            return o
        }({}, v(e), n),
            o = e.getAttribute("src");
        if (!o) throw new Error("A default URL must be specified");
        return {
            fieldOfVision: r.fieldOfVision || 150,
            src: o,
            hover: r.hover || "",
            points: r.points || (t = [u, l], c(function(n) {
                var e = t.map(function(e) {
                    return e.subscribe(n.next)
                });
                return function() {
                    return e.forEach(function(e) {
                        return e.unsubscribe()
                    })
                }
            })),
            looks: r.looks || [],
            timeToDefault: r.timeToDefault || 1e3,
            resetOnCancel: !(!1 === r.resetOnCancel),
            throttle: r.throttle || 100,
            onDebug: r.onDebug || d,
            onAttach: r.onAttach || d,
            onDetach: r.onDetach || d
        }
    }
    var b = function(e) {
        var n = e.getBoundingClientRect(),
            t = n.top + window.pageYOffset + n.height / 2,
            r = n.left + window.pageXOffset + n.width / 2;
        return {
            y: t,
            x: r
        }
    };
    var m = function(e, n) {
        return f((o = i([window.scrollX, window.scrollY], n), u = b(e), c = [u.x, u.y], t = o.map(function(e, n) {
            return e - c[n]
        }), r = 90, [t[0] * Math.cos(a(r)) - t[1] * Math.sin(a(r)), t[0] * Math.sin(a(r)) + t[1] * Math.cos(a(r))]));
        var t, r, o, c, u
    }, p = function(e) {
        return 180 < Math.abs(e) ? e - 360 * ((n = e) ? n < 0 ? -1 : 1 : 0) : e;
        var n
    }, g = function(e, n) {
        return n.slice(0).sort((t = e, function(e, n) {
            return Math.abs(p(e.angle - t)) - Math.abs(p(n.angle - t))
        }))[0];
        var t
    }, y = function(e, n, t) {
        return n <= e && e <= t
    }, O = function(e, n) {
        return document.elementFromPoint ? document.elementFromPoint(n[0], n[1]) === e : (t = e.getBoundingClientRect(), r = [n[0], n[1]], o = t.left, c = t.top, u = t.right, i = t.bottom, y(r[0], o, u) && y(r[1], c, i));
        var t, r, o, c, u, i
    }, w = function(h, b) {
        return c(function(r) {
            var e, n, t, o, c, u, i, a, f, s, l, d = (e = function() {
                return r.next({
                    src: b.src,
                    options: b
                })
            }, n = b.timeToDefault, (o = function() {
                t && clearTimeout(t), t = setTimeout(function() {
                    t = null, e()
                }, n)
            }).clear = function() {
                t && (clearTimeout(t), t = null)
            }, o),
                v = b.points.subscribe((c = function(e) {
                    var n = m(h, e),
                        t = function(e, n, t, r) {
                            var o = r.looks,
                                c = r.hover,
                                u = r.fieldOfVision,
                                i = r.src;
                            if (c && O(e, n)) i = c;
                            else {
                                var a = g(t, o);
                                Math.abs(p(a.angle - t)) < u / 2 && (i = a.src)
                            }
                            return i
                        }(h, e, n, b);
                    r.next({
                        point: e,
                        angle: n,
                        src: t,
                        options: b
                    }), d()
                }, u = b.throttle, f = 0, s = function() {
                    f = Date.now(), i = null, c(a)
                }, (l = function(e) {
                    var n = Date.now(),
                        t = u - (n - f);
                    a = e, t <= 0 || u < t ? (i && (clearTimeout(i), i = null), f = n, c(e)) : i || (i = setTimeout(s, t))
                }).clear = function() {
                    i && clearTimeout(i), f = 0, i = null
                }, l));
            return function() {
                d.clear(), v.unsubscribe()
            }
        })
    }, M = function(t, e) {
        var n, r, o, c, u = h(t, e),
            i = function(e) {
                t.src = e
            }, a = !1,
            f = function() {
                a = !0
            };
        return n = t, r = function(e) {
            if (!a) {
                u.onAttach();
                var n = w(t, u).subscribe(function(e) {
                    i(e.src), u.onDebug(e)
                });
                f = function() {
                    n.unsubscribe(), u.resetOnCancel && i(u.src), u.onDetach(), e()
                }
            }
        }, s((c = (o = u).looks.map(function(e) {
            return e.src
        }), o.src && c.push(o.src), o.hover && c.push(o.hover), c), function(e) {
            n.creepyfaceReachableImages = e, r(function() {
                delete n.creepyfaceReachableImages
            })
        }),
        function() {
            return f()
        }
    }, o = function e(n, t) {
        e.cancel(n);
        var r = d,
            o = function(t, n, r) {
                var o = function(e) {
                    return e ? n() : r()
                };
                if (MutationObserver) {
                    var c = document.body && document.body.contains(t);
                    c && o(!0);
                    var e = new MutationObserver(function(e) {
                        var n = document.body && document.body.contains(t);
                        !n && c ? (o(!1), c = !1) : n && !c && (o(!0), c = !0)
                    });
                    return e.observe(document, {
                        childList: !0,
                        subtree: !0
                    }),
                    function() {
                        return e.disconnect()
                    }
                }
                return document.body && document.body.contains(t) && o(!0), t.addEventListener("DOMNodeInserted", function() {
                    return o(!0)
                }, !1), t.addEventListener("DOMNodeRemoved", function() {
                    return o(!1)
                }, !1), d
            }(n, function() {
                r = M(n, t)
            }, function() {
                return e.cancel(n)
            });
        return n.creepyfaceCancel = function() {
            o(), r(), delete n.creepyfaceCancel
        }
    };
    return o.cancel = function(e) {
        var n = e.creepyfaceCancel;
        n && n()
    }, document.addEventListener("DOMContentLoaded", function() {
        for (var e = document.querySelectorAll("img[data-creepy],img[data-creepyface]"), n = 0; n < e.length; n++) {
            var t = e[n];
            t instanceof HTMLImageElement && o(t)
        }
    }), o
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.