{"id":13426575,"url":"https://github.com/bespokejs/bespoke","last_synced_at":"2025-12-17T15:47:39.573Z","repository":{"id":5927196,"uuid":"7147058","full_name":"bespokejs/bespoke","owner":"bespokejs","description":"DIY Presentation Micro-Framework","archived":false,"fork":false,"pushed_at":"2020-09-08T20:46:55.000Z","size":304,"stargazers_count":4807,"open_issues_count":5,"forks_count":454,"subscribers_count":148,"default_branch":"master","last_synced_at":"2025-12-09T10:45:29.958Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://markdalgleish.com/projects/bespoke.js/","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/bespokejs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-MIT","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-13T11:16:38.000Z","updated_at":"2025-12-07T19:29:25.000Z","dependencies_parsed_at":"2022-07-20T13:32:19.151Z","dependency_job_id":null,"html_url":"https://github.com/bespokejs/bespoke","commit_stats":null,"previous_names":["markdalgleish/bespoke.js"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/bespokejs/bespoke","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespokejs%2Fbespoke","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespokejs%2Fbespoke/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespokejs%2Fbespoke/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespokejs%2Fbespoke/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bespokejs","download_url":"https://codeload.github.com/bespokejs/bespoke/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bespokejs%2Fbespoke/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27784495,"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","status":"online","status_checked_at":"2025-12-17T02:00:08.291Z","response_time":55,"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":[],"created_at":"2024-07-31T00:01:38.210Z","updated_at":"2025-12-17T15:47:39.557Z","avatar_url":"https://github.com/bespokejs.png","language":"JavaScript","readme":"[![Build Status](https://img.shields.io/travis/bespokejs/bespoke/master.svg?style=flat)](http://travis-ci.org/bespokejs/bespoke) [![Coverage Status](https://img.shields.io/coveralls/bespokejs/bespoke/master.svg?style=flat)](https://coveralls.io/r/bespokejs/bespoke) [![Gitter](https://img.shields.io/badge/gitter-join%20chat-45cba1.svg?style=flat)](https://gitter.im/bespokejs/bespoke)\n\n# Bespoke.js\n\n### DIY Presentation Micro-Framework\n\n[Bespoke.js](http://markdalgleish.com/projects/bespoke.js) is a super minimal (1KB min'd and gzipped), modular presentation library for modern browsers, designed to foster a rich [plugin ecosystem](#plugins).\n\nThe core library [sets up the presentation](#javascript), provides a simple [control API](#control-api) and manages [events](#events). Any other functionality is implemented as a [plugin](#plugins).\n\nJoining the Bespoke.js ecosystem is simple with the suite of official [Yeoman](http://yeoman.io) generators:\n - [Bespoke.js Generator](https://github.com/bespokejs/generator-bespoke)\n - [Bespoke.js Plugin Generator](https://github.com/bespokejs/generator-bespokeplugin)\n - [Bespoke.js Theme Generator](https://github.com/bespokejs/generator-bespoketheme)\n\n## Creating a Presentation\n\nDue to the highly modular nature of Bespoke.js, the quickest way to get started is with [Bespoke.js Generator](https://github.com/bespokejs/generator-bespoke), a [Yeoman](http://yeoman.io) generator that scaffolds a boilerplate presentation with a [Gulp](http://gulpjs.com) build system.\n\nAssuming you have [Node.js](http://nodejs.org) installed, in a blank directory:\n\n```bash\n$ npm install -g generator-bespoke\n$ yo bespoke\n```\n\nIn your newly scaffolded project, you can use the following Gulp tasks:\n\n * ```$ gulp serve``` to run a preview server with LiveReload.\n * ```$ gulp deploy``` to deploy to GitHub Pages.\n * ```$ gulp``` to compile static assets to 'public'.\n\nFor more detailed instructions, check out the [Bespoke.js Generator](https://github.com/bespokejs/generator-bespoke) repo.\n\nIf you'd prefer to craft a new presentation from scratch, you can install Bespoke.js from [npm](http://npmjs.org) with `npm install bespoke`, [Bower](http://bower.io) with `bower install bespoke.js`, or manually download either the [production version][min] or the [development version][max]. The Bespoke.js core is extremely lightweight, so you'll probably want to include some [plugins](#plugins).\n\n[min]: https://raw.github.com/bespokejs/bespoke/master/dist/bespoke.min.js\n[max]: https://raw.github.com/bespokejs/bespoke/master/dist/bespoke.js\n\n## Basic Usage\n\n### Loading Bespoke\n\nBespoke.js is shipped in a [UMD format](https://github.com/umdjs/umd), meaning that `bespoke` and its plugins are available as CommonJS/AMD modules or browser globals.\n\n### Markup\n\nIt's completely up to you which tags you use, but the following is a good starting point:\n\n```html\n\u003carticle id=\"presentation\"\u003e\n  \u003csection\u003eSlide 1\u003c/section\u003e\n  \u003csection\u003eSlide 2\u003c/section\u003e\n  \u003csection\u003eSlide 3\u003c/section\u003e\n\u003c/article\u003e\n```\n\n#### JavaScript\n\nTo create a new presentation, Bespoke.js provides the `from(selector[, plugins])` method, which takes a selector or element reference and an array of [plugins](#plugins), and returns a [deck instance](#deck-instances).\n\n```js\nvar deck = bespoke.from('#presentation', [plugins]);\n\n// Next slide\ndeck.next();\n\n// Previous slide\ndeck.prev();\n\n// Go to a specific slide\ndeck.slide(0);\n\n// Get the active slide index\ndeck.slide(); // 0\n```\n\nBy default, all non-script child elements of the resolved parent element become slides.\nYou can customize this behavior by passing a custom selector.\n\n## Plugins\n\n### Official Plugins\n\nAll official plugins can be installed from npm or Bower, e.g. `$ npm install bespoke-keys` or `$ bower install bespoke-touch`\n\n - [bespoke-keys](https://github.com/bespokejs/bespoke-keys) for keyboard and remote control interaction.\n - [bespoke-touch](https://github.com/bespokejs/bespoke-touch) for touch interaction.\n - [bespoke-classes](https://github.com/bespokejs/bespoke-classes) for deck status classes.\n - [bespoke-bullets](https://github.com/bespokejs/bespoke-bullets) for animated bullet lists.\n - [bespoke-scale](https://github.com/bespokejs/bespoke-scale) for responsive slide scaling.\n - [bespoke-hash](https://github.com/bespokejs/bespoke-hash) for hash routing.\n - [bespoke-backdrop](https://github.com/bespokejs/bespoke-backdrop) for animated backdrop elements.\n - [bespoke-state](https://github.com/bespokejs/bespoke-state) for slide-specific deck styles.\n - [bespoke-progress](https://github.com/bespokejs/bespoke-progress) for progress bars.\n - [bespoke-forms](https://github.com/bespokejs/bespoke-forms) for form element support.\n - [bespoke-loop](https://github.com/bespokejs/bespoke-loop) for looped presentations.\n - [bespoke-vcr](https://github.com/bespokejs/bespoke-vcr) for recording and playback.\n\n### All Plugins\n\nYou can view the [full list of Bespoke.js plugins on npm](https://www.npmjs.org/browse/keyword/bespoke-plugin) by browsing the [bespoke-plugin](https://www.npmjs.org/browse/keyword/bespoke-plugin) keyword.\n\n### Using Plugins\n\nAll official plugins are provided in a [UMD format](https://github.com/umdjs/umd), meaning they are available as CommonJS/AMD modules or browser globals.\n\nFor example, if you're using CommonJS modules via [browserify](http://browserify.org/) or [webpack](http://webpack.github.io/), it would look something like this:\n\n```js\nvar bespoke = require('bespoke'),\n  classes = require('bespoke-classes'),\n  keys = require('bespoke-keys'),\n  touch = require('bespoke-touch');\n\nvar deck = bespoke.from('#presentation', [\n  classes(),\n  keys(),\n  touch()\n]);\n```\n\nIf you're using browser globals, all official plugins are added to the `bespoke.plugins` object, for example:\n\n```js\nvar deck = bespoke.from('#presentation', [\n  bespoke.plugins.classes(),\n  bespoke.plugins.keys(),\n  bespoke.plugins.touch()\n]);\n```\n\nThe first slide is activated automatically after all plugins are called unless one of those plugins has already activated a slide.\n\n## Themes\n\n### Official Themes\n\n - [Cube](https://github.com/bespokejs/bespoke-theme-cube) \u0026mdash; [(view demo)](http://bespokejs.github.io/bespoke-theme-cube)\n - [Voltaire](https://github.com/bespokejs/bespoke-theme-voltaire) \u0026mdash; [(view demo)](http://bespokejs.github.io/bespoke-theme-voltaire)\n - [Nebula](https://github.com/bespokejs/bespoke-theme-nebula) \u0026mdash; [(view demo)](http://bespokejs.github.io/bespoke-theme-nebula)\n\nAs with plugins, all official themes can be installed from npm or Bower, e.g. `$ npm install bespoke-theme-cube` or `$ bower install bespoke-theme-voltaire`\n\n### All Themes\n\nYou can view the [full list of Bespoke.js themes on npm](https://www.npmjs.org/browse/keyword/bespoke-theme) by browsing the [bespoke-theme](https://www.npmjs.org/browse/keyword/bespoke-theme) keyword.\n\n### Using Themes\n\nThemes are included just like any other plugin:\n\n```js\nvar bespoke = require('bespoke'),\n  cube = require('bespoke-theme-cube'),\n  keys = require('bespoke-keys'),\n  touch = require('bespoke-touch');\n\nvar deck = bespoke.from('#presentation', [\n  cube(),\n  keys(),\n  touch()\n]);\n```\n\nIf you're using browser globals, all official themes are added to the `bespoke.themes` object, for example:\n\n```js\nvar deck = bespoke.from('#presentation', [\n  bespoke.themes.cube(),\n  bespoke.plugins.keys(),\n  bespoke.plugins.touch()\n]);\n```\n\n## Advanced Usage\n\n### From HTMLElement\n\nIf you already have a reference to a DOM node, you can pass it directly to the `from` method.\n\n```js\nbespoke.from(element);\n```\n\n### Slide Selector\n\nYou can specify which elements become slides by passing an options Hash containing the key `parent` and, optionally, the key `slides`) to the `from` method.\nThe value of either key can be a CSS selector or a DOM node.\n\n```js\nbespoke.from({ parent: selectorOrElement, slides: selectorOrElementList });\n```\n\nFor example:\n\n```js\nbespoke.from({ parent: '#presentation', slides: '#presentation \u003e section' });\n```\n\nThis advanced usage allows you to include auxiliary HTML inside the parent element, skip slides that don't match the selector or explicitly filter out slides before passing on the collection.\n\n### Deck Instances\n\nDeck instances are provided to plugins and returned when instantiating a presentation. The following properties are available on each instance.\n\n*Note: The optional [`eventData`](#custom-event-data) parameter is an object that will be merged with the `event` object in subsequent [event handlers](#events).*\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003enext(\u003cem\u003e[eventData]\u003c/em\u003e)\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eNext slide.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eprev(\u003cem\u003e[eventData]\u003c/em\u003e)\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003ePrevious slide.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eslide([\u003cem\u003eindex[, eventData]]\u003c/em\u003e)\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eGet or set the active slide index.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eon(\u003cem\u003eevent, callback\u003c/em\u003e)\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eAttach \u003ca href=\"#events\"\u003eevent handlers\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eoff(\u003cem\u003eevent, callback\u003c/em\u003e)\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eUnbind \u003ca href=\"#events\"\u003eevent handlers\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003efire(\u003cem\u003eevent[, eventData]\u003c/em\u003e)\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eFire custom events. \u003cem\u003eThis method is primarily designed for plugin authors.\u003c/em\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eparent\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eThe deck's parent element\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eslides\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eAn array of slide elements\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003edestroy\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eFire the destroy event. \u003cem\u003eThis method can be used to remove the deck from the DOM.\u003c/em\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n### Events\n\n##### Binding Events\n\nEvents are bound via the [deck instance](#deck-instances). Each event is passed an event object containing a reference to the relevant slide and its index.\n\n```js\ndeck.on(eventName, function(event) {\n  event.slide; // Relevant slide\n  event.index; // Index of relevant slide\n\n  // Prevent default functionality (for deck interaction events only)\n  return false;\n});\n```\n\n##### Standard Events\n\nIn most cases, you will only need to use these standard events.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eactivate\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eA slide has been activated. \u003cstrong\u003eevent.slide\u003c/strong\u003e is the \u003cem\u003eactivated\u003c/em\u003e slide.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003edeactivate\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eA slide has been deactivated. \u003cstrong\u003eevent.slide\u003c/strong\u003e is the \u003cem\u003edeactivated\u003c/em\u003e slide.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003edestroy\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003ePresentation is about to be destroyed, it's time for clean-up.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n##### Deck Interaction Events\n\nThese events are fired when the deck has been interacted with, but *before* the interaction has had any effect.\n\nThis allows you to intercept the default behaviour by returning `false` from the event handler.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003enext\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eThe next slide has been requested, even if last slide is active. \u003cstrong\u003eevent.slide\u003c/strong\u003e is the \u003cem\u003ecurrent\u003c/em\u003e slide.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eprev\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eThe previous slide has been requested, even if first slide is active. \u003cstrong\u003eevent.slide\u003c/strong\u003e is the \u003cem\u003ecurrent\u003c/em\u003e slide.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cstrong\u003eslide\u003c/strong\u003e\u003c/td\u003e\n    \u003ctd\u003eA specific slide has been requested. \u003cstrong\u003eevent.slide\u003c/strong\u003e is the \u003cem\u003erequested\u003c/em\u003e slide.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n##### Unbinding events\n\nWhen binding events, the `on` method returns a function that can be used to remove the event handler.\n\n```js\nvar off = deck.on('activate', function() {\n  // ...\n});\n\n// Unbind event\noff();\n```\n\nYou can also use the `off` method. However, you must use the same function reference that was used when registering the event.\n\n```js\n// Bind event\ndeck.on('activate', onActivate);\n\n// Unbind event\ndeck.off('activate', onActivate);\n```\n\n## Creating Plugins\n\nWant a boilerplate plugin? Use the official [Bespoke.js Plugin Generator](https://github.com/bespokejs/generator-bespokeplugin).\n\nIf you'd like to learn by example, check out the [list of existing plugins](#plugins).\n\n### Basic Plugins\n\nPlugins are simply functions that are called when presentations are created. They are passed a [deck instance](#deck-instances) which allows you to interact with the deck's state, bind events and modify its elements.\n\nTo be consistent with the suite of official Bespoke.js plugins, it is highly recommended that you implement your plugin as a function that takes configuration and returns a plugin function.\n\n```js\n// Creating the plugin\nvar myPlugin = function() {\n  return function() {\n    deck.on('activate', function(e) {\n      console.log('Activated slide ' + (e.index + 1) + ' of ' + deck.slides.length);\n    });\n  }\n};\n```\n\nThe plugin can now be provided in the plugins array when using the `from(selector[, plugins])` method.\n\n```js\n// Using the plugin\nbespoke.from('#presentation', [\n  myPlugin()\n]);\n```\n\n### Plugins with Options\n\nIf your plugin needs some configurability, your plugin factory function can take options and return a configured plugin function.\n\n```js\n// Creating the plugin with options\nvar myPlugin = function(options) {\n  return function(deck) {\n    var showTotal = options \u0026\u0026 options.showTotal;\n\n    deck.on('activate', function(e) {\n      console.log('Activated slide ' + (e.index + 1) +\n        (showTotal ? ' of ' + deck.slides.length : ''));\n    });\n  }\n};\n\n// Using the plugin with options\nbespoke.from('#presentation', [\n  myPlugin({ showTotal: true })\n]);\n```\n\n### Custom Event Data\n\nAdditional event data can be supplied to `next`, `prev` and `slide`, which is merged with the final `event` object in subsequent event handlers.\n\nThis functionality is particularly useful if you need to differentiate between events caused by your plugin, and those caused by your end users or other plugins.\n\n```js\nvar myPlugin = function() {\n  return function(deck) {\n\n    // Differentiating our plugin's events\n    deck.on('activate', function(event) {\n      if (event.foo === 'bar') {\n        // Triggered by my plugin...\n      } else {\n        // Triggered by end user, or another plugin...\n      }\n    });\n\n    // Providing custom event data\n    deck.next({\n      foo: 'bar'\n    });\n\n  };\n}\n```\n\n## Creating Themes\n\nThemes are essentially just plugins that also happen to insert styles into the page.\n\nYou can quickly scaffold a boilerplate theme project with the official [Bespoke.js Theme Generator](https://github.com/bespokejs/generator-bespoketheme).\n\n## Presentations\n\n - [A State of Change — On the future of Object.observe](https://github.com/markdalgleish/presentation-a-state-of-change-object-observe) by [Mark Dalgleish](http://twitter.com/markdalgleish)\n - [Build Wars: Gulp vs Grunt](http://markdalgleish.github.io/presentation-build-wars-gulp-vs-grunt/) by [Mark Dalgleish](http://twitter.com/markdalgleish)\n - [Bespoke.js: The Road to 1KB](http://markdalgleish.github.io/presentation-bespoke.js-the-road-to-1kb/) by [Mark Dalgleish](http://twitter.com/markdalgleish)\n - [DIY Presentations With Bespoke.js](http://markdalgleish.com/presentations/bespoke.js/) by [Mark Dalgleish](http://twitter.com/markdalgleish)\n - [Javascript's Slightly Stricter Mode](http://geelen.github.io/web-directions-talk/) by [Glen Maddern](http://twitter.com/glenmaddern)\n - [The Trials of Transition Height: Auto](http://superhighfives.github.io/tweetflight-presentation/) by [Charlie Gleason](http://twitter.com/superhighfives)\n - [Welcome Our New ES5 Overlords](http://mikemaccana.github.io/rejectjs2013) by [Mike MacCana](https://twitter.com/mikemaccana)\n - [Rapid Web App Dev With Yeoman](http://mjt01.github.io/slides-yeoman/) by [Michael Taranto](http://twitter.com/michaeltaranto)\n - [Projects vs Products](http://joho.github.io/wdyk/) by [John Barton](http://twitter.com/johnbarton)\n - [Learn You The Node.js For Much Win](http://r.va.gg/presentations/campjs-learn-you-node/) by [Rod Vagg](http://twitter.com/rvagg)\n - [A Real Database Rethink](http://r.va.gg/presentations/nodeconfeu.2013) by [Rod Vagg](http://twitter.com/rvagg)\n - [Feature Flags with Directives](http://mjt01.github.io/slides-feature-flags/) by [Michael Taranto](http://twitter.com/michaeltaranto)\n - [Introduction to hapi](http://wolfe.id.au/presentations/hapi/) by [Mark Wolfe](http://twitter.com/wolfeidau)\n - [How to Cook a Graph Database in a Night](http://nodejsconfit.levelgraph.io) by [Matteo Collina](http://twitter.com/matteocollina)\n - [Asynchronous JavaScript Interfaces](http://medikoo.com/asynchronous-javascript-interfaces/?notes) by [Mariusz Nowak](http://medikoo.com)\n - [MQTT and Node.js - Messaging in the Internet of Things](http://mcollina.github.io/mqtt_and_nodejs/) by [Matteo Collina](http://twitter.com/matteocollina)\n - [At Least 6 Ways to Win with CSS Modules](https://github.com/joshwnj/6-ways-to-win) by [Josh Johnston](https://twitter.com/joshwnj)\n\nMade a presentation with Bespoke.js? [Let me know](http://twitter.com/markdalgleish).\n\n## Questions?\n\nContact me on GitHub or Twitter: [@markdalgleish](http://twitter.com/markdalgleish)\n\n## License\n\n[MIT License](http://markdalgleish.mit-license.org)\n","funding_links":[],"categories":["JavaScript","Presentation Tools","Uncategorized","JavaScript And HTML5 Presentation Frameworks","Sliders","others","Sliders [🔝](#readme)","幻灯片","Open Source"],"sub_categories":["Use The Source","Uncategorized","Runner","运行器","运行器e2e测试"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbespokejs%2Fbespoke","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbespokejs%2Fbespoke","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbespokejs%2Fbespoke/lists"}