{"id":17239013,"url":"https://github.com/binarymuse/kinetophone","last_synced_at":"2025-04-14T02:30:48.621Z","repository":{"id":27467223,"uuid":"30946395","full_name":"BinaryMuse/kinetophone","owner":"BinaryMuse","description":"Stitch together and play back time-sequenced events with durations","archived":false,"fork":false,"pushed_at":"2016-03-17T15:18:27.000Z","size":27948,"stargazers_count":8,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-07T02:42:33.874Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://binarymuse.github.io/kinetophone/","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/BinaryMuse.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":"2015-02-18T01:01:34.000Z","updated_at":"2016-06-27T11:21:33.000Z","dependencies_parsed_at":"2022-08-31T00:00:24.640Z","dependency_job_id":null,"html_url":"https://github.com/BinaryMuse/kinetophone","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BinaryMuse%2Fkinetophone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BinaryMuse%2Fkinetophone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BinaryMuse%2Fkinetophone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BinaryMuse%2Fkinetophone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BinaryMuse","download_url":"https://codeload.github.com/BinaryMuse/kinetophone/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248810876,"owners_count":21165191,"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":[],"created_at":"2024-10-15T05:47:30.122Z","updated_at":"2025-04-14T02:30:48.587Z","avatar_url":"https://github.com/BinaryMuse.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Kinetophone\n===========\n\n![Kinetophone](https://raw.githubusercontent.com/BinaryMuse/kinetophone/master/images/kinetophone.jpg)\n\nKinetophone is a library for stitching together and controlling the playback of time-sequenced events with durations. Its primary use-case is to turn a series of audio and image files into a faux video.\n\nInstallation\n------------\n\nKinetophone is available on npm:\n\n    npm install [--save] kinetophone\n\nYou can then require it as normal:\n\n    var Kinetophone = require(\"kinetophone\");\n\nKinetophone is also available on Bower:\n\n    bower install [--save] kinetophone\n\nKinetophone also works with browser module bundlers like Browserify and webpack.\n\nExample\n-------\n\nHere's a simple Kinetophone app that will display a series of images, one per second.\n\n```html\n\u003cimage id=\"display\"\u003e\n```\n\n```javascript\nvar numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\nvar numberChannel = {\n  name: \"numbers\",\n  timings: numbers.map(function(number, index) {\n    return {\n      start: 1000 * index,\n      duration: 1000,\n      data: {\n        src: \"/media/image\" + number + \".png\"\n      }\n    };\n  })\n};\n\nvar kinetophone = new Kinetophone([numberChannel], 10000),\n    image = document.getElementById(\"display\");\n\nkinetophone.on(\"enter\", function(evt) {\n  image.src = evt.data.src;\n});\n\nkinetophone.play();\n```\n\nFor more complete examples, check out [the demos on the Kinetophone home page](http://binarymuse.github.io/kinetophone/) and the [associated source code](https://github.com/BinaryMuse/kinetophone/tree/gh-pages).\n\nUsage\n-----\n\n**`new Kinetophone(channels, totalDuration[, options])`**\n\nConstructs a new Kinetophone instance.\n\n* `channels` - an array of channels (see [Channels](#channels), below)\n* `totalDuration` - the total duration of the timeline. All timings must start on or after `0` ms and end on or before `totalDuration` ms.\n* `options` - an optional object containing options:\n  * `options.timeUpdateResolution` - the minimum number of milliseconds between internal updates (controls how often Kinetophone checks for \"current\" timings and the frequency of `timeupdate` events); defaults to `33`\n  * `options.tickImmediately` - if true, Kinetophone will emit a `timeupdate` event for time `0` and any timings with a `start` of `0` on the next tick (to give you time to attach event handlers); defaults to `false`\n\n**`Kinetophone#addChannel(channel)`**\n\nAdds a channel to the Kinetophone.\n\n* `channel` - the channel to add (see [Channels](#channels), below)\n\n**`Kinetophone#addTiming(channelName, timing)`**\n\nAdds a timing to an existing channel identified by the name `channelName`.\n\n* `channelName` - the name of the channel to add the timing to\n* `timing` - the timing to add\n\n**`Kinetophone#totalDuration([duration])`**\n\nGets (when given no arguments) or sets (when given a numeric argument) the Kinetophone's total timeline duration. Note that setting this value rebuilds the internal interval tree for every channel, so it's better to set this before you add any channels (e.g. in the constructor).\n\n* `duration` - the total duration of the timeline in milliseconds.\n\n**`Kinetophone#pause()`**\n\nPauses the Kinetophone.\n\n**`Kinetophone#play()`**\n\nStarts (or resumes) the Kinetophone.\n\n**`Kinetophone#playbackRate([rate])`**\n\nGets (when given no arguments) or sets (when given a numeric argument) the Kinetophone's playback rate. `0.25` will play at quarter speed, while `3` will play three times as fast as normal.\n\n**`Kinetophone#currentTime([ms])`**\n\nGets (when given no arguments) or sets (when given a numeric argument) the Kinetophone's current time in milliseconds.\n\n* `ms` - optional time in milliseconds to set the current playback time to; if not given, returns the current playback time instead\n\n**`Kinetophone#playing()`**\n\nReturns whether or not the Kinetophone is currently playing.\n\n**`{channelName: [timings]} : Kinetophone#getTimingsAt(time[, channels])`**\n\nReturns the timings that are active at `time` milliseconds.\n\n* `time` - the time, in milliseconds, to find timings at\n* `channels` - an optional string or array of strings indicating which channels to search\n\n**`{channelName: [timings]} : Kinetophone#getTimingsBetween(start, end[, channels])`**\n\nReturns the timings that are active at some point between `start` and `end` milliseconds. Returns timings that start *before* `start` or that end *after* `end` as long as they are active at some point in the given range.\n\n* `start` - the time, in milliseconds, to start finding timings at\n* `end` - the time, in milliseconds, to stop finding timings at\n* `channels` - an optional string or array of strings indicating which channels to search\n\n**`Kinetophone#on(event, handler)`**\n\nFrom [EventEmitter3](https://github.com/primus/eventemitter3), subscribes to events on the Kinetophone. See [the Node.js EventEmitter API](http://nodejs.org/api/events.html) for more details.\n\nAlso `Kinetophone#addListener(event, handler)`\n\n**`Kinetophone#off(event, handler)`**\n\nAlso `Kinetophone#removeListener(event, handler)`\n\nFrom [EventEmitter3](https://github.com/primus/eventemitter3), unsubscribes from events on the Kinetophone. See [the Node.js EventEmitter API](http://nodejs.org/api/events.html) for more details.\n\n**Other EventEmitter Methods**\n\nSince Kinetophone instances inherit from EventEmitter3, all other [EventEmitter methods](http://nodejs.org/api/events.html) are available.\n\n### Events\n\nDuring playback, a Kinetophone instance will emit events indicating that channel timings (see [Channels](#channels), below, for more information on timings) have entered or exited and to indicate other status changes. Here are the events Kinetophone emits and the arguments passed to the event handlers.\n\n**`enter(timing)`**\n\n**`enter:chname(timing)`**\n\nIndicates a channel's timing has been entered. For example, if a timing has a `start` of `1000`, when the Kinetophone playback reaches 1000 milliseconds, an `enter` event will be emitted for that timing.\n\nEvent handlers for `enter` will fire for every channel's timings; event handlers for `enter:chname`, where `chname` is the name of a channel, will fire only for timings from that channel.\n\n* `chname` - the name of a channel, used to scope listeners to specific channels\n* `timing` - the channel timing entering\n  * `timing.name` - the name of the channel the timing belongs to\n  * `timing.start` - the start time of the timing\n  * `timing.end` - the end time of the timing if provided\n  * `timing.duration` - the duration of the timing if provided\n  * `timing.data` - the data for the timing if provided\n\n**`exit(timing)`**\n\n**`exit:chname(timing)`**\n\nIndicates a channel's timing has been exited. For example, if a timing has a `start` of `0` and a `duration` or `end` of `1000`, when the Kinetophone playback reaches 1000 milliseconds, an `exit` event will be emitted for that timing.\n\nEvent handlers for `exit` will fire for every channel's timings; event handlers for `exit:chname`, where `chname` is the name of a channel, will fire only for timings from that channel.\n\n* `chname` - the name of a channel, used to scope listeners to specific channels\n* `timing` - the channel timing exiting\n  * `timing.name` - the name of the channel the timing belongs to\n  * `timing.start` - the start time of the timing\n  * `timing.end` - the end time of the timing if provided\n  * `timing.duration` - the duration of the timing if provided\n  * `timing.data` - the data for the timing if provided\n\n**`play`**\n\nIndicates the Kinetophone was started or resumed.\n\n**`pause`**\n\nIndicates the Kinetophone was paused.\n\n**`timeupdate(time)`**\n\nIndicates the Kinetophone's playhead has moved. Also emitted after calling `currentTime(ms)`. Emitted before timings at the new time are entered/exited.\n\n* `time` - the current (new) playhead time\n\n**`seeking(time)`**\n\nIndicates the Kinetophone received a request to move the playhead to a new time using `currentTime(ms)`. Emitted before timings at the new time are entered/exited.\n\n**`seek(time)`**\n\nIndicates the Kinetophone's playhead was seeked to a specific time using `currentTime(ms)`. Emitted after the timings at the new time are entered/exited.\n\n* `time` - the time that was seeked to\n\n**`end`**\n\nIndicates the Kinetophone has stopped because it reached the end of its total duration.\n\n**`rateupdate(rate)`**\n\nIndicates the Kinetophone's playback rate has changed.\n\n### Channels\n\nA channel is a description of a series of related timings. For example, a single Kinetophone instance might contain a channel containing clips of audio to play at certain times in the timeline and another channel containing images to display at other times. Each channel has a name and an array of timings; every channel must have a unique name per Kinetophone instance.\n\nFrom a technical standpoint, a channel conforms to the following specification:\n\n```javascript\nvar channel = {\n  name: String,\n  timings: [Timing]\n};\n```\n\nwhere an timing is defined as:\n\n```javascript\n{\n  start: Number,\n  [end | duration: Number],\n  [data: Mixed]\n}\n```\n\n`start` is the time in milliseconds that the timing should start at; `end` is the time in milliseconds that the timing should end. You can pass `duration` instead of `end` and Kinetophone will calculate the end time for you, but you cannot pass both. If you pass neither, the timing will last for 1 millisecond. `data` is also optional, and if provided, can be any data that describes the timing.\n\nFor example, here's how you might define a channel that displays a different image every second for four seconds.\n\n```javascript\nvar imageChannel = {\n  name: \"images\",\n  timings: [\n    { start: 0,    end: 1000, data: { src: \"/public/image01.png\" } },\n    { start: 1000, end: 2000, data: { src: \"/public/image02.png\" } },\n    { start: 2000, end: 3000, data: { src: \"/public/image03.png\" } },\n    { start: 3000, end: 4000, data: { src: \"/public/image04.png\" } }\n  ]\n};\n```\n\nChannels can describe any data you want; while it's common to use them to describe when audio, video, or images should be displayed, you can use them to determine when you should preload data, when you should show or hide text, or when to execute arbitrary code.\n\nLicense\n-------\n\nKinetophone is licensed under the [MIT license](LICENSE).\n\n\u003e The MIT License (MIT)\n\u003e\n\u003e Copyright (c) 2015 Michelle Tilley\n\u003e\n\u003e Permission is hereby granted, free of charge, to any person obtaining a copy\n\u003e of this software and associated documentation files (the \"Software\"), to deal\n\u003e in the Software without restriction, including without limitation the rights\n\u003e to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n\u003e copies of the Software, and to permit persons to whom the Software is\n\u003e furnished to do so, subject to the following conditions:\n\u003e\n\u003e The above copyright notice and this permission notice shall be included in\n\u003e all copies or substantial portions of the Software.\n\u003e\n\u003e THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n\u003e IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n\u003e FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n\u003e AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n\u003e LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n\u003e OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n\u003e THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinarymuse%2Fkinetophone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinarymuse%2Fkinetophone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinarymuse%2Fkinetophone/lists"}