diff --git a/src/client/ui/visitor/b.vue b/src/client/ui/visitor/b.vue
index 6c7366c6f2..e3cac4125c 100644
--- a/src/client/ui/visitor/b.vue
+++ b/src/client/ui/visitor/b.vue
@@ -1,61 +1,14 @@
 <template>
 <div class="mk-app">
-	<div class="side" v-if="!narrow">
-		<div :style="{ backgroundImage: `url(${ $store.state.instance.meta.backgroundImageUrl })` }">
-			<div class="fade"></div>
-			<h1 v-if="meta"><img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span></h1>
-			<div class="about" v-if="meta">
-				<div class="desc" v-html="meta.description || $t('introMisskey')"></div>
-			</div>
-			<div class="action">
-				<button class="_buttonPrimary" @click="signup()">{{ $t('signup') }}</button>
-				<button class="_button" @click="signin()">{{ $t('login') }}</button>
-			</div>
-			<div class="announcements panel">
-				<header>{{ $t('announcements') }}</header>
-				<MkPagination :pagination="announcements" #default="{items}" class="list">
-					<section class="item" v-for="(announcement, i) in items" :key="announcement.id">
-						<div class="title">{{ announcement.title }}</div>
-						<div class="content">
-							<Mfm :text="announcement.text"/>
-							<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
-						</div>
-					</section>
-				</MkPagination>
-			</div>
-		</div>
+	<div class="side" v-if="!narrow && $route.path !== '/'">
+		<XKanban class="kanban" full/>
 	</div>
 
 	<div class="main">
-		<div v-if="narrow" class="banner" :style="{ backgroundImage: `url(${ $store.state.instance.meta.bannerUrl })` }">
-			<h1 v-if="meta">
-				<MkA to="/" class="link"><img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span></MkA>
-			</h1>
-			<template v-if="$route.path === '/'">
-				<div class="about" v-if="meta">
-					<div class="desc" v-html="meta.description || $t('introMisskey')"></div>
-				</div>
-				<div class="action">
-					<button class="_buttonPrimary" @click="signup()">{{ $t('signup') }}</button>
-					<button class="_button" @click="signin()">{{ $t('login') }}</button>
-				</div>
-				<div class="announcements panel">
-					<header>{{ $t('announcements') }}</header>
-					<MkPagination :pagination="announcements" #default="{items}" class="list">
-						<section class="item" v-for="(announcement, i) in items" :key="announcement.id">
-							<div class="title">{{ announcement.title }}</div>
-							<div class="content">
-								<Mfm :text="announcement.text"/>
-								<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
-							</div>
-						</section>
-					</MkPagination>
-				</div>
-			</template>
-		</div>
+		<XKanban class="banner" :full="$route.path === '/'" v-if="narrow || $route.path === '/'"/>
 
-		<div class="contents" :class="{ wallpaper }">
-			<XHeader class="header" :info="pageInfo"/>
+		<div class="contents">
+			<XHeader class="header" :info="pageInfo" v-if="$route.path !== '/'"/>
 			<main>
 				<router-view v-slot="{ Component }">
 					<transition :name="$store.state.device.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
@@ -104,12 +57,14 @@ import XSigninDialog from '@/components/signin-dialog.vue';
 import XSignupDialog from '@/components/signup-dialog.vue';
 import MkButton from '@/components/ui/button.vue';
 import XHeader from './header.vue';
