How to constraint object to perspective user viewport (Not render camera)
Keep context object centered on largest viewport in screen.

The view is set up similarly to the camera, ie it looks down its $-Z$ axis.
Rotate an object to camera view
Access view orientation from python?
whereas meshes are normally $Z$ up $-Y$ forward.
The view_align method below, looks for the largest 3d view, then using its matrix aligns the context object such that it looks directly at the view, from 5 global units away.
The rest is basically the modal timer operator template, similarly to question
import bpy
from mathutils import Vector, Matrix
from bpy_extras.io_utils import axis_conversion

distance_from_view = 5

A = axis_conversion(
        from_forward='Y',
        from_up='Z',
        to_forward='-Z',
        to_up='Y').to_4x4()

def view_align(context):
    areas =  sorted(
            [
                a 
                for a in context.screen.areas 
                if a.type == 'VIEW_3D'
            ], 
            key=lambda a : a.width * a.height
        )
        
    if areas:
        screen = context.screen
        ob = context.object
        mw = ob.matrix_world
        r3d = areas.pop().spaces.active.region_3d
        M = r3d.view_matrix
        V = M.inverted()
        # maintain global distance from camera
        T = Matrix.Translation(V @ Vector((0, 0, -distance_from_view)))
        # keep original transform align to view
        #T = Matrix.Translation(mw.translation)
        R = M.to_3x3().transposed().to_4x4()
        S = Matrix.Diagonal(mw.to_scale()).to_4x4()
        ob.matrix_world = T @ (R @ A) @ S
        
        
class ModalTimerOperator(bpy.types.Operator):
    &quot;&quot;&quot;Operator which runs its self from a timer&quot;&quot;&quot;
    bl_idname = &quot;wm.modal_timer_operator&quot;
    bl_label = &quot;Modal Timer Operator&quot;

    _timer = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            view_align(context)

        return {'PASS_THROUGH'}

    def execute(self, context):
        wm = context.window_manager
        self._timer = wm.event_timer_add(0.01, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)


def register():
    bpy.utils.register_class(ModalTimerOperator)


def unregister():
    bpy.utils.unregister_class(ModalTimerOperator)


if __name__ == &quot;__main__&quot;:
    register()

    # test call
    bpy.ops.wm.modal_timer_operator()