{"id":19273742,"url":"https://github.com/thisdougb/typetastic","last_synced_at":"2026-06-08T23:32:14.518Z","repository":{"id":62585958,"uuid":"256501683","full_name":"thisdougb/typetastic","owner":"thisdougb","description":"Python utility to make recording screencasts easier.","archived":false,"fork":false,"pushed_at":"2020-05-16T12:41:14.000Z","size":224,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-28T08:40:02.220Z","etag":null,"topics":["automation","python","robot","screencast","tutorial","video-tutorial"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/typetastic/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thisdougb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-17T12:50:27.000Z","updated_at":"2024-05-09T16:49:53.000Z","dependencies_parsed_at":"2022-11-03T22:07:29.470Z","dependency_job_id":null,"html_url":"https://github.com/thisdougb/typetastic","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/thisdougb/typetastic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thisdougb%2Ftypetastic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thisdougb%2Ftypetastic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thisdougb%2Ftypetastic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thisdougb%2Ftypetastic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thisdougb","download_url":"https://codeload.github.com/thisdougb/typetastic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thisdougb%2Ftypetastic/sbom","scorecard":{"id":881636,"data":{"date":"2025-08-11","repo":{"name":"github.com/thisdougb/typetastic","commit":"7ce23732ba436cbb043a74b503fc5ab7bcaee6d2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.1,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/12 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":3,"reason":"7 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2021-142 / GHSA-8q59-q68h-6hv4","Warn: Project is vulnerable to: PYSEC-2018-49 / GHSA-rprw-h62v-c2w7","Warn: Project is vulnerable to: PYSEC-2013-22 / GHSA-27x4-j476-jp5f","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: PYSEC-2022-43012 / GHSA-r9hx-vwmv-q579","Warn: Project is vulnerable to: PYSEC-2022-43017 / GHSA-qwmp-2cf2-g9g6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T08:25:55.573Z","repository_id":62585958,"created_at":"2025-08-24T08:25:55.573Z","updated_at":"2025-08-24T08:25:55.573Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34085321,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["automation","python","robot","screencast","tutorial","video-tutorial"],"created_at":"2024-11-09T20:43:57.615Z","updated_at":"2026-06-08T23:32:14.502Z","avatar_url":"https://github.com/thisdougb.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TypeTastic\n[![thisdougb](https://circleci.com/gh/thisdougb/typetastic.svg?style=shield)](https://circleci.com/gh/thisdougb/typetastic)\n\nPython utility to make creating screencasts easier, and doing live demo's less stressful.\n```\n$ pip install typetastic\n```\n\n## Intro\nA while back I did some Ansible training sessions, for which I did some screen recordings.\nFrustrated by the time it takes to make a screen capture look good, I built a little robot to help.\nThe bot runs the commands for me, so I am able to record perfectly paced typing in a repeatable way.\n\nI'm doing some more training sessions, so I thought I'd clean up the project and open-source it.\nFeedback welcome, just log an issue.\n\nMain features:\n* No more typos in your screen recordings!\n* Let the bot do your show-and-tell demo, while you focus on your audience\n* Define a list of commands, and replay as often as you like.\n* SSH into other hosts and run stuff.\n* Choose the typing speed, and color the commands for clarity.\n* Config and commands live together, so building a library is easy.\n\nWhat this is not:\n* A video recording tool.\n* An orchestration tool.\n* A way to skive at work by having the bot do your bidding! 😈\n\nThere's a video [here on Vimeo](https://vimeo.com/224764672) of the screencast I did that led me to building this tool.\nIt shows examples of most features.\n## Hello World\nFirst up, we can do the easy example.\nTypeTastic uses a Robot to type commands for you.\nIn the simplest form you can pass the commands in as an array.\n\nLook here, in Python's interactive mode:\n```\n% python\nPython 3.8.2 (default, Mar 11 2020, 00:29:50)\n\u003e\u003e\u003e import typetastic\n\u003e\u003e\u003e robot = typetastic.Robot()\n\u003e\u003e\u003e robot.load(['ls', 'echo \"Hello World\\!\"'])\n\u003e\u003e\u003e robot.run()\n$ ls\nLICENSE\t\t\tbuild\t\t\tdist\t\t\tnosetests.json\t\tsetup.py\t\ttypetastic\nREADME.md\t\tdeploy_locally.sh\texamples\t\tpackage_admin.md\ttests\t\t\ttypetastic.egg-info\n$ echo \"Hello World!\"\nHello World!\n\u003e\u003e\u003e\n```\n## Something Useful\nNow we see the gist of it, we can do something more useful.\nTo run TypeTastic command files, I use this simple runner script.\n```\n# tt-robot.py\n#\n# Run a typetastic command file.\n#\n# Usage:\n#   tt-robot.py \u003cfile\u003e\n\nimport argparse\nimport typetastic\n\n\ndef main():\n    \"\"\"Run a typetastic file.\"\"\"\n\n    arg_parser = argparse.ArgumentParser()\n    arg_parser.add_argument(\"inputfile\")\n    args = arg_parser.parse_args()\n\n    robot = typetastic.Robot()\n    robot.load(args.inputfile)\n    robot.run()\n\n\nif __name__ == \"__main__\":\n    main()\n```\nLet's say we want to show Mac OSX users how to find their shell profile.\n\nOur yaml file has a config and a commands section.\nThe config section has defaults, so it's optional.\nThe commands are simply listed as you'd type them.\n```\n# ./tt-something-useful.yaml\n\nconfig:\n    prompt-string: \"$ \"\n    typing-color: cyan\n    typing-speed: moderate\n\ncommands:\n    - echo ~\n    - ls -l ~/.zshrc\n    - cat ~/.zshrc\n```\nWhen we run this:\n```\ndougb % python examples/tt-robot.py examples/tt-something-useful.yaml\n$ echo ~\n/Users/dougb\n$ ls -l ~/.zshrc\n-rw-r--r--  1 dougb  staff  93 13 Mar 09:14 /Users/dougb/.zshrc\n$ cat ~/.zshrc\nexport GPG_TTY=$(tty)\nexport PATH=\"/usr/local/opt/python@3.8/bin:$PATH\"\nalias python=python3\n$\n```\n## Config\nThe config options are fairly simple.\n\n#### Prompt String\nKeep it simple is my advice.\nPlain strings are good, complicated escape codes are less good.\n\n#### Typing Color\nThe options are: black, red, green, yellow, blue, purple, cyan, white.\n\nAdditional modifiers are \u003ci\u003ebold\u003c/i\u003e and \u003ci\u003ebright\u003c/i\u003e.\nThese can be used as, \u003ci\u003ebold-green\u003c/i\u003e or \u003ci\u003ebold-bright-green\u003c/i\u003e.\n\n#### Typing Speed\nThe options are: slow, moderate, supersonic.\n\nSupersonic is great for testing.  🚀\n\n## Meta Commands\nScreen recording often requires stitching together video clips, or pausing for a voice-over.\nSo I added a couple of meta commands to help with the mechanics of making a great video.\n\n#### NEWLINE\nThis does what is says, just prints a new line with the prompt.\nIt has the same effect as pressing \u003ci\u003ereturn\u003c/i\u003e in a real session.\n\nI use this mainly to create whitespace around something to make it clearer for the viewer.\nFor example, when you cat some files, a blank line often helps visually separate them.\n```\n# using NEWLINE\n\ncommands:\n    - clear\n    - cat ~/.aws/credentials\n    - NEWLINE\n    - cat ~/.aws/config\n    - NEWLINE\n    - aws sts get-caller-identity\n```\n#### PAUSE\nIn this example of using AWS CLI, we use the meta command PAUSE.\nThis will pause the robot until a key is pressed.\n\nI find this useful on two counts.\nFirst to give time to give a voice-over explanation of the config files.\nA pause makes it easier to cut the recording in iMovie, etc.\n\nAnd second, in a parallel (not recorded) terminal window I can copy in fake .aws files so I don't show my real credentials.\nThis is a nifty use of PAUSE that helps make real use cases in a safe way.\nIt avoids having to blur or block-out passwords, etc.\n```\n# using PAUSE\n\ncommands:\n    - clear\n    - cat ~/.aws/credentials\n    - NEWLINE\n    - cat ~/.aws/config\n    - NEWLINE\n    - PAUSE\n    - aws sts get-caller-identity\n    - PAUSE\n```\nJust tap a key to resume the bot.\n## Editor Commands\nEditors are tricky for the bot.\nBy tricky I mean it's impossible to automate an interactive editor (vi, emacs, etc) session.\n\nSo I made editor commands simply call PAUSE instead.\nThis lets you splice into your screencast a second screen recording of just the editor session.\n\nRecording an editor session still needs to be done manually.\nBut, it will be a much smaller overall effort (using TypeTastic for the bulk of the work).\nAnd what you do in an editor typically isn't reliant on a smooth typing pace for longer commands.\n\nThe key thing here is that after you splice the editor clip into the main screencast, it visually just flows.\nThe visible shell history makes logical sense, just like you exited the editor for real.\n\nRemember to tap a key to resume the bot.\n\nDetected editor commands are:\n* vi\n* emacs\n* crontab\n\nThis is maybe best with a video example.\nIn [this screencast](https://vimeo.com/413113839) I use the technique to edit the crontab.\nI recorded the crontab edit afterwards, and spliced it into the main screen recording.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthisdougb%2Ftypetastic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthisdougb%2Ftypetastic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthisdougb%2Ftypetastic/lists"}