diff --git a/blog.css b/blog.css
new file mode 100644
index 0000000..6792edb
--- /dev/null
+++ b/blog.css
@@ -0,0 +1,36 @@
+body {
+  background-color: #E0B0FF;
+  font-family: monospace;
+}
+
+table {
+  width: 100%;
+}
+
+td {
+  width: 50%;
+  vertical-align:top;
+}
+
+td p {
+  word-wrap:anywhere;
+}
+
+a {
+	text-decoration: none;
+	font-weight:bold;
+	color:blueviolet;
+}
+
+a:hover {
+    animation: rainbow 1s infinite;
+}
+
+@keyframes rainbow {
+    20%{color: red;}
+    40%{color: orange;}
+    60%{color: yellow;}
+    80%{color: green;}
+    100%{color: blue;}
+}
+
diff --git a/blog.tmpl.html b/blog.tmpl.html
new file mode 100644
index 0000000..4c697a8
--- /dev/null
+++ b/blog.tmpl.html
@@ -0,0 +1,34 @@
+
+
+  
+		web log of tilde town
+    
+    
+    
+	
+	
+    
+      
+        | + +a world wide web log for tilde town!+          {{ range .News }}
+{{.Title}}+            {{.Pubdate}}
+            {{.Content}}
+          {{ end }}
+ | + +the town lights+
+a dot is a user. + means they've established a webpage. * means they are logged into
+          the server.+
+ 
+          {{ .Lights }}
+          <3
+          + | 
+    
+
+
diff --git a/genblog.go b/genblog.go
index 27b0b88..0671e3f 100644
--- a/genblog.go
+++ b/genblog.go
@@ -7,37 +7,83 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
+	"sort"
 	"text/template"
 )
 
-const statsPath = "/town/bin/stats"
+const statsPath = "/usr/local/bin/stats"
 
 //go:embed blog.tmpl.html
 var blogTmpl string
 
 type newsEntry struct {
-	Title   string `json:"title"`   // Title of entry
-	Pubdate string `json:"pubdate"` // Human readable date
-	Content string `json:"content"` // HTML of entry
+	Title   string // Title of entry
+	Pubdate string // Human readable date
+	Content string // HTML of entry
+}
+
+type User struct {
+	Username string
+	Default  bool
 }
 
 type tildeData struct {
-	News []newsEntry `json:"news"` // Collection of town news entries
+	News        []newsEntry
+	Users       []User
+	ActiveUsers []string `json:"active_users"`
 }
 
+type ByName []User
+
+func (n ByName) Len() int           { return len(n) }
+func (n ByName) Swap(i, j int)      { n[i], n[j] = n[j], n[i] }
+func (n ByName) Less(i, j int) bool { return n[i].Username < n[j].Username }
+
 func _main() error {
 	data, err := stats()
 	if err != nil {
 		return err
 	}
 
+	type tmplData struct {
+		News   []newsEntry
+		Lights string
+	}
+
+	td := &tmplData{
+		News:   data.News,
+		Lights: "",
+	}
+
+	sort.Sort(ByName(data.Users))
+
+	isActive := func(username string) bool {
+		for _, u := range data.ActiveUsers {
+			if u == username {
+				return true
+			}
+		}
+
+		return false
+	}
+
+	for _, u := range data.Users {
+		if isActive(u.Username) {
+			td.Lights += fmt.Sprintf("*", u.Username)
+		} else if !u.Default {
+			td.Lights += fmt.Sprintf("+", u.Username)
+		} else {
+			td.Lights += "."
+		}
+	}
+
 	t, err := template.New("blog").Parse(blogTmpl)
 	if err != nil {
 		return fmt.Errorf("failed to parse the blog template: %w", err)
 	}
 
 	out := bytes.Buffer{}
-	if err = t.Execute(&out, data); err != nil {
+	if err = t.Execute(&out, td); err != nil {
 		return fmt.Errorf("failed to render blog template: %w", err)
 	}
 
@@ -56,7 +102,7 @@ func stats() (*tildeData, error) {
 		return nil, err
 	}
 
-	data := tildeData{}
+	var data tildeData
 
 	err = json.Unmarshal(sout.Bytes(), &data)
 	if err != nil {