+import XKanban from './kanban.vue';
 
 const DESKTOP_THRESHOLD = 1100;
 
 export default defineComponent({
 	components: {
 		XHeader,
+		XKanban,
 		MkPagination,
 		MkButton,
 	},
@@ -231,108 +186,14 @@ export default defineComponent({
 	> .side {
 		width: 500px;
 		height: 100vh;
-		text-align: center;
 
-		> div {
+		> .kanban {
 			position: fixed;
 			top: 0;
 			left: 0;
 			width: 500px;
 			height: 100vh;
 			overflow: auto;
-			background-position: center;
-			background-size: cover;
-
-			> .panel {
-				-webkit-backdrop-filter: blur(8px);
-				backdrop-filter: blur(8px);
-				background: rgba(0, 0, 0, 0.5);
-				border-radius: var(--radius);
-
-				&, * {
-					color: #fff !important;
-				}
-			}
-
-			> .fade {
-				position: absolute;
-				z-index: -1;
-				top: 0;
-				left: 0;
-				width: 100%;
-				height: 300px;
-				background: linear-gradient(rgba(#000, 0.5), transparent);
-			}
-
-			> h1 {
-				display: block;
-				margin: 0;
-				padding: 64px 32px 48px 32px;
-				color: #fff;
-
-				> .logo {
-					vertical-align: bottom;
-					max-height: 150px;
-				}
-			}
-
-			> .about {
-				display: block;
-				margin: 0 64px 16px 64px;
-				padding: 24px;
-				text-align: center;
-				box-sizing: border-box;
-				text-shadow: 0 0 8px black;
-				color: #fff;
-			}
-
-			> .action {
-				padding: 0 64px;
-
-				> button {
-					display: block;
-					width: 100%;
-					padding: 10px;
-					box-sizing: border-box;
-					text-align: center;
-					border-radius: 999px;
-
-					&._button {
-						background: var(--panel);
-					}
-
-					&:first-child {
-						margin-bottom: 16px;
-					}
-				}
-			}
-
-			> .announcements {
-				margin: 64px 64px 16px 64px;
-				text-align: left;
-
-				> header {
-					padding: 12px 16px;
-					border-bottom: solid 1px rgba(255, 255, 255, 0.5);
-				}
-
-				> .list {
-					max-height: 300px;
-					overflow: auto;
-
-					> .item {
-						padding: 12px 16px;
-
-						& + .item {
-							border-top: solid 1px rgba(255, 255, 255, 0.5);
-						}
-
-						> .title {
-							font-weight: bold;
-						}
-					}
-				}
-			}
 		}
 	}
 
@@ -340,109 +201,6 @@ export default defineComponent({
 		flex: 1;
 
 		> .banner {
-			position: relative;
-			width: 100%;
-			background-size: cover;
-			background-position: center;
-
-			&:after {
-				content: "";
-				display: block;
-				position: absolute;
-				bottom: 0;
-				left: 0;
-				width: 100%;
-				height: 64px;
-				background: linear-gradient(transparent, var(--bg));
-			}
-
-			> h1 {
-				position: relative;
-				z-index: 2;
-				margin: 0;
-				padding: 32px;
-				text-align: center;
-				color: #fff;
-				text-shadow: 0 0 8px #000;
-
-				> .link {
-					display: block;
-
-					> ::v-deep(.logo) {
-						vertical-align: bottom;
-						max-height: 100px;
-					}
-				}
-			}
-
-			> .panel {
-				-webkit-backdrop-filter: blur(8px);
-				backdrop-filter: blur(8px);
-				background: rgba(0, 0, 0, 0.5);
-				border-radius: var(--radius);
-
-				&, * {
-					color: #fff !important;
-				}
-			}
-
-			> .about {
-				display: block;
-				margin: 0 0 16px 0;
-				padding: 0 16px 24px 16px;
-				text-align: center;
-				box-sizing: border-box;
-				text-shadow: 0 0 8px black;
-				color: #fff;
-			}
-
-			> .action {
-				padding: 0 64px;
-
-				> button {
-					display: block;
-					width: 100%;
-					padding: 10px;
-					box-sizing: border-box;
-					text-align: center;
-					border-radius: 999px;
-
-					&._button {
-						background: var(--panel);
-					}
-
-					&:first-child {
-						margin-bottom: 16px;
-					}
-				}
-			}
-
-			> .announcements {
-				margin: 64px 64px 16px 64px;
-				text-align: left;
-
-				> header {
-					padding: 12px 16px;
-					border-bottom: solid 1px rgba(255, 255, 255, 0.5);
-				}
-
-				> .list {
-					max-height: 300px;
-					overflow: auto;
-
-					> .item {
-						padding: 12px 16px;
-
-						& + .item {
-							border-top: solid 1px rgba(255, 255, 255, 0.5);
-						}
-
-						> .title {
-							font-weight: bold;
-						}
-					}
-				}
-			}
 		}
 
 		> .contents {
diff --git a/src/client/ui/visitor/kanban.vue b/src/client/ui/visitor/kanban.vue
new file mode 100644
index 0000000000..263b7ca038
--- /dev/null
+++ b/src/client/ui/visitor/kanban.vue
@@ -0,0 +1,229 @@
+<template>
+<div class="rwqkcmrc" :style="{ backgroundImage: `url(${ $store.state.instance.meta.backgroundImageUrl })` }">
+	<div class="back"></div>
+	<div class="fade"></div>
+	<div class="contents">
+		<div class="wrapper">
+			<h1 v-if="meta" :class="{ full }">
+				<MkA to="/" class="link"><img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span></MkA>
+			</h1>
+			<template v-if="full">
+				<div class="about" v-if="meta">
+					<div class="desc" v-html="meta.description || $t('introMisskey')"></div>
+				</div>
+				<div class="action">
+					<button class="_buttonPrimary" @click="signup()">{{ $t('signup') }}</button>
+					<button class="_button" @click="signin()">{{ $t('login') }}</button>
+				</div>
+				<div class="announcements panel">
+					<header>{{ $t('announcements') }}</header>
+					<MkPagination :pagination="announcements" #default="{items}" class="list">
+						<section class="item" v-for="(announcement, i) in items" :key="announcement.id">
+							<div class="title">{{ announcement.title }}</div>
+							<div class="content">
+								<Mfm :text="announcement.text"/>
+								<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
+							</div>
+						</section>
+					</MkPagination>
+				</div>
+			</template>
+		</div>
+	</div>
+</div>
+</template>
+
+<script lang="ts">
+import { defineComponent, defineAsyncComponent } from 'vue';
+import { } from '@fortawesome/free-solid-svg-icons';
+import { host, instanceName } from '@/config';
+import * as os from '@/os';
+import MkPagination from '@/components/ui/pagination.vue';
+import XSigninDialog from '@/components/signin-dialog.vue';
+import XSignupDialog from '@/components/signup-dialog.vue';
+import MkButton from '@/components/ui/button.vue';
+
+export default defineComponent({
+	components: {
+		MkPagination,
+		MkButton,
+	},
+
+	props: {
+		full :{
+			type: Boolean,
+			required: false,
+			default: false,
+		}
+	},
+
+	data() {
+		return {
+			host,
+			instanceName,
+			pageInfo: null,
+			meta: null,
+			narrow: window.innerWidth < 1280,
+			announcements: {
+				endpoint: 'announcements',
+				limit: 10,
+			},
+		};
+	},
+
+	created() {
+		os.api('meta', { detail: true }).then(meta => {
+			this.meta = meta;
+		});
+	},
+
+	methods: {
+		signin() {
+			os.popup(XSigninDialog, {
+				autoSet: true
+			}, {}, 'closed');
+		},
+
+		signup() {
+			os.popup(XSignupDialog, {
+				autoSet: true
+			}, {}, 'closed');
+		}
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+.rwqkcmrc {
+	position: relative;
+	text-align: center;
+	background-position: center;
+	background-size: cover;
+	// TODO: パララックスにしたい
+
+	> .back {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		background: var(--bg);
+		opacity: 0.5;
+	}
+
+	> .fade {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 300px;
+		background: linear-gradient(rgba(#000, 0.5), transparent);
+	}
+
+	> .contents {
+		position: relative;
+		z-index: 1;
+		height: inherit;
+		overflow: auto;
+
+		> .wrapper {
+			max-width: 380px;
+			padding: 0 16px;
+			box-sizing: border-box;
+			margin: 0 auto;
+
+			> .panel {
+				-webkit-backdrop-filter: blur(8px);
+				backdrop-filter: blur(8px);
+				background: rgba(0, 0, 0, 0.5);
+				border-radius: var(--radius);
+
+				&, * {
+					color: #fff !important;
+				}
+			}
+
+			> h1 {
+				display: block;
+				margin: 0;
+				padding: 32px 0 32px 0;
+				color: #fff;
+
+				&.full {
+					padding: 64px 0 0 0;
+
+					> .link {
+						> ::v-deep(.logo) {
+							max-height: 130px;
+						}
+					}
+				}
+
+				> .link {
+					display: block;
+
+					> ::v-deep(.logo) {
+						vertical-align: bottom;
+						max-height: 100px;
+					}
+				}
+			}
+
+			> .about {
+				display: block;
+				margin: 24px 0;
+				text-align: center;
+				box-sizing: border-box;
+				text-shadow: 0 0 8px black;
+				color: #fff;
+			}
+
+			> .action {
+				> button {
+					display: block;
+					width: 100%;
+					padding: 10px;
+					box-sizing: border-box;
+					text-align: center;
+					border-radius: 999px;
+
+					&._button {
+						background: var(--panel);
+					}
+
+					&:first-child {
+						margin-bottom: 16px;
+					}
+				}
+			}
+
+			> .announcements {
+				margin: 32px 0;
+				text-align: left;
+
+				> header {
+					padding: 12px 16px;
+					border-bottom: solid 1px rgba(255, 255, 255, 0.5);
+				}
+
+				> .list {
+					max-height: 300px;
+					overflow: auto;
+
+					> .item {
+						padding: 12px 16px;
+
+						& + .item {
+							border-top: solid 1px rgba(255, 255, 255, 0.5);
+						}
+
+						> .title {
+							font-weight: bold;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+</style>