changeset 154:bdcc610eeed8

[Markdown Converter][GuiZe] Added markdown coverter in C and wasm rule sets. Needs further view on this as I haven't taken a look. Written by Claude.
author June Park <parkjune1995@gmail.com>
date Mon, 12 Jan 2026 09:11:58 -0800
parents 790930d9bb90
children 3bb45eb67906
files .bazelrc MODULE.bazel MODULE.bazel.lock gui_ze/gui_ze.bzl markdown_converter/BUILD markdown_converter/markdown_to_html.c markdown_converter/markdown_to_html.h markdown_converter/markdown_to_html_wasm.c markdown_converter/markdown_to_html_wasm.js mrjunejune/BUILD seobeo/s_web.c
diffstat 11 files changed, 1910 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.bazelrc	Sun Jan 11 08:11:24 2026 -0800
+++ b/.bazelrc	Mon Jan 12 09:11:58 2026 -0800
@@ -3,3 +3,6 @@
 
 # Suppress duplicate library warnings from openssl BCR module on macOS
 build:macos --linkopt=-Wl,-no_warn_duplicate_libraries
+
+# Wasm support? 
+build:wasm --platforms=@emsdk//bazel/emscripten_toolchain:wasm_platform
--- a/MODULE.bazel	Sun Jan 11 08:11:24 2026 -0800
+++ b/MODULE.bazel	Mon Jan 12 09:11:58 2026 -0800
@@ -3,6 +3,8 @@
 bazel_dep(name = "bazel_skylib", version = "1.8.2")
 bazel_dep(name = "rules_shell", version = "0.6.1")
 bazel_dep(name = "openssl", version = "3.3.1.bcr.7")
+bazel_dep(name = "emsdk", version = "4.0.17")
+
 
 http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
 
--- a/MODULE.bazel.lock	Sun Jan 11 08:11:24 2026 -0800
+++ b/MODULE.bazel.lock	Mon Jan 12 09:11:58 2026 -0800
@@ -17,6 +17,10 @@
     "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896",
     "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
     "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": "517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b",
+    "https://bcr.bazel.build/modules/aspect_bazel_lib/1.42.3/MODULE.bazel": "e4529e12d8cd5b828e2b5960d07d3ec032541740d419d7d5b859cabbf5b056f9",
+    "https://bcr.bazel.build/modules/aspect_bazel_lib/1.42.3/source.json": "80cb66069ad626e0921555cd2bf278286fd7763fae2450e564e351792e8303f4",
+    "https://bcr.bazel.build/modules/aspect_rules_js/1.42.0/MODULE.bazel": "f19e6b4a16f77f8cf3728eac1f60dbfd8e043517fd4f4dbf17a75a6c50936d62",
+    "https://bcr.bazel.build/modules/aspect_rules_js/1.42.0/source.json": "abbb3eac3b6af76b8ce230a9a901c6d08d93f4f5ffd55314bf630827dddee57e",
     "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b",
     "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
     "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
@@ -32,6 +36,7 @@
     "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
     "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc",
     "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
+    "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b",
     "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
     "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
     "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
@@ -53,6 +58,8 @@
     "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/source.json": "a2d30458fd86cf022c2b6331e652526fa08e17573b2f5034a9dbcacdf9c2583c",
     "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
     "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
+    "https://bcr.bazel.build/modules/emsdk/4.0.17/MODULE.bazel": "a10c49d7063e5dffeec0c5b43753ab2575179fbb679851059861af7d2a781c6a",
+    "https://bcr.bazel.build/modules/emsdk/4.0.17/source.json": "8463664bc6319425d29ef0d7edd8660daf1bf0ec33c367420243d4db35e0f482",
     "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8",
     "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350",
     "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a",
@@ -170,6 +177,9 @@
     "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
     "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
     "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
+    "https://bcr.bazel.build/modules/rules_nodejs/5.8.2/MODULE.bazel": "6bc03c8f37f69401b888023bf511cb6ee4781433b0cb56236b2e55a21e3a026a",
+    "https://bcr.bazel.build/modules/rules_nodejs/6.3.2/MODULE.bazel": "42e8d5254b6135f890fecca7c8d7f95a7d27a45f8275b276f66ec337767530ef",
+    "https://bcr.bazel.build/modules/rules_nodejs/6.3.2/source.json": "80e0a68eb81772f1631f8b69014884eebc2474b3b3025fd19a5240ae4f76f9c9",
     "https://bcr.bazel.build/modules/rules_perl/0.4.1/MODULE.bazel": "4d09ad3a3cf71e606faab258a753ba9f0516b5d3c6aff9b813d06ea65c04702f",
     "https://bcr.bazel.build/modules/rules_perl/0.4.1/source.json": "70e943e2deea44c1b2ddfafe178a294b82f8b8a24ee25d547eaaa202142f1b4d",
     "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
@@ -193,7 +203,8 @@
     "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
     "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7",
     "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43",
-    "https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917",
+    "https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13",
+    "https://bcr.bazel.build/modules/rules_python/1.3.0/source.json": "25932f917cd279c7baefa6cb1d3fa8750a7a29de522024449b19af6eab51f4a0",
     "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251",
     "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/source.json": "37c10335f2361c337c5c1f34ed36d2da70534c23088062b33a8bdaab68aa9dea",
     "https://bcr.bazel.build/modules/rules_shell/0.1.2/MODULE.bazel": "66e4ca3ce084b04af0b9ff05ff14cab4e5df7503973818bb91cbc6cda08d32fc",
@@ -207,6 +218,7 @@
     "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186",
     "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
     "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
+    "https://bcr.bazel.build/modules/stardoc/0.5.4/MODULE.bazel": "6569966df04610b8520957cb8e97cf2e9faac2c0309657c537ab51c16c18a2a4",
     "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef",
     "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd",
     "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c",
@@ -256,6 +268,334 @@
         ]
       }
     },
