Category Archives: Animation

Some tries with LÖVE game engine in Lua

* Ce billet est également disponible en français.

Drawn with Pencil2D and MyPaint, animated using meshes in LÖVE (Lua language), I also made some tests in C with libSDL, but it is probably faster to prototype in Lua with LÖVE, and then add FFI libs for compute intensive part (in these cases light computations, GL is used for rendering), or port it to c+SDL at second time, when algorithms are validated. All used software are 100% FOSS used on a GNU/Linux system.

This one use simply a mesh on a picture, and deform them using circular motions, as I done in TIC-80 in July 2021.

The picture used for the mesh:

A modified version, with fixed hard skull, I keep both version, this one is interesting for anthropomorphic head, the other for more realistic invertebrate.

This test gather different tests with shaders. I apply a threeshold, above is one colour under, is another, this allow to have interesting clean 2 colours effects Source code of these shaders for LÖVE is available on Framagit (demo01.love file on this site).

This other one also use a mesh on a picture with 2 steps, swapping from one to each other moving the drawing shape, but instead, of deforming it by sin(), it curve the mesh, by adding curvature at each step, and a little sinus wave to simulate something that goes through the body.

the liquid the the monster reject, is a texture, that is copied to a Canvas, to wrap it and loop it, This part was inspired by the game “Conan Chop Chop”. But I fine tuned a bit: A shader is then applied on the canvas when drawing on screen surface, it scale the pixels along the path of the liquid, and add a light waving motion. the splash at the end is a cycle between 3 pictures.

The quickly drawn 2 steps monster, it could be optimized on disk by creating the duplication of the body after loading, LÖVE is not convenient as libSDL for textures mesh:
bidule spritesheet

The picture used as texture for for the shader:
flux de vomit intense

The splash at the end, each part are displayed sequentially in loop, this was animated with Pencil2D (MyPaint branch):
Eclaboussure de vomit

The animation is first made with Pencil2D, then saved with one picture (PNG with transparency) by frame, and then ImageMagick package, “montage” is used to build the spritesheet the following wy:

montage sprite0001.png sprite0006.png sprite0010.png -tile 3x1 -geometry 64x128 spritesheet.png

Using about the same methods, I then improved my code to manage a more generic way, hand drawn animation made with Pencil2d as mesh. Here is an animated sketch of flower opening, as proof of concept.

Blooming flower

Update of march 19:

It uses 8 frames, with various framerates, managed in a table, is here the frame number table:

table = {1,1,2,2,2,3,3,4,4,4,5,5,6,6,7,8,8,8,8,8}

