๐Ÿ๐Ÿ๐Ÿ
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more proj shift updates

autumn 29c0e326 9b669479

+175 -123
+4 -5
sketch/webserver.py
··· 4 4 from pathlib import Path 5 5 from urllib.parse import unquote, urlparse 6 6 7 - from lib import log 7 + #from lib import log 8 8 9 9 # TODO make it upgrade to https instead of just fucking throwing exceptions 10 10 ··· 109 109 except KeyboardInterrupt: 110 110 raise 111 111 except: 112 - log.trace() 112 + #log.trace() 113 113 continue 114 114 with conn: 115 115 request = conn.recv(4096) ··· 117 117 conn.sendall(response) 118 118 print("served!") 119 119 120 - def init(): 121 - schedule(run, None) 122 - 120 + if __name__ == "__main__": 121 + main()
+3
webui/content/main.html
··· 12 12 </head> 13 13 <body> 14 14 <script src="main.js"></script> 15 + <script> 16 + $mod("layout/nothing", document.body); 17 + </script> 15 18 </body> 16 19 </html> 17 20
+16
webui/content/orb/projective_shift.orb
··· 1 + 2 + h2 { Projective Shift Map } 3 + 4 + f(z) = (r + cos(ฮธ-ฯ†))e^(iฮธฯˆ) - c 5 + where z_n = r * cos(ฮธ) 6 + 7 + b{click and drag} to move around, b{scroll} to zoom in and out; b{press F} to go fullscreen 8 + 9 + div[style=height: 75%]{ $gpu/proj_shift {} } 10 + 11 + this visualization is treating each pixel coordinate as a starting value z_0 in the complex plane, and running it through the iterative equation above many times, keeping track of where it ends up. points that exceed the "escape distance" from the origin are grayscale, darker the longer they took to reach that escape threshold. the rest of the points are colored according to their final location (as you increase the iterations count, you can watch them jump around). green is based on distance from the origin, while blue and red are based on the angle around the origin. you can set iterations to zero to see what the color mapping looks like prior to any of the points moving. 12 + 13 + i{p.s. you can use the input boxes to exceed the bounds of the sliders} 14 + 15 + i{p.p.s. you can save the canvas as an image in the right click menu} 16 +
-36
webui/content/orb/test.orb
··· 1 - 2 - blog blog blog blog 3 - 4 - here's some bold{ bold text } and italic{ italic text }, i hope it renders right 5 - 6 - code: 7 - height300 { code/highlight { 8 - function fibonacci(n) { 9 - if (n <= 1) return n; 10 - return fibonacci(n - 1) + fibonacci(n - 2); 11 - } 12 - } } 13 - 14 - demo: 15 - demo { gpu/proj_shift {} } 16 - 17 - For mathematical expressions, I can write things like math{ \int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2} } inline, or display them in blocks: 18 - 19 - math { 20 - E = mc^2 21 - 22 - \nabla \times \mathbf{E} = -\frac{\partial \mathbf{B}}{\partial t} 23 - } 24 - 25 - Sometimes I want to embed interactive demos. If your browser supports WebGPU, you can play with this fractal: 26 - 27 - sandbox { 28 - fractal { 29 - type: mandelbrot 30 - zoom: 1.5 31 - center: [-0.5, 0] 32 - } 33 - } 34 - 35 - This text tests \{ escape sequences \}! 36 -
+20
webui/content/proj_shift.html
··· 1 + 2 + <!DOCTYPE html> 3 + <html lang="en"> 4 + <head> 5 + <meta charset="UTF-8"> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 + <meta http-equiv="X-UA-Compatible" content="ie=edge"> 8 + <title>WebUI</title> 9 + <link rel="icon" href="favicon.png"> 10 + <link id="themeLink" rel="stylesheet" type="text/css" href="style/theme/themes.css"> 11 + <link rel="stylesheet" type="text/css" href="style/main.css"> 12 + </head> 13 + <body> 14 + <script src="main.js"></script> 15 + <script> 16 + $mod("code/orb", document.body, ["projective_shift.orb"]); 17 + </script> 18 + </body> 19 + </html> 20 +
+12 -6
webui/content/wgsl/proj_shift.wgsl
··· 95 95 96 96 var color: vec4<f32>; 97 97 if (escaped) { 98 - let escape_speed = pow(f32(iter) / f32(uniforms.max_iter), 0.5); 99 - color = vec4<f32>(0.0, escape_speed, 0.0, 1.0); 98 + let escape_speed = 1.0 - pow(f32(iter) / f32(uniforms.max_iter), 2.0); 99 + color = vec4<f32>(escape_speed, escape_speed, escape_speed, 1.0); 100 100 } else { 101 101 let final_mag = complex_mag(z); 102 - let scaled_mag = log(final_mag); 103 - let final_x = scaled_mag * (z.x / final_mag); 104 - let final_y = scaled_mag * (z.y / final_mag); 105 - color = vec4<f32>(0.5 + 0.5 * final_x, 0.0, 0.5 + 0.5 * final_y, 1.0); 102 + let final_angle = complex_angle(z); 103 + //let scaled_mag = log(final_mag); 104 + //let final_x = scaled_mag * (z.x / final_mag); 105 + //let final_y = scaled_mag * (z.y / final_mag); 106 + //color = vec4<f32>(0.5 + 0.5 * final_x, 0.0, 0.5 + 0.5 * final_y, 1.0); 107 + let scaled_mag = pow(final_mag / escape_threshold, 0.5); 108 + let scaled_angle = (final_angle + 3.1415926535) / 6.283185307179586; 109 + let r = max(0, 2.0 * scaled_angle - 1.0); 110 + let b = max(0, 2.0 * (1.0 - scaled_angle) - 1.0); 111 + color = vec4<f32>(r, scaled_mag, b, 1.0); 106 112 } 107 113 108 114 textureStore(output_texture, vec2<i32>(i32(px), i32(py)), color);
+3 -12
webui/js/code/orb.js
··· 6 6 height: 100%; 7 7 overflow-y: scroll; 8 8 } 9 - 10 - .orb-container .demo { 11 - height: 500px; 12 - } 13 - 14 - .orb-container .height300 { 15 - height: 300px; 16 - } 17 - 18 9 `); 19 10 20 - export async function main(target) { 11 + export async function main(target, orb) { 21 12 const container = document.createElement("div"); 22 13 container.classList = "orb-container"; 23 14 24 15 const parserModule = await import(`/code/orb/parse.js`); 25 16 const buildModule = await import(`/code/orb/build.js`); 26 17 27 - const parsed = await parserModule.parse("test.orb"); 18 + const parsed = await parserModule.parse(orb); 28 19 29 - await parserModule.debugParse("test.orb"); 20 + //await parserModule.debugParse("test.orb"); 30 21 31 22 await buildModule.build(container, parsed.nodes, parsed.source); 32 23
+44 -26
webui/js/code/orb/build.js
··· 2 2 const TEXT = "builtin_text"; 3 3 const BREAK = "builtin_break"; 4 4 5 - const inlineElements = { 6 - bold: "b", 7 - italic: "i" 8 - } 9 - 10 - const simpleBlocks = { 11 - demo: { element: "div", class: "demo" }, 12 - height300: { element: "div", class: "height300" } 13 - } 5 + const inlineElements = ["b", "i"]; 14 6 15 7 export async function build(target, nodes, source, inline=false) { 16 8 let segment = document.createElement(inline ? "span" : "p"); ··· 41 33 continue; 42 34 } 43 35 44 - if (tag in inlineElements) { 45 - const bold = document.createElement(inlineElements[tag]); 46 - await build(bold, node.content.nodes, source, true); 36 + let bracketArgs = []; 37 + if (node.args.start !== null) { 38 + bracketArgs = source.substring(node.args.start, node.args.end + 1).split("|"); 39 + } 40 + 41 + if (inlineElements.includes(tag)) { 42 + const tagElement = document.createElement(tag); 43 + await build(tagElement, node.content.nodes, source, true); 44 + for (const arg of bracketArgs) { 45 + const split = arg.split("="); 46 + console.log(split); 47 + tagElement[split[0].trim()] = split[1]; 48 + } 47 49 segment.appendChild(document.createTextNode(" ")); 48 - segment.appendChild(bold); 50 + segment.appendChild(tagElement); 49 51 inlineEnded = true; 50 52 continue; 51 53 } 52 54 53 - if (tag in simpleBlocks) { 54 - target.appendChild(segment); 55 - segment = document.createElement(inline ? "span" : "p"); 56 - const block = simpleBlocks[tag]; 57 - const container = document.createElement(block.element); 58 - container.classList = block.class; 59 - await build(container, node.content.nodes, source); 60 - target.appendChild(container); 55 + if (tag[0] !== "$") { 56 + if (segment.childNodes.length > 0) { 57 + target.appendChild(segment); 58 + segment = document.createElement(inline ? "span" : "p"); 59 + } 60 + try { 61 + const tagElement = document.createElement(tag); 62 + for (const arg of bracketArgs) { 63 + const split = arg.split("="); 64 + console.log(split); 65 + tagElement[split[0].trim()] = split[1]; 66 + } 67 + await build(tagElement, node.content.nodes, source); 68 + target.appendChild(tagElement); 69 + } 70 + catch { 71 + const _sp = document.createElement("span"); 72 + _sp.innerText = ` [no tag "${tag}"] `; 73 + segment.appendChild(_sp); 74 + } 61 75 continue; 62 76 } 63 77 64 78 try { 65 - target.appendChild(segment); 66 - segment = document.createElement(inline ? "span" : "p"); 67 - await $mod(tag, target, [source.substring(node.content.start, node.content.end)]); 79 + if (segment.childNodes.length > 0) { 80 + target.appendChild(segment); 81 + segment = document.createElement(inline ? "span" : "p"); 82 + } 83 + await $mod(tag.substring(1), target, [...bracketArgs, source.substring(node.content.start, node.content.end)]); 68 84 } 69 85 catch { 70 86 const _sp = document.createElement("span"); 71 - _sp.innerText = ` [unrecognized tag "${tag}"] `; 87 + _sp.innerText = ` [no module "${tag}"] `; 72 88 segment.appendChild(_sp); 73 89 } 74 90 } 75 91 76 - target.appendChild(segment); 92 + if (segment.childNodes.length > 0) { 93 + target.appendChild(segment); 94 + } 77 95 } 78 96
+50 -15
webui/js/code/orb/parse.js
··· 45 45 let contentEnd = null; 46 46 let tagStart = null; 47 47 let tagEnd = null; 48 + let argStart = null; 49 + let argEnd = null; 48 50 49 51 let newlineCount = 0; 50 52 ··· 59 61 continue; 60 62 } 61 63 64 + if (!escapeNext && char === "]" && argStart !== null && argEnd === null) { 65 + argEnd = scanPosition - 1; 66 + scanPosition++; 67 + continue; 68 + } 69 + 62 70 if (!escapeNext && char === '{') { 63 71 if (contentStart !== null) { 64 72 nodes.push({ 65 73 tag: {symbol: TEXT, start: null, end: null}, 66 74 content: {start: contentStart, end: contentEnd}, 67 - origin: 0 75 + args: {start: null, end: null}, 76 + origin: "text_before_block" 68 77 }); 69 78 70 79 contentStart = null; ··· 73 82 74 83 scanPosition += 1; // skip the { 75 84 76 - 77 - const tag = tagStart === null ? TEXT : input.substring(tagStart, tagEnd + 1); 85 + let tag; 86 + if (argStart !== null && argEnd === null) { 87 + // args-only tag => implicit div 88 + tag = tagStart === argStart - 1 ? "div" : input.substring(tagStart, argStart - 1); 89 + argEnd = tagEnd; 90 + } else { 91 + if (argStart !== null) { 92 + tag = tagStart === argStart - 1 ? "div" : input.substring(tagStart, argStart - 1); 93 + } else { 94 + tag = tagStart === null ? TEXT : input.substring(tagStart, tagEnd + 1); 95 + } 96 + } 78 97 79 98 if (shouldParseContent(tag)) { 80 99 const parsed = parseSource(input, scanPosition); 81 100 82 101 nodes.push({ 83 102 tag: {symbol: tag, start: tagStart, end: tagEnd}, 84 - content: {nodes: parsed.nodes, start: scanPosition, end: parsed.scanPosition} 103 + content: {nodes: parsed.nodes, start: scanPosition, end: parsed.scanPosition}, 104 + args: {start: argStart, end: argEnd}, 105 + origin: "parsed_block" 85 106 }); 86 107 scanPosition = parsed.scanPosition + 1; 87 108 } else { ··· 89 110 const closingPosition = findClosingBracket(input, scanPosition); 90 111 nodes.push({ 91 112 tag: {symbol: tag, start: tagStart, end: tagEnd}, 92 - content: {start: scanPosition, end: closingPosition} 113 + content: {start: scanPosition, end: closingPosition}, 114 + args: {start: argStart, end: argEnd}, 115 + origin: "unparsed_block" 93 116 }); 94 117 scanPosition = closingPosition + 1; 95 118 } 96 119 97 120 tagStart = null; 98 121 tagEnd = null; 122 + argStart = null; 123 + argEnd = null; 99 124 100 125 newlineCount = 0; 101 126 ··· 108 133 escapeNext = false; 109 134 110 135 const isWhitespace = /\s/.test(char); 111 - if (isWhitespace) { 136 + const takingArgs = argStart !== null && argEnd === null; 137 + if (!takingArgs && isWhitespace) { 112 138 if (char === "\n") { 113 139 newlineCount += 1; 114 140 if (newlineCount === 2) { ··· 117 143 nodes.push({ 118 144 tag: {symbol: TEXT, start: null, end: null}, 119 145 content: {start: contentStart, end: tagEnd}, 120 - origin: 1 146 + args: {start: argStart, end: argEnd}, 147 + origin: "text_before_break" 121 148 }); 122 149 contentStart = null; 123 150 contentEnd = null; 124 151 tagStart = null; 125 152 tagEnd = null; 153 + argStart = null; 154 + argEnd = null; 126 155 } 127 156 nodes.push({ 128 157 tag: {symbol: BREAK, start: null, end: null}, 129 158 content: {start: null, end: null}, 130 - origin: 2 159 + args: {start: null, end: null}, 160 + origin: "break" 131 161 }); 132 162 } 133 163 } ··· 153 183 } 154 184 } 155 185 186 + if (char === "[" && !takingArgs) { 187 + argStart = scanPosition + 1; 188 + } 189 + 156 190 scanPosition += 1; 157 191 } 158 192 ··· 161 195 nodes.push({ 162 196 tag: {symbol: TEXT, start: null, end: null}, 163 197 content: { start: contentStart ?? tagStart, end: tagEnd }, 164 - origin: 3 198 + args: {start: null, end: null}, 199 + origin: "trailing_text" 165 200 }); 166 201 } 167 202 ··· 193 228 } 194 229 195 230 function shouldParseContent(tag) { 196 - return tag !== "fractal"; 231 + return tag !== "$"; 197 232 } 198 233 199 234 function dumpNodes(nodes, input) { 200 235 for (const node of nodes) { 201 - let content; 202 - 203 236 if (node.content.nodes !== undefined) { 204 - console.log(`TAG{${node.tag.symbol}}[${node.origin}] | CONTENT[next ${node.content.nodes.length} nodes]`); 237 + const args = node.args.start === null ? "" : input.substring(node.args.start, node.args.end + 1); 238 + console.log(`<${node.tag.symbol}>[${args}](${node.origin}){next ${node.content.nodes.length} nodes}`); 205 239 dumpNodes(node.content.nodes, input); 206 240 } else { 207 - content = input.substring(node.content.start, node.content.end + 1); 208 - console.log(`TAG{${node.tag.symbol}}[${node.origin}] | CONTENT{${content}}`); 241 + const content = input.substring(node.content.start, node.content.end + 1); 242 + const args = node.args.start === null ? "" : input.substring(node.args.start, node.args.end + 1); 243 + console.log(`<${node.tag.symbol}>[${args}](${node.origin}){${content}}`); 209 244 } 210 245 } 211 246 }
+22 -20
webui/js/gpu/proj_shift.js
··· 19 19 let centerY = 0.0; 20 20 let zoom = 4.0; 21 21 22 + 23 + // z_{n+1} = (r + cos(ฮธ-ฯ†))e^(iฮธฯˆ) - c 22 24 $mod("control/panel", container, [[ 23 25 { 24 26 type: "number", 25 - label: "phi", 26 - value: phi, 27 + label: "c", 28 + value: c, 27 29 min: 0, 28 - max: $tau, 30 + max: 1, 29 31 step: 0.001, 30 32 onUpdate: (value, set) => { 31 - phi = value; 33 + c = value; 32 34 render(); 33 35 } 34 36 }, 35 37 { 36 38 type: "number", 37 - label: "c", 38 - value: c, 39 + label: "ฯˆ", 40 + value: psi, 39 41 min: 0, 40 - max: 1, 42 + max: 12, 41 43 step: 0.001, 42 44 onUpdate: (value, set) => { 43 - c = value; 45 + psi = value; 46 + render(); 47 + } 48 + }, 49 + { 50 + type: "number", 51 + label: "ฯ†", 52 + value: phi, 53 + min: 0, 54 + max: $tau, 55 + step: 0.001, 56 + onUpdate: (value, set) => { 57 + phi = value; 44 58 render(); 45 59 } 46 60 }, ··· 57 71 iterations = 0; 58 72 set(0); 59 73 } 60 - render(); 61 - } 62 - }, 63 - { 64 - type: "number", 65 - label: "psi", 66 - value: psi, 67 - min: 0, 68 - max: 12, 69 - step: 0.001, 70 - onUpdate: (value, set) => { 71 - psi = value; 72 74 render(); 73 75 } 74 76 },
-2
webui/js/main.js
··· 52 52 53 53 $mod("theme", document.body); 54 54 55 - $mod("layout/nothing", document.body); 56 -
+1 -1
webui/js/spinner.js
··· 83 83 } 84 84 `); 85 85 86 - export async function main(target, modNext = "nothing") { 86 + export async function main(target, modNext = "layout/nothing") { 87 87 let spinner = document.createElement('div'); 88 88 let orb0 = document.createElement('div'); 89 89 let orb1 = document.createElement('div');