{"id":13394224,"url":"https://github.com/chrisvxd/story2sketch","last_synced_at":"2025-05-16T18:09:51.118Z","repository":{"id":28626877,"uuid":"118790550","full_name":"chrisvxd/story2sketch","owner":"chrisvxd","description":"Convert Storybook into Sketch symbols 💎","archived":false,"fork":false,"pushed_at":"2022-12-09T16:55:32.000Z","size":882,"stargazers_count":406,"open_issues_count":58,"forks_count":32,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-05-07T06:04:30.260Z","etag":null,"topics":["components","design-systems","react","sketch","storybook","styleguide"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chrisvxd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2018-01-24T16:22:51.000Z","updated_at":"2025-03-30T00:44:21.000Z","dependencies_parsed_at":"2022-09-11T10:40:45.389Z","dependency_job_id":null,"html_url":"https://github.com/chrisvxd/story2sketch","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisvxd%2Fstory2sketch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisvxd%2Fstory2sketch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisvxd%2Fstory2sketch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisvxd%2Fstory2sketch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisvxd","download_url":"https://codeload.github.com/chrisvxd/story2sketch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254582907,"owners_count":22095518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["components","design-systems","react","sketch","storybook","styleguide"],"created_at":"2024-07-30T17:01:13.035Z","updated_at":"2025-05-16T18:09:51.099Z","avatar_url":"https://github.com/chrisvxd.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Community Addons","Sketch","📦 Legacy \u0026 Inactive Projects"],"sub_categories":["Handoff"],"readme":"# story2sketch 💎\n\n[![NPM](https://img.shields.io/npm/v/story2sketch.svg)](https://www.npmjs.com/package/story2sketch) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-prettier-brightgreen.svg)](https://prettier.io)\n\nConvert [Storybook](https://storybook.js.org) stories into [Sketch](https://www.sketchapp.com) symbols.\n\n\u003e Uses the amazing [`html-sketchapp`](https://github.com/html-sketchapp/html-sketchapp). Only supports web.\n\n## Quickstart\n\nFirstly, get [Sketch](https://sketchapp.com) and [npm](https://nodejs.org/en/download/). Then install [`asketch2sketch.sketchplugin`](https://github.com/html-sketchapp/html-sketchapp/releases/download/v4.4.1/asketch2sketch-4-4-1.sketchplugin.zip) into Sketch:\n\n\u003cimg src=\"https://i.imgur.com/9eDm6NQ.png\" width=\"450\" alt=\"Installing Sketch plugin\" title=\"Installing Sketch plugin\" /\u003e\n\nInstall `story2sketch`:\n\n```sh\nnpm i story2sketch -g\n```\n\nRun `story2sketch`, pointing towards a Storybook iframe URL. You can find an existing iframe URL in Storybook by clicking 'Open canvas in new tab':\n\n![Open canvas in new tab](https://i.imgur.com/Vo87WSM.png)\n\nSee [configuration](#configuration) for more options, or if you have a lot of stories.\n\n```sh\nstory2sketch --url https://localhost:9001/iframe.html --output stories.asketch.json\n```\n\nImport the generated file into Sketch via `Plugins \u003e From *Almost* Sketch to Sketch` in Sketch menu bar.\n\n![Using sketch plugin](https://i.imgur.com/aA94aNN.png)\n\nSuccess!\n\n### Storybook 3.x\n\nIf you're using Storybook 3.3 or above (but not Storybook 4 or above), you'll want to [take full control of your Storybook webpack.config.js](https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode) if you haven't already done so, adding:\n\n```js\nmodule.exports = (storybookBaseConfig, configType) =\u003e {\n  const newConfig = {\n    ...storybookBaseConfig\n  };\n\n  // Add this:\n  // Export bundles as libraries so we can access them on page scope.\n  newConfig.output.library = \"[name]\";\n\n  return newConfig;\n};\n```\n\nManually export the `getStorybook` function in your `./config/storybook/config.js` file:\n\n```js\nimport { getStorybook } from \"@storybook/react\";\n\n...\n\nexport { getStorybook }\n```\n\nRun story2sketch:\n\n```sh\nstory2sketch --url https://localhost:9001/iframe.html --output stories.asketch.json\n```\n\n## Why?\n\nAs stated by [`react-sketchapp`](https://github.com/airbnb/react-sketchapp), it's complicated to manage assets in a design system. Many teams building design systems or component libraries already produce Sketch files for distributing designs and use [Storybook](https://storybook.js.org) to prototype and present the developed components. It can become difficult to keep designs up to date with the latest components, with designers ever playing catchup. `story2sketch` generates a Sketch file from your components via Storybook, so your Sketch designs always stay up to date.\n\n\u003ca name=\"configuration\"\u003e\u003ca/\u003e\n\n## Configuration\n\nYou can configure `story2sketch` using [the API](#api) via the CLI, configuring your `package.json` or adding a `story2sketch.config.js` file.\n\n### CLI\n\nSimply call `story2sketch` with options from the [API](#api).\n\n```sh\n$ story2sketch --stories all --output dist/great-ui.asketch.json\n```\n\n### package.json\n\nAdd the following to your package.json:\n\n```json\n{\n  \"story2sketch\": {\n    \"stories\": \"all\",\n    \"output\": \"dist/great-ui.asketch.json\"\n  }\n}\n```\n\n### story2sketch.config.js\n\nCreate a file called `story2sketch.config.js` on the root of your project:\n\n```js\nmodule.exports = {\n  output: \"dist/great-ui.asketch.json\",\n  stories: \"all\"\n};\n```\n\n\u003ca name=\"api\"\u003e\u003c/a\u003e\n\n## API\n\n| Parameter           | Explanation                                                                                                                                                                    | Input Type        | Default                                                                             |\n| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------- | ----------------------------------------------------------------------------------- |\n| output              | Specifies the filename for the generated asketch.json file or a folder when outputBy === 'kind'.                                                                               | string            | `\"dist/stories.asketch.json\"`                                                       |\n| input               | The location of Storybook's generated iframe.html. Use this over `url` if possible for performance.                                                                            | string            | `\"dist/iframe.html\"`                                                                |\n| url                 | Storybook iframe URL. Will end in `iframe.html`. Prefer `input` for performance if possible.                                                                                   | string            | `\"http://localhost:9001/iframe.html\"`                                               |\n| stories             | Stories to extract from Storybook. You should probably override the default.                                                                                                   | object/string     | `\"all\"`                                                                             |\n| concurrency         | Number of headless Chrome tabs to run in parallel. Defaults to number of threads available on your machine.                                                                    | integer           | dynamic                                                                             |\n| symbolGutter        | Gutter to place between symbols in Sketch.                                                                                                                                     | integer           | `100`                                                                               |\n| viewports           | Viewport configuration. Will be arranged left-to-right by width. Try to avoid changing the key, as this is used to identify the symbol.                                        | object            | Mobile viewport (320px wide) and desktop viewport (1920px wide). See example below. |\n| querySelector       | Query selector to select your node on each page. Uses `document.querySelectorAll`.                                                                                             | string            | `\"#root\"`                                                                           |\n| verbose             | Verbose logging output.                                                                                                                                                        | boolean           | `false`                                                                             |\n| fixPseudo           | Attempt to insert real elements in place of pseudo-elements                                                                                                                    | boolean           | `false`                                                                             |\n| puppeteerOptions    | Options to be passed directly to `puppeteer.launch`. See [puppeteer docs](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions) for usage. | object            | `{}`                                                                                |\n| removePreviewMargin | Remove preview margin from the iframe body.                                                                                                                                    | boolean           | `true`                                                                              |\n| layoutBy            | Group symbols in the sketch output by the \"kind\" or \"group\" key                                                                                                                | \"kind\" \\| \"group\" | null                                                                                |\n| outputBy            | Write multiple sketch files by \"kind\" or the \"group\" key                                                                                                                       | \"kind\" \\| \"group\" | null                                                                                |\n\n## Example configurations\n\n### Basic\n\nAutomatically detect the stories, outputting two viewports for each story in a single Sketch file as symbols.\n\n```js\nmodule.exports = {\n  output: \"dist/great-ui.asketch.json\",\n  input: \"dist/iframe.html\", // Same as default\n  pageTitle: \"great-ui\"\n};\n```\n\n### Manual stories\n\nManually define stories to have granular control over what stories are output. This might help if you're getting empty output, since some stories may break story2sketch.\n\n```js\nmodule.exports = {\n  stories: [\n    {\n      kind: \"Buttons/Button\",\n      stories: [\n        {\n          name: \"Button\"\n        }\n      ]\n    },\n    {\n      kind: \"Buttons/ButtonGroup\",\n      stories: [\n        {\n          name: \"Default\",\n          displayName: \"Horizontal\"\n        },\n        {\n          name: \"Vertical\"\n        }\n      ]\n    },\n    {\n      kind: \"Table\",\n      stories: [\n        {\n          name: \"Table\"\n        }\n      ]\n    }\n  ]\n};\n```\n\n### Custom viewports\n\nOutput symbols based on custom viewports:\n\n```js\nmodule.exports = {\n  viewports: {\n    narrow: {\n      width: 320,\n      height: 1200,\n      symbolPrefix: \"Mobile/\"\n    },\n    standard: {\n      width: 1920,\n      height: 1200,\n      symbolPrefix: \"Desktop/\"\n    }\n  }\n};\n```\n\n### Split output into multiple files based on kind\n\nOutputs one file for each Storybook \"kind\". Useful if managing large component libraries, allowing you to distribute smaller files.\n\n```js\nmodule.exports = {\n  output: \"dist\", // Define output directory. File names are defined by \"kind\"\n  outputBy: \"kind\" // Also supports \"group\", see below.\n};\n```\n\n### Layout based on kind\n\nRenders the sketch layout by kind, but keeps them in one file.\n\n```js\nmodule.exports = {\n  layoutBy: \"kind\" // Also supports \"group\", see below.\n};\n```\n\n### Split output into multiple files based on custom group\n\nThis example outputs two files based on a custom grouping: `dist/Buttons.asketch.json` and `dist/Data.asketch.json`.\n\n```js\nmodule.exports = {\n  output: \"dist\",\n  outputBy: \"group\",\n  stories: [\n    {\n      group: \"Buttons\",\n      kind: \"Buttons/Button\",\n      stories: [\n        {\n          name: \"Button\"\n        }\n      ]\n    },\n    {\n      group: \"Buttons\",\n      kind: \"Buttons/ButtonGroup\",\n      stories: [\n        {\n          name: \"Default\",\n          displayName: \"Horizontal\"\n        },\n        {\n          name: \"Vertical\"\n        }\n      ]\n    },\n    {\n      group: \"Data\",\n      kind: \"Table\",\n      stories: [\n        {\n          name: \"Table\"\n        }\n      ]\n    }\n  ]\n};\n```\n\n## Continuous Integration\n\nIf you want `story2sketch` to run in a CI environment you might have to add the following configuration to puppeteer in your `story2sketch.config.js`.\n\n```js\nmodule.exports = {\n  puppeteerOptions: {\n    args: ['--no-sandbox', '--disable-setuid-sandbox']\n  },\n  ...\n};\n```\n\n\u003ca name=\"questions\"\u003e\u003ca/\u003e\n\n## Questions\n\n### Why does my stuff look bad?\n\nIf your stuff looks bad, either it's not supported by [`html-sketchapp`](https://github.com/html-sketchapp/html-sketchapp) yet (see [support here](https://github.com/html-sketchapp/html-sketchapp/wiki/What's-supported%3F)), or you need to [configure story2sketch](#configuration).\n\n### Why don't you use `react-sketchapp` instead of `html-sketchapp`?\n\n[`react-sketchapp`](https://github.com/airbnb/react-sketchapp) only supports React Native, or forces you to use React Native component naming conventions. [`html-sketchapp`](https://github.com/html-sketchapp/html-sketchapp) supports good ol' fashioned HTML, and doesn't care what web framework you're using.\n\n### Can I use this on anything other than Storybook?\n\nNot yet, but we have plans to add support for multiple and custom adaptors.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisvxd%2Fstory2sketch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisvxd%2Fstory2sketch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisvxd%2Fstory2sketch/lists"}