diff --git a/stdlib/src/canvas.rs b/stdlib/src/canvas.rs
index ffcc7a20..248737f3 100644
--- a/stdlib/src/canvas.rs
+++ b/stdlib/src/canvas.rs
@@ -11,238 +11,298 @@ use techscript_runtime::{
context::{Capability, RuntimeContext},
error::RuntimeError,
function::Callable,
- value::RuntimeValue,
+ value::{DslBlockValue, RuntimeValue},
};
/// Convert a DslBlockValue to SVG string.
-fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
- match val {
- RuntimeValue::DslBlock(dsl) => {
- if is_dragon {
- match dsl.kind.as_str() {
- "logo" => {
- let mut text_val = None;
- let mut color_val = None;
- let mut size_val = None;
-
- for p in &dsl.properties {
- match p.name.as_str() {
- "text" => text_val = p.value.as_ref().map(|v| v.to_string()),
- "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
- "size" => {
- size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- _ => {}
- }
- }
+fn render_circuits(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {
+ if is_dragon {
+ // Subtle circular grids / tech lines background
- let text = text_val.unwrap_or_else(|| "Logo".to_string());
- let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
- let size = size_val.unwrap_or(48);
- let _ = write!(
- svg,
- r#"{}"#,
- size, color, text
- );
- }
- "rings" => {
- // BLUE FLAME / WING (Bottom-Left Swirl)
- svg.push_str(
- r##""##
- );
- }
- "emblem" => {
- // ORANGE-RED TAIL (Bottom-Right Swirl)
- svg.push_str(
- r##"
- "##
- );
- }
- "letter" => {
- // GOLDEN DRAGON HEAD (Top-Center Crest)
- svg.push_str(
- r##"
-
- "##
- );
- }
- "circuits" => {
- // Subtle circular grids / tech lines background
- svg.push_str(
- r##"
- "##
- );
- }
- _ => {}
- }
- } else {
- // RENDER OLD GEOMETRIC LOGO
- match dsl.kind.as_str() {
- "logo" => {
- let mut text_val = None;
- let mut color_val = None;
- let mut size_val = None;
-
- for p in &dsl.properties {
- match p.name.as_str() {
- "text" => text_val = p.value.as_ref().map(|v| v.to_string()),
- "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
- "size" => {
- size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- _ => {}
- }
- }
+ svg.push_str(
- let text = text_val.unwrap_or_else(|| "Logo".to_string());
- let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
- let size = size_val.unwrap_or(48);
- let _ = write!(
- svg,
- r#"{}"#,
- size, color, text
- );
- }
- "rings" => {
- let mut count_val = None;
- let mut color_val = None;
- let mut size_val = None;
- let mut thickness_val = None;
-
- for p in &dsl.properties {
- match p.name.as_str() {
- "count" => {
- count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
- "size" => {
- size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- "thickness" => {
- thickness_val =
- p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- _ => {}
- }
- }
+ r##"
- let count = count_val.unwrap_or(3);
- let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
- let size = size_val.unwrap_or(40);
- let thickness = thickness_val.unwrap_or(3);
- for i in 0..count {
- let r = 80 + i as i64 * (size / 2);
- let opacity = 0.4 - (i as f32 * 0.08);
- let _ = write!(
- svg,
- r#""#,
- r, color, thickness, opacity
- );
- }
- }
- "emblem" => {
- let mut color_val = None;
- let mut size_val = None;
-
- for p in &dsl.properties {
- match p.name.as_str() {
- "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
- "size" => {
- size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- _ => {}
- }
- }
+ "##
- let color = color_val.unwrap_or_else(|| "#0088cc".to_string());
- let size = size_val.unwrap_or(120);
- let x = 250 - size / 2;
- let y = 180 - size / 2;
- let _ = write!(
- svg,
- r#""#,
- x,
- y,
- size,
- size,
- size / 4,
- color
- );
- }
- "letter" => {
- let mut ch_val = None;
- let mut color_val = None;
- let mut size_val = None;
-
- for p in &dsl.properties {
- match p.name.as_str() {
- "char" => ch_val = p.value.as_ref().map(|v| v.to_string()),
- "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
- "size" => {
- size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- _ => {}
- }
- }
+ );
+ } else {
+ let mut color_val = None;
- let ch = ch_val.unwrap_or_else(|| "T".to_string());
- let color = color_val.unwrap_or_else(|| "#0a0e27".to_string());
- let size = size_val.unwrap_or(32);
- let _ = write!(
- svg,
- r#"{}"#,
- size, color, ch
- );
- }
- "core" => {
- let mut color_val = None;
- let mut size_val = None;
-
- for p in &dsl.properties {
- match p.name.as_str() {
- "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
- "size" => {
- size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
- }
- _ => {}
- }
- }
+ for p in &dsl.properties {
+ if p.name == "color" {
+ color_val = p.value.as_ref().map(|v| v.to_string());
+ }
+ }
- let color = color_val.unwrap_or_else(|| "#66e0ff".to_string());
- let size = size_val.unwrap_or(40);
- let _ = write!(
- svg,
- r#""#,
- size / 2,
- color
- );
- }
- "circuits" => {
- let mut color_val = None;
+ let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
- for p in &dsl.properties {
- if p.name == "color" {
- color_val = p.value.as_ref().map(|v| v.to_string());
- }
- }
+ let _ = write!(
+ svg,
+ r#"
- let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
- let _ = write!(
- svg,
- r#"
-
-
-
-
- "#,
- color, color, color, color, color, color
- );
- }
- _ => {}
+
+
+
+
+
+
+
+
+ "#,
+ color, color, color, color, color, color
+ );
+ }
+}
+
+fn render_letter(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {
+ if is_dragon {
+ // GOLDEN DRAGON HEAD (Top-Center Crest)
+
+ svg.push_str(
+
+ r##"
+
+
+
+ "##
+
+ );
+ } else {
+ let mut ch_val = None;
+
+ let mut color_val = None;
+
+ let mut size_val = None;
+
+ for p in &dsl.properties {
+ match p.name.as_str() {
+ "char" => ch_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ _ => {}
+ }
+ }
+
+ let ch = ch_val.unwrap_or_else(|| "T".to_string());
+
+ let color = color_val.unwrap_or_else(|| "#0a0e27".to_string());
+
+ let size = size_val.unwrap_or(32);
+
+ let _ = write!(
+ svg,
+ r#"{}"#,
+ size, color, ch
+ );
+ }
+}
+
+fn render_logo(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {
+ if is_dragon {
+ let mut text_val = None;
+
+ let mut color_val = None;
+
+ let mut size_val = None;
+
+ for p in &dsl.properties {
+ match p.name.as_str() {
+ "text" => text_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ _ => {}
+ }
+ }
+
+ let text = text_val.unwrap_or_else(|| "Logo".to_string());
+
+ let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
+
+ let size = size_val.unwrap_or(48);
+
+ let _ = write!(
+ svg,
+ r#"{}"#,
+ size, color, text
+ );
+ } else {
+ let mut text_val = None;
+
+ let mut color_val = None;
+
+ let mut size_val = None;
+
+ for p in &dsl.properties {
+ match p.name.as_str() {
+ "text" => text_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ _ => {}
+ }
+ }
+
+ let text = text_val.unwrap_or_else(|| "Logo".to_string());
+
+ let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
+
+ let size = size_val.unwrap_or(48);
+
+ let _ = write!(
+ svg,
+ r#"{}"#,
+ size, color, text
+ );
+ }
+}
+
+fn render_core(svg: &mut String, dsl: &DslBlockValue) {
+ let mut color_val = None;
+ let mut size_val = None;
+
+ for p in &dsl.properties {
+ match p.name.as_str() {
+ "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
+ "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+ _ => {}
+ }
+ }
+
+ let color = color_val.unwrap_or_else(|| "#66e0ff".to_string());
+ let size = size_val.unwrap_or(40);
+ let _ = write!(
+ svg,
+ r#""#,
+ size / 2,
+ color
+ );
+}
+
+fn render_emblem(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {
+ if is_dragon {
+ // ORANGE-RED TAIL (Bottom-Right Swirl)
+
+ svg.push_str(
+
+ r##"
+
+ "##
+
+ );
+ } else {
+ let mut color_val = None;
+
+ let mut size_val = None;
+
+ for p in &dsl.properties {
+ match p.name.as_str() {
+ "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ _ => {}
+ }
+ }
+
+ let color = color_val.unwrap_or_else(|| "#0088cc".to_string());
+
+ let size = size_val.unwrap_or(120);
+
+ let x = 250 - size / 2;
+
+ let y = 180 - size / 2;
+
+ let _ = write!(
+ svg,
+ r#""#,
+ x,
+ y,
+ size,
+ size,
+ size / 4,
+ color
+ );
+ }
+}
+
+fn render_rings(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {
+ if is_dragon {
+ // BLUE FLAME / WING (Bottom-Left Swirl)
+
+ svg.push_str(
+
+ r##""##
+
+ );
+ } else {
+ let mut count_val = None;
+
+ let mut color_val = None;
+
+ let mut size_val = None;
+
+ let mut thickness_val = None;
+
+ for p in &dsl.properties {
+ match p.name.as_str() {
+ "count" => count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ "color" => color_val = p.value.as_ref().map(|v| v.to_string()),
+
+ "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ "thickness" => thickness_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()),
+
+ _ => {}
+ }
+ }
+
+ let count = count_val.unwrap_or(3);
+
+ let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
+
+ let size = size_val.unwrap_or(40);
+
+ let thickness = thickness_val.unwrap_or(3);
+
+ for i in 0..count {
+ let r = 80 + i as i64 * (size / 2);
+
+ let opacity = 0.4 - (i as f32 * 0.08);
+
+ let _ = write!(
+ svg,
+ r#""#,
+ r, color, thickness, opacity
+ );
+ }
+ }
+}
+
+fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
+ if let RuntimeValue::DslBlock(dsl) = val {
+ match dsl.kind.as_str() {
+ "circuits" => render_circuits(svg, dsl, is_dragon),
+ "letter" => render_letter(svg, dsl, is_dragon),
+ "logo" => render_logo(svg, dsl, is_dragon),
+ "core" => {
+ if !is_dragon {
+ render_core(svg, dsl);
}
}
+ "emblem" => render_emblem(svg, dsl, is_dragon),
+ "rings" => render_rings(svg, dsl, is_dragon),
+ _ => {}
}
- _ => {}
}
}
diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs
index ce296064..50a54c49 100644
--- a/stdlib/tests/stdlib_tests.rs
+++ b/stdlib/tests/stdlib_tests.rs
@@ -540,7 +540,9 @@ fn test_http_module() {
&mut ctx_unprivileged,
vec![RuntimeValue::Str(format!("http://127.0.0.1:{}", port))],
);
- assert!(matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")));
+ assert!(
+ matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))
+ );
let post = http.exports.get("post").unwrap();
let res_post = post.call(
@@ -550,7 +552,9 @@ fn test_http_module() {
RuntimeValue::Str("body".to_string()),
],
);
- assert!(matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")));
+ assert!(
+ matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))
+ );
// Test with Network capability
let mut caps = HashSet::new();