Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
accelerator-core
Advanced tools
[![Build Status](https://travis-ci.org/furkleindustries/accelerator-core.svg?branch=master)](https://travis-ci.org/furkleindustries/accelerator-core)
A lightweight, reactive hypertext fiction framework with the conveniences of modern web dev and few of the pain points. This repository is the framework's runtime, which is more or less what is generated for you when you use the Accelerator devtool (git repository, npm package) to create a new Accelerator project.
Accelerator was motivated by my desire to make Twine-style hypertext stories with the convenience and power of bleeding-edge web technologies and a fully-featured IDE. As such, it is probably a poor fit for someone who is not already a web programmer or doesn't wish to learn things like a command-line shell, React, or the modern JavaScript module system.
It is, however, a good choice if you want many or all of the following:
npm
and other such modern conveniences. Seriously, though, if what you want is to make a cool piece of interactive fiction, and not a bleeding-edge, industrial-quality web application which accomplishes the same, just use something else. This is not a magic bullet. It is rather a series of devtools, primitives, and build toolchains intended to make development of web-first interactive fiction more efficient and powerful for users who prefer command lines and code IDEs. Accelerate was built to interoperate best with Visual Studio Code, a free and open-source editor by Microsoft available here, but it will be nearly as powerful in any new IDE intended for web development.
In a command-line shell of your choice (assuming it has a modern version of npm
/npx
), do either:
npm install -g accelerator-tool
to install the tool to your environment, then:
xlr8r create %YOUR_STORY_NAME%
where %YOUR_STORY_NAME%
should be replaced by the obvious, or:
npx accelerator-tool create %YOUR_STORY_NAME%
to download a temporary copy of the tool and execute it once.
After a minute or so, the installation should be complete, and a folder named %YOUR_STORY_NAME%
will be in the specified directory.
An Accelerator story is notionally similar to a Twine story: it is a series of passages, joined by links. Each of these passages are TypeScript or JavaScript files which traditionally render one or more Markdown-React file, parsed by [mdx]. They contain a small amount of metadata and React component constructor (either a class implementing React.Component or React.PureComponent, or a stateless functional component) or a React element. Each is placed in the passages
directory.
To write a new passage, either use xlr8r new passage %YOUR_PASSAGE_NAME%
, or manually create a code file (ending in .jsx
or .tsx
) within the passages directory. A complete passage file will look something like this.
The exported object must be the passage object, and it must be the default export. You can use any valid JSX, including functional and class-based components. You may use any named export for whatever you please. You may also feel free to organize your files however you please, as Accelerator will search any number of folders deep within the passages
folder.
Note that passage files must end in .jsx
or .tsx
. This is convenient because it fits VS Code's syntax highlighting for files containing JSX elements, and also because it reserves all .js
or .ts
files for you to use and import as you see fit. Additionally, no files or folders in the base directory beginning with _
will be processed as passages.
If you are using TypeScript (allowing for the full value of Accelerator's built-in functionalities), you should indicate the type of the passage object by replacing const passage =
with const passage: passagesBundle.IPassage =
, and setting the props type of the React component to passagesBundle.IPassageProps
, importing these interfaces from ..//src/passages/passagesBundle
. This will allow full type-checking of your story passages. (You can also just destructure the bundle, or the passages property, so that you can refer directly to IPassage
and IPassageProps
.)
All Accelerator passages have simple access to the bundle imports, located in bundles/
. (Note that passages
and src/passages
are different folders with wholly different purposes.) Each bundle import is typically imported as so: import * as passages from '../../bundles/passages';
. There are at present four export bundles intended for common author reuse:
If
.If
.Iterator
. Uses no children and no props, and acts as a stand-in value to be replaced within the results list by each successive item in the collection.Click*
components.bar
and baz
from [ 'foo', 'bar', 'baz', 'bux', ]
.CyclingLink
, allowing cycling between any pieces of content (not just strings as with CyclingLink
), and aditionally accepts a callback which is fired when cycles are performed.OneOf
, and allows any random number (but not random order) of its children to be displayed.IPassage
, an interface detailing the properties of the passage object, which is the default export of all passage files.IPassageProps
, an interface detailing the properties passed to the content
property of the passage object, assuming content
is a React component.builtInStyles
, an CSS modules object containing the classes and IDs defined in the passage's base stylesheet (located at [/src/passages/passage.less]). This could be automatically used/injected, but I intend on making it as easy as possible to do without default styling. This may change in the future.tagsBundle
:BuiltInTags
, an enum which expresses the tags already configured for use by the Accelerator runtime.getTag
, a function which accepts a tag array and desired key, and produces either true
if the key was in the array as a plain string, or the value string if the key was the key property of a key-value tag.Tag
, the type alias for tags.There is also the pluginsBundle, which contains interfaces for plugins and the DebugPlugin
, and the actionsBundle, which contains Redux action interfaces and creator functions, if you want to e.g. manually dispatch built-in Accelerator actions with the dispatch
function.
For each passage, your ES6 class component (extending React.Component
or React.PureComponent
), or functional component (of type React.FunctionComponent
), or React's new stateful functional component types, will be passed relevant passage props automatically by the higher-order PassageContainer
component. These props, defined in IPassageProps
and IPassageFunctions
, are as follows:
config
, a normalized copy of the Accelerator configuration file as it existed at build-time. This is of type IAcceleratorConfigNormalized
.passageObject
, the object from your authored passage file. This is of type IPassage
.storyState
, a copy of the story state. Due to the way Redux and its bindings update components, this object will always be up-to-date, relative to the actual, hidden state store, and changes to it are pointless. If you want to change the story state, use setStoryState
.lastLinkTags
, a list of any tags which were attached to the link (or programmatic, "off-screen" equivalent) which caused the previous passage navigation action.soundManager
, a full installation of sound-manager, along with bindings to simply produce user-facing options affecting individual sounds or channels.setStoryState
, accepting an object of new state keys and values object as its single argument. This will automatically update the state and any rendered instances of it.navigateTo
, which allows passage navigation actions without the need for user-facing Link
components.bookmark
, which produces a new rewind point in the story.rewind
, which moves the story back a single passage in the history, and whatever number of timing ticks occurred on the current passage.restart
, which restarts the entire story and deletes all state whatsoever from a playthrough.dispatch
, a no-complexity wrapper of the Redux state store's dispatch
function, allowing lower-level dispatching of Redux actions. This will likely not be useful unless you're doing some sort of notional reflection with the Accelerator internals, or you're authoring your own actions and have modified the default state store accordingly.Accelerator includes many facilities to increase development velocity. Its development server comes bundled with hot-reloading, error reporting, and linting. In order to start the development server, run npm run start
. Note that you may need to shut down and restart the dev server if you add or remove a passage file. Otherwise, anything you change in your code should, to some extent, be reflected in the browser without the need for refreshes, renavigation, or story restarts. See Reasons to restart the dev environment for more details on what doesn't work well with hot reloading.
Accelerator uses Jest for testing. Basic tests are placed in each passage folder when a passage is generated by accelerator-tool
, and these should be added to validate any necessary logic or behavior. You should additionally, as a matter of good practice, write tests for any additional functions you write for your story.
You can run tests using npm run test
. By default, tests are only executed if they or the files they cover have changed since the last commit. They are also run by default in watch mode, which updates whenever you save a file under test coverage. You can run the tests outside of watch mode with npm run test -- --dontWatch
. You may additionally generate a full test coverage document (created by Jest using Istanbul) by appending the --coverage
option, like so: npm run test -- --dontWatch --coverage
.
To build the code bundle and HTML file for release on the web, run npm run build
. After this completes, the relevant files will be in build-web
. If you would also like to automatically create Electron desktop executables from your story, run npm run build-with-desktop
. Note that for technical reasons regarding Windows' treatment of symlinks when unzipping archives, it is not possible (as of 10/18) to build macOS executables on Windows machines. If you need a macOS executable, you can use this library on macOS or any Linux. The executables will be in distribution-specific folders in build-desktop
.
Many configuration semantics can be altered through the Accelerator config file. The default configuration file is located at accelerator.config.js, and is heavily commented. I have additionally reproduced the type signature of the configuration file below. Note that this is not the type signature of the normalized configuration provided at runtime to the Accelerator engine, which is represented by IAcceleratorConfigNormalized. Note that the debug
variable will cause significant changes in what is rendered to the screen, what sort of console messages are emitted, and potentially the performance of your application. This value is ignored when publishing; it is not possible to publish a debug version of the story with the toolchain, and means to make stats or debug-oriented builds through lower-level Webpack invocations are provided in scripts.
interface IAcceleratorConfig extends Record<string, any> {
readonly coreVersion: string;
readonly debug: boolean;
readonly historyStackLimit: number;
readonly historySaveTypes: OneOrMaybeReadonlyArray<string | ActionTypes>
readonly historySynchronizeUnrewindableStateWithPresent: boolean;
readonly publicUrl: string;
readonly rendererName: BuiltInRenderers | string;
readonly showMenu: boolean;
readonly storyDescription: string;
readonly storyTitle: string;
readonly toolVersion: string;
readonly fontsToLoad?: OneOrMaybeReadonlyArray<IFontLoadingDetails | string>;
readonly subsetFont?: IFontSubsettingDetails | string;
}
More information specifically on how to alter and override the default rendering semantics in Accelerator is located here.
You can instruct Accelerator to render specific pieces of content below or above each passage using headers and footers, respectively. Use the following xlr8r
command to create a new header:
xlr8r new header my-cool-header
and a new footer:
xlr8r new footer my-cool-header
.
Headers and footers are stored in the headers/
and footers/
directories, analogously to how passages are stored in passages/
. You may also generate
Construction of headers and footers is largely identical to the construction of passages, though headers and footers do not have tags of any kind. Both templates have an extra argument in the default export object, precedence
, which allows you to control the order in which headers and footers are rendered to the page. For example, a header with precedence of 4
will always be rendered above an header with precedence 3
. Headers and footers with no precedence property are rendered last. All headers and footers of the same precedence level are further sorted in lexicographic order. So, for example, a footer with precedence 3
and the name aardvark
will be rendered above a footer with precedence 3
and the name badger
, whereas badger
would be rendered first if it was of precedence 5
.
Accelerator also allows the use of plugins, which hook into lifecycle events in the Accelerator rendering and state cycles. The available lifecycle methods are as follows:
afterStoryInit
beforePassageChange
beforeRender
afterPassageChange
afterStoryStateChange
beforeRestart
Accelerator comes bundled with a single plugin, DebugPlugin, which is included automatically in the plugin stack if you are running the development server and the debug
property has been set to true
in the Accelerator config file. You may also consult the template (JavaScript version here) for further details on which methods receive which arguments.
Plugins follow the same precedence rules as headers and footers, and are stored in the plugins/
directory.
One important note is that, while it is generally true the beforeRender
method fires once and only once per passage navigation, this cannot be guaranteed. Therefore, try to assume this method may be called any number of times, and try to keep the logic there pure and separate from state mutation. If you want or need to update state within this method, try to be sure that the values are updated idempotently. That is, in pseudocode terms, set x to 5
, rather than set x to x + 1
, because the former will produce the same result no matter how many times it is performed, and the latter will not. Failing to abide this recommendation will likely result in confusing game-side behavior and complex debugging.
The Accelerator devtool (accelerator-tool
, aliased in installations and documentation as xlr8r
) uses templates to construct new passages. These templates are stored locally in src/templates
. Feel free to modify them as you see fit. Note that, given the inherent problems which result from using a strictly typed codefile as a template, there may be some linting errors in these templates, and cannot be tested or linted like normal codefiles. You may avoid these through liberal usage of // @ts-ignore
, but be aware that this will be copied into your template-built passages, and potentially conceal real issues later on.
There is also automatic rewriting of templated files generated by xlr8r new
based on some values in the configuration, most notably publicUrl
, which is used to build URLs correctly for installations on non-root server URLs, as well as storyTitle
and storyDescription
, which do what they sound like.
Like any software project, Accelerator is influenced by and indebted to the software I have used and enjoyed over the past couple years. The most prominent of those are:
The first six of these are also used extensively within Accelerator.
FAQs
[![Build Status](https://travis-ci.org/furkleindustries/accelerator-core.svg?branch=master)](https://travis-ci.org/furkleindustries/accelerator-core)
The npm package accelerator-core receives a total of 8 weekly downloads. As such, accelerator-core popularity was classified as not popular.
We found that accelerator-core demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.