rewrite to support frame callback