diff --git a/locales/en-US.yml b/locales/en-US.yml
index ad81376f89..b1455430f8 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1266,6 +1266,8 @@ fromX: "From {x}"
 genEmbedCode: "Generate embed code"
 noteOfThisUser: "Notes by this user"
 clipNoteLimitExceeded: "No more notes can be added to this clip."
+timeTravel: "Time Travel"
+timeTravelDescription: "Show posts before this date."
 _delivery:
   status: "Delivery status"
   stop: "Suspended"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 0d76361d6f..4d2d1f653d 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -1277,6 +1277,8 @@ signinWithPasskey: "使用通行密钥登录"
 unknownWebAuthnKey: "此通行密钥未注册。"
 passkeyVerificationFailed: "验证通行密钥失败。"
 passkeyVerificationSucceededButPasswordlessLoginDisabled: "通行密钥验证成功,但账户未开启无密码登录。"
+timeTravel: "时光机"
+timeTravelDescription: "显示该日期以前的帖子"
 _delivery:
   status: "投递状态"
   stop: "停止投递"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 74c03befd1..26420e7a56 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -1283,6 +1283,8 @@ signinWithPasskey: "使用密碼金鑰登入"
 unknownWebAuthnKey: "未註冊的金鑰。"
 passkeyVerificationFailed: "驗證金鑰失敗。"
 passkeyVerificationSucceededButPasswordlessLoginDisabled: "雖然驗證金鑰成功,但是無密碼登入的方式是停用的。"
+timeTravel: "時光機"
+timeTravelDescription: "回到指定的日期"
 _delivery:
   status: "傳送狀態"
   stop: "停止發送"
diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue
index ca87316bf7..7cb27e1c36 100644
--- a/packages/frontend/src/components/MkTimeline.vue
+++ b/packages/frontend/src/components/MkTimeline.vue
@@ -61,7 +61,8 @@ type TimelineQueryType = {
   visibility?: string,
   listId?: string,
   channelId?: string,
-  roleId?: string
+  roleId?: string,
+  untilDate?: number,
 }
 
 const prComponent = shallowRef<InstanceType<typeof MkPullToRefresh>>();
@@ -89,7 +90,7 @@ function prepend(note) {
 
 let connection: Misskey.ChannelConnection | null = null;
 let connection2: Misskey.ChannelConnection | null = null;
-let paginationQuery: Paging | null = null;
+const paginationQuery = ref<Paging | null>(null);
 
 const stream = useStream();
 
@@ -124,7 +125,7 @@ function connectChannel() {
 		});
 	} else if (props.src === 'mentions') {
 		connection = stream.useChannel('main');
-		connection.on('mention', prepend);
+		connection?.on('mention', prepend);
 	} else if (props.src === 'directs') {
 		const onNote = note => {
 			if (note.visibility === 'specified') {
@@ -132,7 +133,7 @@ function connectChannel() {
 			}
 		};
 		connection = stream.useChannel('main');
-		connection.on('mention', onNote);
+		connection?.on('mention', onNote);
 	} else if (props.src === 'list') {
 		if (props.list == null) return;
 		connection = stream.useChannel('userList', {
@@ -159,7 +160,7 @@ function disconnectChannel() {
 	if (connection2) connection2.dispose();
 }
 
-function updatePaginationQuery() {
+function updatePaginationQuery(untilDate?: Date) {
 	let endpoint: keyof Misskey.Endpoints | null;
 	let query: TimelineQueryType | null;
 
@@ -224,14 +225,19 @@ function updatePaginationQuery() {
 		query = null;
 	}
 
+	if (untilDate && Number(untilDate)) {
+		query = query ?? {};
+		query.untilDate = Number(untilDate);
+	}
+
 	if (endpoint && query) {
-		paginationQuery = {
+		paginationQuery.value = {
 			endpoint: endpoint,
 			limit: 10,
 			params: query,
 		};
 	} else {
-		paginationQuery = null;
+		paginationQuery.value = null;
 	}
 }
 
@@ -267,7 +273,12 @@ function reloadTimeline() {
 	});
 }
 
+function timetravel(date: Date) {
+	updatePaginationQuery(date);
+}
+
 defineExpose({
 	reloadTimeline,
+	timetravel,
 });
 </script>
diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue
index f1a451808f..ff58a8f5fc 100644
--- a/packages/frontend/src/components/global/MkPageHeader.vue
+++ b/packages/frontend/src/components/global/MkPageHeader.vue
@@ -56,6 +56,7 @@ const props = withDefaults(defineProps<{
 	actions?: PageHeaderItem[] | null;
 	thin?: boolean;
 	displayMyAvatar?: boolean;
+	hideTitle?: boolean;
 }>(), {
 	tabs: () => ([] as Tab[]),
 });
@@ -66,7 +67,7 @@ const emit = defineEmits<{
 
 const pageMetadata = injectReactiveMetadata();
 
-const hideTitle = inject('shouldOmitHeaderTitle', false);
+const hideTitle = props.hideTitle || inject('shouldOmitHeaderTitle', false);
 const thin_ = props.thin || inject('shouldHeaderThin', false);
 
 const el = shallowRef<HTMLElement | undefined>(undefined);
diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue
index 22c5231dd9..f1be5de13a 100644
--- a/packages/frontend/src/pages/antenna-timeline.vue
+++ b/packages/frontend/src/pages/antenna-timeline.vue
@@ -55,11 +55,12 @@ function top() {
 
 async function timetravel() {
 	const { canceled, result: date } = await os.inputDate({
-		title: i18n.ts.date,
+		title: i18n.ts.timeTravel as string,
+		text: i18n.ts.timeTravelDescription as string,
 	});
 	if (canceled) return;
 
-	tlEl.value.timetravel(date);
+	tlEl.value?.timetravel(date);
 }
 
 function settings() {
diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue
index 12e2db2293..b8b4203809 100644
--- a/packages/frontend/src/pages/timeline.vue
+++ b/packages/frontend/src/pages/timeline.vue
@@ -221,11 +221,12 @@ function saveTlFilter(key: keyof typeof defaultStore.state.tl.filter, newValue:
 
 async function timetravel(): Promise<void> {
 	const { canceled, result: date } = await os.inputDate({
-		title: i18n.ts.date,
+		title: i18n.ts.timeTravel as string,
+		text: i18n.ts.timeTravelDescription as string,
 	});
 	if (canceled) return;
 
-	tlComponent.value.timetravel(date);
+	tlComponent.value?.timetravel(date);
 }
 
 function focus(): void {
@@ -323,10 +324,10 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
 	iconOnly: true,
 	onClick: chooseAntenna,
 }, {
-	icon: 'ti ti-device-tv',
-	title: i18n.ts.channel,
+	icon: 'ti ti-calendar-time',
+	title: i18n.ts.timeTravel,
 	iconOnly: true,
-	onClick: chooseChannel,
+	onClick: timetravel,
 }] as Tab[]);
 
 const headerTabsWhenNotLogin = computed(() => [...availableBasicTimelines().map(tl => ({