diff --git a/app-proto/sketch-outline/.gitignore b/app-proto/sketch-outline/.gitignore
new file mode 100644
index 0000000..238273d
--- /dev/null
+++ b/app-proto/sketch-outline/.gitignore
@@ -0,0 +1,3 @@
+target
+dist
+Cargo.lock
\ No newline at end of file
diff --git a/app-proto/sketch-outline/Cargo.toml b/app-proto/sketch-outline/Cargo.toml
new file mode 100644
index 0000000..522c994
--- /dev/null
+++ b/app-proto/sketch-outline/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "sketch-outline"
+version = "0.1.0"
+authors = ["Aaron"]
+edition = "2021"
+
+[features]
+default = ["console_error_panic_hook"]
+
+[dependencies]
+js-sys = "0.3.70"
+nalgebra = "0.33.0"
+sycamore = "0.9.0-beta.3"
+
+# The `console_error_panic_hook` crate provides better debugging of panics by
+# logging them with `console.error`. This is great for development, but requires
+# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
+# code size when deploying.
+console_error_panic_hook = { version = "0.1.7", optional = true }
+
+[dependencies.web-sys]
+version = "0.3.69"
+
+[dev-dependencies]
+wasm-bindgen-test = "0.3.34"
+
+[profile.release]
+opt-level = "s" # optimize for small code size
+debug = true # include debug symbols
diff --git a/app-proto/sketch-outline/index.html b/app-proto/sketch-outline/index.html
new file mode 100644
index 0000000..5474fe9
--- /dev/null
+++ b/app-proto/sketch-outline/index.html
@@ -0,0 +1,9 @@
+
+
+
+
+ Sketch outline
+
+
+
+
diff --git a/app-proto/sketch-outline/main.css b/app-proto/sketch-outline/main.css
new file mode 100644
index 0000000..2e6aedc
--- /dev/null
+++ b/app-proto/sketch-outline/main.css
@@ -0,0 +1,50 @@
+body {
+ margin-left: 20px;
+ margin-top: 20px;
+ color: #fcfcfc;
+ background-color: #222;
+}
+
+ul {
+ width: 450px;
+ padding: 8px;
+ border: 1px solid #888;
+ border-radius: 16px;
+}
+
+li {
+ display: flex;
+ padding: 3px;
+ list-style-type: none;
+ background-color: #444;
+ border-radius: 8px;
+}
+
+li:not(:last-child) {
+ margin-bottom: 8px;
+}
+
+li > .elt-name {
+ flex-grow: 1;
+ padding: 2px 0px 2px 4px;
+}
+
+li > .elt-rep {
+ display: flex;
+}
+
+li > .elt-rep > div {
+ padding: 2px;
+ margin-left: 3px;
+ text-align: center;
+ width: 60px;
+ background-color: #333;
+}
+
+li > .elt-rep > div:first-child {
+ border-radius: 6px 0px 0px 6px;
+}
+
+li > .elt-rep > div:last-child {
+ border-radius: 0px 6px 6px 0px;
+}
\ No newline at end of file
diff --git a/app-proto/sketch-outline/src/editor.rs b/app-proto/sketch-outline/src/editor.rs
new file mode 100644
index 0000000..b0d3f2e
--- /dev/null
+++ b/app-proto/sketch-outline/src/editor.rs
@@ -0,0 +1,61 @@
+use nalgebra::DVector;
+use sycamore::{prelude::*, web::tags::div};
+
+#[derive(Clone, PartialEq)]
+struct Element {
+ id: i64,
+ name: String,
+ rep: DVector,
+ color: [f32; 3]
+}
+
+struct EditorState {
+ elements: Signal>
+}
+
+#[component]
+pub fn Editor() -> View {
+ let state = EditorState {
+ elements: create_signal(vec![
+ Element {
+ id: 1,
+ name: String::from("Central"),
+ rep: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.25, -1.0]),
+ color: [0.75_f32, 0.75_f32, 0.75_f32]
+ },
+ Element {
+ id: 2,
+ name: String::from("Wing A"),
+ rep: DVector::::from_column_slice(&[0.5, 0.5, 0.0, 0.5, -0.25]),
+ color: [1.00_f32, 0.25_f32, 0.00_f32]
+ },
+ Element {
+ id: 3,
+ name: String::from("Wing B"),
+ rep: DVector::::from_column_slice(&[-0.5, -0.5, 0.0, 0.5, -0.25]),
+ color: [1.00_f32, 0.25_f32, 0.00_f32]
+ }
+ ])
+ };
+
+ view! {
+ ul {
+ Keyed(
+ list=state.elements,
+ view=|elt| {
+ let name = elt.name.clone();
+ let rep_components = elt.rep.iter().map(
+ |u| View::from(div().children(u.to_string().replace("-", "\u{2212}")))
+ ).collect::>();
+ view! {
+ li {
+ div(class="elt-name") { (name) }
+ div(class="elt-rep") { (rep_components) }
+ }
+ }
+ },
+ key=|elt| elt.id
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app-proto/sketch-outline/src/main.rs b/app-proto/sketch-outline/src/main.rs
new file mode 100644
index 0000000..8b7ce30
--- /dev/null
+++ b/app-proto/sketch-outline/src/main.rs
@@ -0,0 +1,13 @@
+use sycamore::prelude::*;
+
+mod editor;
+
+use editor::Editor;
+
+fn main() {
+ sycamore::render(|| {
+ view! {
+ Editor {}
+ }
+ });
+}
\ No newline at end of file