diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts
index 2e70cf1a..691a1329 100644
--- a/quartz/plugins/transformers/ofm.ts
+++ b/quartz/plugins/transformers/ofm.ts
@@ -5,6 +5,7 @@ import { findAndReplace } from "mdast-util-find-and-replace"
 import { slugify } from "../../path"
 import rehypeRaw from "rehype-raw"
 import { visit } from "unist-util-visit"
+import path from "path"
 
 export interface Options {
   highlight: boolean
@@ -111,21 +112,56 @@ export class ObsidianFlavoredMarkdown extends QuartzTransformerPlugin {
         const backlinkRegex = new RegExp(/!?\[\[([^\[\]\|\#]+)(#[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/, "g")
         return (tree: Root, _file) => {
           findAndReplace(tree, backlinkRegex, (value: string, ...capture: string[]) => {
+            const [fp, rawHeader, rawAlias] = capture
+            const anchor = rawHeader?.trim() ?? ""
+            const alias = rawAlias?.slice(1).trim()
+
+            // embed cases
             if (value.startsWith("!")) {
-              // TODO: handle embeds
-            } else {
-              const [path, rawHeader, rawAlias] = capture
-              const anchor = rawHeader?.trim() ?? ""
-              const alias = rawAlias?.slice(1).trim() ?? path
-              const url = slugify(path.trim() + anchor)
-              return {
-                type: 'link',
-                url,
-                children: [{
-                  type: 'text',
-                  value: alias
-                }]
+              const ext = path.extname(fp).toLowerCase()
+              const url = slugify(fp.trim()) + ext
+              if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg"].includes(ext)) {
+                const dims = alias ?? ""
+                let [width, height] = dims.split("x", 2)
+                width ||= "auto"
+                height ||= "auto"
+                return {
+                  type: 'image',
+                  url,
+                  data: {
+                    hProperties: {
+                      width, height
+                    }
+                  }
+                }
+              } else if ([".mp4", ".webm", ".ogv", ".mov", ".mkv"].includes(ext)) {
+                return {
+                  type: 'html',
+                  value: ``
+                }
+              } else if ([".mp3", ".webm", ".wav", ".m4a", ".ogg", ".3gp", ".flac"].includes(ext)) {
+                return {
+                  type: 'html',
+                  value: ``
+                }
+              } else if ([".pdf"].includes(ext)) {
+                return {
+                  type: 'html',
+                  value: ``
+                }
               }
+              // otherwise, fall through to regular link
+            }
+
+            // internal link
+            const url = slugify(fp.trim() + anchor)
+            return {
+              type: 'link',
+              url,
+              children: [{
+                type: 'text',
+                value: alias ?? fp
+              }]
             }
           })
         }
diff --git a/quartz/processors/parse.ts b/quartz/processors/parse.ts
index 173675ec..4fc13f80 100644
--- a/quartz/processors/parse.ts
+++ b/quartz/processors/parse.ts
@@ -92,7 +92,7 @@ export function createFileParser(baseDir: string, fps: string[], verbose: boolea
           console.log(`[process] ${fp} -> ${file.data.slug}`)
         }
       } catch (err) {
-        console.log(chalk.red(`Failed to process \`${fp}\`: `) + err)
+        console.log(chalk.red(`\nFailed to process \`${fp}\`: `) + err)
         process.exit(1)
       }
     }
diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss
index 260f007e..f0390357 100644
--- a/quartz/styles/base.scss
+++ b/quartz/styles/base.scss
@@ -219,3 +219,8 @@ section {
     padding: 0 1em
   }
 }
+
+audio, video {
+  width: 100%;
+  border-radius: 5px;
+}