diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 0aa4c619cedc963c99aaff105a9608fdd717c8d5..24f7911e756f1d37bd1ad4cac32efdc359991c89 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -3,7 +3,6 @@
   "build": {
       "dockerfile": "Dockerfile"
   },
-  "updateContentCommand": "sbt fastOptJS fullOptJS",
   "postCreateCommand": "nohup http-server -p 8080 &",
   "extensions": [
       "scalameta.metals",
diff --git a/build.sbt b/build.sbt
index 8c27747bcbf2c29c1726efb44c2628502e36f00b..e96a965b13b3ec042d8c8d282fce9b50ef10307a 100644
--- a/build.sbt
+++ b/build.sbt
@@ -7,14 +7,10 @@ scalaVersion := "3.1.0"
 // Don't automatically call main
 scalaJSUseMainModuleInitializer := false
 
-resolvers += "jitpack" at "https://jitpack.io"
-
-updateOptions := updateOptions.value.withLatestSnapshots(false)
+//updateOptions := updateOptions.value.withLatestSnapshots(false)
 
 libraryDependencies ++= Seq(
-//  "org.scala-js" %%% "scalajs-dom" % "1.1.0",
-  "com.github.wbillingsley.veautiful" %%% "veautiful" % "v0.3-SNAPSHOT",
-  "com.github.wbillingsley.veautiful" %%% "doctacular" % "v0.3-SNAPSHOT",
+  "com.wbillingsley" %%% "doctacular" % "0.3-M3",
 )
 
 
diff --git a/project/build.properties b/project/build.properties
index b46cfa1486de2ef70521d29ac2789db6dbade475..ff2eef04e3b60e0f6a8e46147f05e440e7faa5e3 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version = 1.6.2
\ No newline at end of file
+sbt.version = 1.8.0
\ No newline at end of file
diff --git a/src/main/scala/acssite/Common.scala b/src/main/scala/acssite/Common.scala
index 6b5ab3b241603be63807e7ef7f173ee47ae09f2c..e4356eb92cce8224961765c5aec475f576036ea2 100644
--- a/src/main/scala/acssite/Common.scala
+++ b/src/main/scala/acssite/Common.scala
@@ -5,7 +5,7 @@
 
 package acssite
 
-import com.wbillingsley.veautiful.html.{<, DElement, Markup, VHtmlNode, ^}
+import com.wbillingsley.veautiful.html.{<, DElement, Markup, DHtmlContent, ^}
 import com.wbillingsley.veautiful.templates.{DeckBuilder, VSlides}
 
 import scala.collection.mutable
@@ -18,7 +18,7 @@ object Common {
 
   given markdownGenerator:Markup = new Markup({ (s:String) => js.Dynamic.global.marked.parse(s).asInstanceOf[String] })
 
-  def markdown(s:String):VHtmlNode = markdownGenerator.Fixed(s)
+  def markdown(s:String) = markdownGenerator.Fixed(s)
 
 
   /** Circuits Up! Logo */
@@ -26,7 +26,7 @@ object Common {
     <.span()
   }
 
-  def downloadFromGitHub(project:String, user:String="UNEcosc250"):VHtmlNode = {
+  def downloadFromGitHub(project:String, user:String="UNEcosc250"):DHtmlContent = {
     <.a(
       ^.cls := "btn btn-secondary",
       ^.href := s"https://github.com/$user/$project/archive/master.zip",
diff --git a/src/main/scala/acssite/Template.scala b/src/main/scala/acssite/Template.scala
index 9b37d18eb4a233c74d0517a3f159006814576d70..5f99a2959681ab2cd06cd010344e445fa8baac23 100644
--- a/src/main/scala/acssite/Template.scala
+++ b/src/main/scala/acssite/Template.scala
@@ -1,6 +1,6 @@
 package acssite
 
-import com.wbillingsley.veautiful.html.{<, VHtmlNode, ^}
+import com.wbillingsley.veautiful.html.{<, DHtmlContent, ^}
 import com.wbillingsley.veautiful.templates.DeckBuilder
 
 /**
@@ -35,7 +35,7 @@ extension (db:DeckBuilder) {
   }
 
   /** A title slide for the front of the deck */
-  def titleSlide(title:String, subtitle:String, authorCard:VHtmlNode, logos:VHtmlNode):DeckBuilder = {
+  def titleSlide(title:String, subtitle:String, authorCard:DHtmlContent, logos:DHtmlContent):DeckBuilder = {
     db.veautifulSlide(
       <.div(
         <.h1(^.attr("style") := "margin-bottom: 0; font-size: 60px", title),
@@ -63,7 +63,7 @@ extension (db:DeckBuilder) {
 
 
 
-def bootStrapMediaBox(imageUrl:String, content:VHtmlNode) = {
+def bootStrapMediaBox(imageUrl:String, content:DHtmlContent) = {
   <.div(^.cls := "media",
     <.img(^.src := imageUrl, ^.cls := "mr-3", ^.attr("style") := "height: 150px"),
     <.div(^.cls := "media-body", ^.attr("style") := "text-align: left;", content)
diff --git a/src/main/scala/courses/HPlanPrereqWidget.scala b/src/main/scala/courses/HPlanPrereqWidget.scala
index e9f4fe6eddea7aa2c32b961a428473ec8920b228..3819efe1364e8a0193fe505e2194ad6999b5f370 100644
--- a/src/main/scala/courses/HPlanPrereqWidget.scala
+++ b/src/main/scala/courses/HPlanPrereqWidget.scala
@@ -2,6 +2,7 @@ package courses
 
 import com.wbillingsley.veautiful.Unique
 import com.wbillingsley.veautiful.html.{<, DElement, SVG, Styling, VHtmlComponent, ^, EventMethods}
+import com.wbillingsley.veautiful.svg.DSvgContent
 import org.scalajs.dom
 
 
@@ -14,7 +15,7 @@ case class HPlanChooser(course:Course) extends VHtmlComponent {
       <("select")(
         ^.on("change") ==> { (evt) =>
           selected = evt.inputValue
-          rerender(),
+          rerender()
         },
         ^.attr("name") := "Plan",
         for 
@@ -189,7 +190,7 @@ case class HPlanPrereqWidget(course:Course, plan:Plan) extends VHtmlComponent {
   def columnTransform(i:Int, gutter:Boolean = false):String = s"translate(${columnX(i, gutter)}, 0)"
 
 
-  def svg(el:PrereqElement):(Int, <.SingleChild[dom.svg.G]) = el match {
+  def svg(el:PrereqElement):(Int, DSvgContent) = el match {
     // A single unit is 
     case s:String =>
       1 -> singleUnitBox(s)
diff --git a/src/main/scala/courses/PlanPrereqWidget.scala b/src/main/scala/courses/PlanPrereqWidget.scala
index 0681ab60a46845bb2e82fb275f2067b51abf8dbf..5e8ce6a59311ad3a79d33475f395a9d0c2dc59e5 100644
--- a/src/main/scala/courses/PlanPrereqWidget.scala
+++ b/src/main/scala/courses/PlanPrereqWidget.scala
@@ -1,14 +1,15 @@
 package courses
 
 import com.wbillingsley.veautiful.Unique
-import com.wbillingsley.veautiful.html.{<, DElement, SVG, Styling, VHtmlComponent, ^}
+import com.wbillingsley.veautiful.html.{<, DElement, SVG, Styling, ^}
+import com.wbillingsley.veautiful.svg.{DSvgContent, DSvgComponent}
 import org.scalajs.dom
 
 /**
  * Lays out the structure of a course vertically, so that groups of subjects can be seen
  * more easily
  */
-case class PlanPrereqWidget(plan:Plan) extends VHtmlComponent {
+case class PlanPrereqWidget(plan:Plan) extends DSvgComponent {
 
   import acssite.given
 
@@ -110,7 +111,7 @@ case class PlanPrereqWidget(plan:Plan) extends VHtmlComponent {
     }
 
 
-  def svg(offset:Int, el:PrereqElement):(Int, <.SingleChild[dom.svg.G]) = el match {
+  def svg(offset:Int, el:PrereqElement):(Int, DSvgContent) = el match {
     case s:String =>
       1 -> singleUnitBox(offset, s)
       /*SVG.g(
@@ -141,7 +142,7 @@ case class PlanPrereqWidget(plan:Plan) extends VHtmlComponent {
   }
 
   val planStrings = flatStrings(plan)
-  println(planStrings)
+//  println(planStrings)
 
   def prereqLines(plan: Plan, active:Option[String]) =
     def arrow(startRow:Int, endRow:Int, number:Int) =