diff --git a/Makefile b/Makefile
index f41c0962e0c22b9375f2eacb25e272444fb31ada..e02faf1570b6b74d44e37de52a1a44b2ef903e02 100644
--- a/Makefile
+++ b/Makefile
@@ -59,6 +59,7 @@ $(MARKDOWN): %.markdown: 00_macros.md %.md 10_footer.md
 deploy: all
 	mkdir -p phys
 	mkdir -p phys/planets
+	mkdir -p phys/field_lines
 	cp cours.html phys/index.html
 	cp cours.pdf phys/cours.pdf
 	make -C exercices
@@ -75,6 +76,11 @@ deploy: all
 	cp practical_work/planets/*.pdf phys/planets/
 	cp practical_work/planets/*.html phys/planets/
 	cd practical_work/planets && tar czvf skeleton.tar.gz skeleton && cp *.gz ../../phys/planets
+	cd ..
+	make -C practical_work/electric_fl
+	cp practical_work/electric_fl/*.pdf phys/field_lines/
+	cp practical_work/electric_fl/*.html phys/field_lines/
+	cd practical_work/electric_fl && tar czvf utils.tar.gz utils && cp *.gz ../../phys/field_lines
 
 
 clean:
diff --git a/practical_work/electric_fl/.gitignore b/practical_work/electric_fl/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1eaef2cb14a56a92ab516ecd669e47dcd92178d6
--- /dev/null
+++ b/practical_work/electric_fl/.gitignore
@@ -0,0 +1 @@
+!electric_field.pdf
\ No newline at end of file
diff --git a/practical_work/electric_fl/enonce.md b/practical_work/electric_fl/enonce.md
index 008d0005a971dead27c9e140966fd96036c5db5b..6d09cec54e6871f4736274e49331619e5c174ad6 100644
--- a/practical_work/electric_fl/enonce.md
+++ b/practical_work/electric_fl/enonce.md
@@ -29,7 +29,7 @@ urlcolor: blue
 # Rappel théorique
 
 Comme nous l'avons vu en classe, chaque particule possédant une charge $Q$
-induit un champs $E$ qui modifie l'espace autour d'elle. Il est possible de
+induit un champs $E$ qui influe sur l'espace autour d'elle. Il est possible de
 représenter ce champs électrique à l'aide d'un champs de vecteur. Lorsque que
 l'on a une seule particule chargée, chaque vecteur décrit en un point l'action
 induite par la particule chargée à cette distance. L'intensité de ce champs à
@@ -43,7 +43,7 @@ particule.
 
 ![Champs de vecteurs représentant de champs électrique d'une charge positive.
 Source: Wikipédia,
-<https://bit.ly/3kUEcGu>.](https://upload.wikimedia.org/wikipedia/commons/f/f0/E_FieldOnePointCharge.svg){#fig:champ_e
+<https://bit.ly/3kUEcGu>.](figs/electric_field.pdf){#fig:champ_e
 width=50%}
 
 En réalité, on rencontre souvent (très souvent) plus d'une particule chargée,
@@ -54,16 +54,16 @@ chacune de nos particules chargées.
 Une autre représentation du champs électrique peut se faire à l'aide de courbes
 appelées lignes de champs.
 
-![Lignes de champs électrique reliant en présence de deux charges positives
-(gauche) et une charge négative et une positive (droite). Les lignes de champs
+![Lignes de champs électrique en présence de deux charges positives
+(gauche) et deux charges opposées (droite). Les lignes de champs
 sont sortantes de la charge positive, et entrantes dans la charge négative.
 Source: Wikipédia,
-<https://bit.ly/3dPsUk2>.](https://upload.wikimedia.org/wikipedia/commons/8/8f/Camposcargas.PNG){#fig:plus_minus_field
+<https://bit.ly/3dPsUk2>.](figs/two_particles_field.png){#fig:plus_minus_field
 width=80%}
 
 Pour réaliser cette simulation numérique, nous devons commencer par définir
 notre univers discret. Dans le cadre de ce travail, notre univers est un
-rectangle $[0,1]\times[0,1]$.
+rectangle $[0;1]\times[0;1]$.
 
 Chaque particule possède une position appartenant à notre univers, ainsi qu'une
 charge (multiple de la charge élementaire).
@@ -132,8 +132,8 @@ void gfx_draw_circle(struct gfx_context_t *ctxt, coordinates_t c,
 Pour tester votre fonction de dessin de droites, vous dessinerez dans une
 fenêtre de 100x100 les droites suivantes :
 
-- $(50,50) \rightarrow (75,50)$, $(50,50) \rightarrow (72,62)$, $(50,50)
-  \rightarrow (62,72)$
+- $(50,50) \rightarrow (75,50)$^[Le segment reliant le point $(x_0,y_0)$ au
+point $(x_1,y_1)$], $(50,50) \rightarrow (72,62)$, $(50,50) \rightarrow (62,72)$
 - $(50,50) \rightarrow (50,75)$, $(50,50) \rightarrow (38,72)$, $(50,50)
   \rightarrow (28,62)$
 - $(50,50) \rightarrow (25,50)$, $(50,50) \rightarrow (28,38)$, $(50,50)
diff --git a/practical_work/electric_fl/figs/electric_field.pdf b/practical_work/electric_fl/figs/electric_field.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..b21029c8e5c304df2a9e5c2b1bb34d62425ec6cf
Binary files /dev/null and b/practical_work/electric_fl/figs/electric_field.pdf differ
diff --git a/practical_work/electric_fl/figs/two_particles_field.png b/practical_work/electric_fl/figs/two_particles_field.png
new file mode 100644
index 0000000000000000000000000000000000000000..2a5dd0b3fb7b5caff2f025e9df2c079069765e6f
Binary files /dev/null and b/practical_work/electric_fl/figs/two_particles_field.png differ
diff --git a/practical_work/electric_fl/utils/gfx/gfx.c b/practical_work/electric_fl/utils/gfx/gfx.c
new file mode 100644
index 0000000000000000000000000000000000000000..cd6662f178c2bc3eb8326efae92ca7fa7436c1c6
--- /dev/null
+++ b/practical_work/electric_fl/utils/gfx/gfx.c
@@ -0,0 +1,105 @@
+/// @file gfx.c
+/// @author Florent Gluck
+/// @date November 6, 2016
+/// Helper routines to render pixels in fullscreen graphic mode.
+/// Uses the SDL2 library.
+
+#include "gfx.h"
+#include <assert.h>
+
+/// Create a fullscreen graphic window.
+/// @param title Title of the window.
+/// @param width Width of the window in pixels.
+/// @param height Height of the window in pixels.
+/// @return a pointer to the graphic context or NULL if it failed.
+struct gfx_context_t *gfx_create(char *title, uint32_t width, uint32_t height)
+{
+    if (SDL_Init(SDL_INIT_VIDEO) != 0)
+        goto error;
+    SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED,
+                                          SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_RESIZABLE);
+    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
+    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
+                                             SDL_TEXTUREACCESS_STREAMING, width, height);
+    uint32_t *pixels = malloc(width * height * sizeof(uint32_t));
+    struct gfx_context_t *ctxt = malloc(sizeof(struct gfx_context_t));
+
+    if (!window || !renderer || !texture || !pixels || !ctxt)
+        goto error;
+
+    ctxt->renderer = renderer;
+    ctxt->texture = texture;
+    ctxt->window = window;
+    ctxt->width = width;
+    ctxt->height = height;
+    ctxt->pixels = pixels;
+
+    SDL_ShowCursor(SDL_DISABLE);
+    gfx_clear(ctxt, COLOR_BLACK);
+    return ctxt;
+
+error:
+    return NULL;
+}
+
+/// Draw a pixel in the specified graphic context.
+/// @param ctxt Graphic context where the pixel is to be drawn.
+/// @param column X coordinate of the pixel.
+/// @param row Y coordinate of the pixel.
+/// @param color Color of the pixel.
+void gfx_putpixel(struct gfx_context_t *ctxt, uint32_t column, uint32_t row, uint32_t color)
+{
+    if (column < ctxt->width && row < ctxt->height)
+        ctxt->pixels[ctxt->width * row + column] = color;
+}
+
+/// Clear the specified graphic context.
+/// @param ctxt Graphic context to clear.
+/// @param color Color to use.
+void gfx_clear(struct gfx_context_t *ctxt, uint32_t color)
+{
+    int n = ctxt->width * ctxt->height;
+    while (n)
+        ctxt->pixels[--n] = color;
+}
+
+/// Display the graphic context.
+/// @param ctxt Graphic context to clear.
+void gfx_present(struct gfx_context_t *ctxt)
+{
+    SDL_UpdateTexture(
+        ctxt->texture, NULL, ctxt->pixels, ctxt->width * sizeof(uint32_t));
+    SDL_RenderCopy(ctxt->renderer, ctxt->texture, NULL, NULL);
+    SDL_RenderPresent(ctxt->renderer);
+}
+
+/// Destroy a graphic window.
+/// @param ctxt Graphic context of the window to close.
+void gfx_destroy(struct gfx_context_t *ctxt)
+{
+    SDL_ShowCursor(SDL_ENABLE);
+    SDL_DestroyTexture(ctxt->texture);
+    SDL_DestroyRenderer(ctxt->renderer);
+    SDL_DestroyWindow(ctxt->window);
+    free(ctxt->pixels);
+    ctxt->texture = NULL;
+    ctxt->renderer = NULL;
+    ctxt->window = NULL;
+    ctxt->pixels = NULL;
+    SDL_Quit();
+    free(ctxt);
+}
+
+/// If a key was pressed, returns its key code (non blocking call).
+/// List of key codes: https://wiki.libsdl.org/SDL_Keycode
+/// @return the key that was pressed or 0 if none was pressed.
+SDL_Keycode gfx_keypressed()
+{
+    SDL_Event event;
+    if (SDL_PollEvent(&event))
+    {
+        if (event.type == SDL_KEYDOWN)
+            return event.key.keysym.sym;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/practical_work/electric_fl/utils/gfx/gfx.h b/practical_work/electric_fl/utils/gfx/gfx.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d9d13a965b264265a47243d650b7a5965a92b81
--- /dev/null
+++ b/practical_work/electric_fl/utils/gfx/gfx.h
@@ -0,0 +1,40 @@
+#ifndef _GFX_H_
+#define _GFX_H_
+
+#include <SDL2/SDL.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#define MAKE_COLOR(r, g, b) \
+    ((uint32_t)b | ((uint32_t)g << 8) | ((uint32_t)r << 16))
+
+#define COLOR_GET_B(color) (color & 0xff)
+#define COLOR_GET_G(color) ((color >> 8) & 0xff)
+#define COLOR_GET_R(color) ((color >> 16) & 0xff)
+
+#define COLOR_BLACK 0x00000000
+#define COLOR_RED 0x00FF0000
+#define COLOR_GREEN 0x0000FF00
+#define COLOR_BLUE 0x000000FF
+#define COLOR_WHITE 0x00FFFFFF
+#define COLOR_YELLOW 0x00FFFF00
+
+struct gfx_context_t
+{
+    SDL_Window *window;
+    SDL_Renderer *renderer;
+    SDL_Texture *texture;
+    uint32_t *pixels;
+    uint32_t width;
+    uint32_t height;
+};
+
+extern void gfx_putpixel(
+    struct gfx_context_t *ctxt, uint32_t column, uint32_t row, uint32_t color);
+extern void gfx_clear(struct gfx_context_t *ctxt, uint32_t color);
+extern struct gfx_context_t *gfx_create(char *text, uint32_t width, uint32_t height);
+extern void gfx_destroy(struct gfx_context_t *ctxt);
+extern void gfx_present(struct gfx_context_t *ctxt);
+extern SDL_Keycode gfx_keypressed();
+
+#endif
diff --git a/practical_work/electric_fl/utils.c b/practical_work/electric_fl/utils/utils.c
similarity index 100%
rename from practical_work/electric_fl/utils.c
rename to practical_work/electric_fl/utils/utils.c
diff --git a/practical_work/electric_fl/utils.h b/practical_work/electric_fl/utils/utils.h
similarity index 100%
rename from practical_work/electric_fl/utils.h
rename to practical_work/electric_fl/utils/utils.h