+    "@@aspect_bazel_lib+//lib:extensions.bzl%toolchains": {
+      "general": {
+        "bzlTransitiveDigest": "x2ZXNHQB1YYLKrvA8u2W0AEQkJUyosb5KZyGwg7vTtA=",
+        "usagesDigest": "1c7PNX163TGNqWzfejRnWpH/hiT4/GRG0kYxuez0Uz0=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "copy_directory_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_platform_repo",
+            "attributes": {
+              "platform": "darwin_amd64"
+            }
+          },
+          "copy_directory_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_platform_repo",
+            "attributes": {
+              "platform": "darwin_arm64"
+            }
+          },
+          "copy_directory_freebsd_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_platform_repo",
+            "attributes": {
+              "platform": "freebsd_amd64"
+            }
+          },
+          "copy_directory_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_platform_repo",
+            "attributes": {
+              "platform": "linux_amd64"
+            }
+          },
+          "copy_directory_linux_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_platform_repo",
+            "attributes": {
+              "platform": "linux_arm64"
+            }
+          },
+          "copy_directory_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_platform_repo",
+            "attributes": {
+              "platform": "windows_amd64"
+            }
+          },
+          "copy_directory_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_directory_toolchain.bzl%copy_directory_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "copy_directory"
+            }
+          },
+          "copy_to_directory_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo",
+            "attributes": {
+              "platform": "darwin_amd64"
+            }
+          },
+          "copy_to_directory_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo",
+            "attributes": {
+              "platform": "darwin_arm64"
+            }
+          },
+          "copy_to_directory_freebsd_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo",
+            "attributes": {
+              "platform": "freebsd_amd64"
+            }
+          },
+          "copy_to_directory_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo",
+            "attributes": {
+              "platform": "linux_amd64"
+            }
+          },
+          "copy_to_directory_linux_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo",
+            "attributes": {
+              "platform": "linux_arm64"
+            }
+          },
+          "copy_to_directory_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo",
+            "attributes": {
+              "platform": "windows_amd64"
+            }
+          },
+          "copy_to_directory_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "copy_to_directory"
+            }
+          },
+          "jq_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo",
+            "attributes": {
+              "platform": "darwin_amd64",
+              "version": "1.6"
+            }
+          },
+          "jq_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo",
+            "attributes": {
+              "platform": "darwin_arm64",
+              "version": "1.6"
+            }
+          },
+          "jq_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo",
+            "attributes": {
+              "platform": "linux_amd64",
+              "version": "1.6"
+            }
+          },
+          "jq_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo",
+            "attributes": {
+              "platform": "windows_amd64",
+              "version": "1.6"
+            }
+          },
+          "jq": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_host_alias_repo",
+            "attributes": {}
+          },
+          "jq_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "jq"
+            }
+          },
+          "yq_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "darwin_amd64",
+              "version": "4.25.2"
+            }
+          },
+          "yq_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "darwin_arm64",
+              "version": "4.25.2"
+            }
+          },
+          "yq_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "linux_amd64",
+              "version": "4.25.2"
+            }
+          },
+          "yq_linux_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "linux_arm64",
+              "version": "4.25.2"
+            }
+          },
+          "yq_linux_s390x": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "linux_s390x",
+              "version": "4.25.2"
+            }
+          },
+          "yq_linux_ppc64le": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "linux_ppc64le",
+              "version": "4.25.2"
+            }
+          },
+          "yq_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo",
+            "attributes": {
+              "platform": "windows_amd64",
+              "version": "4.25.2"
+            }
+          },
+          "yq": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_host_alias_repo",
+            "attributes": {}
+          },
+          "yq_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "yq"
+            }
+          },
+          "coreutils_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo",
+            "attributes": {
+              "platform": "darwin_amd64",
+              "version": "0.0.16"
+            }
+          },
+          "coreutils_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo",
+            "attributes": {
+              "platform": "darwin_arm64",
+              "version": "0.0.16"
+            }
+          },
+          "coreutils_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo",
+            "attributes": {
+              "platform": "linux_amd64",
+              "version": "0.0.16"
+            }
+          },
+          "coreutils_linux_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo",
+            "attributes": {
+              "platform": "linux_arm64",
+              "version": "0.0.16"
+            }
+          },
+          "coreutils_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo",
+            "attributes": {
+              "platform": "windows_amd64",
+              "version": "0.0.16"
+            }
+          },
+          "coreutils_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "coreutils"
+            }
+          },
+          "bsd_tar_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:tar_toolchain.bzl%bsdtar_binary_repo",
+            "attributes": {
+              "platform": "darwin_amd64"
+            }
+          },
+          "bsd_tar_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:tar_toolchain.bzl%bsdtar_binary_repo",
+            "attributes": {
+              "platform": "darwin_arm64"
+            }
+          },
+          "bsd_tar_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:tar_toolchain.bzl%bsdtar_binary_repo",
+            "attributes": {
+              "platform": "linux_amd64"
+            }
+          },
+          "bsd_tar_linux_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:tar_toolchain.bzl%bsdtar_binary_repo",
+            "attributes": {
+              "platform": "linux_arm64"
+            }
+          },
+          "bsd_tar_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:tar_toolchain.bzl%bsdtar_binary_repo",
+            "attributes": {
+              "platform": "windows_amd64"
+            }
+          },
+          "bsd_tar_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:tar_toolchain.bzl%tar_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "bsd_tar"
+            }
+          },
+          "expand_template_darwin_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_platform_repo",
+            "attributes": {
+              "platform": "darwin_amd64"
+            }
+          },
+          "expand_template_darwin_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_platform_repo",
+            "attributes": {
+              "platform": "darwin_arm64"
+            }
+          },
+          "expand_template_freebsd_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_platform_repo",
+            "attributes": {
+              "platform": "freebsd_amd64"
+            }
+          },
+          "expand_template_linux_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_platform_repo",
+            "attributes": {
+              "platform": "linux_amd64"
+            }
+          },
+          "expand_template_linux_arm64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_platform_repo",
+            "attributes": {
+              "platform": "linux_arm64"
+            }
+          },
+          "expand_template_windows_amd64": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_platform_repo",
+            "attributes": {
+              "platform": "windows_amd64"
+            }
+          },
+          "expand_template_toolchains": {
+            "repoRuleId": "@@aspect_bazel_lib+//lib/private:expand_template_toolchain.bzl%expand_template_toolchains_repo",
+            "attributes": {
+              "user_repository_name": "expand_template"
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "aspect_bazel_lib+",
+            "aspect_bazel_lib",
+            "aspect_bazel_lib+"
+          ],
+          [
+            "aspect_bazel_lib+",
+            "bazel_skylib",
+            "bazel_skylib+"
+          ],
+          [
+            "aspect_bazel_lib+",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    },
     "@@rules_android+//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": {
       "general": {
         "bzlTransitiveDigest": "NAy+0M15JNVEBb8Tny6t7j3lKqTnsAMjoBB6LJ+C370=",
@@ -335,6 +675,163 @@
           ]
         ]
       }
+    },
+    "@@rules_nodejs+//nodejs:extensions.bzl%node": {
+      "general": {
+        "bzlTransitiveDigest": "rphcryfYrOY/P3emfTskC/GY5YuHcwMl2B2ncjaM8lY=",
+        "usagesDigest": "QSe6cWQvIHxGp1J+99fPJMNXT1Hr7PtV5kHJsfET99A=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "nodejs_linux_amd64": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "linux_amd64"
+            }
+          },
+          "nodejs_linux_arm64": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "linux_arm64"
+            }
+          },
+          "nodejs_linux_s390x": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "linux_s390x"
+            }
+          },
+          "nodejs_linux_ppc64le": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "linux_ppc64le"
+            }
+          },
+          "nodejs_darwin_amd64": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "darwin_amd64"
+            }
+          },
+          "nodejs_darwin_arm64": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "darwin_arm64"
+            }
+          },
+          "nodejs_windows_amd64": {
+            "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories",
+            "attributes": {
+              "node_download_auth": {},
+              "node_repositories": {},
+              "node_urls": [
+                "https://nodejs.org/dist/v{version}/{filename}"
+              ],
+              "node_version": "20.18.0",
+              "include_headers": false,
+              "platform": "windows_amd64"
+            }
+          },
+          "nodejs": {
+            "repoRuleId": "@@rules_nodejs+//nodejs/private:nodejs_repo_host_os_alias.bzl%nodejs_repo_host_os_alias",
+            "attributes": {
+              "user_node_repository_name": "nodejs"
+            }
+          },
+          "nodejs_host": {
+            "repoRuleId": "@@rules_nodejs+//nodejs/private:nodejs_repo_host_os_alias.bzl%nodejs_repo_host_os_alias",
+            "attributes": {
+              "user_node_repository_name": "nodejs"
+            }
+          },
+          "nodejs_toolchains": {
+            "repoRuleId": "@@rules_nodejs+//nodejs/private:nodejs_toolchains_repo.bzl%nodejs_toolchains_repo",
+            "attributes": {
+              "user_node_repository_name": "nodejs"
+            }
+          }
+        },
+        "recordedRepoMappingEntries": []
+      }
+    },
+    "@@rules_python+//python/uv:uv.bzl%uv": {
+      "general": {
+        "bzlTransitiveDigest": "Xpqjnjzy6zZ90Es9Wa888ZLHhn7IsNGbph/e6qoxzw8=",
+        "usagesDigest": "vJ5RHUxAnV24M5swNGiAnkdxMx3Hp/iOLmNANTC5Xc8=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "uv": {
+            "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo",
+            "attributes": {
+              "toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'",
+              "toolchain_names": [
+                "none"
+              ],
+              "toolchain_implementations": {
+                "none": "'@@rules_python+//python:none'"
+              },
+              "toolchain_compatible_with": {
+                "none": [
+                  "@platforms//:incompatible"
+                ]
+              },
+              "toolchain_target_settings": {}
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_python+",
+            "platforms",
+            "platforms"
+          ]
+        ]
+      }
     }
   }
 }
