function render() {
    var tmpyaw;

    if (loaded) {
        // Keep a tmp value of yaw for autoRotate comparison later
        tmpyaw = config.yaw;

        // Optionally avoid showing background (empty space) on left or right by adapting min/max yaw
        var hoffcut = 0,
            voffcut = 0;
        if (config.avoidShowingBackground) {
            var canvas = renderer.getCanvas(),
                hfov2 = config.hfov / 2,
                vfov2 = Math.atan2(Math.tan(hfov2 / 180 * Math.PI), (canvas.width / canvas.height)) * 180 / Math.PI,
                transposed = config.vaov > config.haov;
            if (transposed) {
                voffcut = vfov2 * (1 - Math.min(Math.cos((config.pitch - hfov2) / 180 * Math.PI),
                                                Math.cos((config.pitch + hfov2) / 180 * Math.PI)));
            } else {
                hoffcut = hfov2 * (1 - Math.min(Math.cos((config.pitch - vfov2) / 180 * Math.PI),
                                                Math.cos((config.pitch + vfov2) / 180 * Math.PI)));
            }
        }

        // Ensure the yaw is within min and max allowed
        var yawRange = config.maxYaw - config.minYaw,
            minYaw = -180,
            maxYaw = 180;
        if (yawRange < 360) {
            minYaw = config.minYaw + config.hfov / 2 + hoffcut;
            maxYaw = config.maxYaw - config.hfov / 2 - hoffcut;
            if (yawRange < config.hfov) {
                // Lock yaw to average of min and max yaw when both can be seen at once
                minYaw = maxYaw = (minYaw + maxYaw) / 2;
            }
            config.yaw = Math.max(minYaw, Math.min(maxYaw, config.yaw));
        }
        
        if (config.yaw > 180) {
            config.yaw -= 360;
        } else if (config.yaw < -180) {
            config.yaw += 360;
        }

        // Check if we autoRotate in a limited by min and max yaw
        // If so reverse direction
        if (config.autoRotate !== false && tmpyaw != config.yaw &&
            prevTime !== undefined) { // this condition prevents changing the direction initially
            config.autoRotate *= -1;
        }

        // Ensure the calculated pitch is within min and max allowed
        var canvas = renderer.getCanvas();
        var vfov = 2 * Math.atan(Math.tan(config.hfov / 180 * Math.PI * 0.5) /
            (canvas.width / canvas.height)) / Math.PI * 180;
        var minPitch = config.minPitch + vfov / 2,
            maxPitch = config.maxPitch - vfov / 2;
        var pitchRange = config.maxPitch - config.minPitch;
        if (pitchRange < vfov) {
            // Lock pitch to average of min and max pitch when both can be seen at once
            minPitch = maxPitch = (minPitch + maxPitch) / 2;
        }
        if (isNaN(minPitch))
            minPitch = -90;
        if (isNaN(maxPitch))
            maxPitch = 90;
        config.pitch = Math.max(minPitch, Math.min(maxPitch, config.pitch));
        
        renderer.render(config.pitch * Math.PI / 180, config.yaw * Math.PI / 180, config.hfov * Math.PI / 180, {roll: config.roll * Math.PI / 180});
        
        renderHotSpots();
        
        // Update compass
        if (config.compass) {
            compass.style.transform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
            compass.style.webkitTransform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
        }
    }
}