{"id":15616985,"url":"https://github.com/titaniumbones/twelvety","last_synced_at":"2026-04-24T09:32:34.720Z","repository":{"id":141872381,"uuid":"502499933","full_name":"titaniumbones/twelvety","owner":"titaniumbones","description":null,"archived":false,"fork":false,"pushed_at":"2022-06-12T02:25:07.000Z","size":2445,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-08T03:56:31.789Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/titaniumbones.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2022-06-12T02:23:13.000Z","updated_at":"2022-06-12T02:25:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"e8cbe26b-953a-4525-ad20-6c199eb95be2","html_url":"https://github.com/titaniumbones/twelvety","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/titaniumbones/twelvety","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/titaniumbones%2Ftwelvety","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/titaniumbones%2Ftwelvety/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/titaniumbones%2Ftwelvety/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/titaniumbones%2Ftwelvety/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/titaniumbones","download_url":"https://codeload.github.com/titaniumbones/twelvety/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/titaniumbones%2Ftwelvety/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32216915,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T08:24:32.376Z","status":"ssl_error","status_checked_at":"2026-04-24T08:24:26.731Z","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":[],"created_at":"2024-10-03T07:40:38.991Z","updated_at":"2026-04-24T09:32:29.713Z","avatar_url":"https://github.com/titaniumbones.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🕛 Twelvety\n\n[See the demo site](https://twelvety.netlify.app)\n\nTwelvety is a pre-configured Eleventy starter project built to be fast. It includes:\n\n- Component architecture\n- CSS pipeline using Sass, PostCSS and CleanCSS\n- JS pipeline using Browserify, Babel and Uglify\n- Page-specific CSS and JS\n- Inline critical CSS and defer non-critical CSS\n- Minified HTML, CSS and JS\n- Responsive picture shortcode **with AVIF and WebP support**\n- Content-hash of assets\n\nWrite components like this:\n\n```html\n\u003cmain class=\"home\"\u003e\n  \u003ch1 class=\"home__title\"\u003eTwelvety\u003c/h1\u003e\n\u003c/main\u003e\n\n{% stylesheet 'scss' %}\n  @import \"mixins\";\n\n  .home {\n    @include container;\n\n    \u0026__title {\n      color: red;\n    }\n  }\n{% endstylesheet %}\n\n{% javascript %}\n  console.log(\"Super fast 💨\");\n{% endjavascript %}\n```\n\n## Deploy to netlify\n\nTo quickly deploy your own instance of Twelvety to netlify, just click the button below and follow the instructions.\n\n[![Deploy to netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gregives/twelvety)\n\n**What will happen when I click this button?** Netlify will clone the Twelvety git repository to your GitHub account (it will ask your permission to do this), add the new repository to your netlify account and deploy it!\n\n## Run Locally\n\nClick the \u003ckbd\u003eUse this template\u003c/kbd\u003e button at the top of this repository to make your own Twelvety repository in your GitHub account. Clone or download your new Twelvety repository onto your computer.\n\nYou'll need [Node.js](https://nodejs.org) and npm (included with Node.js). To install the required packages, run\n\n```sh\nnpm install\n```\n\n### Commands\n\n- Run `npm run serve` to run a development server and live-reload\n- Run `npm run build` to build for production\n- Run `npm run clean` to clean the output folder and Twelvety cache\n\nThe brains of Twelvety live in the `utils` folder: if you just want to make a website, then you don't need to touch anything inside `utils`. However, if you want to change any of the shortcodes, have a look around!\n\n## Features\n\nTwelvety sets up transforms, shortcodes and some sensible Eleventy options. Click the features below to learn how they work.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003estylesheet\u003c/code\u003e paired shortcode\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nUse the `stylesheet` paired shortcode to include your Sass. You can import Sass files from your `styles` directory (defined in `.twelvety.js`) and from `node_modules`. The Sass will be rendered using [dart-sass](https://github.com/sass/dart-sass#javascript-api), passed into [PostCSS](https://github.com/postcss/postcss) (with [PostCSS Preset Env](https://github.com/csstools/postcss-preset-env) and [Autoprefixer](https://github.com/postcss/autoprefixer) for compatibility) and either minified using [clean-css](https://github.com/jakubpawlowicz/clean-css) or beautified by [JS Beautifier](https://github.com/beautify-web/js-beautify) (in production and development respectively).\n\n```html\n{% stylesheet 'scss' %}\n  @import \"normalize.css/normalize\";\n  @import \"mixins\";\n\n  .home {\n    @include container;\n\n    color: $color--red;\n  }\n{% endstylesheet %}\n```\n\nThe second parameter of the `stylesheet` paired shortcode is the language; currently, this does nothing and is included solely to align with Shopify's definition of the shortcode. If you want to use Sass **indented syntax**, you can change the `indentedSass` Twelvety option, found in `.twelvety.js`.\n\nThe `stylesheet` paired shortcode also has a third parameter, which by default is set to `page.url`, the URL of the current page being rendered. This means that only the required CSS is included in each page. You can make your own 'chunk' of CSS using this parameter, for example, a CSS file common to all pages of your website.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003estyles\u003c/code\u003e shortcode\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nThe `styles` shortcode collects together all Sass written in `stylesheet` paired shortcodes for the given chunk and outputs the rendered CSS. The 'chunk' defaults to `page.url`, the URL of the current page being rendered.\n\n```html\n\u003c!-- Inline all styles on current page --\u003e\n\u003cstyle\u003e\n  {% styles page.url %}\n\u003c/style\u003e\n\n\u003c!-- Capture styles on current page --\u003e\n{% capture css %}\n  {% styles page.url %}\n{% endcapture %}\n\u003c!-- And output asset using `asset` shortcode --\u003e\n\u003clink rel=\"stylesheet\" href=\"{% asset css, 'css' %}\" /\u003e\n```\n\nNote that the `styles` shortcode must be placed below any `stylesheet` paired shortcodes in the template; see the `append` paired shortcode and transform for more information.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003ejavascript\u003c/code\u003e paired shortcode\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nInclude your JavaScript using the `javascript` paired shortcode. Twelvety uses [Browserify](http://browserify.org) so that you can `require('modules')` and [Babel](https://babeljs.io) so you can use the latest JavaScript. Your JavaScript will then be minified using [Uglify](https://github.com/mishoo/UglifyJS) in production or beautified by [JS Beautifier](https://github.com/beautify-web/js-beautify) in development.\n\n```html\n{% javascript %}\n  const axios = require(\"axios\");\n\n  axios.get(\"/api/endpoint\")\n    .then((response) =\u003e {\n      console.log(\"Yay, it worked!\");\n    })\n    .catch((error) =\u003e {\n      console.log(\"Uh oh, something went wrong\");\n    });\n{% endjavascript %}\n```\n\nThe `javascript` paired shortcode has a second parameter, which by default is set to `page.url`, the URL of the current page being rendered. This means that only the required JavaScript is included in each page. You can make your own 'chunk' of JavaScript using this parameter, for example, a JavaScript file for all vendor code.\n\nThe output of each `javascript` paired shortcode will be wrapped in an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) so that your variables do not pollute global scope. If you want to define something on `window`, use `window.something =`.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003escript\u003c/code\u003e shortcode\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nThe `script` shortcode collects together all the JavaScript for the given chunk and outputs the JavaScript (after transpilation and minification). The 'chunk' defaults to `page.url`, the URL of the current page being rendered.\n\n```html\n\u003c!-- Inline all JavaScript on current page --\u003e\n\u003cscript\u003e\n  {% script page.url %}\n\u003c/script\u003e\n\n\u003c!-- Capture JavaScript on current page --\u003e\n{% capture js -%}\n  {% script page.url %}\n{%- endcapture -%}\n\u003c!-- And output asset using `asset` shortcode --\u003e\n\u003cscript src=\"{% asset js, 'js' %}\" defer\u003e\u003c/script\u003e\n```\n\nNote that the `script` shortcode must be placed below any `javascript` paired shortcodes in the template; usually this is not a problem as JavaScript is often included immediately preceding `\u003c/body\u003e`. If you want the JavaScript somewhere else, see the `append` paired shortcode and transform.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003easset\u003c/code\u003e shortcode\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nThe `asset` shortcode outputs a content-hashed asset with the given content and extension. The content may be either a `String` or `Buffer`. Assets will be saved to the `assets` directory inside the `output` directory (both defined within `.twelvety.js`).\n\n```html\n\u003c!-- Capture some content --\u003e\n{% capture css %}\nh1 {\n  color: red;\n}\n{% endcapture %}\n\n\u003c!-- Save content to content-hashed file with .css extension --\u003e\n\u003clink rel=\"stylesheet\" href=\"{% asset css, 'css' %}\" /\u003e\n\n\u003c!-- Output of shortcode --\u003e\n\u003clink rel=\"stylesheet\" href=\"/_assets/58f4b924.css\" /\u003e\n```\n\nYou can import the `asset` shortcode function in JavaScript: this is how the `picture` shortcode saves your responsive images into the `assets` directory.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003epicture\u003c/code\u003e shortcode\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nThe `picture` shortcode takes `src` and `alt` parameters and outputs a responsive picture element with AVIF* and WebP support. Your images must be stored within the `images` directory, defined within `.twelvety.js`. Twelvety will save the outputted images to the `assets` directory inside the `output` directory (both defined within `.twelvety.js`). The `picture` shortcode also takes two other parameters: `sizes` which defaults to `90vw, (min-width: 1280px) 1152px`, based upon the breakpoint sizes; and `loading` which defaults to `lazy`, can also be `eager`.\n\n*AVIF is disabled by default due to long build times. You can enable it in `.twelvety.js`.\n\n```html\n\u003c!-- Picture shortcode with src, alt, sizes and loading --\u003e\n{% picture 'car.jpg', 'Panning photo of grey coupe on road', '90vw', 'eager' %}\n\n\u003c!-- Absolute paths also work --\u003e\n{% picture '/src/_assets/images/car.jpg', 'Panning photo of grey coupe on road', '90vw', 'eager' %}\n\n\u003c!-- Output of shortcode --\u003e\n\u003cpicture style=\"background-color:rgb(38%,28%,26%);padding-bottom:50%\"\u003e\n  \u003csource srcset=\"/_assets/2263c1d0.avif 320w,/_assets/519fcdec.avif 640w,/_assets/b59349f7.avif 960w,/_assets/e8dae22f.avif 1280w,/_assets/4ba755ff.avif 1600w,/_assets/87c06dd1.avif 1920w\" sizes=\"90vw\" type=\"image/avif\"\u003e\n  \u003csource srcset=\"/_assets/0e7cdd2f.webp 320w,/_assets/ba4e43dd.webp 640w,/_assets/bc541ea5.webp 960w,/_assets/6d620165.webp 1280w,/_assets/756857ea.webp 1600w,/_assets/483e9c95.webp 1920w\" sizes=\"90vw\" type=\"image/webp\"\u003e\n  \u003csource srcset=\"/_assets/6a3b0321.jpeg 320w,/_assets/2bf90b83.jpeg 640w,/_assets/4a810813.jpeg 960w,/_assets/601b629c.jpeg 1280w,/_assets/c39ac58c.jpeg 1600w,/_assets/25a2b530.jpeg 1920w\" sizes=\"90vw\" type=\"image/jpeg\"\u003e\n  \u003cimg src=\"/_assets/25a2b530.jpeg\" alt=\"Panning photo of grey coupe on road\" width=\"2400\" height=\"1200\" loading=\"lazy\"\u003e\n\u003c/picture\u003e\n```\n\nThe `picture` shortcode uses native lazy-loading but it would be easy to add support for `lazysizes` or a similar library if you wished. The `picture` shortcode calculates the average colour of the image to show while the image loads, using `padding-bottom` to avoid layout shift.\n\nThe `picture` shortcode is automatically used for every image in Markdown. To disable this, you'll need to edit the instance of markdown-it (see Markdown feature).\n\n```md\n\u003c!-- Automatically uses picture shortcode --\u003e\n![Panning photo of grey coupe on road](car.jpg)\n```\n\n**The images outputted by the `picture` shortcode are cached.** If you want to clear the cache, delete `.twelvety.cache` (just a JSON file) or run `npm run clean` to delete the cache and the output directory. If you delete the output directory but `.twelvety.cache`, things will break.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eappend\u003c/code\u003e paired shortcode and transform\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nOkay folks, here it is: the one _gotcha_ with Twelvety. In order for the `styles` shortcode to work, it must come after all `stylesheet` paired shortcodes, which would usually be in the `body`. However, we want our CSS to be linked or inlined in the `head`. This is where the `append` paired shortcode and transform come in, to move the output of the `styles` shortcode back into the `head` where we want it.\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003c!-- Everything in append paired shortcode will be moved here --\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003c!-- Stylesheet paired shortcodes can go here --\u003e\n    ...\n    \u003c!-- Append paired shortcode with styles inside --\u003e\n    {% append 'head' %}\n      \u003cstyle\u003e\n        {% styles page.url %}\n      \u003c/style\u003e\n    {% endappend %}\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe `append` paired shortcode will actually be replaced with a `template`. The `append` transform then uses [jsdom](https://github.com/jsdom/jsdom) to append the contents of the `template` to the given selector (in this case, `head`).\n\nThe same problem exists for the `script` shortcode, however, this is not such a problem because it's very common to include JavaScript from the bottom of `body` anyway.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003emarkdown\u003c/code\u003e paired shortcode and configuration\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nTwelvety sets its own instance of markdown-it. The configuration options are:\n\n```js\n{\n  html: true,\n  breaks: true,\n  typographer: true\n}\n```\n\nTwelvety also modifies the `image` rule of the renderer: instead of outputting an `img` element, Twelvety uses the responsive `picture` shortcode to render each image. If you want to disable this, remove the following lines in `utils/markdown.js`.\n\n```js\nmd.renderer.rules.image = function (tokens, index) {\n  const token = tokens[index];\n  const src = token.attrs[token.attrIndex(\"src\")][1];\n  const alt = token.content;\n  return pictureShortcode(src, alt);\n};\n```\n\nTwelvety also adds a `markdown` paired shortcode which uses the markdown-it configuration.\n\n```html\n{% markdown %}\n# `markdown` paired shortcode\n\nLets you use **Markdown** like _this_.\n{% endmarkdown %}\n```\n\nThis is also really useful for including Markdown files into a template.\n\n```html\n{% markdown %}\n  {%- include 'content.md' -%}\n{% endmarkdown %}\n```\n\nBe careful of the [common pitfall of indented code blocks](https://www.11ty.dev/docs/languages/markdown/#there-are-extra-and-in-my-output) when using the `markdown` paired shortcode. If indented code blocks are becoming a nuisance, you can disable them in `utils/markdown.js` whilst retaining fenced code blocks.\n\n```diff\n   // Uncomment the following line to disable indented code blocks\n-  // .disable(\"code\")\n+  .disable(\"code\")\n```\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003ecritical\u003c/code\u003e transform\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nInstead of using a transform, Twelvety now uses [eleventy-critical-css](https://github.com/gregives/eleventy-critical-css) to extract and inline critical-path CSS on every page.\n\n___\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eformat\u003c/code\u003e transform\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr\u003e\n\nThe `format` transform beautifies HTML in development using [JS Beautifier](https://github.com/beautify-web/js-beautify) and minifies HTML in production using [HTMLMinifier](https://github.com/kangax/html-minifier). Any inline CSS and JavaScript will also be beautified or minified.\n\n___\n\n\u003c/details\u003e\n\n## Visual Studio Code\n\nIf you're using Visual Studio Code I recommend this [Liquid extension](https://github.com/panoply/vscode-liquid) so that your Sass and JavaScript will be highlighted correctly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftitaniumbones%2Ftwelvety","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftitaniumbones%2Ftwelvety","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftitaniumbones%2Ftwelvety/lists"}