summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-16 16:16:19 +0200
committeruser <user@clank>2026-08-16 16:16:19 +0200
commita540b74dd3bb04d33a69219487cb2db32f2022f1 (patch)
tree4e21d8c3cf739c0f9cd2e91983e23fd4e796cb63 /contrib
parentsl0ppty: sin and cos (diff)
downloadslosh-a540b74dd3bb04d33a69219487cb2db32f2022f1.tar.gz
slosh-a540b74dd3bb04d33a69219487cb2db32f2022f1.tar.xz
slosh-a540b74dd3bb04d33a69219487cb2db32f2022f1.zip
sl0ppty: PI is 180
Angles here are degrees, and pi in an angle language is not a number -- it is a half turn. So `PI` is 180, `TAU` is 360, and a formula written the radian way ports across as written: sin(TAU * x / cols) one cycle over the pane's width sin(TAU * p * 3 / perim) three lobes fitted exactly to a border PI / 2 a quarter turn PI / 6 thirty degrees, exactly That last line is the argument. A numeric pi would be 3 in this language, and `3.14159 / 6` in integers is 0 -- so radians cannot express a sixth of a turn here at all, while degrees give it as a whole number. The pun is not a compromise; it is the more precise reading of the two. Which is why there is no `deg2rad` or `rad2deg` beside them, and asking for one says `unknown function`. There is one angle unit. A conversion could only lose the angle (`deg2rad(90)` is 1, and `sin(1)` is nearly nothing) or invent a second scale for the language to disagree with itself about. Spelled-out numbers rather than variables: they read no environment, carry no dependency, and fold into the program like the literals they are. The browser preview learned the same two, from the same table. Verified: 12 cases in `tests/expr_test.c`, including that `deg2rad` and `rad2deg` are refused; the cross-check agrees with the compiler on 700 evaluations, now including `sin(TAU * x / cols)` and friends. Two smaller things ride along, both from the repl. `PI`/`TAU` tab-complete, and its drift test grew a third table to check -- it already caught `sin`/`cos` missing before I did. And it now checks the script *parses* before starting a pane that runs it: I broke the indentation of one line here, and the failure arrived as `IndexError: list index out of range` from a pane that died before its prompt, which is a long way from "line 212".
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/shader-repl6
-rw-r--r--contrib/shadertoy.html7
2 files changed, 12 insertions, 1 deletions
diff --git a/contrib/shader-repl b/contrib/shader-repl
index f154bb8..4410a24 100755
--- a/contrib/shader-repl
+++ b/contrib/shader-repl
@@ -65,6 +65,8 @@ PROPS = ["amount=", "color=", "channel=", "where=", "at=", "radius=", "band=",
VALUES = ['"chrome"', '"content"', '"fg"', '"bg"', '"both"']
VARS = ["x", "y", "cols", "rows", "curx", "cury", "cursor", "focused", "t",
"since"]
+# Angles are degrees, so pi is a half turn: `PI` is 180 and `TAU` is 360.
+CONSTS = ["PI", "TAU"]
FUNCS = ["min(", "max(", "abs(", "clamp(", "dist(", "sin(", "cos("]
HISTORY = os.path.join(
@@ -77,7 +79,7 @@ def complete(text, state):
inside an expression, but a prompt that guesses which you meant and offers
nothing when it guesses wrong is worse company than one that offers
everything starting with what you typed."""
- words = COMMANDS + SHADERS + PROPS + VALUES + VARS + FUNCS
+ words = COMMANDS + SHADERS + PROPS + VALUES + VARS + CONSTS + FUNCS
hits = [w for w in words if w.startswith(text)]
return hits[state] if state < len(hits) else None
@@ -207,6 +209,8 @@ def main():
print(" shaders: " + " ".join(SHADERS))
print(" keys: " + " ".join(p.rstrip("=") for p in PROPS))
print(" vars: " + " ".join(VARS))
+ print(" consts: " + " ".join(CONSTS)
+ + " (degrees, so PI is a half turn)")
print(" funcs: " + " ".join(f.rstrip("(") for f in FUNCS))
print(" tab completes all of it; up/down and ctrl-r are history")
continue
diff --git a/contrib/shadertoy.html b/contrib/shadertoy.html
index 070f139..b1c9614 100644
--- a/contrib/shadertoy.html
+++ b/contrib/shadertoy.html
@@ -134,6 +134,12 @@
const DEP = { POS: 1, CURSOR: 2, TIME: 4, FOCUS: 8, SIZE: 16 };
+/* Pi is not a number in an angle language, it is a half turn -- and angles here
+ are degrees, so `PI` is 180 and `TAU` is 360. A radian-shaped formula ports
+ across unchanged, and the common fractions of a turn stay whole. Same table as
+ src/expr.c, spelled-out numbers rather than variables. */
+const CONSTS = { PI: 180, TAU: 360 };
+
const VARS = {
x: { dep: DEP.POS },
y: { dep: DEP.POS },
@@ -206,6 +212,7 @@ function compile(src) {
ws(); if (src[i] !== ")") fail("expected )"); i++;
return makeCall(name, args);
}
+ if (name in CONSTS) { const k = CONSTS[name]; return () => k; }
const v = VARS[name];
if (!v) { i = s; fail("unknown name"); }
deps |= v.dep;