--- a/gui_ze/gui_ze.bzl	Sun Jan 11 08:11:24 2026 -0800
+++ b/gui_ze/gui_ze.bzl	Mon Jan 12 09:11:58 2026 -0800
@@ -1,3 +1,69 @@
+def _wasm_binary_impl(ctx):
+    """
+    Compile C source to WASM using clang --target=wasm32.
+    No libc - suitable for standalone WASM modules.
+
+    Requires LLVM with wasm32 support (e.g., Homebrew LLVM on macOS).
+    """
+    src = ctx.file.src
+    out = ctx.actions.declare_file(ctx.label.name + ".wasm")
+
+    # Shell script to find clang with wasm support and set PATH for wasm-ld
+    setup_cmd = """
+    export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
+    if [ -x /opt/homebrew/opt/llvm/bin/clang ]; then
+      CLANG=/opt/homebrew/opt/llvm/bin/clang
+    elif [ -x /usr/local/opt/llvm/bin/clang ]; then
+      CLANG=/usr/local/opt/llvm/bin/clang
+    else
+      CLANG=clang
+    fi
+    """
+
+    # Build clang command
+    cmd_parts = [
+        setup_cmd,
+        "$CLANG",
+        "--target=wasm32",
+        "-nostdlib",
+        "-O2",
+        "-Wl,--no-entry",
+        "-Wl,--export-dynamic",
+    ]
+
+    # Add exported functions
+    for fn in ctx.attr.exports:
+        cmd_parts.append("-Wl,--export=" + fn)
+
+    cmd_parts.append("-o")
+    cmd_parts.append(out.path)
+    cmd_parts.append(src.path)
+
+    ctx.actions.run_shell(
+        inputs = [src],
+        outputs = [out],
+        command = " ".join(cmd_parts),
+        progress_message = "Compiling {} to WASM".format(src.basename),
+        execution_requirements = {"no-sandbox": "1"},
+    )
+
+    return [DefaultInfo(files = depset([out]))]
+
+wasm_binary = rule(
+    implementation = _wasm_binary_impl,
+    attrs = {
+        "src": attr.label(
+            allow_single_file = [".c"],
+            mandatory = True,
+            doc = "The C source file to compile",
+        ),
+        "exports": attr.string_list(
+            default = [],
+            doc = "List of function names to export (without leading underscore)",
+        ),
+    },
+)
+
 def _foo_impl(ctx):
   out = ctx.actions.declare_file(ctx.label.name)
   ctx.actions.write(
--- a/markdown_converter/BUILD	Sun Jan 11 08:11:24 2026 -0800
+++ b/markdown_converter/BUILD	Mon Jan 12 09:11:58 2026 -0800
@@ -1,3 +1,7 @@
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("//gui_ze:gui_ze.bzl", "wasm_binary")
+
+# JavaScript implementation (original)
 filegroup(
   name = "markdown_to_html",
   srcs = glob([
@@ -6,4 +10,26 @@
   visibility = ["//visibility:public"],
 )
 
+# C implementation for native use
+cc_library(
+  name = "markdown_to_html_c",
+  srcs = ["markdown_to_html.c"],
+  hdrs = ["markdown_to_html.h"],
+  visibility = ["//visibility:public"],
+)
 
+# WASM binary for browser FFI
+wasm_binary(
+  name = "markdown_to_html_wasm",
+  src = "markdown_to_html_wasm.c",
+  exports = [
+    "malloc",
+    "free",
+    "heap_reset",
+    "markdown_to_html",
+    "markdown_strlen",
+  ],
+  visibility = ["//visibility:public"],
+)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/markdown_to_html.c	Mon Jan 12 09:11:58 2026 -0800
@@ -0,0 +1,545 @@
+/**
+ * Markdown to HTML Converter - C Implementation
+ * Supports: headers, bold, italic, links, lists, code blocks, blockquotes, horizontal rules
+ */
+
+#include "markdown_to_html.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define INITIAL_BUFFER_SIZE 4096
+
+// String buffer for building HTML output
+typedef struct {
+  char  *data;
+  size_t length;
+  size_t capacity;
+} StringBuffer;
+
+static StringBuffer *buffer_create(size_t initial_capacity)
+{
+  StringBuffer *buf = (StringBuffer *)malloc(sizeof(StringBuffer));
+  if (!buf) return NULL;
+
+  buf->data = (char *)malloc(initial_capacity);
+  if (!buf->data) {
+    free(buf);
+    return NULL;
+  }
+  buf->data[0] = '\0';
+  buf->length = 0;
+  buf->capacity = initial_capacity;
+  return buf;
+}
+
+static void buffer_grow(StringBuffer *buf, size_t needed)
+{
+  if (buf->length + needed + 1 > buf->capacity) {
+    size_t new_capacity = buf->capacity * 2;
+    while (new_capacity < buf->length + needed + 1)
+      new_capacity *= 2;
+
+    char *new_data = (char *)realloc(buf->data, new_capacity);
+    if (new_data) {
+      buf->data = new_data;
+      buf->capacity = new_capacity;
+    }
+  }
+}
+
+static void buffer_append(StringBuffer *buf, const char *str)
+{
+  size_t len = strlen(str);
+  buffer_grow(buf, len);
+  memcpy(buf->data + buf->length, str, len + 1);
+  buf->length += len;
+}
+
+static void buffer_append_n(StringBuffer *buf, const char *str, size_t n)
+{
+  buffer_grow(buf, n);
+  memcpy(buf->data + buf->length, str, n);
+  buf->length += n;
+  buf->data[buf->length] = '\0';
+}
+
+static void buffer_append_char(StringBuffer *buf, char c)
+{
+  buffer_grow(buf, 1);
+  buf->data[buf->length++] = c;
+  buf->data[buf->length] = '\0';
+}
+
+static void buffer_free(StringBuffer *buf)
+{
+  if (buf) {
+    free(buf->data);
+    free(buf);
+  }
+}
+
+// Check if line starts with pattern (after trimming whitespace)
+static int starts_with(const char *line, const char *pattern)
+{
+  while (*line && isspace((unsigned char)*line)) line++;
+  return strncmp(line, pattern, strlen(pattern)) == 0;
+}
+
+// Count leading # characters
+static int count_heading_level(const char *line)
+{
+  int count = 0;
+  while (*line && isspace((unsigned char)*line)) line++;
+  while (line[count] == '#' && count < 6) count++;
+  if (count > 0 && line[count] == ' ') return count;
+  return 0;
+}
+
+// Skip whitespace
+static const char *skip_whitespace(const char *str)
+{
+  while (*str && isspace((unsigned char)*str)) str++;
+  return str;
+}
+
+// Check if line is empty (only whitespace)
+static int is_empty_line(const char *line)
+{
+  while (*line) {
+    if (!isspace((unsigned char)*line)) return 0;
+    line++;
+  }
+  return 1;
+}
+
+// Check if line is horizontal rule (---, ***, ___)
+static int is_horizontal_rule(const char *line)
+{
+  line = skip_whitespace(line);
+  char first = *line;
+  if (first != '-' && first != '*' && first != '_') return 0;
+
+  int count = 0;
+  while (*line) {
+    if (*line == first) count++;
+    else if (!isspace((unsigned char)*line)) return 0;
+    line++;
+  }
+  return count >= 3;
+}
+
+// Check if line is unordered list item
+static int is_unordered_list(const char *line)
+{
+  line = skip_whitespace(line);
+  return (*line == '-' || *line == '*' || *line == '+') && line[1] == ' ';
+}
+
+// Check if line is ordered list item
+static int is_ordered_list(const char *line)
+{
+  line = skip_whitespace(line);
+  while (*line && isdigit((unsigned char)*line)) line++;
+  return *line == '.' && line[1] == ' ';
+}
+
+// Process inline markdown (bold, italic, code, links, strikethrough)
+static void process_inline(StringBuffer *buf, const char *text, size_t len)
+{
+  size_t i = 0;
+
+  while (i < len) {
+    // Links: [text](url)
+    if (text[i] == '[') {
+      size_t link_start = i + 1;
+      size_t link_end = link_start;
+      while (link_end < len && text[link_end] != ']') link_end++;
+
+      if (link_end < len && link_end + 1 < len && text[link_end + 1] == '(') {
+        size_t url_start = link_end + 2;
+        size_t url_end = url_start;
+        while (url_end < len && text[url_end] != ')') url_end++;
+
+        if (url_end < len) {
+          buffer_append(buf, "<a href=\"");
+          buffer_append_n(buf, text + url_start, url_end - url_start);
+          buffer_append(buf, "\">");
+          buffer_append_n(buf, text + link_start, link_end - link_start);
+          buffer_append(buf, "</a>");
+          i = url_end + 1;
+          continue;
+        }
+      }
+    }
+
+    // Images: ![alt](url)
+    if (text[i] == '!' && i + 1 < len && text[i + 1] == '[') {
+      size_t alt_start = i + 2;
+      size_t alt_end = alt_start;
+      while (alt_end < len && text[alt_end] != ']') alt_end++;
+
+      if (alt_end < len && alt_end + 1 < len && text[alt_end + 1] == '(') {
+        size_t url_start = alt_end + 2;
+        size_t url_end = url_start;
+        while (url_end < len && text[url_end] != ')') url_end++;
+
+        if (url_end < len) {
+          buffer_append(buf, "<img src=\"");
+          buffer_append_n(buf, text + url_start, url_end - url_start);
+          buffer_append(buf, "\" alt=\"");
+          buffer_append_n(buf, text + alt_start, alt_end - alt_start);
+          buffer_append(buf, "\">");
+          i = url_end + 1;
+          continue;
+        }
+      }
+    }
+
+    // Bold: **text** or __text__
+    if ((text[i] == '*' && i + 1 < len && text[i + 1] == '*') ||
+        (text[i] == '_' && i + 1 < len && text[i + 1] == '_')) {
+      char marker = text[i];
+      size_t start = i + 2;
+      size_t end = start;
+      while (end + 1 < len && !(text[end] == marker && text[end + 1] == marker)) end++;
+
+      if (end + 1 < len) {
+        buffer_append(buf, "<strong>");
+        process_inline(buf, text + start, end - start);
+        buffer_append(buf, "</strong>");
+        i = end + 2;
+        continue;
+      }
+    }
+
+    // Strikethrough: ~~text~~
+    if (text[i] == '~' && i + 1 < len && text[i + 1] == '~') {
+      size_t start = i + 2;
+      size_t end = start;
+      while (end + 1 < len && !(text[end] == '~' && text[end + 1] == '~')) end++;
+
+      if (end + 1 < len) {
+        buffer_append(buf, "<del>");
+        process_inline(buf, text + start, end - start);
+        buffer_append(buf, "</del>");
+        i = end + 2;
+        continue;
+      }
+    }
+
+    // Italic: *text* or _text_
+    if ((text[i] == '*' || text[i] == '_') && i + 1 < len && !isspace((unsigned char)text[i + 1])) {
+      char marker = text[i];
+      size_t start = i + 1;
+      size_t end = start;
+      while (end < len && text[end] != marker) end++;
+
+      if (end < len && end > start) {
+        buffer_append(buf, "<em>");
+        process_inline(buf, text + start, end - start);
+        buffer_append(buf, "</em>");
+        i = end + 1;
+        continue;
+      }
+    }
+
+    // Inline code: `code`
+    if (text[i] == '`') {
+      size_t start = i + 1;
+      size_t end = start;
+      while (end < len && text[end] != '`') end++;
+
+      if (end < len) {
+        buffer_append(buf, "<code>");
+        buffer_append_n(buf, text + start, end - start);
+        buffer_append(buf, "</code>");
+        i = end + 1;
+        continue;
+      }
+    }
+
+    // HTML escape special characters
+    if (text[i] == '<') {
+      buffer_append(buf, "&lt;");
+    } else if (text[i] == '>') {
+      buffer_append(buf, "&gt;");
+    } else if (text[i] == '&') {
+      buffer_append(buf, "&amp;");
+    } else {
+      buffer_append_char(buf, text[i]);
+    }
+    i++;
+  }
+}
+
+// Convert markdown to HTML
+MDAPI char *markdown_to_html(const char *markdown)
+{
+  if (!markdown) return NULL;
+
+  StringBuffer *buf = buffer_create(INITIAL_BUFFER_SIZE);
+  if (!buf) return NULL;
+
+  const char *ptr = markdown;
+  const char *line_start;
+
+  while (*ptr) {
+    line_start = ptr;
+
+    // Find end of line
+    while (*ptr && *ptr != '\n') ptr++;
+    size_t line_len = ptr - line_start;
+
+    // Create null-terminated line copy
+    char *line = (char *)malloc(line_len + 1);
+    if (!line) {
+      buffer_free(buf);
+      return NULL;
+    }
+    memcpy(line, line_start, line_len);
+    line[line_len] = '\0';
+
+    // Skip empty lines
+    if (is_empty_line(line)) {
+      free(line);
+      if (*ptr == '\n') ptr++;
+      continue;
+    }
+
+    // Headings: # H1, ## H2, etc.
+    int heading_level = count_heading_level(line);
+    if (heading_level > 0) {
+      const char *content = skip_whitespace(line);
+      while (*content == '#') content++;
+      content = skip_whitespace(content);
+
+      char tag[8];
+      snprintf(tag, sizeof(tag), "<h%d>", heading_level);
+      buffer_append(buf, tag);
+      process_inline(buf, content, strlen(content));
+      snprintf(tag, sizeof(tag), "</h%d>", heading_level);
+      buffer_append(buf, tag);
+
+      free(line);
+      if (*ptr == '\n') ptr++;
+      continue;
+    }
+
+    // Code block: ```
+    if (starts_with(line, "```")) {
+      buffer_append(buf, "<pre><code>");
+      free(line);
+      if (*ptr == '\n') ptr++;
+
+      // Collect code content
+      while (*ptr) {
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (starts_with(line, "```")) {
+          free(line);
+          if (*ptr == '\n') ptr++;
+          break;
+        }
+
+        // Escape HTML in code blocks
+        for (size_t i = 0; i < line_len; i++) {
+          if (line[i] == '<') buffer_append(buf, "&lt;");
+          else if (line[i] == '>') buffer_append(buf, "&gt;");
+          else if (line[i] == '&') buffer_append(buf, "&amp;");
+          else buffer_append_char(buf, line[i]);
+        }
+        buffer_append_char(buf, '\n');
+
+        free(line);
+        if (*ptr == '\n') ptr++;
+      }
+
+      buffer_append(buf, "</code></pre>");
+      continue;
+    }
+
+    // Blockquote: >
+    if (starts_with(line, ">")) {
+      buffer_append(buf, "<blockquote>");
+
+      while (1) {
+        const char *content = skip_whitespace(line);
+        if (*content == '>') content++;
+        content = skip_whitespace(content);
+        process_inline(buf, content, strlen(content));
+        buffer_append_char(buf, ' ');
+
+        free(line);
+        if (*ptr == '\n') ptr++;
+
+        // Check next line
+        if (!*ptr) break;
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (!starts_with(line, ">")) {
+          // Put back the line pointer
+          ptr = line_start;
+          free(line);
+          break;
+        }
+      }
+
+      buffer_append(buf, "</blockquote>");
+      continue;
+    }
+
+    // Horizontal rule
+    if (is_horizontal_rule(line)) {
+      buffer_append(buf, "<hr>");
+      free(line);
+      if (*ptr == '\n') ptr++;
+      continue;
+    }
+
+    // Unordered list
+    if (is_unordered_list(line)) {
+      buffer_append(buf, "<ul>");
+
+      while (1) {
+        const char *content = skip_whitespace(line);
+        content += 2; // Skip "- " or "* " or "+ "
+
+        buffer_append(buf, "<li>");
+        process_inline(buf, content, strlen(content));
+        buffer_append(buf, "</li>");
+
+        free(line);
+        if (*ptr == '\n') ptr++;
+
+        // Check next line
+        if (!*ptr) break;
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (!is_unordered_list(line)) {
+          ptr = line_start;
+          free(line);
+          break;
+        }
+      }
+
+      buffer_append(buf, "</ul>");
+      continue;
+    }
+
+    // Ordered list
+    if (is_ordered_list(line)) {
+      buffer_append(buf, "<ol>");
+
+      while (1) {
+        const char *content = skip_whitespace(line);
+        while (*content && isdigit((unsigned char)*content)) content++;
+        if (*content == '.') content++;
+        content = skip_whitespace(content);
+
+        buffer_append(buf, "<li>");
+        process_inline(buf, content, strlen(content));
+        buffer_append(buf, "</li>");
+
+        free(line);
+        if (*ptr == '\n') ptr++;
+
+        // Check next line
+        if (!*ptr) break;
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (!is_ordered_list(line)) {
+          ptr = line_start;
+          free(line);
+          break;
+        }
+      }
+
+      buffer_append(buf, "</ol>");
+      continue;
+    }
+
+    // Regular paragraph
+    buffer_append(buf, "<p>");
+
+    while (1) {
+      const char *content = skip_whitespace(line);
+      process_inline(buf, content, strlen(content));
+
+      free(line);
+      if (*ptr == '\n') ptr++;
+
+      // Check next line - continue paragraph if not special
+      if (!*ptr) break;
+      line_start = ptr;
+      while (*ptr && *ptr != '\n') ptr++;
+      line_len = ptr - line_start;
+
+      line = (char *)malloc(line_len + 1);
+      if (!line) break;
+      memcpy(line, line_start, line_len);
+      line[line_len] = '\0';
+
+      if (is_empty_line(line) ||
+          count_heading_level(line) > 0 ||
+          starts_with(line, "```") ||
+          starts_with(line, ">") ||
+          is_horizontal_rule(line) ||
+          is_unordered_list(line) ||
+          is_ordered_list(line)) {
+        ptr = line_start;
+        free(line);
+        break;
+      }
+
+      buffer_append_char(buf, ' ');
+    }
+
+    buffer_append(buf, "</p>");
+  }
+
+  char *result = buf->data;
+  free(buf); // Free struct but not data
+  return result;
+}
+
+// Free the returned HTML string
+MDAPI void markdown_free(char *html)
+{
+  free(html);
+}
+
+// Get length of HTML string (for WASM memory allocation)
+MDAPI size_t markdown_get_length(const char *html)
+{
+  return html ? strlen(html) : 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/markdown_to_html.h	Mon Jan 12 09:11:58 2026 -0800
@@ -0,0 +1,60 @@
+#ifndef MARKDOWN_TO_HTML_H
+#define MARKDOWN_TO_HTML_H
+
+#include <stddef.h>
+
+// Export macro for WASM/Emscripten
+#ifdef __EMSCRIPTEN__
+  #include <emscripten.h>
+  #define MDAPI EMSCRIPTEN_KEEPALIVE
+#else
+  #ifdef _WIN32
+    #ifdef MARKDOWN_EXPORTS
+      #define MDAPI __declspec(dllexport)
+    #else
+      #define MDAPI __declspec(dllimport)
+    #endif
+  #else
+    #define MDAPI extern
+  #endif
+#endif
+
+/**
+ * Convert markdown string to HTML string.
+ *
+ * @param markdown The input markdown string (null-terminated)
+ * @return Newly allocated HTML string. Caller must free with markdown_free().
+ *         Returns NULL on allocation failure.
+ *
+ * Supported markdown features:
+ * - Headers: # H1, ## H2, ... ###### H6
+ * - Bold: **text** or __text__
+ * - Italic: *text* or _text_
+ * - Strikethrough: ~~text~~
+ * - Links: [text](url)
+ * - Images: ![alt](url)
+ * - Inline code: `code`
+ * - Code blocks: ```code```
+ * - Unordered lists: -, *, +
+ * - Ordered lists: 1., 2., etc.
+ * - Blockquotes: > text
+ * - Horizontal rules: ---, ***, ___
+ */
+MDAPI char *markdown_to_html(const char *markdown);
+
+/**
+ * Free HTML string returned by markdown_to_html.
+ *
+ * @param html The HTML string to free
+ */
+MDAPI void markdown_free(char *html);
+
+/**
+ * Get length of HTML string (useful for WASM memory operations).
+ *
+ * @param html The HTML string
+ * @return Length of the string, or 0 if NULL
+ */
+MDAPI size_t markdown_get_length(const char *html);
+
+#endif // MARKDOWN_TO_HTML_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/markdown_to_html_wasm.c	Mon Jan 12 09:11:58 2026 -0800
@@ -0,0 +1,565 @@
+/**
+ * Markdown to HTML Converter - Standalone WASM Implementation
+ * No libc dependencies - can be compiled with: clang --target=wasm32
+ */
+
+#define WASM_EXPORT __attribute__((visibility("default")))
+
+typedef unsigned long size_t;
+typedef int int32_t;
+
+// Simple bump allocator for WASM
+#define HEAP_SIZE (1024 * 1024)  // 1MB heap
+static char heap[HEAP_SIZE];
+static size_t heap_offset = 0;
+
+WASM_EXPORT void *malloc(size_t size)
+{
+  // Align to 8 bytes
+  size_t aligned_offset = (heap_offset + 7) & ~7;
+  if (aligned_offset + size > HEAP_SIZE) return 0;
+
+  void *ptr = &heap[aligned_offset];
+  heap_offset = aligned_offset + size;
+  return ptr;
+}
+
+WASM_EXPORT void free(void *ptr)
+{
+  // Simple bump allocator - no actual free
+  (void)ptr;
+}
+
+WASM_EXPORT void heap_reset(void)
+{
+  heap_offset = 0;
+}
+
+// String functions
+static size_t strlen(const char *s)
+{
+  size_t len = 0;
+  while (s[len]) len++;
+  return len;
+}
+
+static void *memcpy(void *dest, const void *src, size_t n)
+{
+  char *d = (char *)dest;
+  const char *s = (const char *)src;
+  while (n--) *d++ = *s++;
+  return dest;
+}
+
+static int isspace_c(int c)
+{
+  return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
+}
+
+static int isdigit_c(int c)
+{
+  return c >= '0' && c <= '9';
+}
+
+// String buffer for building HTML output
+typedef struct {
+  char  *data;
+  size_t length;
+  size_t capacity;
+} StringBuffer;
+
+static StringBuffer *buffer_create(size_t initial_capacity)
+{
+  StringBuffer *buf = (StringBuffer *)malloc(sizeof(StringBuffer));
+  if (!buf) return 0;
+
+  buf->data = (char *)malloc(initial_capacity);
+  if (!buf->data) return 0;
+
+  buf->data[0] = '\0';
+  buf->length = 0;
+  buf->capacity = initial_capacity;
+  return buf;
+}
+
+static void buffer_grow(StringBuffer *buf, size_t needed)
+{
+  if (buf->length + needed + 1 > buf->capacity) {
+    size_t new_capacity = buf->capacity * 2;
+    while (new_capacity < buf->length + needed + 1)
+      new_capacity *= 2;
+
+    char *new_data = (char *)malloc(new_capacity);
+    if (new_data) {
+      memcpy(new_data, buf->data, buf->length + 1);
+      buf->data = new_data;
+      buf->capacity = new_capacity;
+    }
+  }
+}
+
+static void buffer_append(StringBuffer *buf, const char *str)
+{
+  size_t len = strlen(str);
+  buffer_grow(buf, len);
+  memcpy(buf->data + buf->length, str, len + 1);
+  buf->length += len;
+}
+
+static void buffer_append_n(StringBuffer *buf, const char *str, size_t n)
+{
+  buffer_grow(buf, n);
+  memcpy(buf->data + buf->length, str, n);
+  buf->length += n;
+  buf->data[buf->length] = '\0';
+}
+
+static void buffer_append_char(StringBuffer *buf, char c)
+{
+  buffer_grow(buf, 1);
+  buf->data[buf->length++] = c;
+  buf->data[buf->length] = '\0';
+}
+
+// Check if line starts with pattern (after trimming whitespace)
+static int starts_with(const char *line, const char *pattern)
+{
+  while (*line && isspace_c(*line)) line++;
+  size_t plen = strlen(pattern);
+  for (size_t i = 0; i < plen; i++) {
+    if (line[i] != pattern[i]) return 0;
+  }
+  return 1;
+}
+
+// Count leading # characters
+static int count_heading_level(const char *line)
+{
+  int count = 0;
+  while (*line && isspace_c(*line)) line++;
+  while (line[count] == '#' && count < 6) count++;
+  if (count > 0 && line[count] == ' ') return count;
+  return 0;
+}
+
+// Skip whitespace
+static const char *skip_whitespace(const char *str)
+{
+  while (*str && isspace_c(*str)) str++;
+  return str;
+}
+
+// Check if line is empty
+static int is_empty_line(const char *line)
+{
+  while (*line) {
+    if (!isspace_c(*line)) return 0;
+    line++;
+  }
+  return 1;
+}
+
+// Check if line is horizontal rule
+static int is_horizontal_rule(const char *line)
+{
+  line = skip_whitespace(line);
+  char first = *line;
+  if (first != '-' && first != '*' && first != '_') return 0;
+
+  int count = 0;
+  while (*line) {
+    if (*line == first) count++;
+    else if (!isspace_c(*line)) return 0;
+    line++;
+  }
+  return count >= 3;
+}
+
+// Check if line is unordered list item
+static int is_unordered_list(const char *line)
+{
+  line = skip_whitespace(line);
+  return (*line == '-' || *line == '*' || *line == '+') && line[1] == ' ';
+}
+
+// Check if line is ordered list item
+static int is_ordered_list(const char *line)
+{
+  line = skip_whitespace(line);
+  while (*line && isdigit_c(*line)) line++;
+  return *line == '.' && line[1] == ' ';
+}
+
+// Process inline markdown
+static void process_inline(StringBuffer *buf, const char *text, size_t len)
+{
+  size_t i = 0;
+
+  while (i < len) {
+    // Links: [text](url)
+    if (text[i] == '[') {
+      size_t link_start = i + 1;
+      size_t link_end = link_start;
+      while (link_end < len && text[link_end] != ']') link_end++;
+
+      if (link_end < len && link_end + 1 < len && text[link_end + 1] == '(') {
+        size_t url_start = link_end + 2;
+        size_t url_end = url_start;
+        while (url_end < len && text[url_end] != ')') url_end++;
+
+        if (url_end < len) {
+          buffer_append(buf, "<a href=\"");
+          buffer_append_n(buf, text + url_start, url_end - url_start);
+          buffer_append(buf, "\">");
+          buffer_append_n(buf, text + link_start, link_end - link_start);
+          buffer_append(buf, "</a>");
+          i = url_end + 1;
+          continue;
+        }
+      }
+    }
+
+    // Images: ![alt](url)
+    if (text[i] == '!' && i + 1 < len && text[i + 1] == '[') {
+      size_t alt_start = i + 2;
+      size_t alt_end = alt_start;
+      while (alt_end < len && text[alt_end] != ']') alt_end++;
+
+      if (alt_end < len && alt_end + 1 < len && text[alt_end + 1] == '(') {
+        size_t url_start = alt_end + 2;
+        size_t url_end = url_start;
+        while (url_end < len && text[url_end] != ')') url_end++;
+
+        if (url_end < len) {
+          buffer_append(buf, "<img src=\"");
+          buffer_append_n(buf, text + url_start, url_end - url_start);
+          buffer_append(buf, "\" alt=\"");
+          buffer_append_n(buf, text + alt_start, alt_end - alt_start);
+          buffer_append(buf, "\">");
+          i = url_end + 1;
+          continue;
+        }
+      }
+    }
+
+    // Bold: **text** or __text__
+    if ((text[i] == '*' && i + 1 < len && text[i + 1] == '*') ||
+        (text[i] == '_' && i + 1 < len && text[i + 1] == '_')) {
+      char marker = text[i];
+      size_t start = i + 2;
+      size_t end = start;
+      while (end + 1 < len && !(text[end] == marker && text[end + 1] == marker)) end++;
+
+      if (end + 1 < len) {
+        buffer_append(buf, "<strong>");
+        process_inline(buf, text + start, end - start);
+        buffer_append(buf, "</strong>");
+        i = end + 2;
+        continue;
+      }
+    }
+
+    // Strikethrough: ~~text~~
+    if (text[i] == '~' && i + 1 < len && text[i + 1] == '~') {
+      size_t start = i + 2;
+      size_t end = start;
+      while (end + 1 < len && !(text[end] == '~' && text[end + 1] == '~')) end++;
+
+      if (end + 1 < len) {
+        buffer_append(buf, "<del>");
+        process_inline(buf, text + start, end - start);
+        buffer_append(buf, "</del>");
+        i = end + 2;
+        continue;
+      }
+    }
+
+    // Italic: *text* or _text_
+    if ((text[i] == '*' || text[i] == '_') && i + 1 < len && !isspace_c(text[i + 1])) {
+      char marker = text[i];
+      size_t start = i + 1;
+      size_t end = start;
+      while (end < len && text[end] != marker) end++;
+
+      if (end < len && end > start) {
+        buffer_append(buf, "<em>");
+        process_inline(buf, text + start, end - start);
+        buffer_append(buf, "</em>");
+        i = end + 1;
+        continue;
+      }
+    }
+
+    // Inline code: `code`
+    if (text[i] == '`') {
+      size_t start = i + 1;
+      size_t end = start;
+      while (end < len && text[end] != '`') end++;
+
+      if (end < len) {
+        buffer_append(buf, "<code>");
+        buffer_append_n(buf, text + start, end - start);
+        buffer_append(buf, "</code>");
+        i = end + 1;
+        continue;
+      }
+    }
+
+    // HTML escape
+    if (text[i] == '<') {
+      buffer_append(buf, "&lt;");
+    } else if (text[i] == '>') {
+      buffer_append(buf, "&gt;");
+    } else if (text[i] == '&') {
+      buffer_append(buf, "&amp;");
+    } else {
+      buffer_append_char(buf, text[i]);
+    }
+    i++;
+  }
+}
+
+// Append heading tag
+static void append_heading_tag(StringBuffer *buf, int level, int closing)
+{
+  buffer_append_char(buf, '<');
+  if (closing) buffer_append_char(buf, '/');
+  buffer_append_char(buf, 'h');
+  buffer_append_char(buf, '0' + level);
+  buffer_append_char(buf, '>');
+}
+
+// Convert markdown to HTML
+WASM_EXPORT char *markdown_to_html(const char *markdown)
+{
+  if (!markdown) return 0;
+
+  StringBuffer *buf = buffer_create(4096);
+  if (!buf) return 0;
+
+  const char *ptr = markdown;
+  const char *line_start;
+
+  while (*ptr) {
+    line_start = ptr;
+
+    // Find end of line
+    while (*ptr && *ptr != '\n') ptr++;
+    size_t line_len = ptr - line_start;
+
+    // Create line copy
+    char *line = (char *)malloc(line_len + 1);
+    if (!line) return buf->data;
+    memcpy(line, line_start, line_len);
+    line[line_len] = '\0';
+
+    // Skip empty lines
+    if (is_empty_line(line)) {
+      if (*ptr == '\n') ptr++;
+      continue;
+    }
+
+    // Headings
+    int heading_level = count_heading_level(line);
+    if (heading_level > 0) {
+      const char *content = skip_whitespace(line);
+      while (*content == '#') content++;
+      content = skip_whitespace(content);
+
+      append_heading_tag(buf, heading_level, 0);
+      process_inline(buf, content, strlen(content));
+      append_heading_tag(buf, heading_level, 1);
+
+      if (*ptr == '\n') ptr++;
+      continue;
+    }
+
+    // Code block
+    if (starts_with(line, "```")) {
+      buffer_append(buf, "<pre><code>");
+      if (*ptr == '\n') ptr++;
+
+      while (*ptr) {
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        char *code_line = (char *)malloc(line_len + 1);
+        if (!code_line) break;
+        memcpy(code_line, line_start, line_len);
+        code_line[line_len] = '\0';
+
+        if (starts_with(code_line, "```")) {
+          if (*ptr == '\n') ptr++;
+          break;
+        }
+
+        for (size_t i = 0; i < line_len; i++) {
+          if (code_line[i] == '<') buffer_append(buf, "&lt;");
+          else if (code_line[i] == '>') buffer_append(buf, "&gt;");
+          else if (code_line[i] == '&') buffer_append(buf, "&amp;");
+          else buffer_append_char(buf, code_line[i]);
+        }
+        buffer_append_char(buf, '\n');
+
+        if (*ptr == '\n') ptr++;
+      }
+
+      buffer_append(buf, "</code></pre>");
+      continue;
+    }
+
+    // Blockquote
+    if (starts_with(line, ">")) {
+      buffer_append(buf, "<blockquote>");
+
+      while (1) {
+        const char *content = skip_whitespace(line);
+        if (*content == '>') content++;
+        content = skip_whitespace(content);
+        process_inline(buf, content, strlen(content));
+        buffer_append_char(buf, ' ');
+
+        if (*ptr == '\n') ptr++;
+        if (!*ptr) break;
+
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (!starts_with(line, ">")) {
+          ptr = line_start;
+          break;
+        }
+      }
+
+      buffer_append(buf, "</blockquote>");
+      continue;
+    }
+
+    // Horizontal rule
+    if (is_horizontal_rule(line)) {
+      buffer_append(buf, "<hr>");
+      if (*ptr == '\n') ptr++;
+      continue;
+    }
+
+    // Unordered list
+    if (is_unordered_list(line)) {
+      buffer_append(buf, "<ul>");
+
+      while (1) {
+        const char *content = skip_whitespace(line);
+        content += 2;
+
+        buffer_append(buf, "<li>");
+        process_inline(buf, content, strlen(content));
+        buffer_append(buf, "</li>");
+
+        if (*ptr == '\n') ptr++;
+        if (!*ptr) break;
+
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (!is_unordered_list(line)) {
+          ptr = line_start;
+          break;
+        }
+      }
+
+      buffer_append(buf, "</ul>");
+      continue;
+    }
+
+    // Ordered list
+    if (is_ordered_list(line)) {
+      buffer_append(buf, "<ol>");
+
+      while (1) {
+        const char *content = skip_whitespace(line);
+        while (*content && isdigit_c(*content)) content++;
+        if (*content == '.') content++;
+        content = skip_whitespace(content);
+
+        buffer_append(buf, "<li>");
+        process_inline(buf, content, strlen(content));
+        buffer_append(buf, "</li>");
+
+        if (*ptr == '\n') ptr++;
+        if (!*ptr) break;
+
+        line_start = ptr;
+        while (*ptr && *ptr != '\n') ptr++;
+        line_len = ptr - line_start;
+
+        line = (char *)malloc(line_len + 1);
+        if (!line) break;
+        memcpy(line, line_start, line_len);
+        line[line_len] = '\0';
+
+        if (!is_ordered_list(line)) {
+          ptr = line_start;
+          break;
+        }
+      }
+
+      buffer_append(buf, "</ol>");
+      continue;
+    }
+
+    // Paragraph
+    buffer_append(buf, "<p>");
+
+    while (1) {
+      const char *content = skip_whitespace(line);
+      process_inline(buf, content, strlen(content));
+
+      if (*ptr == '\n') ptr++;
+      if (!*ptr) break;
+
+      line_start = ptr;
+      while (*ptr && *ptr != '\n') ptr++;
+      line_len = ptr - line_start;
+
+      line = (char *)malloc(line_len + 1);
+      if (!line) break;
+      memcpy(line, line_start, line_len);
+      line[line_len] = '\0';
+
+      if (is_empty_line(line) ||
+          count_heading_level(line) > 0 ||
+          starts_with(line, "```") ||
+          starts_with(line, ">") ||
+          is_horizontal_rule(line) ||
+          is_unordered_list(line) ||
+          is_ordered_list(line)) {
+        ptr = line_start;
+        break;
+      }
+
+      buffer_append_char(buf, ' ');
+    }
+
+    buffer_append(buf, "</p>");
+  }
+
+  return buf->data;
+}
+
+// Get string length (for JS interop)
+WASM_EXPORT size_t markdown_strlen(const char *str)
+{
+  return str ? strlen(str) : 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/markdown_to_html_wasm.js	Mon Jan 12 09:11:58 2026 -0800
@@ -0,0 +1,143 @@
+/**
+ * Markdown to HTML Converter - WASM FFI Wrapper
+ * Loads the C implementation via WebAssembly and provides JavaScript API
+ *
+ * Build the WASM with: bazel build //markdown_converter:markdown_to_html_wasm
+ */
+
+class MarkdownConverterWasm {
+  constructor() {
+    this.wasm = undefined;
+    this.ready = false;
+  }
+
+  /**
+   * Initialize the WASM module
+   * @param {string} wasmPath - Path to the .wasm file
+   * @returns {Promise<void>}
+   */
+  async init(wasmPath = '/markdown_to_html_wasm.wasm') {
+    if (this.ready) return;
+
+    try {
+      this.wasm = await WebAssembly.instantiateStreaming(fetch(wasmPath), {
+        env: {}
+      });
+      this.ready = true;
+    } catch (err) {
+      console.error('Failed to load markdown WASM module:', err);
+      throw err;
+    }
+  }
+
+  /**
+   * Write string to WASM memory
+   * @private
+   */
+  _writeString(str) {
+    const encoder = new TextEncoder();
+    const bytes = encoder.encode(str + '\0');
+    const ptr = this.wasm.instance.exports.malloc(bytes.length);
+    const memory = new Uint8Array(this.wasm.instance.exports.memory.buffer);
+    memory.set(bytes, ptr);
+    return ptr;
+  }
+
+  /**
+   * Read string from WASM memory
+   * @private
+   */
+  _readString(ptr) {
+    const memory = new Uint8Array(this.wasm.instance.exports.memory.buffer);
+    let end = ptr;
+    while (memory[end] !== 0) end++;
+    const bytes = memory.slice(ptr, end);
+    const decoder = new TextDecoder();
+    return decoder.decode(bytes);
+  }
+
+  /**
+   * Reset the WASM heap (call between conversions to reclaim memory)
+   */
+  resetHeap() {
+    if (this.ready) {
+      this.wasm.instance.exports.heap_reset();
+    }
+  }
+
+  /**
+   * Convert markdown string to HTML string using WASM
+   * @param {string} markdown - The markdown text to convert
+   * @returns {string} The converted HTML
+   */
+  convert(markdown) {
+    if (!this.ready) {
+      throw new Error('WASM module not initialized. Call init() first.');
+    }
+
+    // Reset heap before each conversion to reclaim memory
+    this.resetHeap();
+
+    // Write markdown to WASM memory
+    const inputPtr = this._writeString(markdown);
+
+    // Call the C function
+    const outputPtr = this.wasm.instance.exports.markdown_to_html(inputPtr);
+
+    // Read the result
+    const html = this._readString(outputPtr);
+
+    return html;
+  }
+
+  /**
+   * Convert markdown to DOM elements (compatible with original API)
+   * @param {string} markdown - The markdown text to convert
+   * @returns {Array<HTMLElement>} Array of DOM elements
+   */
+  convertToElements(markdown) {
+    const html = this.convert(markdown);
+    const template = document.createElement('template');
+    template.innerHTML = html;
+    return Array.from(template.content.children);
+  }
+}
+
+// Singleton instance
+const markdownWasm = new MarkdownConverterWasm();
+
+/**
+ * Convert markdown to DOM elements (WASM version)
+ * Compatible with original markdownConverter() API
+ * @param {string} value - Markdown string
+ * @returns {Promise<Array<HTMLElement>>} Array of DOM elements
+ */
+async function markdownConverterWasm(value) {
+  if (!markdownWasm.ready) {
+    await markdownWasm.init();
+  }
+  return markdownWasm.convertToElements(value);
+}
+
+/**
+ * Render markdown to a container element (WASM version)
+ * Compatible with original renderMarkdown() API
+ * @param {HTMLElement} container - Container element
+ * @param {string} markdown - Markdown string
+ */
+async function renderMarkdownWasm(container, markdown) {
+  if (!markdownWasm.ready) {
+    await markdownWasm.init();
+  }
+  container.innerHTML = markdownWasm.convert(markdown);
+}
+
+// Export for use in other files
+if (typeof module !== 'undefined' && module.exports) {
+  module.exports = {
+    MarkdownConverterWasm,
+    markdownWasm,
+    markdownConverterWasm,
+    renderMarkdownWasm
+  };
+}
--- a/mrjunejune/BUILD	Sun Jan 11 08:11:24 2026 -0800
+++ b/mrjunejune/BUILD	Mon Jan 12 09:11:58 2026 -0800
@@ -15,6 +15,7 @@
   name = "compiled_ts",
   srcs = [
     "//markdown_converter:markdown_to_html",
+    "//markdown_converter:markdown_to_html_wasm",
   ],
   dest = "src",
 )
--- a/seobeo/s_web.c	Sun Jan 11 08:11:24 2026 -0800
+++ b/seobeo/s_web.c	Mon Jan 12 09:11:58 2026 -0800
@@ -219,6 +219,7 @@
       goto clean_up;
     }
 
+    Seobeo_Log(SEOBEO_DEBUG, "Serving Static Files\n");
     // Serve static file
     const char *mime = "application/octet-stream";
     if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8";