{"id":15714419,"url":"https://github.com/jesselawson/campfirejs-prototype","last_synced_at":"2026-02-24T02:32:18.164Z","repository":{"id":71056141,"uuid":"139869598","full_name":"jesselawson/campfirejs-prototype","owner":"jesselawson","description":"A tiny, pure JS tool for writing interactive stories and experiences.","archived":false,"fork":false,"pushed_at":"2018-07-15T15:15:41.000Z","size":20299,"stargazers_count":4,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-07T07:34:39.899Z","etag":null,"topics":["interactive-storytelling","javascript","storytelling","text-based-game-engine"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jesselawson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2018-07-05T15:38:01.000Z","updated_at":"2024-07-26T12:55:26.000Z","dependencies_parsed_at":"2023-02-21T23:31:13.624Z","dependency_job_id":null,"html_url":"https://github.com/jesselawson/campfirejs-prototype","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/jesselawson/campfirejs-prototype","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesselawson%2Fcampfirejs-prototype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesselawson%2Fcampfirejs-prototype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesselawson%2Fcampfirejs-prototype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesselawson%2Fcampfirejs-prototype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jesselawson","download_url":"https://codeload.github.com/jesselawson/campfirejs-prototype/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesselawson%2Fcampfirejs-prototype/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29769176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T01:40:24.820Z","status":"online","status_checked_at":"2026-02-24T02:00:07.497Z","response_time":75,"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":["interactive-storytelling","javascript","storytelling","text-based-game-engine"],"created_at":"2024-10-03T21:36:41.723Z","updated_at":"2026-02-24T02:32:18.143Z","avatar_url":"https://github.com/jesselawson.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Campfire\n\n\u003cimg align=\"left\" width=\"100\" height=\"100\" src=\"campfire-logo.png\"\u003eA lightweight, pure JavaScript tool for writing interactive experiences. Think of Campfire as a set of \"if-this-then-that\" tools that let you work with the reader or player and provide feedback based on their actions and choices. \n\nGood use cases--and future examples--include games, books, courses, and more. \n\nThere's an interactive tutorial in development [here](https://codepen.io/lawsonry/full/wxaYqm/). Check it out!\n\n# Quick Start\n\nInclude `campfire.js` or `campfire.min.js` in your project. The most recent build of `campfire.min.js` can loaded with the following link:\n\n```html\n\u003cscript src=\"https://gitcdn.link/repo/lawsonry/campfirejs/master/dist/campfire.min.js\"\u003e\u003c/script\u003e\n```\n\nThis build will always correspond to the most recent release--and not necessarily the most recent version in the repository. \n\nWith Campfire loaded up, go on and write a cool, interactive experience. \n\n# Introduction\n\nCampfire is a single function that exports a ton of features for scaffolding a rich interactive experience. There are three main pieces to every Campfire experience: \n\n1. The `Campfire()` object\n2. The `onLoad()` function\n3. The `begin()` function\n\nThe most bare bones Campfire looks like this:\n\n```html\n\u003cscript\u003e\nvar story = new Campfire()\n\nstory.onLoad(function() {\n    // Anything you want to happen before the experience starts, such as element binding, calculations, etc.\n})\n\nstory.begin()\n\n\u003c/script\u003e\n```\n\n# Functionality\n\nThe rest of this readme will describe the delivered functionality of Campfire.\n\n## Triggers\n\nYou can create triggers based on a condition. There are two types of triggers: a **function** trigger, and an **event** trigger. In Campfire, **events** are little pieces of delivered functionality. \n\nFunction triggers will call a function when a given trigger occurs. \n\nEvent triggers can call an array of events, and may call a function when a given trigger occurs.\n\n### Basic Trigger\n\nA basic trigger has a condition--`trigger`--and something that happens when the trigger condition is true--`then`. Think of it like, when `trigger`, `then` (do something):\n\n```js\nvar story = new Campfire()\n\nstory.RegisterTrigger({\n    trigger: ()=\u003e { \n        document.readyState === 'complete' \n    },\n    then: ()=\u003e { \n        console.log(\"Hello, world!\")\n    }\n})\n```\n\nThe above trigger will write \"Hello, world!\" to the console window once the document object has entered the ready state. \n\nBasic triggers like this are great ways to ensure that you have a function that is called exactly one time during your story based on some condition. \n\n```js\nvar playerIsDead = false\nvar gameOver = false\n\nvar story = new Campfire()\n\nstory.RegisterTrigger({\n    trigger: ()=\u003e { return (playerIsDead) },\n    then: ()=\u003e{ \n        gameOver = true\n        document.getElementById('player-dead-message').classList.add('fade-in-message')\n    }\n})\n```\n\nThe above will create a trigger that will fire **once** as soon as `playerIsDead` is true.\n\nHere's another example: a trigger that uses your own custom functions:\n\n```js\nvar story = new Campfire()\n\nstory.RegisterTrigger({\n    trigger: PlayerIsDead(), then: HandleGameOver()\n})\n```\n\nThe above example would call `HandleGameOver()` exactly once when `PlayerIsDead()` returns true. \n\n### Event Triggers\n\nCampfire delivers a special type of trigger called an \"event trigger,\" which allows you to use any one of the delivered event methods inside your trigger. \n\nTwo of the most basic event methods are `addClass` and `removeClass`, which will add and remove a css class to a target element respectively:\n\n```js\nstory.RegisterTrigger({\n    trigger: function() {\n        // Some condition that must be true\n    },\n    events: [\n        {\n            targetId: 'my-element',\n            addClass: 'fade-in-text'\n        },\n        {\n            targetId: 'another-element',\n            removeClass: 'fade-to-black'\n        },\n        {\n            targetId: 'sidebar-meta',\n            setContent: 'Something is awry...'\n        }\n    ],\n    function() {\n        // Do these once all the triggers have fired\n    }\n})\n```\n\nThe `events` property can have as many events as you want that will be fired exactly once when the `trigger` condition is true. For a list of delivered events, see the documentation. \n\n### Checking on a trigger's status\n\nTriggers are not the same as callback functions, and therefore, you cannot call them \"directly\" per se. The whole point of triggers is that they wait for other things to change and then are handled in the background. \n\nCalling a trigger just requires you to think about conditions; what is the trigger's condition, and how can I change it? \n\nWhile you can't call a trigger directly per se, you *can* check on a trigger's status with `fired()`. \n\n`fired()` returns true or false, based on whether that trigger has been fired or not.\n\nLet's say you have the following trigger: \n\n```js\nvar story = new Campfire()\n\nstory.registerTrigger({\n    trigger: () =\u003e { return isSomethingTrue() },\n    then: () =\u003e { doSomething() }\n})\n```\n\nIn order to use the `fired()` function, you'll need to assign a `label:` to the trigger's parameter object:\n\n```js\nvar story = new Campfire()\n\nstory.registerTrigger({\n    label: 'something', \n    trigger: () =\u003e { return isSomethingTrue() },\n    then: () =\u003e { doSomething() }\n})\n```\n\nWith the `label:` element set, you can now get the status of this trigger:\n\n```js\nconsole.log( story.fired('something') )\n// Output: \"false\"\n```\n\nYou can even use a trigger's status as a condition for another trigger! Triggers that are fired when other triggers are fired. Imagine the inception!\n\n## Switches\n\nSwitches are simple string properties that either do or do not exist. They are useful for keeping track of **choices** that someone makes for the duration of their experience.\n\nThere are two functions involved: `remember()` and `recall()`, which set and retrieve the state of the switches, respectively.\n\n### Create a New Switch\n\nCreate a new switch with a single, unique string identifier:\n\n```js\nstory.remember('some memorable, unique string')\n```\n\nSet switches will always evaluate to `true` unless you explicitly declare this as one you want to evaluate to `false`:\n\n```js\nstory.remember('player loves puppies', false)\n```\n\n### Query a switch\n\n```js\nvar thisIsTrue = story.recall('some memorable, unique string')\nvar thisIsFalse = story.recall('player loves puppies')\nvar thisIsNull = story.recall('an unset switch')\n```\n\n### Switch Example \n\nI want to remember if a player takes longer than five seconds to save someone from having to experience more pain:\n\n```js\nvar story = new Campfire()\n\n// ...\n\nvar playerSadismTimer = setTimeout(function() { story.remember('ch1_player_likes_seeing_pain') }, 5000);\n\nfunction handleStopPainButton() {\n    clearTimout(playerSadismTimer)\n}\n```\n\n```html\n\u003ca id=\"player-sadism-button\" class=\"btn btn-lg\" onclick=\"handleStopPainButton()\"\u003eStop the Electrocution\u003c/a\u003e\n```\n\nIn the above example, if the player does not press the button (`#player-sadism-button`) in five seconds, the function `story.remember()` will be called and add `ch1_player_likes_seeing_pain` to Campfire's list of remembered switches. \n\nLater, I can write some dialogue like this:\n\n```html\n\u003cp\u003eYou always were different from others, weren't you? \u003cspan id=\"player-is-sadist\"\u003e\u003c/span\u003e Regardless, we have work to do.\u003c/p\u003e\n\n\u003c!-- ... --\u003e\n\n\u003cscript\u003e\nif( story.recall('ch1_player_likes_seeing_pain') ) {\n    document.getElementById('player-is-sadist').innerHTML = \"Your curiosity about the suffering of others is a little stronger than you ever anticipated, isn't it?\"\n}\n\u003c/script\u003e\n```\n\n### Integrated Example\n\nYou can use triggers to set switches, too:\n\n```js\nvar story = new Campfire()\n\nstory.registerTrigger({\n    trigger: () =\u003e { story.recall('player hates cheese') },\n    events: [\n        {\n            targetId: 'player-cheese-preferences',\n            setContent: 'Hates it!'\n        }\n    ]\n})\n```\n\nHere's another example. In a choose-your-own-adventure game I am working on, the player's interactions with NPCs is dependent on the player's karma--which, subsequently, is influenced by their choices. \n\nHere, the first time that `story.recall('player helped the paladin')` returns true, the function `AddKarmaToPlayer()` will fire--and it will fire exactly one time for the duration of the game. This allows you to use the trigger and switch systems together as a sort of pseudo-achievements system. \n\n```js\nvar story = new Campfire()\n\nstory.registerTrigger({\n    trigger: () =\u003e { story.recall('player helped the paladin') },\n    then: () =\u003e { AddKarmaToPlayer() }\n})\n```\n\n# Contributing\n\nFeel free to tackle some of the issues and/or submit your own new features as a merge request. \n\n## Getting Started\n\n1. Clone the repo and enter the dir with `git clone https://www.github.com/lawsonry/campfirejs \u0026\u0026 cd campfirejs`\n2. Install dev dependencies with `npm install`\n3. Do amazing things.\n4. Build the campfire.min.js file with `npm run-script build`\n\n## Testing\n\nCampfireJS uses the [TaoJS testing tool](https://www.github.com/lawsonry/taojs).\n\nTo use it, just run any dev server **in your project's root folder** and then navigate to `/tests`.\n\n**Running a dev server in Python**\n```bash\npython -m SimpleHTTPServer\n```\n\n**Running a dev server via Node and live-server**\n```bash\nnpm install -g live-server\nlive-server\n```\n\n**Running a dev server in PHP**\n```bash\nphp -S localhost:8080\n```\n\n# Changelog\n\n**0.1.2**\n\n* Add support for trigger label elements and `fired()` to check if a trigger has been fired or not\n\n**0.1.1**\n\n* Add support for switches with `remember` and `recall`\n\n**0.1.0**\n\n* Initial release","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjesselawson%2Fcampfirejs-prototype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjesselawson%2Fcampfirejs-prototype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjesselawson%2Fcampfirejs-prototype/lists"}