# Welcome Odyc.js is a tiny JavaScript library designed to create narrative games by combining pixels, sounds, text, and a bit of logic. Everything is built **through code**, but without unnecessary complexity: your entire game can fit in a single file. --- ## One Function to Make a Game Creating a game with Odyc.js is as simple as calling `createGame()`. You provide your sprites, dialogs, sounds, and interactions โ€” and the engine takes care of the rest. ```js createGame({ player: { sprite: 7, position: [2, 5] }, map: ` ######## #......# #..X...# #......# ######## `, templates: { X: { sprite: 4, dialog: 'Hello, adventurer!' } } }) ``` --- ## Where to Start? The documentation is organized into **three main sections**: ### ๐Ÿงฑ World Building Define the player, the map, sprites, sounds, and dialogs. ### โš™๏ธ Interaction & Logic Make your world interactive using events and game actions. ### ๐ŸŽจ Configuration Customize the appearance, filters, controls, colors, and screen. --- ## Questions or Ideas? Odyc.js is an open and free project. Youโ€™re welcome to contribute to the documentation, suggest ideas, or ask questions on [GitHub](https://github.com/achtaitaipai/odyc) or via email at [slt@charlescailleteau.com](mailto:slt@charlescailleteau.com). --- ๐Ÿ’ซ **Have fun!** --- # Getting Started with Odyc.js Want to create a game quickly? Here are **three ways to start**, depending on your preferences: --- ## Use the Online Editor The easiest way to get started is to use the [online editor](/playground). No setup required: just open the link and start coding your game directly in your browser. --- ## Use a CDN If you prefer working locally **without a complex setup**, you can import Odyc.js from a CDN. 1. Create an `index.html` file 2. Paste the following code: ```html ``` 3. Open the file in your browser. --- ## Use a Bundler (Vite, Webpackโ€ฆ) For more advanced projects, you can install Odyc.js via npm: ```bash npm install odyc ``` Then in your main JavaScript or TypeScript file: ```js import { createGame } from 'odyc' const game = createGame({ title: 'My Awesome Game' }) ``` --- # The Player The `player` is the character you control in the game. It is defined by two properties: **its appearance** and **its starting position**. --- ## Player Appearance The playerโ€™s appearance is set using the `sprite` property. It can be: ### A number between `0` and `9` In this case, the player will be shown as a solid-colored rectangle using the corresponding color: ```js createGame({ player: { sprite: 7 } }) ``` ### A string This allows you to define a more complex sprite, line by line. Each digit corresponds to a color, and `.` represents a transparent pixel: ```js createGame({ player: { sprite: ` ...44... ...88... ...88... .434434. 4.3443.4 1.3333.1 ..3333.. ..3..3.. ` } }) ``` --- ## Starting Position You can define the playerโ€™s initial position on the map using the `position` key. It should be an array in the form `[x, y]`, where `x` is the column and `y` is the row in the grid. For example, `[2, 5]` places the character in the 2nd column and 5th row (from the top): ```js createGame({ player: { sprite: 7, position: [3, 4] } }) ``` By default, the player appears at the top-left corner of the map, at position `[0, 0]`. --- # Sprites Like everything else in Odyc.js, sprites are defined directly in code. Theyโ€™re described using **strings**, a bit like _ASCII art_. ```js createGame({ player: { sprite: ` ...55... ...55... .000000. 0.0000.0 5.0000.5 ..3333.. ..3..3.. ..0..0.. ` } //... }) ``` --- ## A Simple Colored Block If you want an element to appear as a plain colored rectangle, just assign a single character that corresponds to a palette color: ```js sprite: '5' ``` --- ## Drawing Sprites Sometimes itโ€™s easier to draw than to explain. Use the editor below to try out how sprite definitions work. On one side, you can draw; on the other, youโ€™ll see the code string that represents your sprite. Each line represents a row of pixels, and each character is a pixel: - **Characters `0โ€“9`, `aโ€“z`, `Aโ€“Z`**: correspond to entries in your palette (up to 62 colors total) - **Newline**: starts a new row - **Spaces, tabs, blank lines**: are ignored - **Other characters**: represent transparent pixels (e.g. `.`) --- ## Sprite Inspiration Here are two useful resources for generating or browsing sprite ideas: - [Pixeltwist](https://pixeltwist.achtaitaipai.com/) โ€“ an infinite stream of random sprites. - [Baxel](https://baxel.achtaitaipai.com/) โ€“ a growing, open collection of community-created sprites. --- # Templates and the Map `templates` define all the objects in your game โ€” obstacles, items, characters, etc. Each template is associated with a unique character (e.g. `"X"`, `"$"`, `"e"`, `"#"`). You can then assign a set of properties to each template and place them in the `map`. --- ## Template properties Each template accepts the following properties: | Property | Default value | Description | | --------- | ------------- | ---------------------------------------------------------------------------------------------------------- | | `solid` | `false` | Determines whether the player can pass through the object. | | `visible` | `true` | Whether the sprite is visible or not. | | `sprite` | None | Defines the visual appearance of the object ([see sprites](/doc/world-building/sprites)). | | `sound` | None | Sound played when interacting with the object ([see sounds](/doc/world-building/sounds)). | | `dialog` | None | Dialog displayed when the player interacts with the object ([see dialogs](/doc/world-building/dialogues)). | | `end` | None | Ends the game with a custom message ([see title & end screen](/doc/world-building/title-and-end)). | ```js createGame({ templates: { r: { sprite: 6, sound: ['HIT', 999], visible: false, end: 'Game Over' }, g: { sprite: 7, dialog: "I'm grass.", solid: false } } }) ``` --- ## The Map The `map` defines how objects are arranged in the world using an ASCII grid. Each character in the grid corresponds to a `template`. ๐Ÿ’ก Creating a map is a lot like drawing a sprite! - Each character defined in `templates` is interpreted. - Spaces, tabs, and empty lines are ignored. - Any undefined character is treated as an empty cell. ```js createGame({ templates: { x: { sprite: 0 }, g: { sprite: 7 }, r: { sprite: 4 } }, map: ` xxxxxxxxxxxxxxxx x..............x x...........g..x x..............x x..............x x....r.........x x..............x xxxxxxxxxxxxxxxx ` }) ``` --- ## Dynamic Templates A `template` doesnโ€™t have to be a fixed object โ€” you can also define it as a **function that returns an object**. This is useful when you want to create elements that are **slightly different each time they appear**. For example, to create a wall where **each instance has a different color**: ```js createGame({ templates: { x: () => ({ sprite: Math.floor(Math.random() * 9) }) } //... }) ``` The function is called **every time an `x` element is placed on the map**. This lets you introduce variability or conditional logic into your game world. --- # Sounds Odyc.js uses **PFXR**, a lightweight JavaScript library made specifically for generating procedural sound effects. It allows you to create, customize, and play very compact audio assets. --- ## Defining a sound in a template A sound can be associated with a game element using the `sound` key. It will automatically be played when the player interacts with that element. ```js templates: { E: { sprite: 3, sound: "HIT" } } ``` --- ## Accepted formats The `sound` key accepts several formats: ### A preset name ```js sound: 'FALL' ``` Here's a list of available presets. Click a name to hear an example. Each click generates a random variation. Be careful with `RANDOM` โ€” turn your volume down before clicking. ### An array `[preset, seed]` If you want the sound to always be the same, you can specify a number (seed): ```js sound: ['LASER', 12345] ``` You can use the Sound tool in the playground to find the perfect sound. ### A PFXR URL You can create a custom sound using [the Pfxr interface](https://achtaitaipai.github.io/pfxr/) and paste the generated URL: ```js sound: 'https://achtaitaipai.github.io/pfxr/?fx=1,0.3,...' ``` ### A configuration object For full control, use an object describing the sound parameters: ```js sound: { waveForm: 2, frequency: 440, sustainTime: 0.2, decayTime: 0.5 } ``` You can find the complete list of parameters [here](https://github.com/achtaitaipai/pfxr/tree/main/packages/synth#sound). --- ## Global volume The overall sound volume can be adjusted via the `volume` key in the initial game configuration: ```js createGame({ volume: 0.8 }) ``` Default value: `0.5` --- # Dialogues Dialogues let you add conversations, hints, or narrative elements to your game. You can also enhance them with visual effects and color highlights. --- ## Defining a dialogue To assign a dialogue to a game element, use the `dialog` property in the `templates` section: ```javascript createGame({ templates: { '@': { dialog: 'Hello world!' } } }) ``` Every time the player interacts with the `@` element, a dialogue box will display `Hello world!`. --- ## Splitting a dialogue To force a line break, use the `|` character. ```js 'Hello!|How are you?|Have a great day!' ``` --- ## Adding effects and colors to text You can make your dialogue more expressive with simple syntax for **visual effects** and **color changes**.