diff --git a/packages/client/src/components/CkFollowMouse.vue b/packages/client/src/components/CkFollowMouse.vue
new file mode 100644
index 000000000..ce7e3c79a
--- /dev/null
+++ b/packages/client/src/components/CkFollowMouse.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/client/src/components/mfm.ts b/packages/client/src/components/mfm.ts
index a194de9cd..19e7623c7 100644
--- a/packages/client/src/components/mfm.ts
+++ b/packages/client/src/components/mfm.ts
@@ -1,6 +1,7 @@
import { defineComponent, h } from "vue";
import * as mfm from "mfm-js";
import type { VNode } from "vue";
+import CkFollowMouse from "./CkFollowMouse.vue";
import MkUrl from "@/components/global/MkUrl.vue";
import MkTime from '@/components/global/MkTime.vue';
import MkLink from "@/components/MkLink.vue";
@@ -275,6 +276,24 @@ export default defineComponent({
style = `transform: ${rotate}(${degrees}deg); transform-origin: center center;`;
break;
}
+ case 'followmouse': {
+ // Make sure advanced MFM is on and that reduced motion is off
+
+ let x = (!!token.props.args.x);
+ let y = (!!token.props.args.y);
+
+ if (!x && !y) {
+ x = true;
+ y = true;
+ }
+
+ return h(CkFollowMouse, {
+ x: x,
+ y: y,
+ speed: validTime(token.props.args.speed) ?? '0.1s',
+ rotateByVelocity: !!token.props.args.rotateByVelocity,
+ }, genEl(token.children));
+ }
case "position": {
const x = parseFloat(token.props.args.x ?? "0");
const y = parseFloat(token.props.args.y ?? "0");