commit 3544b46ca917de42b17dcb039e39a68d5ed05d31
parent 2b54915fd106c0df96475298fa0a37afa610e21a
Author: massi <mdsiboldi@gmail.com>
Date: Fri, 2 Aug 2024 06:14:55 -0700
path fn updates, styling sesh
Diffstat:
7 files changed, 175 insertions(+), 57 deletions(-)
diff --git a/shared/static/shared-assets/spiral-for-dark-mode.svg b/shared/static/shared-assets/spiral-for-dark-mode.svg
@@ -2,8 +2,8 @@
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
- width="1rem"
- height="1rem"
+ width="0.8rem"
+ height="0.8rem"
viewBox="-1 0 20 20"
version="1.1"
id="svg1"
diff --git a/shared/static/shared-assets/spiral-for-light-mode.svg b/shared/static/shared-assets/spiral-for-light-mode.svg
@@ -2,8 +2,8 @@
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
- width="1rem"
- height="1rem"
+ width="0.8em"
+ height="0.8em"
viewBox="-1 0 20 20"
version="1.1"
id="svg1"
diff --git a/site/md/color-synth.templ.md b/site/md/color-synth.templ.md
@@ -1,26 +1,27 @@
-# color-synth
+@(samples)
- [git repo here](https://git.massi.world/color-synth)
- [check out color-synth here!](https://color-synth.massi.world)
-@(samples)
-
-## About
+# About
Color-synth is a virtual modular [video synthesizer](https://en.wikipedia.org/wiki/Video_synthesizer). Add and hook up various signal-generating modules, connect them to the video output channels, and watch the colors start dancing in your eyes.
-## Current State
+# Current State
Color-synth is under __active development__. Everything is subject to change, and any programs you save to url may become invalid in the future.
-## How To Synthesize
+# How To Synthesize
- Add a module using the buttons on the bottom right.
+
- To connect a module, drag from its purple connector on the top-right of the module, to either a green input port of another module, or the video output channels (lightness, chroma, hue) on the top right of the screen.
+
- To disconnect a module, do the same thing you did to connect it.
+
- When you've made something you want to share, click on the `save` button at the bottom right corner. This will save your patch to the url.
-## The Modules
+# The Modules
- The __oscillator__ module generates a waveform signal. In the audio realm, you usually have knobs to control an oscillator's octave, semitone, and cents. Each knob is more precise than the last, and accomplishes different effects - pitching up or down an octave, transposing, and fine-tuning. In the video realm, there are some similarities to this system. Three knobs working at different harmonic levels. `Coarse` controls how the waveform repeats over the entire screen. For example, `coarse` set to `1` means that from the first pixel drawn on the screen to the last, the waveform will go through one cycle. `Fine` works on the row level - each increment of the fine knob will cycle the waveform once per row of pixels. `Superfine` is akin to cents. It enables movement by slightly adjusting the frequency of the wave so that it doesn't perfectly line up with the screen. Finally, you can select between a sine, square, or sawtooth wave with `waveform`.
@@ -34,12 +35,18 @@ Color-synth is under __active development__. Everything is subject to change, an
- The __image oscillator__ module currently adds a smiley face. In the _future_, you'll be able provide an image of your own! It has one control, `speed`, that is probably confusing right now. Basically, you can think of the color values of an image as a complicated waveform. That waveform has a frequency. In the current state of this module, a speed of `100,000` will display the image at full size. `200,000` will display a 2x2 grid of the image. `300,000`, 3x3. Etc.
-## Roadmap
+# Roadmap
- Better inputs. There is much to do here. The current ones are imprecise and unwieldy.
+
- Image module overhaul. Having inputs for scaleX, scaleY, and image URL would be a good start.
+
- Workspace improvements. There are a lot of impactful things here. The ability to hide all modules! The ability to move all modules at once and/or pan the workspace. Improvements to the initial positioning of new modules.
+
- Workflow improvements. Undo/Redo! The ability to delete modules! Adding a module in between two connected modules! Better disconnect ergonomics!
+
- Module design overhaul. My long-term goal is to style each module in its own unique way, as a nod to all the unique modular synthesis gear out there.
+
- Mobile support.
+
- MIDI support, so you can route midi to your browser and sync color-synth with your music!
diff --git a/site/style.templ.css b/site/style.templ.css
@@ -1,14 +1,40 @@
:root {
--dark-bg: #1d2c3a;
--dark-fg: #acbdcf;
+ --dark-link: white;
+
--light-bg: #def0ff;
--light-fg: #455564;
+ --light-link: black;
+
+ --bg: var(--light-bg);
+ --fg: var(--light-fg);
+ --link: var(--light-link);
+
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --bg: var(--dark-bg);
+ --fg: var(--dark-fg);
+ --link: var(--dark-link);
+ }
+}
+
+@media (max-width: 600px) {
+ header {
+ line-height: 1.2;
+ }
+ header > *:nth-child(2n)::after {
+ content: "\A";
+ white-space: pre;
+ }
}
html {
- font-size: 24px;
- color: var(--light-fg);
- background: var(--light-bg);
+ font-size: 20px;
+ color: var(--fg);
+ background: var(--bg);
}
@@ -19,8 +45,65 @@ body {
padding: 0.75rem;
}
-h1 {
- font-size: 2rem;
+a {
+ color: var(--link);
+ text-decoration: 1px underline;
+ text-underline-offset: 0.1em;
+}
+
+.md h1 {
+ font-size: 1.4rem;
+ font-weight: normal;
+ margin: 0.5rem 0;
+}
+
+.md p, .md ul, .md ol {
+ margin-top: 0;
+}
+
+h1 > a, h2 > a, h3 > a, h4 > a {
+ color: inherit;
+ text-decoration: none;
+ position: relative;
+ left: -1.2rem;
+ padding-left: 1.2rem;
+}
+
+#svg-arrow {
+ vertical-align: middle;
+ width: 1em;
+ height: 1em;
+ padding: 0 0.4em;
+}
+
+header {
+ font-size: 1.2rem;
+ padding-bottom: 0.8rem;
+}
+
+header a {
+ color: inherit;
+}
+
+header a:last-child {
+ text-decoration: none;
+}
+
+ul {
+ margin-left: -1rem;
+}
+
+h1:hover > a::after,
+h2:hover > a::after,
+h3:hover > a::after,
+h4:hover > a::after {
+ content: "🔗";
+ position: absolute;
+ right: -1.2rem;
+ font-size: 0.8rem;
+ top: 0;
+ bottom: 0;
+ align-content: center;
}
ul > li {
@@ -28,10 +111,6 @@ ul > li {
}
@media (prefers-color-scheme: dark) {
- html {
- background: var(--dark-bg);
- color: var(--dark-fg);
- }
ul > li {
list-style: url("@(web-root)/shared-assets/spiral-for-dark-mode.svg")
}
diff --git a/src/core.clj b/src/core.clj
@@ -12,6 +12,7 @@
"\t"
words)))
+(def VERBOSE (boolean (System/getenv "MW_VERBOSE")))
(def WEB_ROOT (or (System/getenv "WEB_ROOT") ""))
(defn without-index [path-vec]
@@ -25,6 +26,7 @@
(defn mk-path-fns [domain getspec]
(letfn [(p
+ ([] (p "" (dev?)))
([rest-str]
(p rest-str (dev?)))
([rest-str is-dev]
@@ -62,16 +64,28 @@
:path
(into ["build" domain])
(cstr/join "/")))]
- {:p p
- :p-network-path network-path
- :p-url url
- :p-out outfile
- :p-path path}))
-
-
-(defn inject-path-fns [domain getspec]
- (doseq [[k v] (mk-path-fns domain getspec)]
- (eval `(def ~(symbol k) ~v))))
+ (fn [& args]
+ (let [arg1 (first args)
+ fns {:network-path network-path
+ :url url
+ :out outfile
+ :path path}
+ result (cond
+ (some #(= % arg1) (keys fns))
+ (apply (arg1 fns) (rest args))
+
+ (string? arg1)
+ (apply p args)
+
+ (empty? args)
+ (p)
+
+ :else
+ (throw (Exception. (str "⁉ invalid path call with args " args))))]
+ (when VERBOSE
+ (println "DEBUG: p" result "<-" args))
+
+ result))))
(defn p [path] (str WEB_ROOT path))
(defn mk-p [domain] (if (= (clojure.string/upper-case (or (System/getenv "MW_ENV") "")) "DEV")
diff --git a/src/site.clj b/src/site.clj
@@ -14,34 +14,34 @@
(throw (Exception. (str "ensure check failed! page " key-or-spec " not found.")))
(pages key-or-spec))))
-(core/inject-path-fns domain getspec)
+(def p (core/mk-path-fns domain getspec))
(defn test-path [pgkey]
(println)
(println (str "paths for " pgkey ":\n"))
+
(letfn [(mypp [obj]
(doseq [[k v] obj]
(println (str " " k))
- (println (str " " v)))
- )]
+ (println (str " " v))))]
(println "dev:")
(mypp {:p (p "/is/a/path.txt" true)
- :network-path (p-network-path pgkey true)
- :url (p-url pgkey true)
- :path (p-path pgkey true)})
+ :network-path (p :network-path pgkey true)
+ :url (p :url pgkey true)
+ :path (p :path pgkey true)})
(println "prod:")
(mypp {:p (p "/is/a/path.txt")
- :network-path (p-network-path pgkey)
- :url (p-url pgkey)
- :path (p-path pgkey)})
+ :network-path (p :network-path pgkey)
+ :url (p :url pgkey)
+ :path (p :path pgkey)})
(println "other:")
(mypp
- {:outfile (p-out pgkey)})))
+ {:outfile (p :out pgkey)})))
(defn site-header [spec]
- (concat (core/massi-world-domain-stuff (p-url spec) p spec)
+ (concat (core/massi-world-domain-stuff (p :url spec) p spec)
(list [:link {:rel "stylesheet" :href (p "/style.css")}]
[:link {:rel "manifest" :href (p "/manifest.json")}])))
@@ -61,31 +61,50 @@
(with-head ~spec
~@render))} ~spec)})))
+(defn page-identifier? [thing]
+ (or (map? thing) (keyword? thing)))
+
+(def svg-arrow
+ [:svg {:viewBox "0 0 16 16" :id "svg-arrow"}
+ [:path {:style "fill:var(--fg)" :d "M 9.3370298,4.2576328 8.9740248,4.8872198 13.221,7.329 H 0.72416487 V 8.032 H 13.221 l -4.2469782,2.442097 0.363005,0.629587 5.9300332,-3.4230256 z"}]])
+
+(defn header [& crumbs]
+ (letfn [(mkcrumb
+ ([pg]
+ (cond (page-identifier? pg)
+ [:a {:href (p :path pg)}
+ (:title (getspec pg))]
+
+ (string? pg)
+ [:span pg]
+
+ :else
+ (throw (Exception. "header got wrong stuff.")))))]
+ [:header
+ (interpose [:span {:class "crumb-interposer"} svg-arrow] (map mkcrumb (conj crumbs :home)))]))
-(defn header []
- [:header "massi world 🦝"])
(defn footer []
[:footer
- "Last generated: "
- (.format (java.text.SimpleDateFormat. "MM/dd/yyyy hh:mm:ssa z")
- (new java.util.Date))])
+ "Last generated: "
+ (.format (java.text.SimpleDateFormat. "MM/dd/yyyy hh:mm:ssa z")
+ (new java.util.Date))])
(defn build-manifest []
(core/prnt 1 "🤖" "writing build/massi.world/manifest.json")
(core/process-templ "site/manifest.templ.json"
"build/massi.world/manifest.json"
{:icon-192 (p "/shared-assets/icon-192-192.png")
- :index-url (p-url :home)}))
+ :index-url (p :url :home)}))
(defn build-css []
(core/prnt 1 "🖼" "writing build/massi.world/style.css")
(core/process-templ "site/style.templ.css"
"build/massi.world/style.css"
- {:web-root core/WEB_ROOT}))
+ {:web-root (p "")}))
(defn render-page [pgkey]
(core/prnt 1 "👉" pgkey)
- (let [out-file (p-out pgkey)
+ (let [out-file (p :out pgkey)
out-str (do (core/prnt 2 "🌀" "rendering " pgkey)
(str ((-> pgkey getspec :render))))
out-str (if (cstr/ends-with? out-file ".html")
@@ -106,14 +125,13 @@
[:section
[:h1 "projects"]
[:ul
- [:li [:a {:href (p-path :color-synth)} "color-synth"]]]]
+ [:li [:a {:href (p :path :color-synth)} "color-synth"]]]]
(footer))
-(defpage :color-synth {:path ["projects"
- "color-synth.html"]
+(defpage :color-synth {:path ["projects" "color-synth.html"]
:title "color-synth"
:desc "a modular digital video synthesizer on the web"}
- (header)
+ (header "projects" :color-synth)
[:main.color-synth
[:div.md (core/md "site/md/color-synth.templ.md"
{:samples [:div.samples
diff --git a/src/swatchbuckler.clj b/src/swatchbuckler.clj
@@ -2,7 +2,7 @@
(:require [core]))
(def domain "swatchbuckler.massi.world")
-(core/inject-path-fns domain identity)
+(def p (core/mk-path-fns domain identity))
(def spec {:path ["index.html"]
:title "swatchbuckler"
@@ -21,7 +21,7 @@
(core/fill-templ
(slurp templ-file)
{:head-content (core/massi-world-domain-stuff
- (p-url spec)
+ (p :url spec)
p
spec)}))
html-str (do
@@ -36,7 +36,7 @@
"swatchbuckler/manifest.templ.json"
"build/swatchbuckler.massi.world/manifest.json"
{:icon-192 (p "/shared-assets/icon-192-192.png")
- :index-url (p-url spec)})
+ :index-url (p :url spec)})
(core/prnt 1 "🤖" "wrote build/massi.world/manifest.json")
(print "\t 🕜\t")))
(println))