Skip to content

Commit d58476e

Browse files
Merge pull request #109 from danielsz/bioscoop
Bioscoop, a DSL for creative coding
2 parents c46aa3b + b511c16 commit d58476e

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

deps.edn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
org.soulspace/qclojure {:mvn/version "0.22.0"}
4848
org.babashka/http-client {:mvn/version "0.4.22"}
49+
com.github.danielsz/bioscoop {:mvn/version "1.0.5"}
4950
}
5051

5152
:aliases

site/db.edn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
:url "https://scicloj.github.io/contributors/daslu/"
2222
:affiliation [:scicloj]
2323
:links [{:icon "github" :href "https://github.com/daslu"}]}
24+
{:id :danielsz
25+
:name "Daniel Szmulewicz"
26+
:image "https://avatars.githubusercontent.com/u/859131?v=4"
27+
:url "https://danielsz.github.io/"
28+
:affiliation []
29+
:links [{:icon "github" :href "https://github.com/danielsz"}]}
2430
{:id :alexmiller
2531
:name "Alex Miller"
2632
:image "https://avatars.githubusercontent.com/u/171129?v=4"

src/bioscoop/bioscoop.gif

25.8 KB
Loading

src/bioscoop/masterpiece.gif

1.01 MB
Loading

src/bioscoop/quickstart.clj

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
^{:kindly/hide-code true
2+
:clay {:title "Bioscoop, a DSL for FFmpeg"
3+
:quarto {:author [:danielsz]
4+
:description "Quickstart for Clojurians"
5+
:draft false
6+
:type :post
7+
:date "2025-10-27"
8+
:category :clojure
9+
:tags [:creative_coding]}}}
10+
(ns bioscoop.quickstart
11+
(:require [scicloj.kindly.v4.kind :as kind]
12+
[bioscoop.quickstart :as qs]))
13+
14+
;; This document serves as a quickstart for the Bioscoop library. It is geared toward Clojurians as it assumes knowledge of namespaces, the REPL, etc.
15+
16+
;; Bioscoop is a DSL to program FFmpeg's filtergraphs. Start by requiring the Bioscoop macros and the `bioscoop.built-in` namespace.
17+
18+
(require '[bioscoop.macro :refer [bioscoop defgraph]]
19+
'[bioscoop.built-in :refer [help]])
20+
21+
;; Let's build a simple animation. We will start with a black background. The _color_ filter provides that.
22+
23+
(bioscoop (color))
24+
25+
;; Note that we didn't require _color_. It is available thanks to the `bioscoop.built_in` namespace, alongside all of the other filters.
26+
27+
;; If you need help with the parameters that a filter accepts, type in the REPL:
28+
29+
^:kind/hidden
30+
(help "color")
31+
32+
;; Bioscoop recognizes the same parameters as FFmpeg, with a caveat. In FFmpeg, some filters define the same parameter twice, once fully spelled out, and once in shorthand form (as if the syntax wasn't terse enough). For example, _w_ and _width_. Bioscoop doesn't accept the shorthand version *by design*.
33+
34+
;; On top of that black canvas, we are going to draw text twice per second, positioned randomly. In order to achieve that, we will refer the _x_ and _y_ coordinates to an expression instead of fixed values.
35+
36+
(bioscoop (drawtext {:text "bioscoop" :fontcolor "white" :x "'mod(random(0)*10000,W-tw)'" :y "'mod(random(1)*10000,H-th)'"}))
37+
38+
;; The bioscoop macro accepts a subset of Clojure. You can use _let_ bindings and all of _clojure.core_. It returns a data structure, the internal representation of a filtergraph.
39+
40+
;; Putting everything together, we can write:
41+
42+
(bioscoop (chain (color {:duration 5})
43+
(drawtext {:text "bioscoop"
44+
:fontcolor "white"
45+
:x "'mod(random(0)*10000,W-tw)'"
46+
:y "'mod(random(1)*10000,H-th)'"})
47+
(fps {:fps "2"})))
48+
49+
;; Or, if we need a handle on the filtergraph, we can use _defgraph_ which will intern a Var with a name of our choosing.
50+
51+
(defgraph filtergraph (chain (color {:duration 5})
52+
(drawtext {:text "bioscoop"
53+
:x "'mod(random(0)*10000,W-tw)'"
54+
:y "'mod(random(1)*10000,H-th)'"})
55+
(fps {:fps "2"})))
56+
57+
;; To convert the internal data structure, or the handle, back to a filtergraph, we use _to-ffmpeg_:
58+
59+
(require '[bioscoop.render :refer [to-ffmpeg]])
60+
(to-ffmpeg filtergraph)
61+
62+
;; Finally, the filtergraph is ready to be fed to FFmpeg. While there is a helper in Bioscoop, how and where you run the FFmpeg command is entirely up to you. For example, you can display the animation in the terminal with `ffplay -f lavfi -i` followed by the filtergraph.
63+
;;
64+
;; *Note:* FFplay is a companion player that is most often installed together with FFMpeg.
65+
66+
;; ![Bioscoop](bioscoop.gif)
67+
;;
68+
;; And voilà!
69+
70+
;; Content creators often reuse a preamble in their broadcasts. This use case is an excellent opportunity to demonstrate how Bioscoop provides means of composition.
71+
;; It also demonstrates how you reuse definitions across namespace boundaries.
72+
73+
^:kind/hidden
74+
(in-ns 'bioscoop.masterpiece)
75+
^{:kindly/hide-code true :kindly/kind :kind/hidden}
76+
(clojure.core/refer-clojure)
77+
(require '[bioscoop.quickstart :refer [filtergraph]]
78+
'[bioscoop.macro :refer [bioscoop defgraph]]
79+
'[bioscoop.built-in])
80+
81+
;; We will simulate the actual video content with a FFMpeg dummy filter, _testsrc_. The intro is our filtergraph referred to in the `bioscoop.quickstart` namespace.
82+
83+
(defgraph masterpiece (testsrc))
84+
(bioscoop (compose [filtergraph ["intro"]]
85+
[masterpiece ["masterpiece"]]
86+
[["intro"] ["masterpiece"] (concat {:n 2})]))
87+
88+
;; ![Masterpiece](masterpiece.gif)
89+
;;
90+
91+
;; And voilà, again!
92+
;;
93+
;; What are you going to make? We'll be happy to link to **your** masterpiece in Bioscoop's [gallery](https://github.com/danielsz/bioscoop#gallery).
94+
95+
96+

0 commit comments

Comments
 (0)