Skip to main content

scal_core/
lib.rs

1#![warn(missing_docs)]
2#![warn(clippy::pedantic)]
3#![warn(clippy::nursery)]
4//! ### Easy animation system focused on code.   
5//!
6//! # Example
7//! start by creating a new rust app and import 3 crates:
8//! ``` toml
9//! # /Cargol.toml
10//! [dependencies]
11//! # contains functions and types for defining animations
12//! # that will be sent to the scal-runtime for rendering/preview.
13//! scal-core = "..."
14//! # used for communicating with the scal runtime. you only  use ``#[scal_ipc::main]`` from it
15//! scal-ipc = "..."
16//! # `glam` is a simple and fast linear algebra library for games and graphics.
17//! glam = "0.33.2"
18//! ```
19//! define the animation with:
20//! ```
21//! /// /src/main.rs
22//! use glam::{Vec2, vec2};
23//! use scal_core::prelude::*;
24//! // Size of the virtual canvas not the output resolution - configured by Config.toml
25//! const WINDOW: Vec2 = vec2(1920., 1080.);
26//! // This handles all the ipc communication with the scal runtime
27//! #[scal_ipc::main]
28//! fn main() -> Project {
29//!     // https://github.com/tinted-theming/schemes
30//!     let theme = Theme::from_base16(Base16::from_hex([
31//!         0x11121d, 0x1A1B2A, 0x212234, 0x282c34, 0x4a5057, 0xa0a8cd, 0xa0a8cd, 0xa0a8cd, 0xee6d85,
32//!         0xf6955b, 0xd7a65f, 0x95c561, 0x38a89d, 0x7199ee, 0xa485dd, 0x773440,
33//!     ]));
34//!
35//!     const CW_WIDTH: f32 = 800.;
36//!     const CW_HEIGHT: f32 = 600.;
37//!
38//!     // Simple objects that handles most needs for animating code.
39//!     let cw = code_window()
40//!         .source("fn main() {\n    println!(\"Hello, world!\");\n}\n")
41//!         .font_family("SF Pro Display")
42//!         .font_size(20.)
43//!         .syntax(Syntax::Rust)
44//!         .line_numbers(true)
45//!         .title("fib.rs")
46//!         .width(CW_WIDTH)
47//!         .height(CW_HEIGHT)
48//!         .title_font_size(25.)
49//!         .background_color(Color::new(0.15, 0.15, 0.2, 1.))
50//!         .pos(WINDOW / 2.)
51//!         .build();
52//!
53//!     let pointer = svg()
54//!         .path("./pointer-tool.svg")
55//!         .size(Vec2::new(40., 40.))
56//!         .color(Color::WHITE)
57//!         .stretch(StretchMode::Fit)
58//!         .pos(Vec2::new(500., 500.))
59//!         .z(1.)
60//!         .build();
61//!
62//!     Project {
63//!         scene_settings: SceneSettings {
64//!             background_color: Color::new(0.8, 0.8, 0.8, 0.),
65//!             camera: Camera::new(Vec2::new(1920., 1080.), Vec2::ZERO, 1.),
66//!             default_theme: theme,
67//!         },
68//!         // This is the actual animation sequence
69//!         timeline: timeline![
70//!             // all objects need to be instantiated(layout instantiates all children during its instantiation)
71//!             cw.instantiate(),
72//!             pointer.instantiate(),
73//!
74//!             wait(0.5.s()),
75//!             parallel![
76//!                 cw.add_lines()
77//!                     .str(
78//!                         r"
79//! fn fib(n: u32) -> u32 {
80//!     match n {
81//!         0 => 0,
82//!         1 => 1,
83//!         _ => fib(n - 1) + fib(n - 2),
84//!     }
85//! }
86//!                 "
87//!                     )
88//!                     .over(5.s())
89//!                     .style(CodeAnimationStyle::TypeWriterInstantResize),
90//!             ],
91//!             wait(0.5.s()),
92//!             pointer
93//!                 .transform
94//!                 .position()
95//!                 .object(cw.close_button())
96//!                 .to(vec2(15., 15.))
97//!                 .over(0.5.s())
98//!                 .ease(Ease::InOutCubic),
99//!             cw.close_button().scale().to(Vec2::ONE * 0.8).over(0.3.s()),
100//!             cw.close_button().scale().to(Vec2::ONE).over(0.3.s()),
101//!             parallel![
102//!                 cw.transform
103//!                     .scale()
104//!                     .to(Vec2::ZERO)
105//!                     .over(0.5)
106//!                     .ease(Ease::OutCubic),
107//!                 cw.transform
108//!                     .position()
109//!                     .to((WINDOW - vec2(CW_WIDTH, CW_HEIGHT)) / 2.)
110//!                     .over(0.5)
111//!                     .ease(Ease::OutCubic),
112//!             ],
113//!             wait(0.5.s()),
114//!         ],
115//!     }
116//! }
117//! ```
118//! Basic animation output config.
119//! ``` toml
120//! # /Config.toml
121//! [animation]
122//! binary = "cargo run"
123//!
124//! [rendering]
125//! text_resolution_multiplier = 2.0
126//! width = 3840
127//! height = 2160
128//! fps = 60
129//!
130//! [encoding]
131//! output_path = "test.mov"
132//! codec_type = "H264Nvenc"
133//! ```
134//! make sure that you have installed required system dependencies:
135//!
136//! - Ubuntu/Debian:
137//! ``sudo apt install ffmpeg libwayland-dev libxkbcommon-dev libx11-dev libxcursor-dev libxi-dev libxrandr-dev libxcb1-dev libasound2-dev libpulse-dev``
138//!
139//! - Arch:
140//! ``sudo pacman -S ffmpeg wayland libxkbcommon libx11 libxcursor libxi libxrandr libxcb alsa-lib libpulse``
141//!
142//! - Fedora:
143//! ``sudo dnf install ffmpeg-devel wayland-devel libxkbcommon-devel libX11-devel libXcursor-devel libXi-devel libXrandr-devel libxcb-devel alsa-lib-devel pulseaudio-libs-devel``
144//!
145//! - NixOS:
146//! download flake file:
147//! ```bash
148//! wget https://raw.githubusercontent.com/Feeflak/SCAL/refs/heads/main/flake.nix
149//! ```
150//! Set-up the environment:
151//! ```bash
152//! nix develop
153//! ```
154//!
155//! And now you can just use the scal runtime to render/preview the animation.
156//! ``` bash
157//! ❯ ls
158//! Cargo.toml  Config.toml  pointer-tool.svg  src  test.mov
159//! ❯ scal render
160//! ...
161//! ❯ ffplay ./test.mov
162//! ```
163//! # Features
164//!
165//! ## High Quality Animations of Code with Ease.
166//! First party support for code modification animations, syntax highlighting, custom color schemes, and glyphs.
167//! Supports syntax highlighting for most popular languages using Tree-sitter.
168//! Use standard [Base16 color schemes](https://github.com/tinted-theming/schemes) to configure
169//! syntax highlighting.
170//!
171//! ## Hot Reloading Animation Preview
172//!
173//! Supports preview view with a timeline that automatically reloads upon animation code change.
174//! Audio waveform display support in timeline.
175//! You can click on individual animation operations or sound fx to display what type of animation
176//! they are, and where they are located in the animation source code.
177//!
178//! ## LSP
179//! Thanks to the powerful rust LSP you can read documentation from your editor.
180//!
181//! ## Examples
182//!
183//! If you want to see features of this project you can look at the example directory.
184//!
185//! ## Clear Syntax
186//! you instantly know what every function does.
187//!
188//! ```
189//! let typing = sfx()
190//!     .path("./keeb.wav")
191//!     .volume(5.)
192//!     .pitch(1.)
193//!     .skip_time(0.)
194//!     .duration(5.)
195//!     .pitch_variation(0.05);
196//! ```
197//!
198//! ## Fast Render Times
199//! Using FFmpeg supports hardware H264 encoding for most popular GPU brands- nvidia, intel, apple(I
200//! only have nvidia gpu-s so tests on other platforms are needed)
201//! Uses WGPU to efficiently render scenes.  
202//! ## Multi-platform
203//! Works on all platforms(Linux, Mac, Windows)
204//! (I only have NixOS systems so testing on other platforms is needed)
205//!
206//! ## Audio System
207//! Uses FFmpeg for audio encoding and [cpal](https://github.com/RustAudio/cpal) for preview audio, to deliver stable audio system.
208//!
209//! # Installing Scala Runtime
210//! ## Distro Package
211//! Sadly there are no packages currently for this app, you need to compile it from source or
212//! install using cargo.
213//! ## Nix Flake
214//! You can automatically compile from source using flakes like this:
215//!{
216//!   inputs.scal-runtime = {
217//!     url = "github:Feeflak/scal";
218//!     inputs.nixpkgs.follows = "nixpkgs";
219//!   };
220//!
221//!   outputs = { self, nixpkgs, scal-runtime, ... }: {
222//!     nixosConfigurations.my-pc = nixpkgs.lib.nixosSystem {
223//!       system = "x86_64-linux";
224//!
225//!       modules = [
226//!         ({ pkgs, ... }: {
227//!           environment.systemPackages = [
228//!             scal-runtime.packages.${pkgs.stdenv.hostPlatform.system}.default
229//!           ];
230//!         })
231//!       ];
232//!     };
233//!   };
234//! }
235//! ## Compiling From Source
236//! SCAL uses Cargo to manage all Rust dependencies automatically. Only a few native libraries must be installed manually.
237//!
238//! ## 1. Install Rust
239//!
240//! If you don't already have Rust installed:
241//!
242//! ```bash
243//!     curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
244//! ```
245//!
246//! Verify the installation:
247//!
248//! ```bash
249//! cargo --version
250//! rustc --version
251//! ```
252//!
253//! ---
254//!
255//! ## Linux
256//!
257//! ### Arch Linux
258//!
259//! Install the required packages:
260//!
261//! ```bash
262//! sudo pacman -S \
263//!     ffmpeg \
264//!     pkgconf \
265//!     clang \
266//!     llvm \
267//!     wayland \
268//!     libxkbcommon \
269//!     libx11 \
270//!     libxcursor \
271//!     libxi \
272//!     libxrandr \
273//!     libxcb \
274//!     alsa-lib \
275//!     libpulse
276//! ```
277//!
278//!
279//! ---
280//!
281//! ### Fedora
282//!
283//! Install the required packages:
284//!
285//! ```bash
286//! sudo dnf install \
287//!     ffmpeg-devel \
288//!     pkgconf-pkg-config \
289//!     clang \
290//!     llvm-devel \
291//!     wayland-devel \
292//!     libxkbcommon-devel \
293//!     libX11-devel \
294//!     libXcursor-devel \
295//!     libXi-devel \
296//!     libXrandr-devel \
297//!     libxcb-devel \
298//!     alsa-lib-devel \
299//!     pulseaudio-libs-devel
300//! ```
301//!
302//!
303//! ---
304//!
305//! ## Debian / Ubuntu
306//!
307//! Install the required packages:
308//!
309//! ```bash
310//! sudo apt update
311//!
312//! sudo apt install \
313//!     pkg-config \
314//!     ffmpeg \
315//!     clang \
316//!     libclang-dev \
317//!     libwayland-dev \
318//!     libxkbcommon-dev \
319//!     libx11-dev \
320//!     libxcursor-dev \
321//!     libxi-dev \
322//!     libxrandr-dev \
323//!     libxcb1-dev \
324//!     libasound2-dev \
325//!     libpulse-dev
326//! ```
327//!
328//!
329//! ---
330//!
331//! ## NixOS
332//!
333//! The repository already contains a development shell.
334//!
335//! Enter it with:
336//!
337//! ```bash
338//! nix develop
339//! ```
340//!
341//! or
342//!
343//! ```bash
344//! nix-shell
345//! ```
346//!
347//! All required libraries are provided automatically.
348//!
349//! ---
350//!
351//! # macOS
352//!
353//! Install Homebrew if necessary.
354//!
355//! Then install the required packages:
356//!
357//! ```bash
358//! brew install \
359//!     ffmpeg \
360//!     llvm \
361//!     pkg-config
362//! ```
363//!
364//! The remaining libraries required by SCAL are provided by macOS.
365//!
366//! ---
367//!
368//! # Windows
369//!
370//! Install:
371//!
372//! - Rust (via rustup)
373//! - Visual Studio 2022 with the **Desktop development with C++** workload
374//! - LLVM/Clang
375//! - FFmpeg
376//!
377//! Using Winget:
378//!
379//! ```powershell
380//! winget install Rustlang.Rustup
381//!
382//! winget install LLVM.LLVM
383//!
384//! winget install Gyan.FFmpeg
385//! ```
386//!
387//! After installing Visual Studio Build Tools, restart your terminal.
388//!
389//! ---
390//!
391//! # Building SCAL
392//!
393//! ```bash
394//! cargo install scal-runtime
395//! ```
396//!
397//! # Setting up a new animation project
398//! 1. Init project
399//! ```bash
400//! cargo init <Name>
401//! ````
402//! 2. Add dependencies to Cargo.toml
403//! ``` toml
404//! scal-core = "<version>"
405//! scal-ipc = "<version>"
406//! glam = "0.33.2"
407//! ```
408//! 3.  basic animation output config
409//! ``` toml
410//! # /Config.toml
411//! [animation]
412//! binary = "cargo run"
413//!
414//! [rendering]
415//! text_resolution_multiplier = 2.0
416//! width = 3840
417//! height = 2160
418//! fps = 60
419//!
420//! [encoding]
421//! output_path = "test.mov"
422//! codec_type = "H264Nvenc"
423//! ```
424//! 4. setup the ipc macro
425//! ```
426//! // /scr/main.rs
427//! #[scal_ipc::main]
428//! fn main() -> Project {
429//!     todo!()
430//! }
431//! ```
432//!
433//! That's it, you can start writing any animation you want
434//! simple example:
435//! ```
436//! // /scr/main.rs
437//! use glam::Vec2;
438//! use scal_core::prelude::*;
439//!
440//! #[scal_ipc::main]
441//! fn main() -> Project {
442//!     let rect = rectangle()
443//!         .size(Vec2::new(600., 400.))
444//!         .corner_radius(40.)
445//!         .color(Color::new(0., 0.2, 0.4, 1.))
446//!         .pos(Vec2::new(400., 540.))
447//!         .build();
448//!
449//!     let circle = circle()
450//!         .radius(200.)
451//!         .color(Color::new(0.8, 0.2, 0.2, 1.))
452//!         .pos(Vec2::new(1200., 500.))
453//!         .build();
454//!
455//!     let hex = polygon()
456//!         .radius(180.)
457//!         .sides(6)
458//!         .color(Color::new(0.2, 0.7, 0.3, 1.))
459//!         .pos(Vec2::new(800., 300.))
460//!         .build();
461//!
462//!     let triangle = polygon()
463//!         .radius(150.)
464//!         .sides(3)
465//!         .color(Color::new(0.9, 0.6, 0.1, 1.))
466//!         .pos(Vec2::new(1600., 700.))
467//!         .build();
468//!
469//!     Project {
470//!         scene_settings: SceneSettings {
471//!             background_color: Color::new(0.8, 0.8, 0.8, 1.0),
472//!             camera: Camera::new(Vec2::new(1920., 1080.), Vec2::ZERO, 1.),
473//!             default_theme: Theme::default(),
474//!         },
475//!         timeline: timeline![
476//!             rect.instantiate(),
477//!             circle.instantiate(),
478//!             hex.instantiate(),
479//!             triangle.instantiate(),
480//!             wait(1.s()),
481//!             parallel![
482//!                 triangle
483//!                     .transform
484//!                     .position()
485//!                     .to(Vec2::new(350., 800.))
486//!                     .over(1.s())
487//!                     .ease(Ease::OutBack),
488//!                 rect.transform
489//!                     .position()
490//!                     .to(Vec2::new(960., 540.))
491//!                     .over(1.s())
492//!                     .ease(Ease::InOutBack),
493//!             ],
494//!         ],
495//!     }
496//! }
497//! ```
498//!
499//!
500
501pub mod anim;
502pub mod anim_builders;
503pub mod anim_obj;
504pub mod anim_op;
505pub mod camera;
506pub mod color;
507pub mod ease;
508pub mod highlight_specs;
509#[allow(missing_docs)]
510pub mod object_builders;
511pub mod project;
512pub mod seconds;
513pub mod settings;
514pub mod sfx;
515pub mod theme;
516pub mod transform;
517
518pub use anim_obj::{AnimObj, CodeHandle, CodeWindowHandle, StretchMode, Syntax, TextAlign};
519pub use anim_op::{AnimOP, CodeAnimationStyle, CodeHighlightAction, IntoAnimOp, SourceLoc};
520pub use camera::Camera;
521pub use color::Color;
522pub use ease::Ease;
523pub use project::{Project, SceneSettings};
524pub use scal_ipc_macros::timeline;
525pub use seconds::{DurationExt, Time};
526pub use settings::{CodecType, EncodingSettings, RenderingSettings};
527pub use sfx::{Sfx, SfxBuilder};
528pub use theme::{Base16, Theme};
529pub use transform::Transform;
530
531/// All the stuff that you need to create animations in Scal
532pub mod prelude {
533    pub use crate::anim::*;
534    pub use crate::anim_builders::*;
535    pub use crate::anim_obj::{
536        AnimObj, CodeHandle, CodeWindowHandle, StretchMode, Syntax, TextAlign,
537    };
538    pub use crate::anim_op::{AnimOP, CodeAnimationStyle, CodeHighlightAction, IntoAnimOp};
539    pub use crate::camera::Camera;
540    pub use crate::color::Color;
541    pub use crate::ease::Ease;
542    pub use crate::object_builders::*;
543    pub use crate::project::{Project, SceneSettings};
544    pub use crate::seconds::DurationExt;
545    pub use crate::sfx::{Sfx, sfx};
546    pub use crate::theme::{Base16, Theme};
547    pub use crate::transform::Transform;
548    pub use crate::{parallel, sequence, timeline};
549}