diff --git a/locales/en-US.yml b/locales/en-US.yml
index 6c1cfc9940..913525d7ba 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1095,6 +1095,7 @@ accountMoved: "This user has moved to a new account:"
accountMovedShort: "This account has been migrated."
operationForbidden: "Operation forbidden"
forceShowAds: "Always show ads"
+oneko: "Cat friend :3"
addMemo: "Add memo"
editMemo: "Edit memo"
reactionsList: "Reactions"
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 138c87b765..b9935ae6c9 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4425,6 +4425,10 @@ export interface Locale extends ILocale {
* 常に広告を表示する
*/
"forceShowAds": string;
+ /**
+ * 猫友達 :3
+ */
+ "oneko": string;
/**
* メモを追加
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index a154acca68..b63624f674 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1102,6 +1102,7 @@ accountMoved: "このユーザーは新しいアカウントに移行しまし
accountMovedShort: "このアカウントは移行されています"
operationForbidden: "この操作はできません"
forceShowAds: "常に広告を表示する"
+oneko: "猫友達 :3"
addMemo: "メモを追加"
editMemo: "メモを編集"
reactionsList: "リアクション一覧"
diff --git a/packages/frontend/assets/oneko.gif b/packages/frontend/assets/oneko.gif
new file mode 100644
index 0000000000..a009c2cc19
Binary files /dev/null and b/packages/frontend/assets/oneko.gif differ
diff --git a/packages/frontend/src/components/SkOneko.vue b/packages/frontend/src/components/SkOneko.vue
new file mode 100644
index 0000000000..fbf50067a9
--- /dev/null
+++ b/packages/frontend/src/components/SkOneko.vue
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 2c9c1697e3..3b2946e2b7 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -145,6 +145,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.useSystemFont }}
{{ i18n.ts.disableDrawer }}
{{ i18n.ts.forceShowAds }}
+ {{ i18n.ts.oneko }}
{{ i18n.ts.seasonalScreenEffect }}
@@ -332,6 +333,7 @@ const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle'));
const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer'));
const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages'));
const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds'));
+const oneko = computed(defaultStore.makeGetterSetter('oneko'));
const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages'));
const highlightSensitiveMedia = computed(defaultStore.makeGetterSetter('highlightSensitiveMedia'));
const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab'));
diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue
index 5fccf15df6..ad0903caee 100644
--- a/packages/frontend/src/pages/settings/preferences-backups.vue
+++ b/packages/frontend/src/pages/settings/preferences-backups.vue
@@ -98,6 +98,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'showClipButtonInNoteFooter',
'reactionsDisplaySize',
'forceShowAds',
+ 'oneko',
'numberOfReplies',
'aiChanMode',
'devMode',
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index 3c39288d5b..4dad6ce406 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -407,6 +407,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: false,
},
+ oneko: {
+ where: 'device',
+ default: false,
+ },
clickToOpen: {
where: 'device',
default: true,
diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue
index 0ec036c5cb..ffdb4fa2d8 100644
--- a/packages/frontend/src/ui/_common_/common.vue
+++ b/packages/frontend/src/ui/_common_/common.vue
@@ -42,6 +42,8 @@ SPDX-License-Identifier: AGPL-3.0-only
DEV BUILD
{{ i18n.ts.loggedInAsBot }}
+
+