diff --git a/app/package.json b/app/package.json index ddbefaa..ff55051 100644 --- a/app/package.json +++ b/app/package.json @@ -15,6 +15,7 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-menubar": "^1.0.2", "@radix-ui/react-slider": "^1.1.1", + "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-toolbar": "^1.0.3", "@tauri-apps/api": "^1.3.0", "@tempblade/common": "^2.0.1", diff --git a/app/public/canvaskit.wasm b/app/public/canvaskit.wasm new file mode 100644 index 0000000..3f92994 Binary files /dev/null and b/app/public/canvaskit.wasm differ diff --git a/app/src-tauri/Cargo.lock b/app/src-tauri/Cargo.lock index 1fabb7a..bcc34ee 100644 --- a/app/src-tauri/Cargo.lock +++ b/app/src-tauri/Cargo.lock @@ -3077,6 +3077,7 @@ dependencies = [ "tauri", "tauri-build", "tint", + "uuid", ] [[package]] @@ -3376,11 +3377,24 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" +checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" dependencies = [ "getrandom 0.2.9", + "rand 0.8.5", + "uuid-macro-internal", +] + +[[package]] +name = "uuid-macro-internal" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f67b459f42af2e6e1ee213cb9da4dbd022d3320788c3fb3e1b893093f1e45da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", ] [[package]] diff --git a/app/src-tauri/Cargo.toml b/app/src-tauri/Cargo.toml index 6449b87..79fb77a 100644 --- a/app/src-tauri/Cargo.toml +++ b/app/src-tauri/Cargo.toml @@ -12,7 +12,10 @@ edition = "2021" [build-dependencies] tauri-build = { version = "1.3", features = [] } + [dependencies] + +uuid = { version = "1.3.3", features = ["v4", "fast-rng", "macro-diagnostics"] } tauri = { version = "1.3", features = ["dialog-open", "dialog-save", "shell-open"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -22,9 +25,7 @@ logging_timer = "1.1.0" rayon = "1.7" font-kit = "0.11.0" - [features] # this feature is used for production builds or when `devPath` points to the filesystem # DO NOT REMOVE!! custom-protocol = ["tauri/custom-protocol"] - diff --git a/app/src-tauri/src/animation/primitives/keyframe.rs b/app/src-tauri/src/animation/primitives/keyframe.rs index 8dad504..3e95046 100644 --- a/app/src-tauri/src/animation/primitives/keyframe.rs +++ b/app/src-tauri/src/animation/primitives/keyframe.rs @@ -12,6 +12,7 @@ use super::{ pub struct Keyframe { pub value: f32, pub offset: f32, + pub id: String, pub interpolation: Option, } diff --git a/app/src-tauri/src/animation/primitives/tests.rs b/app/src-tauri/src/animation/primitives/tests.rs index 1b709df..5cac4bb 100644 --- a/app/src-tauri/src/animation/primitives/tests.rs +++ b/app/src-tauri/src/animation/primitives/tests.rs @@ -25,16 +25,19 @@ fn interpolates_the_input() { let keyframes1 = Keyframes { values: vec![ Keyframe { + id: "1".to_string(), value: 0.0, offset: 0.0, interpolation: None, }, Keyframe { + id: "2".to_string(), value: 100.0, offset: 1.0, interpolation: None, }, Keyframe { + id: "3".to_string(), value: 300.0, offset: 3.0, interpolation: None, @@ -45,11 +48,13 @@ fn interpolates_the_input() { let keyframes2 = Keyframes { values: vec![ Keyframe { + id: "4".to_string(), value: -100.0, offset: 0.0, interpolation: None, }, Keyframe { + id: "5".to_string(), value: 0.0, offset: 1.0, interpolation: None, @@ -145,16 +150,19 @@ fn gets_value_at_frame() { let keyframes = Keyframes { values: vec![ Keyframe { + id: "1".to_string(), value: 0.0, offset: 0.0, interpolation: None, }, Keyframe { + id: "2".to_string(), value: 100.0, offset: 1.0, interpolation: None, }, Keyframe { + id: "3".to_string(), value: 300.0, offset: 3.0, interpolation: None, diff --git a/app/src-tauri/src/animation/primitives/values.rs b/app/src-tauri/src/animation/primitives/values.rs index ad1a3ae..6d60835 100644 --- a/app/src-tauri/src/animation/primitives/values.rs +++ b/app/src-tauri/src/animation/primitives/values.rs @@ -3,6 +3,7 @@ use super::{ keyframe::{Keyframe, Keyframes}, }; use serde::{Deserialize, Serialize}; +use uuid::Uuid; pub trait AnimatedValue { fn sort_keyframes(&mut self); @@ -28,6 +29,7 @@ impl AnimatedFloat { AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { + id: Uuid::new_v4().to_string(), value: val, offset: 0.0, interpolation: None, @@ -93,7 +95,7 @@ impl AnimatedValue<(f32, f32, f32)> for AnimatedFloatVec3 { let z = self .keyframes - .1 + .2 .get_value_at_frame(curr_frame, animation_data, fps); return (x, y, z); diff --git a/app/src-tauri/src/animation/timeline.rs b/app/src-tauri/src/animation/timeline.rs index 0878eaa..588a90f 100644 --- a/app/src-tauri/src/animation/timeline.rs +++ b/app/src-tauri/src/animation/timeline.rs @@ -70,6 +70,7 @@ fn build_bg(offset: f32, paint: Paint, size: (i32, i32)) -> AnimatedRectEntity { keyframes: Keyframes { values: vec![ Keyframe { + id: "1".to_string(), value: (size.0 * -1) as f32, offset: 0.0, interpolation: Some(InterpolationType::EasingFunction( @@ -77,6 +78,7 @@ fn build_bg(offset: f32, paint: Paint, size: (i32, i32)) -> AnimatedRectEntity { )), }, Keyframe { + id: "2".to_string(), value: 0.0, offset: 5.0, interpolation: None, @@ -87,6 +89,7 @@ fn build_bg(offset: f32, paint: Paint, size: (i32, i32)) -> AnimatedRectEntity { AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { + id: "3".to_string(), value: 0.0, offset: 0.0, interpolation: None, @@ -100,6 +103,7 @@ fn build_bg(offset: f32, paint: Paint, size: (i32, i32)) -> AnimatedRectEntity { AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { + id: "4".to_string(), interpolation: None, value: size.0 as f32, offset: 0.0, @@ -109,6 +113,7 @@ fn build_bg(offset: f32, paint: Paint, size: (i32, i32)) -> AnimatedRectEntity { AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { + id: "5".to_string(), value: size.1 as f32, offset: 0.0, interpolation: None, @@ -193,6 +198,7 @@ pub fn test_timeline_entities_at_frame( keyframes: Keyframes { values: vec![ Keyframe { + id: "1".to_string(), value: 0.0, offset: 0.0, interpolation: Some(InterpolationType::Spring( @@ -204,6 +210,7 @@ pub fn test_timeline_entities_at_frame( )), }, Keyframe { + id: "2".to_string(), value: (size.0 / 2) as f32, offset: 2.0, interpolation: None, @@ -214,6 +221,7 @@ pub fn test_timeline_entities_at_frame( AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { + id: "3".to_string(), value: (size.1 / 2) as f32, offset: 0.0, interpolation: None, @@ -240,6 +248,7 @@ pub fn test_timeline_entities_at_frame( keyframes: Keyframes { values: vec![ Keyframe { + id: "5".to_string(), value: 0.0, offset: 0.0, interpolation: Some(InterpolationType::Spring( @@ -251,6 +260,8 @@ pub fn test_timeline_entities_at_frame( )), }, Keyframe { + id: "6".to_string(), + value: (size.0 / 2) as f32, offset: 2.0, interpolation: None, @@ -261,6 +272,7 @@ pub fn test_timeline_entities_at_frame( AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { + id: "7".to_string(), value: ((size.1 / 2) as f32) + 80.0, offset: 0.0, interpolation: None, diff --git a/app/src-tauri/src/fonts.rs b/app/src-tauri/src/fonts.rs index 57810bb..b9a6a14 100644 --- a/app/src-tauri/src/fonts.rs +++ b/app/src-tauri/src/fonts.rs @@ -1,4 +1,5 @@ use font_kit::source::SystemSource; +use rayon::prelude::*; #[tauri::command] pub fn get_system_fonts() -> Option> { @@ -9,7 +10,7 @@ pub fn get_system_fonts() -> Option> { match found_fonts { Ok(found_fonts) => { let font_names: Vec = found_fonts - .iter() + .par_iter() .map(|f| f.load()) .filter(|f| f.is_ok()) .map(|f| f.unwrap()) @@ -24,6 +25,15 @@ pub fn get_system_fonts() -> Option> { } } +#[tauri::command] +pub fn get_system_families() -> Option> { + let source = SystemSource::new(); + + let found_families = source.all_families(); + + found_families.ok() +} + #[tauri::command] pub fn get_system_font(font_name: String) -> Option> { let source = SystemSource::new(); diff --git a/app/src-tauri/src/main.rs b/app/src-tauri/src/main.rs index a2aac92..6072e21 100644 --- a/app/src-tauri/src/main.rs +++ b/app/src-tauri/src/main.rs @@ -3,7 +3,7 @@ use crate::{ animation::timeline::calculate_timeline_entities_at_frame, - fonts::{get_system_font, get_system_fonts}, + fonts::{get_system_families, get_system_font, get_system_fonts}, }; pub mod animation; @@ -14,6 +14,7 @@ fn main() { .invoke_handler(tauri::generate_handler![ calculate_timeline_entities_at_frame, get_system_font, + get_system_families, get_system_fonts ]) .run(tauri::generate_context!()) diff --git a/app/src/App.tsx b/app/src/App.tsx index 756c371..7a4ddb8 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -7,12 +7,15 @@ import ToolBar from "components/ToolBar"; import { useEffect } from "react"; import { invoke } from "@tauri-apps/api/tauri"; import { useFontsStore } from "stores/fonts.store"; +import useKeyControls from "hooks/useKeyControls"; export default function App() { const { setFonts } = useFontsStore(); + useKeyControls(); + useEffect(() => { - invoke("get_system_fonts").then((data) => { + invoke("get_system_families").then((data) => { if (data && Array.isArray(data)) { setFonts(data); } diff --git a/app/src/components/Properties/Primitives.tsx b/app/src/components/Properties/Primitives.tsx index 522efdc..5989b74 100644 --- a/app/src/components/Properties/Primitives.tsx +++ b/app/src/components/Properties/Primitives.tsx @@ -127,13 +127,6 @@ export const TextProperties: FC = ({ } > - - onUpdate({ ...entity, origin: updatedEntity }) - } - label="Origin" - entity={entity.origin} - /> ); }; @@ -217,13 +210,6 @@ export const StaggeredTextProperties: FC = ({ }) } /> - - onUpdate({ ...entity, origin: updatedEntity }) - } - label="Origin" - entity={entity.origin} - /> ); }; @@ -240,20 +226,6 @@ export const RectProperties: FC = ({ onUpdate({ ...entity, paint: { ...entity.paint, ...paint } }) } /> - - onUpdate({ ...entity, position: updatedEntity }) - } - label="Position" - entity={entity.position} - /> - - onUpdate({ ...entity, size: updatedEntity }) - } - label="Size" - entity={entity.size} - /> ); }; @@ -270,20 +242,6 @@ export const EllipseProperties: FC = ({ onUpdate({ ...entity, paint: { ...entity.paint, ...paint } }) } /> - - onUpdate({ ...entity, position: updatedEntity }) - } - label="Position" - entity={entity.position} - /> - - onUpdate({ ...entity, radius: updatedEntity }) - } - label="Size" - entity={entity.radius} - /> ); }; diff --git a/app/src/components/Properties/Values.tsx b/app/src/components/Properties/Values.tsx index d12f8c5..93e17c7 100644 --- a/app/src/components/Properties/Values.tsx +++ b/app/src/components/Properties/Values.tsx @@ -5,6 +5,8 @@ import { z } from "zod"; import { produce } from "immer"; import { Interpolation } from "primitives/Interpolation"; import { Color } from "primitives/Paint"; +import { colorToString, parseColor, parseCssColor } from "@tempblade/common"; +import { rgbToHex } from "utils"; const InterpolationProperties: FC< PropertiesProps> @@ -76,8 +78,43 @@ const AnimatedNumberProperties: FC< export const ColorProperties: FC< PropertiesProps> & { label: string; + mode?: "RGB" | "Picker"; } -> = ({ entity, onUpdate }) => { +> = ({ entity, onUpdate, mode = "Picker" }) => { + if (mode === "Picker") { + return ( + + ); + } + return (