I can then cycle easily in the table using math.floor( (time()*fps) % #table), or just parse it one time for exemple here for a flower that just open one time.

I then used it as decoration element. Now it work, I can refine animation, still make it more generic to have only to add minimum information, and be able to add quickly new animations.

After the good result of the first test of the animation with program, I cleaned a little the flower and added some colours. I then noticed than the last frame, where the flower move is stabilized missed. The picture before the last was duplicated as 2 last frames in my spritesheet. Anyway, I need to remove some useless space around the flower, separate stem and flower itself to reduce memory usage; It already take, reduced in 128×128 pixels 180~200 Ko (150 Ko compressed better with zopflipng). This is too fat, if you multiply this by the number of objects/characters you can quickly reach tens of MB (png compressed) on disk, and far more on Graphics RAM, saturating ram, cache and bandwidth, and so slowing down rendering. I believe that separate flower and keeping in a something like 64×64 pixels animation could be fine the stem could be a flat texture, blended by procedural means.

Fleur qui s'ouvre améliorée

”’Update may 2022 ”’
* You can test all of this, from the sources available at https://framagit.org/popolon/reforest.
* Ready last version LÖVE files and archives are available at the address https://framagit.org/popolon/reforest/-/releases (version 0.2 from this site).

Reforest 0.2 Screenshot

relatively full Debian desktop, server or both environnement on RISC-V based LicheeRV.

Table of Contents


* Introduction
* Installing the Image
* Connecting serial
* Booting
* Setting the WiFi
* Audio
* Some minors but useful tuning
* What is working

* Update 2022-03-12: Someone made a full tutorial to build a working image with own kernel and standard debian buildroot.
* Update 2022-04-06: Sehraf made RISC-V Arch Linux builder for Lichee-RV and D1

Image used in this tutorial use a kernel that doesn’t support firewall so don’t forget to use it only behind a well configured router (or box) connexion and don’t use confidential things on it.

Introduction

I managed to have a working Debian desktop environment on RISC-V after previous test and some exchanges on different Sipeed/D1 channels. Most informations are today available on Linux-SunXI.org Wiki dedicated page.

See also the previous article Booting Ubuntu Linux on a LicheeRV.

This image seems to manage more of the SoC features, or at least it announce lot of flags (IMAFDCVU):

$ cat /proc/cpuinfo 
processor	: 0
hart		: 0
isa		: rv64imafdcvu
mmu		: sv39

* IMAF = base ISA, Mul/div, Atomic instruction, (single precision) Float
* D = Double precision float
* V = Vector processor extension
* C = Compressed instructions
* U = User mode hyperverisor

The main problem was to have a working image with Debian, AllWinner and Speed give only a Linux image that can be made on Windows using PhoenixCard tool.

Someone of a Sipeed chat that have access to a Windows installed computer, made the conversion and give it available here (my mirror copy) sha256sum of the image: cf73baf3ed67d480e7606c666ccb81fce21295ba8fbba10e0ad86939065be6ffw. You need an at least 16GB microSD card to use it with LicheeRV and it’s Dock..

As a video exemple of the working image, Glaxnimate animation suite (own made RISC-V version of Debian package) , goes-up quickly to 6 of load, as most applications, but it is still usable:

Installing the Image

To install it, you can follow the following steps:

Install aria2 (Debian based (Debian, Ubuntu, …) sudo apt install aria2, Archlinux based (Arch, Manjaro, …): pacman -S aria2)

Update: someone said me he had problems with aria2, as wrote at the top of this article, you can still download the image from here: give it available here (my mirror copy). Please, verify the sha256sum of the image at the end of the download (Aria2 does automatically): cf73baf3ed67d480e7606c666ccb81fce21295ba8fbba10e0ad86939065be6ffw.

For an USB microSD card reader (I use /dev/sdd for /dev/sdX in my case you can verify which one is your by sudo fdisk -l:

DEVICE=/dev/sdX
aria2c https://popolon.org/depots/RISC-V/D1/images/LicheeRV/20211230_LicheeRV_debian_d1_hdmi_8723ds.ddimg.xz.metalink

It is very important to wipefs to avoid any problems with detections, then write, the downloaded image:

sudo wipefs -a ${DEVICE}
xzcat 20211230_LicheeRV_debian_d1_hdmi_8723ds.ddimg.xz | sudo dd bs=1MB status=progress of=${DEVICE}

Then delete the partition 8:

sudo fdisk ${DEVICE}
d
8
w

Resize the partition 7 to use the remaining space:

sudo parted ${DEVICE}
print

You will see the exact size of your partition (here in bold) that will be used later:

Model: SD ACLCE (sd/mmc)
Disk /dev/mmcblk0: 63.9GB

Then reuse the same value here to use the whole end of the card:

(parted) resizepart 7
End?  [??.?GB]? 63.9GB
(parted) quit

Then now grow the fs itself.
* for an USB sdcard reader (/dev/sdX):

sudo resize2fs ${DEVICE}7

* for an internal sdcard reader (/dev/mmcblkX):

sudo resize2fs ${DEVICE}p7

Now sync (flush data in memory on disk) the card:

sync

You can now extract the card from your reader and put it in the LicheeRV board.

Connecting serial

You should connect the way described on this picture. You can also connect the red wire on one of the 5V pin to power the board if you want:
picture of UART connectors pinout, upper row from left, 5V, 5V, GND, TX, RX

You can then connect using one of the methods I previously described here.

screen /dev/ttyUSB0 115200
Package             commande
busybox             busybox microcom -t 5000 -s 115200 /dev/ttyUSB0
minicom             minicom -D /dev/ttyUSB0 
gtkterm-git (AUR)   gtkterm -s 115200 -p /dev/ttyUSB0
python-pyserial     python -m serial.tools.miniterm /dev/ttyUSB0 115200
screen              screen /dev/ttyUSB0 115200
tinyserial          com /dev/ttyUSB0 115200
picocom             picocom --baud 115200 /dev/ttyUSB0

On the Login prompt, use:
* Login: sipeed
* Password: licheepi

Just for information about PinOut, used to know the serial pins:

You can find a Pineout of the board on the LicheeRV HDK Schematic PDF (local mirror):

And the pineout of the dock in the Dock Datasheet (local mirror)

LicheeRV Dock pineout

Booting

There has several problems at boot due to cgroup not enable in this kernel.

You can disable this problems by:

sudo dpkg -P rtkit
sudo systemctl disable e2scrub_reap
sudo systemctl disable systemd-hostnamed

The first line allow to have more HDMI (including sound) working and stop loop message on all consoles. The second one avoid 2+minutes of wait at booting time. The third one seems to have no effect, the message continue at boot.

Details of the problems:

H2MI to DVI and HDMI to USB dongles I used
Then boot it plugged on a 1080p HDMI screen. It doesn’t work with my HDMI->DVI (tried on a 1680×1050 DVI-A and a 1080p DVI-D) or with my 1080p HDMI->USB dongle. Someone else reported it worked with an HDMI-DVI dongle (reference: 6140063500G).

Update: This was resolved partially by removing rfkit, a watchdog daemon that tried to kill something, probably on a wrong test. The message that come in loop on the console disappear then, the HDMI output on the HDMI to USB dongle worked, this will allow me to record/stream video output, and audio output on HDMI now work too. It could be suggestive, but I feel like system also work a bit faster (testing/killing/restarting things can take a lot of resources) :

sudo dpkg -P rtkit

The error message loops like this in dmesg :

Jan 18 10:50:33 sipeed systemd[1]: Starting RealtimeKit Scheduling Policy Service...
Jan 18 10:50:33 sipeed kernel: Unable to handle kernel paging request at virtual address ffffffdf8099707e
Jan 18 10:50:33 sipeed kernel: Oops [#52]
Jan 18 10:50:33 sipeed kernel: Modules linked in: xt_time xt_multiport xt_mark xt_mac xt_limit xt_comment xt_TCPMSS xt_LOG uvcvideo videobuf2_vmallo>
[…]
Jan 18 10:50:33 sipeed systemd[1]: rtkit-daemon.service: Main process exited, code=killed, status=11/SEGV
[…]
Jan 18 10:50:58 sipeed systemd[1]: rtkit-daemon.service: Failed to get cgroup ID on cgroup /sys/fs/cgroup/system.slice/rtkit-daemon.service, ignorin>

The problem of missing cgroup management in kernel is also the source of long boot and messages:

[FAILED] Failed to start Remove Sta…ext4 Metadata Check Snapshots.
See 'systemctl status e2scrub_reap.service' for details.
[   ***] A start job is running for Raise ne…rk interfaces (1min 7s / 5min 14s)

Looking at journalctl:

journalctl -xeu e2scrub_reap.service

You will see the following message:

e2scrub_reap.service: Failed to get cgroup ID on cgroup /sys/fs/cgroup/system.slice/e2scrub_reap.service, ignoring: Function not implemented
journalctl -xeu systemd-hostnamed.service

systemd-hostnamed.service: Failed to get cgroup ID on cgroup /sys/fs/cgroup/system.slice/systemd-hostnamed.service, ignoring: Fu

If you disable it, the boot will now be 2 minutes faster:

sudo systemctl disable e2scrub_reap
sudo systemctl disable systemd-hostnamed

You can see the whole boot sequence by connecting to UART. See this ASCIInema record of the boot sequence (local copy of the cast).

LigthDM connexion prompt

At the LightDM Login and pass prompt use:
* Login: sipeed
* Password: licheepi

Then you will have after about less than 1 minutes (yes, that’s a bit slow) the desktop.

Setting the WiFi

You can set your WiFi connexion (and even BlueTooth) with connexion manager. It is accessible from the main menu (the most left-bottom gray icon) by Preferences > Connman Settings, see this picture

access to Connman from menu

Then choose Wireless at left of the new box.Activate the Wifi connexion in Connman
* Click on the gray button to start the wifi (1 in red on the picture).
* Select the network you want to connect to (2 in red)
* Click on connect (3 in red).
* A prompt will open, where you will need to enter the passphrase of the WiFi.
Authentication required

The connexion should be established now, with “Connected” wrote at top of the window and “Online” beside the name of the Wifi router name (as on the picture at right.

You can by pressing on the gear at the right of the router name (2) in previous right picture, have access to some control to have the connexion set automatically at each boot.

click on the greyed autoconnect button, it should become blue meaning autoconnect is activated

Click on the IPv4 at left and then on the Method (set to None) button, choose automatic in the menu as shown in the following picture, then apply at bottom right.

Don’t forget to check also that NameServers is set as you want (by DHCP or static).

I noticed it worked better if I uncommented the following lines in /etc/network/interfaces using

sudo vi /etc/network/interfaces

, it seems to work far better when it’s uncommented (there is a typo: wpa-deriver instead of wpa-driver, but works as is. to remove the # comments, just move the cursors to them and press x one time.

auto wlan0 #(wlp3s0 为网卡名)
iface wlan0 inet dhcp
	wpa-deriver wext
 	wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

When finished, quit and save with the sequence of keys: “:“, “x!“, ["enter"] key

You can sync your card and reboot safely now:

sync
sudo reboot

It should work fine the next time. you can verify the ip address on your router, or by connecting on the console or interface, and typing:

sipeed@sipeed:~$ ip address
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: sit0@NONE:  mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
3: wlan0:  mtu 1500 qdisc mq state DOWN group default qlen 1000
    link/ether 74:ee:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.xx.xx/24 brd 192.168.xx.xx scope global dynamic wlan0
       valid_lft 41822sec preferred_lft 41822sec
4: wlan1:  mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 76:ee:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.xx.xx/24 brd 192.168.xx.xx scope global wlan1
       valid_lft forever preferred_lft forever

or, like the former way:

sipeed@sipeed:~$ sudo ifconfig
[sudo] password for sipeed: 
lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 13  bytes 1793 (1.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13  bytes 1793 (1.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=-28669  mtu 1500
        inet 192.168.xx.xx  netmask 255.255.255.0  broadcast 192.168.xx.xx
        ether 74:ee:xx:xx:xx:xx  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan1: flags=-28605  mtu 1500
        inet 192.168.xx.xx  netmask 255.255.255.0  broadcast 192.168.xx.xx
        ether 76:ee:xx:xx:xx:xx  txqueuelen 1000  (Ethernet)
        RX packets 582  bytes 80736 (78.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 504  bytes 82357 (80.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

To be more comfortable I suggest to make a swap file on the microSD if you want to use some desktop application, because, 512MB is really short:

Create a swap file of 1GB (1024M) and format it:

sudo dd bs=1M count=1024 status=progress if=/dev/zero of=/swap
sudo mkswap /swap

Add this to /etc/fstab for automatic mount after reboot:

echo "/swap none swap defaults 0 0" |sudo tee -a /etc/fstab/

Then mount it immediately

sudo swapon -a

For more comfortable serial (UART) console usage, you could also install xterm package. It will give you the resize command. When you type resize from your serial connexion, the serial view will adapt to you local Xterm, VTE term, or whatever terminal you use.

Audio

On this default image to have audio working on HDMI I suggest ton install and use PAVUcontrol, the best tool I know to manage PulseAudio and PipeWire audio daemons.

sudo apt install pavucontrol

You can launch it in a term like the following line or in menu like on this picture:

pavucontrol

With the GUI menu, choose Sound & Video > PulseAudio Volume Control
select Pavu control in menu

Then for HDMI default output in PulseAudio, that is wrapped on PipeWire, select, the Output Devices tab, as blue underlined on picture, then press the green rounded check (I added red square on this picture) beside Build-in Audio Stereo where Analog Output, the first Entry with Headphones is probably the speaker connector on the board (need to try it).
Select Analog Output for HDMI output

Some minors but useful tuning

Crontab installation is broken by default, group crontabs is missing:

apt reinstall cron

To use your language:

sudo vi locale.gen

Uncomment your corresponding line (ex: for french: fr_FR.UTF-8 The two first chars (here fr) are language and the second (here FR) are the country (here France).

You can then set the locale, and the keyboard
You can list available languages layout by:

localectl  list-x11-keymap-layouts
localectl set-locale fr_FR.UTF-8
set-keymap fr
set-x11-keymap fr_FR

To gain some KB you can replace lightdm by xdm (the first default display manager, or nodm that doesn’t prompt for login/password.

For nodm:

sudo apt install nodm

For xdm:

sudo apt install xdm

Anyway you can install both and during the installation, dpkg-configure will ask you in a menu the one you want to use.

By default with nodm, root user will be used, this is really not a good idea. You can change it by editing the nodm config file from root to sipeed:

sudo sed -i s/NODM_USER=root/NODM_USER=sipeed/ /etc/default/nodm

.
or by using debian dpkg-reconfigure that will ask you several question and change the user:

sudo dpkg-reconfigure nodm

Then reboot or stop LightDM and start another dm:

sudo systemctl stop lightdm
sudo systemctl start xdm

As LicheeRV is a very cheap card, the goal is to have an available board to test RISC-V integration, there is no dedicated Video RAM. You can gain lot of performances by disabling X. Stop lightdm will free the resources of X automatically. You will gain RAM and resources for compilation or other tasks.

sudo systemctl stop lightdm

To disable it permanently use systemctl disable, it will keep this state after reboot

sudo systemctl disable lightdm

You can still re-enable it by using systemctl enable:

sudo systemctl enable lightdm

What is working

MuseScore, Scribus and FontForge
Among application working well, I found:
* Graphics tools: GIMP, Krita work a bit slowly. The first time, need to wait long time, and then go to preferences to disable GL acceleration before creating an image, else it will be awfully slow. Everything will go far faster after that.
* Edition tools: MuseScore (see vidéo), FontForge, Scribus, Inkscape.
* Animation tool: Pencil2D, UPDATE: Glaxnimate (see videos below), I made a Debian package.
* Chat: IRC client Hexchat, and Telegram-desktop client (FOSS Android version)
* Blender work but is totally unusable
* Web browser:: They are generally unusable, the exception is Netsurf (package netsurf-gtk, see screenshot below), that is still slow but a minimum usable, a framebuffer version (netsurf-fb) is pre-installed, but should be used in terminal console view, that is not setup by default. Text browsers like w3m, eLinks, etc, can work. Firefox is unavailable (there is an unofficial method to patch it and compile it for RISC-V, need to test it, but I doubt it will be efficient, a 3 or 4 year old version, could be better. There is an official patch but seem to be no more available? As often, Firefox like to block progress on new technologies….
screenshot with Gimp, Pencil2D, Hexchat (irc client)
* Web server: HTTPd Apache and Nginx works You can test my installation of Nginx, when it is up, here. I let up for few days (it should consume 2,5W maximum (5V*0.5A power via serial or sometime USB), but could some times reboot for update, I wait for solar panels to plug it on.

I put checkers on name to not display private informations:
Screenshot with Blender and Telegram

Netsurf-GTK has little display bugs, but is relatively usable. Still not reactive for typing URL in URL bars.
Screenshot of Netsurf-GTK

Telegram rendering of the Glaxnimate animation:

Launching of MuseScore:

64x64x16colours (Sweetie16) PixelArt with Pixelorama “β-karoten – We know whom will be eat”

→ Version en français ici

β-karoten - We know whom will be eat

I participated to the LoveByte Battleground demoparty> that runned this week-end, by posting a drawing last week. Sadly/funnily , there was few mistake ^^:
* I made a 64×64 pixels picture instead of a 128×128 one. The palette for the competition was 16 colours Sweetie16 (the default one on FOSS, TIC-80 fantasy console (Source code)).
* My second mistake is I’ve uploaded a first version, and few hours later another one using (FOSS) source code) on Debian on (FOSH) RISC−V (Specifications, there are lot of free or not implementations) emulator of FOSS Qemu (Source code, Git instance), the first upload worked fine but the second one didn’t work (maybe because my installation of Netsurf doesn’t manage javascript)^^. I also performed in a livecoding match (256 bytes and 25 minutes limits). Result of my poor production, Commented Live coding session record.

This is made with FOSS Pixelorama (Source code), itself made on FOSS Godot game engine (Source code). I use FOSS Arch Linux OS. Also made a ArchLinux AUR package pixelorama-git after pixelorama package (for git version, I would like to use v0.9, still not out, only v0.8 was available). There are pixelorama package (last stable, compiling from source), and pixelorama-bin package (from developers binary tarball). Pixelorama is a Pixel art picture and animation editor. I believe I discovered Pixelorama thanks to blog Librearts.org.

The name is “β-karoten – We know whom will be eat”.

Pixelorama editor screenshot
Screenshot of Pixelorama

Telegram, Lottie animated stickers, Python and Glaxnimate

→ Version en français ici

Table of Content

* Introduction
* A good workflow
* Publication on the web (SVG)
* Telegram Bot

Introduction


I’m a fan of Telegram chat application interface. If the sever is closed source, desktop and mobile applications are open sources, the interface is very well designed and thinked, intuitive, relativly light and full of interesting functionnalities, compared to other applications of this kind. It could be good to patch to have a Jabber/XMPP compatibility. It is the first, as far I know, to use Lottie, since Jully 2019 (and the bot API that goes with it), an animated vector format that I dreamd of for decades, that become an de facto open standard. Animations of this page have been created with Glaxnimate, a tool to make Lottie format animations, as main goal, but that can also be used to export SVG animation. The authors of Lottie published some JavaScript for the World Wide Web, Samsung, made a free and open source rlottie C++ library, as well as WASM version, that allow to play them and has binding for several programming languages. Qt has an included Lottie reader, and there are several tools to create them.


The multiplatofmr free software Glaxnimate allow to make them with a Graphical User Interface, familiar with people creating animation on computers. His main author also made a Python library, python-lottie (AUR: python-lottie-git, pip: Lottie), that allow procedural generation of them. Both alow to convert them to several formats (export animated SVG, Lottie JSON, HTML page all ready, Telegram, mpeg4, PNG, wepb, gif, and I probably forgot some other), and as input to vectorize animated gif, etc… The 2D vector animation Synfig also have a Lottie exporter, but also Blender3D, a plugin made by Glaxnimate author (distributed with python-lottie) for this last one. There are so several choices to create them.


Glaxnimate allow to easily create animations in Lottie format, including .TGS, a version with more limited specifications and gzip compressed for Telegram. This format is more compact but has some constraints, that didn’t stop some artists to make very great artworks since 2 years:
* 512×512 pixels
* 3 secondes
* 64 KB by animated sticker..
* Animated stickers can be grouped in a sticker pack corresponding to several expressions (like emoticons/emoji).

Why for 512×512 pixels with a vector format? Telegram client application render the animation in this dimension. This dimension is already big for some mobile screens. This vector format allow to reduce bandwidth usage and to have a high quality animation (generaly computed by the GPU, SVG accelerators was already in Nokia and Symbian made phones in 2000s). WeChat/微信 choose animated GIF about one decade ago. GIF are probably converted in MPEG nowaday? The instant messaging Discord, populare in Far West, also use the Lottie format since Jully 2021, following Telegram after 2 years.


As a refecence, top of this page animation is:
* 1109 bytes (1,1 KB) in TGS (binary compressed Telegram format)
* 4682 bytes (4.5 KB) in JSON uglified (no more indentation, or carriage return)
* 508054 bytes (500 KB) in WebP
* 9710 bytes (9.6 KB) in animated SVG (there was an useless animated path, I don’t know why for).
* 1804 bytes (1.7 KB) in ainmated SVGZ (gzip compressed SVG). It is more interesting today to let the server compress using Brotli format (Nginx, Apache) or to precompress them (.br). It is really well supported by web browsers
* 6114 bytes (6.1 KB) in SVG, Inkscape optimised compressed (based on Scour)), it’s possible to reduce size more. Today if the option to reduce digits after comma (floats) is less than 3, it will be still kept at 3 digits. In animation parts still not managed there are six 0 (1.000000 or 0.000000 for example). It is still possible to optimize by hand until thes options are added (See sed usage, below), so :
* 5827 bytes (5.8 KB) in SVG, a bit hand finished.
* 5559 bytes (5.5 KB) by removing some useless intermediate groups (warning to don’t break all, try group by group) and replacing numbers like 1.0 by 1


One of the main problems of optimized SVG output from Glaxnimate is that Lottie heavily use groups, where SVG allow to made most of these operation in the objects themselves. So transformation matrix are all in groups containing the objects, instead of in objects themselves. you can see at right the XML source inf Inkscape. This still ask lot of handcrafted work on files nowaday. It should be possible to improve it.

It looks like there are more efficient methods withSVGO, but based on Node.js, and it breaks animations, some of its optimisation methods could be used in python one. I don’t like Node at all due to bad habits of lot of devs around Node. The Inkscape plugin, “inkscape-svgo” is still in this spirit, if we try to compile it with included Makefile, it doesn’t test if Nodes modules are already installed but forcee download Node JS version 11 (and x86_64 only, so not multi-architecture), and recompile all the dependenccies. So one more time with Node, we wast lot of earth limited resources, wit an extention of tens of Megabytes (75 MB, where Inkscape is 145 MB and the Node SVGO library itself is only 5 MB), where it should only be few KB.

A good workflow

* Create object with Inkscape
* Animate it with Glaxnimate
* Export it in SVG format (don’t forget to also save a Glaxnimate format file)
* Open the new file with Inkscape to clean it (extract some groups that are not needed
* Export to optimized output
* Finish by hand.

For the last part there are 2 solution for have an automated one:
* Patch Inkscape optimized output.
* Do a second path optimizer.

Some space can be saved with :

sed s/1.00000/1/g <input.svg | sed s/0.00000/0/g | sed 's/0000;/;/g' >output.svg

One or two digit precision (instead of 3 or 4 today with Scour)), should be good enough.

SVGcleaner is better than Scour in several cases, but itdoesn’t support animations and don’t want to (it’s complex to manage, can easily become a nightmare).

Publication on the web (SVG)

So as I just said, as animated SVG is really more easy to integrate in a web page, after lot of tries with Lottie, I finnaly choose this option. The best is to not compress with SVGZ, but to optimizer the SVG file then to compress with Brotli (.br) and maybe to have a gzip version beside for oldest web browsers.

Its integration in a web page is really simple, it can be done as other pictures format with image:

<img src="/chemin/du/fichier_animation.svg" align="right" width="200" height="250">

That’s what I done in this page, every browser automatically manage them.

Note : It could be interesting to integrate it inline to manipulate an easier way with Javascript. For simple animated illustration, maybe just animated/zoomed/rotated object, without inside details modifications, image is perfect.

For compressing I use the max compression, here is a simple method to compress all files of a single directory beside their uncompressed version:

ls --ignore=*.gz --ignore=*.br | while read file
do
 brotli -q 11 -c <"${file}" >"${file}".br
 gzip -9 -c <"${file}" >"${file}".gz
done

* 5559 murphy_anim0.animoptiv5.svg
* 1303 murphy_anim0.animoptiv5.svg.br
* 1543 murphy_anim0.animoptiv5.svg.gz
* 4682 murphy.json
* 976 murphy.json.br
* 1149 murphy.json.gz

To force loading one of the 2 files format, if it is supported by borwer (I mean if it supports both), Brotli (.br) will be used, with Nginx (after compiled it with the Brotli patch, rules in the Nignx configuration files are realy simples:

brotli_static on;
gzip_static on;

With Apache, Brotli is here by default in versions 2.4, but it’s a bit harder to manage.

To test their support, Curl can be used:

curl -I -H 'Accept-Encoding: gzip, deflate, br' https://host.net/fichier.svg

If brotli is really activated, you will receive the following line in the answer:

content-encoding: br

Telegram Bot

The Python-Lottie library come just right for me, I would like to study Python, including for micropython, used in embedded world and for my work of System and Network administrator, where it is more and more used, replacing step by step Perl, and with some tools like Ansible an automation paltform used to manage computer farms, as well as more and more other basic system tools. After about one year of experience with procedural generation in Lua give me some willing to do this with other languages too (I’m currently preparing a suprise for soon). There are several bot libraries for Telegram in Python, including Python Telegram Bot, that follow well the official Telegram API, and Telethon (Documentation) that allow to communiatte directly in MTproto, the Telegram protocole, instead of using HTTP layer. This reduce one layer and allow a more fine control of exchanges. You can read here about the differences between Bot API (HTTP vs MT Proto).


There are still not too much examples with Python’s Telegram bot, that I started with, but by digging a bit in documentation, it is possible to find what’s needed. By mixing Python-Lottie for procedural generation, Glaxnimate for hand made animation, and the bot there is some interesting possibilities that open. I so made a first Python-Telegram-Bot bot. After some exchanges with Glax, the author of Glaxnimate, he let me know the Telethon Python module, that it uses for its bot, that has some similarities with what I want. It’s called Glaxcomm, and generate Lottie/TGS on the fly. I hope I will manage (time+willing) to rebuild my bot with this module and I hope I can get it where I want it. My next goal would be to be able to use it with other protocols, including ActivityPub (W3C specifications).

Glax made a good set of basic procedural generation examples that greatly help to understand it’s usage, a good documantation about Lottie format, stickers scripts examples.

I started by make a simple bot from python-telegram-bot library examples, but complete explanation about how to use file_id was missing (and I didn’t found them around the net). This is the methode Telegram promote to to send file, by it’s Id instead of sending several times the same file. The file_id is given by Telegram when a file is sent. So ideal method is to keep the ID of already succefuly sent files in a database or a file on the disk. This example create a file containing the ID beside image file, this is probably a bit better to have thei ID in a database (SQL or TOML) :

if os.path.exists(idfile):
  fid = open(idfile)
  stickid = fid.read()
  fid.close()
  msg = update.message.reply_sticker(stickid)
else:
  msg = update.message.reply_sticker(open(stickfile, 'rb'))
  fid = open(idfile, 'w')
  fid.write(msg['sticker']['file_id'])
  fid.close()

Compiler OpenToonz sur Linux avec l’état actuel cassé (septembre 2017)

voir pour le bug report sur le compte Github d’OpenToonz.

git clone https://github.com/opentoonz/opentoonz.git
cd opentoonz
git checkout 14f0fd28bbeec42dfcebcebe59b858931eaeb881
mkdir -p $HOME/.config/OpenToonz
cp -r opentoonz/stuff $HOME/.config/OpenToonz/
cat « EOF > $HOME/.config/OpenToonz/SystemVar.ini
[General]
OPENTOONZROOT="$HOME/.config/OpenToonz/stuff"
OpenToonzPROFILES="$HOME/.config/OpenToonz/stuff/profiles"
TOONZCACHEROOT="$HOME/.config/OpenToonz/stuff/cache"
TOONZCONFIG="$HOME/.config/OpenToonz/stuff/config"
TOONZFXPRESETS="$HOME/.config/OpenToonz/stuff/projects/fxs"
TOONZLIBRARY="$HOME/.config/OpenToonz/stuff/projects/library"
TOONZPROFILES="$HOME/.config/OpenToonz/stuff/profiles"
TOONZPROJECTS="$HOME/.config/OpenToonz/stuff/projects"
TOONZROOT="$HOME/.config/OpenToonz/stuff"
TOONZSTUDIOPALETTE="$HOME/.config/OpenToonz/stuff/projects/studiopalette"
EOF
cd thirdparty/tiff-4.0.3
./configure —with-pic —disable-jbig
make -j4 # choisir le nombre de cœurs
cd ../../toonz
mkdir build
cmake ../sources
make -j4 # choisir le nombre de cœurs
sudo make install # Va aller dans /opt/opentoonz/bin/opentoonz