{"id":20850423,"url":"https://github.com/noteed/videos","last_synced_at":"2026-04-24T12:31:33.111Z","repository":{"id":66654586,"uuid":"345343328","full_name":"noteed/videos","owner":"noteed","description":"How I record videos, in particular The Nix recordings","archived":false,"fork":false,"pushed_at":"2023-01-02T11:55:06.000Z","size":36,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-15T05:39:35.240Z","etag":null,"topics":["nix","nixos"],"latest_commit_sha":null,"homepage":"https://noteed.com/videos/","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/noteed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-07T12:40:09.000Z","updated_at":"2021-03-07T20:49:24.000Z","dependencies_parsed_at":"2023-02-21T13:45:49.484Z","dependency_job_id":null,"html_url":"https://github.com/noteed/videos","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/noteed/videos","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noteed%2Fvideos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noteed%2Fvideos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noteed%2Fvideos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noteed%2Fvideos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/noteed","download_url":"https://codeload.github.com/noteed/videos/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noteed%2Fvideos/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32223818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T10:26:35.452Z","status":"ssl_error","status_checked_at":"2026-04-24T10:25:27.643Z","response_time":64,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nix","nixos"],"created_at":"2024-11-18T03:09:26.924Z","updated_at":"2026-04-24T12:31:33.106Z","avatar_url":"https://github.com/noteed.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Videos\n\nNotes about recording videos (for YouTube), in particular my Nix recordings\nseries.\n\nThe `nix-rec/index.md` file is rendered at `https://noteed.com/videos/`.\n\nVideos are uploaded to\nhttps://www.youtube.com/channel/UCnFhDQZWUBKHfIOHxUXlTsA.\n\n\n# Listing\n\n- [The Nix recording #1 - Creating a virtual machine with\n  doctl](nix-rec/01-create-droplet/README.md) - [View on\n  YouTube](https://www.youtube.com/watch?v=LeasCiM0NRI)\n\n\n# Precautions\n\n- Make sure the `direnv` hook is loaded. Digital Ocean credentials are present\n  in the `digitalocean/.envrc file`, and thus in the environment variables.\n  They should not be leaked.\n- Use the `list-droplets.sh` script:\n  - To make sure a `nix-rec` Droplet doesn't already exist (otherwise the\n    scripts may try to connect to the wrong VM).\n  - To make sure the VM is deleted and doesn't incure additional costs.\n- Make sure the SSH key is loaded in the SSH agent.\n- Sometimes, the SSH `known_hosts` file already contains the VM that we are\n  creating, which will conflict with the fact we expect to have to accept the\n  new host key.\n\n\n# Checklist\n\n- Make sure `noteed.com/videos` has a dedicated page per video (a link to\n  YouTube, and a transcript)\n- Make sure the description is filled on YouTube, possibly updated with links\n  to the next videos.\n- Add subtitles within the YouTube web interface.\n\n\n# Terminal recording\n\n```\n$ cd digitalocean/\n$ ../nix-rec/01-create-droplet/render.sh\n$ cd ../nix-rec/01-create-droplet/\n$ ./assemble.sh\n```\n\nThe last step, `assemble.sh`, generates an MP4 video from a series of PNGs. In\naddition of the PNGs generated by termtosvg, it also adds the frames for the\ntitle sequence, which is generated in `00-title-youtube`. \n\nThe last step uses a `listing.txt` file to control the duration of each image.\nThis is further manually edited to introduce additional delays, to allow the\nnecessary room for the voice over.\n\n\n# Voice recording\n\n```\n$ ffmpeg -y -nostdin -hide_banner -f alsa -i default voice.wav\n```\n\nHit `Ctrl-C` to stop the recording.\n\n\n# Removing background noise\n\nUsing SoX, the three steps are as follow.\n\n- Record a `noise.wav` file, as you would do for the voice to capture the\n  ambiant sounds\n- Build a noise profile\n- Apply the profile to the voice file with a value around 0.20-0.30.\n\n```\n$ ffmpeg -y -nostdin -hide_banner -f alsa -i default noise.wav\n$ sox noise.wav -n noiseprof noise.profile\n$ sox voice.wav filtered.wav noisered noise.profile 0.30\n```\n\n- The command above are based on\n  https://unix.stackexchange.com/questions/140398/.\n- ffmpeg has some options I have to try:\n  https://superuser.com/questions/733061/.\n\n\n# Multiple audio files\n\nIt should be possible to split a longer file containing pauses (silences). But\nI need to find the right values first.\n\n```\n$ sox -V3 voice-1.wav splitted.wav silence 1 2.0 0.5% 1 0.3 0.5% : newfile : restart\n```\n\nSo instead I use the `./record-voice.sh` script, which creates a new file with\na timestamp in the filename, so that I can call it repeatedly. I'd like to use\nmaybe an XBox controller to record/stop, to avoid hearing my keyboard when I\nhit Ctrl-C.\n\nConcatenate multiple files in one:\n\n```\n$ sox sentences/filtered-161460*wav voice-over.wav\n```\n\nTo sync the above voice over files with the video, I generate silences, that I\nname in such a way they are listing in the right spot in the `filtered-*.wav`\nabove. E.g. for 8 seconds of silence:\n\n```\n$ sox -n -b 16 -r 48000 -c 2 silence-8-seconds.wav trim 0.0 8.0\n```\n\nAlternatively I guess I can import all the voice over files at a time in\nBlender and move them around.\n\n\n# Merge audio and video\n\n```\n$ ffmpeg -i video.mp4 -i voice-over.wav \\\n  -c:v copy -c:a aac -filter:a volume=6dB \n  video-voice-over.mp4\n```\n\nThe `-filter:a volume=6dB` is optional and makes the audio a bit louder.\n\n\n# Video editing\n\nTo place a yellow highlighting line over some characters in the video, I\ngenerate MP4s that are overlayed in Blender on top of the main video.\n\n- Go to the right frame\n- Add a \"Movie\"\n- Add a \"Transform\" effect strip (which is linked to the Movie)\n- The Transform is used to place the Movie in the correct spot, and possibly\n  stretch it\n- In Adjust, Compositing, select the Darken Blend mode\n- I have to select the \"bicubic\" interpolation instead of the default\n  \"bilinear\" because the later results in a rendering artefact: a black border\n  appears around the overlayed video.\n\nSee the [`highlighter/`](highlighter/) directory for the MP4 files.\n\n\n# YouTube brand account\n\nIf you have a Google account, you already have a YouTube account. To use a\ndifferent account to publish videos, you have to create a \"brand\" account.\n\nThis is done through the YouTube web interface (this is not available on the\nAndroid app) by creating a new channel, which allows to create a brand account.\n\nLong story short, my brand account is \"noteed\" (although this can be easily\nrenamed), and its URL is\nhttps://www.youtube.com/channel/UCnFhDQZWUBKHfIOHxUXlTsA.\n\n\n# Profile picture\n\nYou can set a profile picture on this page\nhttps://studio.youtube.com/channel/UCnFhDQZWUBKHfIOHxUXlTsA/editing/images.\n\nIn my case, I have made a simple SVG file that I exported as PNG:\n\n```\n$ inkscape -w 512 -h 512 letter-n.svg --export-filename letter-n.png\n```\n\nTODO: I tried to use `IBM Plex Mono` but I don't think it worked. Anyway, the\nmonospace font I use in xterm, and thus that I want to replicate in my\nrecordings,  is `DejaVu Sans Mono for Powerline`, so I have to change that.\n\n\n# Title image\n\nFor each video, it is possible to choose a specific frame to represent the\nvideo in listings, but it is also possible to upload an image. Just like for\nthe profile picture, I tried to do a simple SVG, which again is exported as\nPNG.\n\n```\n$ inkscape title.svg --export-filename title.png -b '#ffffff' -y 255\n```\n\nThe `-b` option specifies a background color, and the `-y` specifies the\nbackground opacity.\n\nThat title image is actually used as the last frame for the title sequence.\n\n\n# Title sequence\n\nThe title sequences for each video are created in the same way. The scripts and\nnecessary assets are in the\n[`nix-rec/00-title-youtube/`](nix-rec/00-title-youtube/) directory.\n\n\n# Interactive terminal setup\n\nOn my laptop, I'm using two side-by-side xterm windows. As it happens, I have\n91 columns (each). (And I have 51 lines.)\n\nThe following two commands results in a 91x24 terminal, with a nice border,\nsuitable for \"live\" recording, or streaming:\n\n```\n$ xterm -b 142 -fa 'DejaVu Sans Mono for Powerline' -fs 14\n$ kitty -o include=~/projects/learn-kitty/CLRS.conf \\\n    -o font_size=14 -o window_padding_width=45.0 -o enable_audio_bell=no\n```\n\nThe results are similar, although there is a small vertical difference.\n\n\n# Scripted terminal setup\n\nBy modifying termtosvg's source code, I've been able to replicate closely the\nabove kitty or xterm terminal setups. The modifications are at\nhttps://github.com/noteed/termtosvg.\n\nI'm rendering individual frames at 2560x1440 (just like my laptop screen),\nconvert them to PNGs using inkscape, then assemble them as an MP4 video using\nffmpeg.\n\nThe interaction during termtosvg recording is scripted using a GNU Screen\nsession and sending it commands, or using expect. The former is useful for\nsomething like Vim, while the later is useful if I have to enter some input\nonly when some specific output has been read.\n\nI guess it is possible to further alter termtosvg to recognise some output and\nlet it enter the input itself at the right time.\n\nNote: I had to create a `.screenrc` to get correct colors within screen.\n\n\n# Weight\n\nIn a very simple test, where I run Vim (which shows its title screen), insert\n\"Hello.\", then quit with \":q\":\n\n- The MP4 video: 140K\n- The 19 frames as SVGs: 144K\n- The 19 frames as PNGs: 988K\n\n\n# Normal terminal\n\nI'm trying to replicate my normal xterm terminal with kitty:\n\n```\n$ kitty -o include=~/projects/learn-kitty/CLRS.conf -o font_size=8 -o window_padding_width=0 -o enable_audio_bell=no -o window_border_width=0 -o window_margin_width=0 -o placement_strategy=top-left -o draw_minimal_borders=no\n```\n\nSome options are not needed. The `placement_strategy` seems interesting; I\nshould try it for the presentation case.\n\n\n# Other approaches\n\n- https://news.ycombinator.com/item?id=21751395, which mentions ttyrec.\n- https://intoli.com/blog/terminal-recorders/#conclusion\n- https://github.com/jwodder/ttyrec2video\n- https://github.com/LegNeato/asciinema-rs. This uses pty-shell, which might be\n  handy to instrument a shell.\n- https://github.com/marionebl/svg-term-cli\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoteed%2Fvideos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoteed%2Fvideos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoteed%2Fvideos/lists"}