diff --git a/src/components/layout.lisp b/src/components/layout.lisp
index 4204c40..dcbf668 100644
--- a/src/components/layout.lisp
+++ b/src/components/layout.lisp
@@ -1,8 +1,6 @@
 (defpackage #:website/components/layout
   (:use #:cl
         #:hsx)
-  (:import-from #:website/components/metadata
-                #:~metadata)
   (:import-from #:website/components/header
                 #:~header)
   (:export #:~layout))
@@ -10,12 +8,7 @@
 
 (defcomp ~layout (&key children)
   (hsx
-   (body
-     :hx-ext "head-support, response-targets, preload, alpine-morph"
-     :hx-boost "true" :hx-target-404 "body" :hx-target-5* "body"
-     :class (<> 
-              "flex flex-col h-[100svh] w-full max-w-[700px] "
-              "px-2 mx-auto")
+   (div :class "flex flex-col h-[100svh] w-full max-w-[700px] px-2 mx-auto"
      (~header)
      (div :class "flex flex-col flex-1 overflow-y-scroll"
        (main :class "flex-1 px-2 py-6 md:px-4 md:py-8"
diff --git a/src/components/metadata.lisp b/src/components/metadata.lisp
index 52ed27e..f95e873 100644
--- a/src/components/metadata.lisp
+++ b/src/components/metadata.lisp
@@ -1,75 +1,66 @@
 (defpackage #:website/components/metadata
   (:use #:cl
         #:hsx)
+  (:import-from #:jingle
+                #:request-uri)
   (:import-from #:website/lib/env
                 #:website-url)
   (:export #:~metadata))
 (in-package #:website/components/metadata)
 
-(defun create-metadata (&key title
-                             description
-                             path
-                             canonical
-                             type
-                             image
-                             error)
-  (list :title title
-        :description description
-        :canonical (or canonical path)
-        :og-title title
-        :og-description description
-        :og-url path
-        :og-type type
-        :og-image (getf image :url)
-        :og-image-width (getf image :width)
-        :og-image-height (getf image :height)
-        :error error))
-
 (defun path->url (path)
   (concatenate 'string
                (website-url)
                (and (not (string= path "/")) path)))
 
-(defparameter *metadata-template*
-  (let ((%title (lambda (title) (format nil "~@[~a - ~]~a" title "skyizwhite.dev")))
-        (%description "The personal website of Akira Tempaku (paku)"))
-    (list :title %title
-          :description %description
-          :canonical #'path->url
-          :og-title %title
-          :og-description %description
-          :og-url #'path->url
-          :og-type "website"
-          :og-site-name "skyizwhite.dev"
-          :og-image (path->url "/img/og.jpg")
-          :og-image-width 1024
-          :og-image-height 1024
-          :error nil)))
+(defparameter *default-metadata*
+  (list :title (lambda (title) (format nil "~@[~a - ~]skyizwhite" title))
+        :description "The personal website of Akira Tempaku (paku)"
+        :canonical nil
+        :type "website"
+        :image (list :url (path->url "/img/og.jpg")
+                     :height 1024
+                     :width 1024)
+        :error nil))
+
+(defun create-metadata (&key title
+                             description
+                             canonical
+                             type
+                             image
+                             error)
+  (let ((path (request-uri jingle:*request*)))
+    (hsx
+     (<>
+       (meta :charset "UTF-8")
+       (meta :name "viewport" :content "width=device-width, initial-scale=1")
+       (title title)
+       (meta :name "description" :content description)
+       (and (not error)
+            (hsx (<>
+                   (meta :property "og:title" :content title)
+                   (meta :property "og:description" :content description)
+                   (meta :property "og:url" :content (path->url path))
+                   (meta :property "og:type" :content type)
+                   (meta :property "og:site_name" :content "skyizwhite")
+                   (meta :property "og:image" :content (getf image :url))
+                   (meta :property "og:image:width" :content (getf image :width))
+                   (meta :property "og:image:height" :content (getf image :height))
+                   (link :rel "canonical" :href (path->url (or canonical path))))))
+       (link :rel "icon" :type "image/png" :href "/img/favicon-96x96.png" :sizes "96x96")
+       (link :rel "icon" :type "image/svg+xml" :href "/img/favicon.svg")
+       (link :rel "shortcut icon" :href "/img/favicon.ico")
+       (link :rel "apple-touch-icon" :sizes "180x180" :href "/img/apple-touch-icon.png")
+       (meta :name "apple-mobile-web-app-title" :content "skyizwhite")
+       (link :rel "manifest" :href "/img/site.webmanifest")))))
 
 (defun complete-metadata (metadata)
   (loop 
-    :for (key template) :on *metadata-template* :by #'cddr
+    :for (key template) :on *default-metadata* :by #'cddr
     :for value := (getf metadata key)
     :append (list key (if (functionp template)
                           (funcall template value)
                           (or value template)))))
 
 (defcomp ~metadata (&key metadata)
-  (let ((%metadata (complete-metadata (apply #'create-metadata metadata))))
-    (hsx
-     (<>
-       (title (getf %metadata :title))
-       (meta :name "description" :content (getf %metadata :description))
-       (and
-        (not (getf %metadata :error))
-        (hsx
-         (<>
-           (meta :property "og:title" :content (getf %metadata :og-title))
-           (meta :property "og:description" :content (getf %metadata :og-description))
-           (meta :property "og:url" :content (getf %metadata :og-url))
-           (meta :property "og:type" :content (getf %metadata :og-type))
-           (meta :property "og:site_name" :content (getf %metadata :og-site-name))
-           (meta :property "og:image" :content (getf %metadata :og-image))
-           (meta :property "og:image:width" :content (getf %metadata :og-image-width))
-           (meta :property "og:image:height" :content (getf %metadata :og-image-height))
-           (link :rel "canonical" :href (getf %metadata :canonical)))))))))
+  (apply #'create-metadata (complete-metadata metadata)))
diff --git a/src/components/scripts.lisp b/src/components/scripts.lisp
new file mode 100644
index 0000000..2b6893d
--- /dev/null
+++ b/src/components/scripts.lisp
@@ -0,0 +1,22 @@
+(defpackage #:website/components/scripts
+  (:use #:cl
+        #:hsx)
+  (:export #:~scripts))
+(in-package #:website/components/scripts)
+
+(defun bust-cache (url)
+  (format nil "~a?v=~a" url #.(get-universal-time)))
+
+(defcomp ~scripts ()
+  (hsx
+   (<>
+     (link :rel "stylesheet" :href (bust-cache "/style/dist.css"))
+     (link :rel "preconnect" :href "https://fonts.googleapis.com")
+     (link :rel "stylesheet" :href "https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic:wght@400;500;700&display=swap")
+     (script :src "https://cdn.jsdelivr.net/npm/htmx.org@2.0.4/dist/htmx.min.js")
+     (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-preload@2.1.1/dist/preload.min.js")
+     (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-head-support@2.0.4/dist/head-support.min.js")
+     (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-response-targets@2.0.3/dist/response-targets.min.js")
+     (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-alpine-morph@2.0.1/alpine-morph.min.js")
+     (script :src "https://cdn.jsdelivr.net/npm/@alpinejs/morph@3.14.9/dist/cdn.min.js" :defer t)
+     (script :src "https://cdn.jsdelivr.net/npm/alpinejs@3.14.9/dist/cdn.min.js" :defer t))))
diff --git a/src/renderer.lisp b/src/renderer.lisp
index 541fa28..987e99b 100644
--- a/src/renderer.lisp
+++ b/src/renderer.lisp
@@ -3,47 +3,19 @@
         #:hsx
         #:trivia)
   (:import-from #:jingle
-                #:get-request-header
                 #:set-response-header)
   (:import-from #:hsx/element
                 #:element)
   (:import-from #:website/lib/env
-                #:website-url
                 #:website-env)
-  (:import-from #:website/components/layout
-                #:~layout)
   (:import-from #:website/components/metadata
-                #:~metadata))
+                #:~metadata)
+  (:import-from #:website/components/scripts
+                #:~scripts)
+  (:import-from #:website/components/layout
+                #:~layout))
 (in-package #:website/renderer)
 
-(defun bust-cache (url)
-  (format nil "~a?v=~a" url #.(get-universal-time)))
-
-(defcomp ~document (&key metadata children)
-  (hsx
-   (html :lang "ja"
-     (head
-       (meta :charset "UTF-8")
-       (meta :name "viewport" :content "width=device-width, initial-scale=1")
-       (~metadata :metadata metadata)
-       (link :rel "icon" :type "image/png" :href "/img/favicon-96x96.png" :sizes "96x96")
-       (link :rel "icon" :type "image/svg+xml" :href "/img/favicon.svg")
-       (link :rel "shortcut icon" :href "/img/favicon.ico")
-       (link :rel "apple-touch-icon" :sizes "180x180" :href "/img/apple-touch-icon.png")
-       (meta :name "apple-mobile-web-app-title" :content "skyizwhite")
-       (link :rel "manifest" :href "/img/site.webmanifest")
-       (link :rel "stylesheet" :href (bust-cache "/style/dist.css"))
-       (link :rel "preconnect" :href "https://fonts.googleapis.com")
-       (link :rel "stylesheet" :href "https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic:wght@400;500;700&display=swap")
-       (script :src "https://cdn.jsdelivr.net/npm/htmx.org@2.0.4/dist/htmx.min.js")
-       (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-preload@2.1.1/dist/preload.min.js")
-       (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-head-support@2.0.4/dist/head-support.min.js")
-       (script :src "https://cdn.jsdelivr.net/npm/htmx-ext-response-targets@2.0.3/dist/response-targets.min.js")
-       ;(script :src "https://cdn.jsdelivr.net/npm/htmx-ext-alpine-morph@2.0.1/alpine-morph.min.js")
-       ;(script :src "https://cdn.jsdelivr.net/npm/@alpinejs/morph@3.14.9/dist/cdn.min.js" :defer t)
-       (script :src "https://cdn.jsdelivr.net/npm/alpinejs@3.14.9/dist/cdn.min.js" :defer t))
-     children)))
-
 (defmethod jingle:process-response ((app jingle:app) result)
   (set-response-header :content-type "text/html; charset=utf-8")
   (set-response-header :cache-control (if (string= (website-env) "dev")
@@ -55,7 +27,12 @@
             (typep body 'element))
      (call-next-method app
                        (hsx:render-to-string
-                        (~document :metadata metadata
-                          (~layout
-                            body)))))
+                        (hsx (html :lang "ja"
+                               (head
+                                 (~metadata :metadata metadata)
+                                 (~scripts))
+                               (body
+                                 :hx-ext "head-support, response-targets, preload, alpine-morph"
+                                 :hx-boost "true" :hx-target-404 "body" :hx-target-5* "body"
+                                 (~layout body)))))))
     (_ (error "Invalid response form"))))
diff --git a/src/routes/about.lisp b/src/routes/about.lisp
index 16fc417..933d554 100644
--- a/src/routes/about.lisp
+++ b/src/routes/about.lisp
@@ -10,8 +10,7 @@
 (in-package :website/routes/about)
 
 (defparameter *metadata*
-  (list :title "about"
-        :path "/about"))
+  (list :title "about"))
 
 (defcomp ~page ()
   (hsx
diff --git a/src/routes/blog.lisp b/src/routes/blog.lisp
index 0f6b3e7..94b33ca 100644
--- a/src/routes/blog.lisp
+++ b/src/routes/blog.lisp
@@ -5,8 +5,7 @@
 (in-package :website/routes/blog)
 
 (defparameter *metadata*
-  (list :title "blog"
-        :path "/blog"))
+  (list :title "blog"))
 
 (defcomp ~page ()
   (hsx
diff --git a/src/routes/work.lisp b/src/routes/work.lisp
index 687f361..a2744dd 100644
--- a/src/routes/work.lisp
+++ b/src/routes/work.lisp
@@ -10,8 +10,7 @@
 (in-package :website/routes/work)
 
 (defparameter *metadata*
-  (list :title "work"
-        :path "/work"))
+  (list :title "work"))
 
 (defcomp ~page ()
   (hsx